Actualiser api.php

This commit is contained in:
2026-06-19 14:17:51 +02:00
parent 22aabe7d49
commit a97ece2e0a
+89 -94
View File
@@ -5,21 +5,18 @@ header("Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization"); header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Pragma: no-cache"); header("Pragma: no-cache");
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200); http_response_code(200);
exit; exit;
} }
define('ENCRYPTION_KEY', 'MaCleSecreteSuperRobuste123!'); define('ENCRYPTION_KEY', 'MaCleSecreteSuperRobuste123!');
try { try {
$pdo = new PDO("mysql:host=localhost;dbname=mon_cinema;charset=utf8mb4", "root", "", [ $pdo = new PDO("mysql:host=localhost;dbname=mon_cinema;charset=utf8mb4", "root", "", [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]); ]);
// Création des tables (ajout de la table config) // Création des tables (rating changé en DECIMAL(3,1) pour accepter les notes Letterboxd comme 2.5, 3.5)
$pdo->exec("CREATE TABLE IF NOT EXISTS users ( $pdo->exec("CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY, username VARCHAR(50) NOT NULL, password_hash VARCHAR(255) NOT NULL id INT PRIMARY KEY, username VARCHAR(50) NOT NULL, password_hash VARCHAR(255) NOT NULL
)"); )");
@@ -27,12 +24,12 @@ try {
key_name VARCHAR(50) PRIMARY KEY, key_value TEXT NOT NULL key_name VARCHAR(50) PRIMARY KEY, key_value TEXT NOT NULL
)"); )");
$pdo->exec("CREATE TABLE IF NOT EXISTS critiques ( $pdo->exec("CREATE TABLE IF NOT EXISTS critiques (
id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL, year VARCHAR(10), director VARCHAR(255), id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL, year VARCHAR(10), director VARCHAR(255),
poster TEXT, rating INT DEFAULT 3, review TEXT, streaming VARCHAR(255) poster TEXT, rating DECIMAL(3,1) DEFAULT 3.0, review TEXT, streaming VARCHAR(255)
)"); )");
$pdo->exec("CREATE TABLE IF NOT EXISTS videotheque ( $pdo->exec("CREATE TABLE IF NOT EXISTS videotheque (
id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL, year VARCHAR(10), director VARCHAR(255), id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL, year VARCHAR(10), director VARCHAR(255),
poster TEXT, format VARCHAR(50), length VARCHAR(50), publisher VARCHAR(255), ean_isbn13 VARCHAR(50), poster TEXT, format VARCHAR(50), length VARCHAR(50), publisher VARCHAR(255), ean_isbn13 VARCHAR(50),
number_of_discs INT DEFAULT 1, aspect_ratio VARCHAR(50), description TEXT number_of_discs INT DEFAULT 1, aspect_ratio VARCHAR(50), description TEXT
)"); )");
} catch (\PDOException $e) { } catch (\PDOException $e) {
@@ -48,13 +45,11 @@ function makeStableId($title, $year) {
function checkAuth($pdo) { function checkAuth($pdo) {
$stmtCheck = $pdo->query("SELECT COUNT(*) FROM users"); $stmtCheck = $pdo->query("SELECT COUNT(*) FROM users");
if ($stmtCheck->fetchColumn() == 0) return true; if ($stmtCheck->fetchColumn() == 0) return true;
$token = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; $token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (empty($token) && function_exists('apache_request_headers')) { if (empty($token) && function_exists('apache_request_headers')) {
$headers = apache_request_headers(); $headers = apache_request_headers();
$token = $headers['Authorization'] ?? $headers['authorization'] ?? ''; $token = $headers['Authorization'] ?? $headers['authorization'] ?? '';
} }
if ($token !== md5(ENCRYPTION_KEY . 'session')) { if ($token !== md5(ENCRYPTION_KEY . 'session')) {
http_response_code(403); http_response_code(403);
echo json_encode(["error" => "Accès interdit."]); echo json_encode(["error" => "Accès interdit."]);
@@ -62,8 +57,6 @@ function checkAuth($pdo) {
} }
} }
// ── FONCTIONS TMDB & CHIFFREMENT ──
function encryptData($data) { function encryptData($data) {
$iv = openssl_random_pseudo_bytes(16); $iv = openssl_random_pseudo_bytes(16);
$key = hash('sha256', ENCRYPTION_KEY, true); $key = hash('sha256', ENCRYPTION_KEY, true);
@@ -93,7 +86,6 @@ function getTmdbApiKey($pdo) {
function fetchTmdbData($title, $year, $apiKey) { function fetchTmdbData($title, $year, $apiKey) {
if (empty($apiKey) || empty($title)) return null; if (empty($apiKey) || empty($title)) return null;
$searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($title) . "&year={$year}&language=fr-FR"; $searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($title) . "&year={$year}&language=fr-FR";
$searchRes = @file_get_contents($searchUrl); $searchRes = @file_get_contents($searchUrl);
if (!$searchRes && function_exists('curl_init')) { if (!$searchRes && function_exists('curl_init')) {
@@ -104,14 +96,11 @@ function fetchTmdbData($title, $year, $apiKey) {
curl_close($ch); curl_close($ch);
} }
if (!$searchRes) return null; if (!$searchRes) return null;
$searchData = json_decode($searchRes, true); $searchData = json_decode($searchRes, true);
if (empty($searchData['results'])) return null; if (empty($searchData['results'])) return null;
$movie = $searchData['results'][0]; $movie = $searchData['results'][0];
$movieId = $movie['id']; $movieId = $movie['id'];
$poster = !empty($movie['poster_path']) ? "https://image.tmdb.org/t/p/w500" . $movie['poster_path'] : ''; $poster = !empty($movie['poster_path']) ? "https://image.tmdb.org/t/p/w500" . $movie['poster_path'] : '';
$creditsUrl = "https://api.themoviedb.org/3/movie/{$movieId}/credits?api_key={$apiKey}&language=fr-FR"; $creditsUrl = "https://api.themoviedb.org/3/movie/{$movieId}/credits?api_key={$apiKey}&language=fr-FR";
$creditsRes = @file_get_contents($creditsUrl); $creditsRes = @file_get_contents($creditsUrl);
if (!$creditsRes && function_exists('curl_init')) { if (!$creditsRes && function_exists('curl_init')) {
@@ -121,7 +110,6 @@ function fetchTmdbData($title, $year, $apiKey) {
$creditsRes = curl_exec($ch); $creditsRes = curl_exec($ch);
curl_close($ch); curl_close($ch);
} }
$director = ''; $director = '';
if ($creditsRes) { if ($creditsRes) {
$creditsData = json_decode($creditsRes, true); $creditsData = json_decode($creditsRes, true);
@@ -134,21 +122,18 @@ function fetchTmdbData($title, $year, $apiKey) {
} }
} }
} }
return ['director' => $director, 'poster' => $poster]; return ['director' => $director, 'poster' => $poster];
} }
// ── ROUTEUR PRINCIPAL ── // ── ROUTEUR PRINCIPAL ──
$action = $_GET['action'] ?? ''; $action = $_GET['action'] ?? '';
$data = json_decode(file_get_contents('php://input'), true) ?? []; $data = json_decode(file_get_contents('php://input'), true) ?? [];
switch ($action) { switch ($action) {
case 'check_security_status': case 'check_security_status':
$stmt = $pdo->query("SELECT COUNT(*) FROM users"); $stmt = $pdo->query("SELECT COUNT(*) FROM users");
echo json_encode(["is_blank" => ($stmt->fetchColumn() == 0)]); echo json_encode(["is_blank" => ($stmt->fetchColumn() == 0)]);
break; break;
case 'login': case 'login':
$stmt = $pdo->query("SELECT COUNT(*) FROM users"); $stmt = $pdo->query("SELECT COUNT(*) FROM users");
if ($stmt->fetchColumn() == 0) { if ($stmt->fetchColumn() == 0) {
@@ -165,7 +150,7 @@ switch ($action) {
} }
} }
break; break;
case 'setup_admin': case 'setup_admin':
case 'update_password': case 'update_password':
checkAuth($pdo); checkAuth($pdo);
@@ -174,8 +159,7 @@ switch ($action) {
$stmt->execute([':pass' => password_hash($pwd, PASSWORD_BCRYPT)]); $stmt->execute([':pass' => password_hash($pwd, PASSWORD_BCRYPT)]);
echo json_encode(["success" => true]); echo json_encode(["success" => true]);
break; break;
// ── NOUVELLE ACTION : SAUVEGARDE DE LA CLÉ EN BASE ──
case 'save_config': case 'save_config':
checkAuth($pdo); checkAuth($pdo);
$keyName = $data['key_name'] ?? ''; $keyName = $data['key_name'] ?? '';
@@ -190,19 +174,18 @@ switch ($action) {
echo json_encode(["error" => "Données invalides."]); echo json_encode(["error" => "Données invalides."]);
} }
break; break;
case 'get_films': case 'get_films':
$crit = $pdo->query("SELECT *, 'critique' AS type FROM critiques ORDER BY id DESC")->fetchAll(); $crit = $pdo->query("SELECT *, 'critique' AS type FROM critiques ORDER BY id DESC")->fetchAll();
$video = $pdo->query("SELECT *, 'videotheque' AS type FROM videotheque ORDER BY id DESC")->fetchAll(); $video = $pdo->query("SELECT *, 'videotheque' AS type FROM videotheque ORDER BY id DESC")->fetchAll();
echo json_encode(array_merge($crit, $video)); echo json_encode(array_merge($crit, $video));
break; break;
case 'save_film': case 'save_film':
checkAuth($pdo); checkAuth($pdo);
$type = $data['type'] ?? 'critique'; $type = $data['type'] ?? 'critique';
$id = !empty($data['id']) ? $data['id'] : makeStableId($data['title'] ?? '', $data['year'] ?? '0000'); $id = !empty($data['id']) ? $data['id'] : makeStableId($data['title'] ?? '', $data['year'] ?? '0000');
// 🔍 RÉCUPÉRATION AUTO TMDB SI CHAMPS VIDES
if (empty($data['director']) || empty($data['poster'])) { if (empty($data['director']) || empty($data['poster'])) {
$apiKey = getTmdbApiKey($pdo); $apiKey = getTmdbApiKey($pdo);
$tmdbData = fetchTmdbData($data['title'] ?? '', $data['year'] ?? '', $apiKey); $tmdbData = fetchTmdbData($data['title'] ?? '', $data['year'] ?? '', $apiKey);
@@ -211,7 +194,7 @@ switch ($action) {
if (empty($data['poster'])) $data['poster'] = $tmdbData['poster']; if (empty($data['poster'])) $data['poster'] = $tmdbData['poster'];
} }
} }
if ($type === 'critique') { if ($type === 'critique') {
$sql = "INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming) $sql = "INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming)
VALUES (?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
@@ -219,7 +202,7 @@ switch ($action) {
$stmt = $pdo->prepare($sql); $stmt = $pdo->prepare($sql);
$stmt->execute([ $stmt->execute([
$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '',
$data['poster'] ?? '', $data['rating'] ?? 3, $data['review'] ?? '', $data['streaming'] ?? '' $data['poster'] ?? '', $data['rating'] ?? 3.0, $data['review'] ?? '', $data['streaming'] ?? ''
]); ]);
} else { } else {
$sql = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description) $sql = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description)
@@ -235,7 +218,7 @@ switch ($action) {
} }
echo json_encode(["success" => true]); echo json_encode(["success" => true]);
break; break;
case 'delete_film': case 'delete_film':
checkAuth($pdo); checkAuth($pdo);
$type = $_GET['type'] ?? 'critique'; $type = $_GET['type'] ?? 'critique';
@@ -246,7 +229,7 @@ switch ($action) {
$stmt->execute([$id]); $stmt->execute([$id]);
echo json_encode(["success" => true]); echo json_encode(["success" => true]);
break; break;
case 'bulk_delete': case 'bulk_delete':
checkAuth($pdo); checkAuth($pdo);
$ids = $data['ids'] ?? []; $ids = $data['ids'] ?? [];
@@ -262,81 +245,93 @@ switch ($action) {
echo json_encode(["success" => false, "error" => "Aucun élément sélectionné."]); echo json_encode(["success" => false, "error" => "Aucun élément sélectionné."]);
} }
break; break;
case 'import_csv': case 'import_csv':
checkAuth($pdo); checkAuth($pdo);
if (isset($_FILES['csv_file'])) { if (isset($_FILES['csv_file'])) {
$file = $_FILES['csv_file']['tmp_name']; $file = $_FILES['csv_file']['tmp_name'];
$type = $_POST['type'] ?? 'critique'; $type = $_POST['type'] ?? 'critique';
$tmdbApiKey = getTmdbApiKey($pdo);
// On récupère la clé une seule fois pour tout l'import try {
$tmdbApiKey = getTmdbApiKey($pdo); if (($handle = fopen($file, "r")) !== FALSE) {
$header = fgetcsv($handle, 0, ",");
if (($handle = fopen($file, "r")) !== FALSE) { if (!$header) throw new Exception("Impossible de lire l'en-tête du CSV.");
$header = fgetcsv($handle, 0, ",");
$header = array_map('trim', $header);
while (($row = fgetcsv($handle, 0, ",")) !== FALSE) {
if (count($row) !== count($header)) continue;
$rowData = array_combine($header, $row);
$title = $rowData['Name'] ?? $rowData['title'] ?? 'Sans titre'; // 🧹 Nettoyage du BOM UTF-8 (très fréquent sur les exports Letterboxd/Excel)
$year = $rowData['Year'] ?? $rowData['year'] ?? '0000'; $header[0] = str_replace("\xEF\xBB\xBF", '', $header[0]);
$director = $rowData['Director'] ?? $rowData['director'] ?? ''; $header = array_map('trim', $header);
$poster = $rowData['Poster'] ?? $rowData['poster'] ?? $rowData['image'] ?? '';
// 🔍 RÉCUPÉRATION AUTO TMDB SI CHAMPS VIDES DANS LE CSV $imported = 0;
if (empty($director) || empty($poster)) { while (($row = fgetcsv($handle, 0, ",")) !== FALSE) {
$tmdbData = fetchTmdbData($title, $year, $tmdbApiKey); if (count($row) !== count($header)) continue; // Ignore les lignes vides ou mal formées
if ($tmdbData) {
if (empty($director)) $director = $tmdbData['director']; $rowData = array_combine($header, $row);
if (empty($poster)) $poster = $tmdbData['poster']; $title = $rowData['Name'] ?? $rowData['title'] ?? 'Sans titre';
$year = $rowData['Year'] ?? $rowData['year'] ?? '0000';
$director = $rowData['Director'] ?? $rowData['director'] ?? '';
$poster = $rowData['Poster'] ?? $rowData['poster'] ?? $rowData['image'] ?? '';
if (empty($director) || empty($poster)) {
$tmdbData = fetchTmdbData($title, $year, $tmdbApiKey);
if ($tmdbData) {
if (empty($director)) $director = $tmdbData['director'];
if (empty($poster)) $poster = $tmdbData['poster'];
}
} }
$id = makeStableId($title, $year);
if ($type === 'critique') {
// 🌟 Conservation de la précision Letterboxd (2.5, 3.5, etc.)
$rating = isset($rowData['Rating']) && $rowData['Rating'] !== '' ? (float)$rowData['Rating'] : 3.0;
$review = $rowData['Review'] ?? $rowData['review'] ?? '';
$streaming = $rowData['Streaming'] ?? $rowData['streaming'] ?? '';
$sql = "INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
rating = VALUES(rating),
review = IF(VALUES(review) != '', VALUES(review), review),
director = IF(VALUES(director) != '', VALUES(director), director),
poster = IF(VALUES(poster) != '', VALUES(poster), poster),
streaming = IF(VALUES(streaming) != '', VALUES(streaming), streaming)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $title, $year, $director, $poster, $rating, $review, $streaming]);
} else {
$format = $rowData['format'] ?? $rowData['Format'] ?? '';
$length = $rowData['length'] ?? $rowData['Length'] ?? '';
$publisher = $rowData['publisher'] ?? $rowData['Publisher'] ?? '';
$ean = $rowData['ean_isbn13'] ?? $rowData['EAN'] ?? '';
$discs = $rowData['number_of_discs'] ?? 1;
$aspect = $rowData['aspect_ratio'] ?? '';
$desc = $rowData['description'] ?? $rowData['Description'] ?? '';
$sql = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
director = IF(VALUES(director) != '', VALUES(director), director),
poster = IF(VALUES(poster) != '', VALUES(poster), poster),
format = IF(VALUES(format) != '', VALUES(format), format),
length = IF(VALUES(length) != '', VALUES(length), length),
publisher = IF(VALUES(publisher) != '', VALUES(publisher), publisher),
ean_isbn13 = IF(VALUES(ean_isbn13) != '', VALUES(ean_isbn13), ean_isbn13),
number_of_discs = IF(VALUES(number_of_discs) != 1, VALUES(number_of_discs), number_of_discs),
aspect_ratio = IF(VALUES(aspect_ratio) != '', VALUES(aspect_ratio), aspect_ratio),
description = IF(VALUES(description) != '', VALUES(description), description)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $title, $year, $director, $poster, $format, $length, $publisher, $ean, $discs, $aspect, $desc]);
}
$imported++;
} }
fclose($handle);
$id = makeStableId($title, $year); echo json_encode(["success" => true, "imported" => $imported]);
} else {
if ($type === 'critique') { throw new Exception("Impossible d'ouvrir le fichier.");
$rating = isset($rowData['Rating']) ? (int)round($rowData['Rating'] * 1) : 3;
$review = $rowData['Review'] ?? $rowData['review'] ?? '';
$streaming = $rowData['Streaming'] ?? $rowData['streaming'] ?? '';
$sql = "INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
rating = VALUES(rating),
review = IF(VALUES(review) != '', VALUES(review), review),
director = IF(VALUES(director) != '', VALUES(director), director),
poster = IF(VALUES(poster) != '', VALUES(poster), poster),
streaming = IF(VALUES(streaming) != '', VALUES(streaming), streaming)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $title, $year, $director, $poster, $rating, $review, $streaming]);
} else {
$format = $rowData['format'] ?? $rowData['Format'] ?? '';
$length = $rowData['length'] ?? $rowData['Length'] ?? '';
$publisher = $rowData['publisher'] ?? $rowData['Publisher'] ?? '';
$ean = $rowData['ean_isbn13'] ?? $rowData['EAN'] ?? '';
$discs = $rowData['number_of_discs'] ?? 1;
$aspect = $rowData['aspect_ratio'] ?? '';
$desc = $rowData['description'] ?? $rowData['Description'] ?? '';
$sql = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
director = IF(VALUES(director) != '', VALUES(director), director),
poster = IF(VALUES(poster) != '', VALUES(poster), poster),
format = IF(VALUES(format) != '', VALUES(format), format),
length = IF(VALUES(length) != '', VALUES(length), length),
publisher = IF(VALUES(publisher) != '', VALUES(publisher), publisher),
ean_isbn13 = IF(VALUES(ean_isbn13) != '', VALUES(ean_isbn13), ean_isbn13),
number_of_discs = IF(VALUES(number_of_discs) != 1, VALUES(number_of_discs), number_of_discs),
aspect_ratio = IF(VALUES(aspect_ratio) != '', VALUES(aspect_ratio), aspect_ratio),
description = IF(VALUES(description) != '', VALUES(description), description)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $title, $year, $director, $poster, $format, $length, $publisher, $ean, $discs, $aspect, $desc]);
}
} }
fclose($handle); } catch (Exception $e) {
http_response_code(500);
echo json_encode(["error" => "Erreur lors de l'import : " . $e->getMessage()]);
} }
echo json_encode(["success" => true]);
} else { } else {
http_response_code(400); http_response_code(400);
echo json_encode(["error" => "Aucun fichier reçu."]); echo json_encode(["error" => "Aucun fichier reçu."]);