Files
WKVS/www/intern/scripts/einstellungen/ajax-upload-image.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
]);