206 lines
5.8 KiB
PHP
206 lines
5.8 KiB
PHP
<?php
|
|
/**
|
|
* Upload Image API
|
|
* Accepts multipart/form-data POST with 'image' file.
|
|
* Converts JPG/PNG to WebP (resized to max 2400px), saves to /files/img/admin_upload/{uid}.webp
|
|
* Returns JSON: { success: true }
|
|
*/
|
|
|
|
// Allow large uploads and enough memory for GD processing
|
|
ini_set('memory_limit', '256M');
|
|
ini_set('upload_max_filesize', '50M');
|
|
ini_set('post_max_size', '55M');
|
|
ini_set('max_execution_time', '120');
|
|
|
|
const MAX_DIMENSION = 2400;
|
|
const MAX_DIMENSION_ICON = 1000;
|
|
const WEBP_QUALITY = 80;
|
|
|
|
$baseDir = $_SERVER['DOCUMENT_ROOT'];
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
if (!isset($baseDir)) {
|
|
$baseDir = $_SERVER['DOCUMENT_ROOT'];
|
|
}
|
|
|
|
require_once $baseDir . '/../scripts/session_functions.php';
|
|
|
|
ini_wkvs_session();
|
|
|
|
check_user_permission('wk_leitung');
|
|
|
|
verify_csrf();
|
|
|
|
|
|
// Only accept POST
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
http_response_code(405);
|
|
echo json_encode(['success' => false, 'message' => 'Method not allowed']);
|
|
exit;
|
|
}
|
|
|
|
$allowedTypes = ['Kampfrichter', 'Trainer', 'Wk_leitung', 'Otl', 'icon', 'logo-normal'];
|
|
|
|
if (!isset($_POST['type']) || !in_array($_POST['type'], $allowedTypes)) {
|
|
http_response_code(400);
|
|
echo json_encode(['success' => false, 'message' => 'Typ nicht angegeben oder nicht erlaubt']);
|
|
exit;
|
|
}
|
|
|
|
$pngs = ['icon', 'logo-normal'];
|
|
|
|
$type = $_POST['type'];
|
|
$isIcon = in_array($type, $pngs);
|
|
|
|
// Check if $_FILES is empty entirely (can happen if post_max_size exceeded)
|
|
if (empty($_FILES)) {
|
|
http_response_code(400);
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => 'No files received. The file may exceed the server upload limit).',
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// Check specific file field
|
|
if (!isset($_FILES['image'])) {
|
|
http_response_code(400);
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => 'No "image" field in upload. Received fields: ' . implode(', ', array_keys($_FILES)),
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
if ($_FILES['image']['error'] !== UPLOAD_ERR_OK) {
|
|
http_response_code(400);
|
|
$errors = [
|
|
UPLOAD_ERR_INI_SIZE => 'File exceeds upload_max_filesize',
|
|
UPLOAD_ERR_FORM_SIZE => 'File exceeds form MAX_FILE_SIZE',
|
|
UPLOAD_ERR_PARTIAL => 'File was only partially uploaded',
|
|
UPLOAD_ERR_NO_FILE => 'No file was uploaded',
|
|
UPLOAD_ERR_NO_TMP_DIR => 'Missing temp directory',
|
|
UPLOAD_ERR_CANT_WRITE => 'Failed to write to disk',
|
|
];
|
|
$code = $_FILES['image']['error'];
|
|
$msg = $errors[$code] ?? "Unknown error code: $code";
|
|
echo json_encode(['success' => false, 'message' => $msg]);
|
|
exit;
|
|
}
|
|
|
|
$file = $_FILES['image'];
|
|
$tmpPath = $file['tmp_name'];
|
|
|
|
// Validate MIME type
|
|
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
|
$mime = $finfo->file($tmpPath);
|
|
|
|
$allowedMimes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
|
|
if (!in_array($mime, $allowedMimes, true)) {
|
|
http_response_code(415);
|
|
echo json_encode(['success' => false, 'message' => "Unsupported file type: $mime"]);
|
|
exit;
|
|
}
|
|
|
|
// Target directory
|
|
|
|
|
|
if ($isIcon) {
|
|
$uploadDir = $baseDir . '/intern/img/';
|
|
} else {
|
|
$uploadDir = $baseDir . '/intern/img/login';
|
|
}
|
|
|
|
if (!is_dir($uploadDir)) {
|
|
mkdir($uploadDir, 0755, true);
|
|
}
|
|
|
|
// Load image into GD
|
|
$srcImage = null;
|
|
switch ($mime) {
|
|
case 'image/jpeg':
|
|
$srcImage = @imagecreatefromjpeg($tmpPath);
|
|
break;
|
|
case 'image/png':
|
|
$srcImage = @imagecreatefrompng($tmpPath);
|
|
break;
|
|
case 'image/webp':
|
|
$srcImage = @imagecreatefromwebp($tmpPath);
|
|
break;
|
|
case 'image/gif':
|
|
$srcImage = @imagecreatefromgif($tmpPath);
|
|
break;
|
|
}
|
|
|
|
if (!$srcImage) {
|
|
http_response_code(500);
|
|
echo json_encode(['success' => false, 'message' => 'Failed to load image into GD. It may be corrupt or too large.']);
|
|
exit;
|
|
}
|
|
|
|
|
|
// ── Resize if needed ────────────────────────────────
|
|
$origW = imagesx($srcImage);
|
|
$origH = imagesy($srcImage);
|
|
|
|
$maxDimension = ($isIcon) ? MAX_DIMENSION_ICON : MAX_DIMENSION;
|
|
|
|
if ($origW > $maxDimension || $origH > $maxDimension) {
|
|
// Calculate new dimensions keeping aspect ratio
|
|
if ($origW >= $origH) {
|
|
$newW = $maxDimension;
|
|
$newH = intval(round($origH * ($maxDimension / $origW)));
|
|
} else {
|
|
$newH = $maxDimension;
|
|
$newW = intval(round($origW * ($maxDimension / $origH)));
|
|
}
|
|
|
|
$resized = imagecreatetruecolor($newW, $newH);
|
|
|
|
// Preserve transparency
|
|
imagealphablending($resized, false);
|
|
imagesavealpha($resized, true);
|
|
$transparent = imagecolorallocatealpha($resized, 0, 0, 0, 127);
|
|
imagefill($resized, 0, 0, $transparent);
|
|
|
|
imagecopyresampled($resized, $srcImage, 0, 0, 0, 0, $newW, $newH, $origW, $origH);
|
|
imagedestroy($srcImage);
|
|
$srcImage = $resized;
|
|
} else {
|
|
// Still preserve transparency
|
|
imagepalettetotruecolor($srcImage);
|
|
imagealphablending($srcImage, true);
|
|
imagesavealpha($srcImage, true);
|
|
}
|
|
|
|
if ($isIcon) {
|
|
// ── Save as PNG ────────────────────────────────────
|
|
$filename = $type . '.png';
|
|
$destPath = $uploadDir . '/' . $filename;
|
|
$webPath = '/intern/img/' . $filename;
|
|
|
|
$pngCompression = 6;
|
|
|
|
$success = imagepng($srcImage, $destPath, $pngCompression);
|
|
} else {
|
|
// ── Save as WebP ────────────────────────────────────
|
|
$filename = 'bg' . $_POST['type'] . '.webp';
|
|
$destPath = $uploadDir . '/' . $filename;
|
|
$webPath = '/intern/img/admin_upload/' . $filename;
|
|
|
|
$success = imagewebp($srcImage, $destPath, WEBP_QUALITY);
|
|
}
|
|
|
|
imagedestroy($srcImage);
|
|
|
|
if (!$success) {
|
|
http_response_code(500);
|
|
echo json_encode(['success' => false, 'message' => 'Failed to convert to WebP']);
|
|
exit;
|
|
}
|
|
|
|
echo json_encode([
|
|
'success' => true
|
|
]);
|