MAX_FILE_MB * 1024 * 1024) { jsonError("File too large. Max " . MAX_FILE_MB . " MB."); exit; } // MIME دقيق $finfo = new finfo(FILEINFO_MIME_TYPE); $mime = $finfo->file($tmpPath) ?: 'application/octet-stream'; if (!in_array($mime, ALLOWED_MIMES, true)) { jsonError("Unsupported file type: $mime"); exit; } // لاحقة الامتداد $extMap = [ 'image/jpeg' => '.jpg', 'image/png' => '.png', 'image/webp' => '.webp', ]; $ext = $extMap[$mime]; // --------- توليد مسار حتمي بدون تاريخ --------- // تنظيف driver_id لاسم ملف آمن $driverIdSafe = preg_replace('/[^A-Za-z0-9_\-]/', '_', $driverId); // شجرة مجلدات ثابتة من hash(driver_id) لتوزيع الملفات $h = hash('sha1', $driverIdSafe); $subdir = substr($h, 0, 2) . '/' . substr($h, 2, 2); $destDir = UPLOAD_ROOT . '/' . $subdir; if (!is_dir($destDir)) { @mkdir($destDir, 0700, true); } // الاسم النهائي بدون تاريخ $serverName = "{$driverIdSafe}__{$docType}{$ext}"; $destPath = $destDir . '/' . $serverName; // استبدال أي نسخة قديمة عن قصد (overwrite) if (is_file($destPath)) { @unlink($destPath); } // نقل الملف if (!move_uploaded_file($tmpPath, $destPath)) { jsonError("Failed to save the uploaded file."); exit; } @chmod($destPath, 0600); // --------- Signed URL --------- // سنضمّن driver_id و doc_type و ext في الرابط والتوقيع. // ext بدون النقطة $extShort = ltrim($ext, '.'); $expires = time() + SIGNED_TTL_SEC; // الرسالة الموقّعة: driver_id:doc_type:ext:expires $message = $driverIdSafe . ':' . $docType . ':' . $extShort . ':' . $expires; $signature = hash_hmac('sha256', $message, SIGN_SECRET); // رابط القراءة عبر البوابة الآمنة فقط // ملاحظة: لا نُرجع المسار الحقيقي، فقط معطيات موقّعة $fileUrl = PUBLIC_BASE . "/secure_image.php" . "?driver_id={$driverIdSafe}" . "&doc_type={$docType}" . "&ext={$extShort}" . "&expires={$expires}" . "&signature={$signature}"; // --------- استجابة --------- printSuccess([ "status" => "success", "success_file" => true, "file_url" => $fileUrl, "file_name" => $serverName, // الاسم الفعلي المحفوظ "driver_id" => $driverIdSafe, "doc_type" => $docType, "mime_type" => $mime, "size_bytes" => $size, "expires_at" => date('c', $expires) ]);