First version, for githup; UNSTABLE, DO NOT USE!
This commit is contained in:
204
www/intern/scripts/einstellungen/ajax-upload-image.php
Normal file
204
www/intern/scripts/einstellungen/ajax-upload-image.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?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');
|
||||
|
||||
session_start();
|
||||
|
||||
|
||||
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
|
||||
http_response_code(403);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
$baseDir = $_SERVER['DOCUMENT_ROOT'];
|
||||
|
||||
|
||||
// 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
|
||||
]);
|
||||
Reference in New Issue
Block a user