<?php if (!defined('DASHBOARD_ROOT')) define('DASHBOARD_ROOT', realpath(__DIR__ . '/../..')); require_once DASHBOARD_ROOT . '/api/bootstrap.php'; header('Content-Type: application/json'); if ($_SERVER['REQUEST_METHOD'] !== 'POST') { exit(json_encode(['success' => false, 'error' => 'POST required'])); } CSRF::enforce(); RBAC::enforce('modify.content'); $itemId = (int)($_POST['item_id'] ?? 0); if (!$itemId) { exit(json_encode(['success' => false, 'error' => 'item_id required'])); } if (empty($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) { exit(json_encode(['success' => false, 'error' => 'No image uploaded'])); } $allowed = ['jpg', 'jpeg', 'png', 'webp', 'gif']; $ext = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION)); if (!in_array($ext, $allowed, true)) { exit(json_encode(['success' => false, 'error' => 'Invalid file type'])); } $finfo = new finfo(FILEINFO_MIME_TYPE); $mime = $finfo->file($_FILES['image']['tmp_name']); $allowedMimes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']; if (!in_array($mime, $allowedMimes, true)) { exit(json_encode(['success' => false, 'error' => 'Invalid file content'])); } $maxSize = 5 * 1024 * 1024; if ($_FILES['image']['size'] > $maxSize) { exit(json_encode(['success' => false, 'error' => 'File too large (max 5MB)'])); } $uploadDir = DASHBOARD_ROOT . '/../public/uploads/builder/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); } $filename = bin2hex(random_bytes(16)) . '.' . $ext; $destPath = $uploadDir . $filename; if (!move_uploaded_file($_FILES['image']['tmp_name'], $destPath)) { exit(json_encode(['success' => false, 'error' => 'Upload failed'])); } $url = '/uploads/builder/' . $filename; Database::execute("UPDATE order_items SET product_image_url = :u WHERE id = :id", [':u' => $url, ':id' => $itemId]); exit(json_encode(['success' => true, 'url' => $url])); 