false, 'error' => 'Méthode non autorisée.']); exit; } if (!isset($_POST['csrf_token'], $_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { http_response_code(403); header('Content-Type: application/json; charset=utf-8'); echo json_encode(['ok' => false, 'error' => 'CSRF invalide.']); exit; } $trashFile = trim($_POST['trash_file'] ?? ''); $trashFiles = $_POST['trash_files'] ?? []; if (!is_array($trashFiles)) $trashFiles = []; // Normalise: accept both single (trash_file) and bulk (trash_files[]) $allTrashFiles = $trashFile !== '' ? [$trashFile] : $trashFiles; $allTrashFiles = array_values(array_filter(array_map('trim', $allTrashFiles), fn($n) => $n !== '')); if (empty($allTrashFiles)) { http_response_code(400); header('Content-Type: application/json; charset=utf-8'); echo json_encode(['ok' => false, 'error' => 'Aucun fichier spécifié.']); exit; } require_once __DIR__ . '/../../../src/Database.php'; $db = new Database(); $storageRoot = STORAGE_ROOT; $trashDir = $storageRoot . '/tmp/_trash'; $restored = 0; $skipped = 0; $errors = []; foreach ($allTrashFiles as $trashFile) { $trashFile = basename($trashFile); $trashPath = $trashDir . '/' . $trashFile; $sidecarPath = $trashPath . '.json'; if (!is_file($trashPath) || !str_starts_with(realpath($trashPath), realpath($trashDir))) { $skipped++; $errors[] = "$trashFile : introuvable dans la corbeille."; continue; } if (!file_exists($sidecarPath)) { $skipped++; $errors[] = "$trashFile : métadonnées absentes (trop ancien ?)."; continue; } $sidecar = json_decode(file_get_contents($sidecarPath), true); if (!is_array($sidecar) || empty($sidecar['file_path']) || empty($sidecar['thesis_id'])) { $skipped++; $errors[] = "$trashFile : métadonnées corrompues."; continue; } $originalPath = $sidecar['file_path']; $thesisId = (int)$sidecar['thesis_id']; $fileType = $sidecar['file_type'] ?? 'other'; $fileName = $sidecar['file_name'] ?? basename($originalPath); $mimeType = $sidecar['mime_type'] ?? 'application/octet-stream'; $fileSize = (int)($sidecar['file_size'] ?? 0); $displayLabel = $sidecar['display_label'] ?? null; $thesis = $db->getThesis($thesisId); if (!$thesis) { $skipped++; $errors[] = "$trashFile : le TFE #$thesisId n'existe plus."; continue; } $absOriginal = $storageRoot . '/' . $originalPath; if (file_exists($absOriginal)) { @unlink($trashPath); @unlink($sidecarPath); $skipped++; $errors[] = "$trashFile : un fichier existe déjà à l'emplacement d'origine."; continue; } $parentDir = dirname($absOriginal); if (!is_dir($parentDir)) { mkdir($parentDir, 0755, true); } if (!rename($trashPath, $absOriginal)) { $skipped++; $errors[] = "$trashFile : échec du déplacement."; continue; } chmod($absOriginal, 0644); @unlink($sidecarPath); $db->insertThesisFile( $thesisId, $fileType, $originalPath, $fileName, $fileSize, $mimeType, $displayLabel, null ); $newId = $db->getConnection()->lastInsertId(); error_log("[restore-trash] thesis_id=$thesisId file_id=$newId restored: $trashFile → $originalPath"); $restored++; } $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); if (isset($_SERVER['HTTP_HX_REQUEST'])) { header('HX-Trigger: refreshStats'); require __DIR__ . '/cleanup-stats-fragment.php'; exit; } header('Content-Type: application/json; charset=utf-8'); echo json_encode([ 'ok' => $restored > 0, 'restored' => $restored, 'skipped' => $skipped, 'errors' => $errors, 'message' => $restored . ' fichier(s) restauré(s).' . ($skipped > 0 ? ' ' . $skipped . ' ignoré(s).' : ''), ]); exit;