upload files

This commit is contained in:
2025-10-17 18:43:12 +03:00
parent 8f76cc9a8a
commit 71bb073934
7 changed files with 456 additions and 0 deletions

141
index.php Normal file
View File

@@ -0,0 +1,141 @@
<?php
declare(strict_types=1);
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
/* === API: upload skin === */
if ($method === 'POST' && $path === '/upload') {
$name = $_POST['username'] ?? '';
if (!preg_match('/^[A-Za-z0-9_]{2,16}$/', $name)) return err('Неправильний нік (216, латиниця/цифри/_).');
$tmp = require_png_upload('file');
[$w, $h] = must_image_size($tmp);
if (!($w === 64 && ($h === 64 || $h === 128))) return err('Скін має бути 64×64 або 64×128.');
$img = @imagecreatefrompng($tmp) ?: err('Пошкоджений PNG.');
if (!is_dir(__DIR__ . '/skins')) @mkdir(__DIR__ . '/skins', 0755, true);
$dest = __DIR__ . "/skins/{$name}.png";
@imagepng($img, $dest) ?: err('Не вдалося зберегти (права на ./skins).');
imagedestroy($img);
json_ok(['skin_url' => base() . "/skins/{$name}.png", 'username' => $name]);
}
/* === API: upload cape === */
if ($method === 'POST' && $path === '/upload-cape') {
$name = $_POST['username'] ?? '';
if (!preg_match('/^[A-Za-z0-9_]{2,16}$/', $name)) return err('Неправильний нік (216, латиниця/цифри/_).');
$tmp = require_png_upload('file');
[$w, $h] = must_image_size($tmp);
// Плащ: співвідношення 2:1, мінімум 64×32, кратні двійці (типові 64×32, 128×64, 256×128, …)
if (!($w === 2 * $h && $w >= 64 && $h >= 32)) {
return err("Плащ має бути зі співвідношенням 2:1 (64×32, 128×64, …). Отримано {$w}×{$h}.");
}
$img = @imagecreatefrompng($tmp) ?: err('Пошкоджений PNG.');
if (!is_dir(__DIR__ . '/capes')) @mkdir(__DIR__ . '/capes', 0755, true);
$dest = __DIR__ . "/capes/{$name}.png";
@imagepng($img, $dest) ?: err('Не вдалося зберегти (права на ./capes).');
imagedestroy($img);
json_ok(['cape_url' => base() . "/capes/{$name}.png", 'username' => $name]);
}
/* === UI === */
if ($method === 'GET' && $path === '/') {
header('Content-Type: text/html; charset=utf-8');
echo <<<HTML
<!doctype html>
<html lang="uk">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MSS - MrAkells Skin Server</title>
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="stylesheet" href="assets/style.css">
</head>
<body>
<div class="shell">
<div class="card">
<form id="form" class="form" autocomplete="off">
<div class="segment" role="tablist" aria-label="Тип">
<button type="button" class="segbtn active" id="seg-skin" aria-selected="true">Скін</button>
<button type="button" class="segbtn" id="seg-cape" aria-selected="false">Плащ</button>
</div>
<div>
<div class="lbl">Нікнейм</div>
<input class="input" name="username" id="username" placeholder="Наприклад, Notch" minlength="2" maxlength="16" pattern="[A-Za-z0-9_]{2,16}" required>
</div>
<div>
<div class="lbl">Файл PNG</div>
<input class="input" type="file" id="file" name="file" accept="image/png" required>
</div>
<button class="btn" id="submit" type="submit">Завантажити</button>
</form>
</div>
</div>
<div id="toasts"></div>
<a href="https://t.me/mrakells" class="credit" target="_blank" rel="noopener">by&nbsp;MrAkells</a>
<script src="assets/app.js"></script>
</body>
</html>
HTML;
exit;
}
/* === 404 === */
http_response_code(404);
header('Content-Type: text/plain; charset=utf-8');
echo "Not Found";
exit;
/* === helpers === */
function err(string $m): void
{
header('Content-Type: application/json; charset=utf-8', true, 400);
echo json_encode(['status' => 'error', 'error' => $m], JSON_UNESCAPED_UNICODE);
exit;
}
function json_ok(array $extra): void
{
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['status' => 'ok'] + $extra, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
exit;
}
function require_png_upload(string $key): string
{
if (!isset($_FILES[$key]) || $_FILES[$key]['error'] !== UPLOAD_ERR_OK) err('Файл не завантажено.');
$tmp = $_FILES[$key]['tmp_name'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $tmp);
finfo_close($finfo);
if ($mime !== 'image/png') err('Лише PNG.');
return $tmp;
}
function must_image_size(string $tmp): array
{
$info = @getimagesize($tmp);
if (!$info) err('Не PNG.');
return [$info[0], $info[1]];
}
function base(): string
{
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (($_SERVER['SERVER_PORT'] ?? '') === '443');
$scheme = $https ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
return $scheme . '://' . $host;
}