diff options
| author | polo <ordipolo@gmx.fr> | 2026-05-11 01:20:16 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2026-05-11 01:20:16 +0200 |
| commit | 80de6834a11734c6d3e047635b63ec93f2f68345 (patch) | |
| tree | e1484030b4b87bc8e0b3ebb26b933f722aaba932 /src/service | |
| parent | 895cf7a438929f74c2e11996667685245a571f2a (diff) | |
| download | cms-80de6834a11734c6d3e047635b63ec93f2f68345.tar.gz cms-80de6834a11734c6d3e047635b63ec93f2f68345.tar.bz2 cms-80de6834a11734c6d3e047635b63ec93f2f68345.zip | |
restauration complète de la BDD (sauf table user)
Diffstat (limited to 'src/service')
| -rw-r--r-- | src/service/Backup.php | 66 | ||||
| -rw-r--r-- | src/service/router.php | 62 |
2 files changed, 114 insertions, 14 deletions
diff --git a/src/service/Backup.php b/src/service/Backup.php index 313d1f6..63368b5 100644 --- a/src/service/Backup.php +++ b/src/service/Backup.php | |||
| @@ -8,12 +8,12 @@ use Symfony\Component\Process\Process; // protection injection dans le shell | |||
| 8 | 8 | ||
| 9 | class Backup | 9 | class Backup |
| 10 | { | 10 | { |
| 11 | static private string $backup_dir = '../var/backups'; | 11 | static public string $backup_dir = '../var/backups'; |
| 12 | static private int $amount_to_keep = 30; | 12 | static private int $amount_to_keep = 30; |
| 13 | 13 | ||
| 14 | static public function mySQLdump(EntityManager $entityManager): string | 14 | static public function mySQLdump(EntityManager $entityManager, string $type): string |
| 15 | { | 15 | { |
| 16 | $file_path = self::$backup_dir . '/db_' . Config::$database . '_' . new DateTime()->format('Y-m-d') . '.sql'; | 16 | $file_path = self::$backup_dir . '/' . Config::$database . '_' . new DateTime()->format('Y-m-d') . '_' . $type . '.sql'; |
| 17 | 17 | ||
| 18 | // les versions de mysql sont comme ci: 8.0.36 | 18 | // les versions de mysql sont comme ci: 8.0.36 |
| 19 | // celles de mariadb sont comme ça: 10.11.6-MariaDB | 19 | // celles de mariadb sont comme ça: 10.11.6-MariaDB |
| @@ -89,4 +89,64 @@ class Backup | |||
| 89 | unlink($file); | 89 | unlink($file); |
| 90 | } | 90 | } |
| 91 | } | 91 | } |
| 92 | |||
| 93 | static public function restoreDatabase(EntityManager $entityManager, string $file_name): void | ||
| 94 | { | ||
| 95 | // backup de sécurité | ||
| 96 | Backup::mySQLdump($entityManager, 'before-restore'); | ||
| 97 | |||
| 98 | $version = $entityManager->getConnection()->fetchOne('SELECT VERSION()'); | ||
| 99 | $engine = stripos($version, 'mariadb') !== false ? 'mariadb' : 'mysql'; | ||
| 100 | |||
| 101 | // choisir les tables à restaurer | ||
| 102 | $tables = $entityManager->getConnection()->createSchemaManager()->listTableNames(); | ||
| 103 | foreach($tables as $key => $elem){ | ||
| 104 | if($elem === TABLE_PREFIX . 'user'){ | ||
| 105 | unset($tables[$key]); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | // sécurité cas pas normal | ||
| 109 | if(empty($tables)){ | ||
| 110 | throw new Exception("Aucune table à supprimer"); | ||
| 111 | } | ||
| 112 | |||
| 113 | $tmp = tempnam('../var', 'tmp_db_codes_'); // crée un fichier avec un nom aléatoire et des droits 600 (concurrence) | ||
| 114 | file_put_contents($tmp, | ||
| 115 | "[client]\n | ||
| 116 | user=" . Config::$user . "\n | ||
| 117 | password=" . Config::$password . "\n | ||
| 118 | host=" . Config::$db_host . "\n"); | ||
| 119 | |||
| 120 | |||
| 121 | |||
| 122 | $command = new Process([ | ||
| 123 | $engine, // mariadb ou mysql | ||
| 124 | '--defaults-extra-file=' . $tmp, // pour ne pas enregistrer les codes dans l'historique de la console ou dans les processus de l'OS | ||
| 125 | Config::$database | ||
| 126 | ]); | ||
| 127 | $command->setInput(file_get_contents(Backup::$backup_dir . '/' . $file_name)); // l'entrée < | ||
| 128 | |||
| 129 | |||
| 130 | |||
| 131 | try{ | ||
| 132 | // tout effacer | ||
| 133 | $tables_with_backquotes = array_map(fn($t) => '`' . $t . '`', $tables); | ||
| 134 | $sql = "SET FOREIGN_KEY_CHECKS=0; DROP TABLE " . implode(', ', $tables_with_backquotes) . "; SET FOREIGN_KEY_CHECKS=1;"; | ||
| 135 | $entityManager->getConnection()->executeStatement($sql); | ||
| 136 | |||
| 137 | // la table user restante va poser problème | ||
| 138 | $entityManager->getConnection()->executeStatement('RENAME TABLE `' . TABLE_PREFIX . 'user` TO `' . TABLE_PREFIX . 'user_dont_touch`;'); | ||
| 139 | |||
| 140 | // restaurer | ||
| 141 | $command->mustRun(); // comme run() mais lance une ProcessFailedException | ||
| 142 | |||
| 143 | // remettre table user comme avant | ||
| 144 | $entityManager->getConnection()->executeStatement('DROP TABLE `' . TABLE_PREFIX . 'user`;'); | ||
| 145 | $entityManager->getConnection()->executeStatement('RENAME TABLE `' . TABLE_PREFIX . 'user_dont_touch` TO `' . TABLE_PREFIX . 'user`;'); | ||
| 146 | } | ||
| 147 | finally{ | ||
| 148 | // exécuté même quand situé après "return" | ||
| 149 | unlink($tmp); | ||
| 150 | } | ||
| 151 | } | ||
| 92 | } \ No newline at end of file | 152 | } \ No newline at end of file |
diff --git a/src/service/router.php b/src/service/router.php index 98f8fd6..8ddaf7f 100644 --- a/src/service/router.php +++ b/src/service/router.php | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | // src/service/router.php | 2 | // src/service/router.php |
| 3 | // | 3 | // |
| 4 | /* fonctionnement: | 4 | /* fonctionnement: |
| 5 | => 1er test, méthode http: GET, POST ou autre chose | 5 | => 1er test, méthode http GET? POST? |
| 6 | => 2ème test, type de contenu (méthode POST uniquement): | 6 | => 2ème test, type de contenu (méthode POST uniquement): |
| 7 | "application/x-www-form-urlencoded" = formulaire | 7 | "application/x-www-form-urlencoded" = formulaire |
| 8 | "application/json" = requête AJAX avec fetch() | 8 | "application/json" = requête AJAX avec fetch() |
| @@ -46,7 +46,7 @@ if($request->getMethod() === 'GET'){ | |||
| 46 | 46 | ||
| 47 | if(IS_ADMIN === true){ | 47 | if(IS_ADMIN === true){ |
| 48 | if($request->query->has('action') && $request->query->get('action') === 'get_mysqldump'){ | 48 | if($request->query->has('action') && $request->query->get('action') === 'get_mysqldump'){ |
| 49 | MaintenanceController::getLastDump($entityManager); | 49 | MaintenanceController::getLastDump(); |
| 50 | die; | 50 | die; |
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| @@ -88,7 +88,6 @@ elseif($request->getMethod() === 'POST'){ | |||
| 88 | } | 88 | } |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | |||
| 92 | if(IS_ADMIN === true) | 91 | if(IS_ADMIN === true) |
| 93 | { | 92 | { |
| 94 | /* -- requêtes AJAX -- */ | 93 | /* -- requêtes AJAX -- */ |
| @@ -244,8 +243,8 @@ elseif($request->getMethod() === 'POST'){ | |||
| 244 | } | 243 | } |
| 245 | } | 244 | } |
| 246 | 245 | ||
| 247 | // upload avec FormData | 246 | /* -- upload avec FormData OU formulaire HTML AVEC fichier -- */ |
| 248 | elseif(strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false) | 247 | elseif(str_starts_with($request->headers->get('Content-Type'), 'multipart/form-data')) // = $_SERVER['CONTENT_TYPE'] |
| 249 | { | 248 | { |
| 250 | // dans tinymce avec le plugin (bouton "insérer une image" de l'éditeur ou glisser-déposer) | 249 | // dans tinymce avec le plugin (bouton "insérer une image" de l'éditeur ou glisser-déposer) |
| 251 | if($request->query->has('action') && $request->query->get('action') === 'upload_image_tinymce'){ | 250 | if($request->query->has('action') && $request->query->get('action') === 'upload_image_tinymce'){ |
| @@ -258,17 +257,38 @@ elseif($request->getMethod() === 'POST'){ | |||
| 258 | elseif($request->query->has('head_foot_image')){ | 257 | elseif($request->query->has('head_foot_image')){ |
| 259 | HeadFootController::uploadAsset($entityManager, $request->query->get('head_foot_image')); | 258 | HeadFootController::uploadAsset($entityManager, $request->query->get('head_foot_image')); |
| 260 | } | 259 | } |
| 260 | |||
| 261 | /* -- page Maintenance -- */ | ||
| 262 | elseif($request->query->has('action') && $request->query->get('action') === 'restore_database' | ||
| 263 | && $request->request->has('hidden') && $request->get('hidden') === '' | ||
| 264 | && $request->files->has('uploaded_sql')) | ||
| 265 | { | ||
| 266 | $url = new URL; | ||
| 267 | if($request->query->has('from')){ | ||
| 268 | $url->addParams(['page' => $request->query->get('from')]); | ||
| 269 | } | ||
| 270 | |||
| 271 | try{ | ||
| 272 | MaintenanceController::downloadSQL($entityManager, $request->files->get('uploaded_sql')); | ||
| 273 | $url->addParams(['database_restauration' => 'successful']); | ||
| 274 | } | ||
| 275 | catch(Exception $e){ | ||
| 276 | $url->addParams(['database_restauration' => $e->getMessage()]); | ||
| 277 | } | ||
| 278 | |||
| 279 | header('Location: ' . $url); | ||
| 280 | die; | ||
| 281 | } | ||
| 261 | } | 282 | } |
| 262 | 283 | ||
| 263 | // requêtes XMLHttpRequest | 284 | // requêtes XMLHttpRequest |
| 264 | elseif(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') | 285 | elseif(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') |
| 265 | { | 286 | { |
| 266 | //echo "requête XMLHttpRequest reçue par le serveur"; | ||
| 267 | echo json_encode(['success' => false]); // noyer le poisson en laissant penser que le site gère les requêtes XHR | 287 | echo json_encode(['success' => false]); // noyer le poisson en laissant penser que le site gère les requêtes XHR |
| 268 | die; | 288 | die; |
| 269 | } | 289 | } |
| 270 | 290 | ||
| 271 | /* -- envoi formulaire HTML -- */ | 291 | /* -- formulaire HTML SANS fichier -- */ |
| 272 | elseif($_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded') | 292 | elseif($_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded') |
| 273 | { | 293 | { |
| 274 | if($request->query->has('action') && $request->query->get('action') === 'delete_article' && isset($_GET['id'])){ | 294 | if($request->query->has('action') && $request->query->get('action') === 'delete_article' && isset($_GET['id'])){ |
| @@ -294,7 +314,6 @@ elseif($request->getMethod() === 'POST'){ | |||
| 294 | 314 | ||
| 295 | 315 | ||
| 296 | /* -- mode Modification d'une page -- */ | 316 | /* -- mode Modification d'une page -- */ |
| 297 | |||
| 298 | // modification du chemins en snake_case | 317 | // modification du chemins en snake_case |
| 299 | elseif(isset($_POST['page_menu_path']) && $_POST['page_menu_path'] !== null | 318 | elseif(isset($_POST['page_menu_path']) && $_POST['page_menu_path'] !== null |
| 300 | && isset($_POST['page_id']) && $_POST['page_id'] !== null | 319 | && isset($_POST['page_id']) && $_POST['page_id'] !== null |
| @@ -318,7 +337,6 @@ elseif($request->getMethod() === 'POST'){ | |||
| 318 | 337 | ||
| 319 | 338 | ||
| 320 | /* -- page Menu et chemins -- */ | 339 | /* -- page Menu et chemins -- */ |
| 321 | |||
| 322 | // création d'une entrée de menu avec une URL | 340 | // création d'une entrée de menu avec une URL |
| 323 | elseif(isset($_POST["label_input"]) && isset($_POST["url_input"]) && isset($_POST["location"])){ | 341 | elseif(isset($_POST["label_input"]) && isset($_POST["url_input"]) && isset($_POST["location"])){ |
| 324 | MenuAndPathsController::newUrlMenuEntry($entityManager); | 342 | MenuAndPathsController::newUrlMenuEntry($entityManager); |
| @@ -339,12 +357,35 @@ elseif($request->getMethod() === 'POST'){ | |||
| 339 | UserController::updatePassword($entityManager); | 357 | UserController::updatePassword($entityManager); |
| 340 | } | 358 | } |
| 341 | 359 | ||
| 360 | /* -- page Maintenance -- */ | ||
| 361 | elseif($request->query->has('action') && $request->query->get('action') === 'restore_database' | ||
| 362 | && $request->request->has('hidden') && $request->get('hidden') === '' | ||
| 363 | && $request->request->has('selected_sql')) | ||
| 364 | { | ||
| 365 | $url = new URL; | ||
| 366 | if($request->query->has('from')){ | ||
| 367 | $url->addParams(['page' => $request->query->get('from')]); | ||
| 368 | } | ||
| 369 | |||
| 370 | try{ | ||
| 371 | MaintenanceController::handleBackupSelection($entityManager, $request->request->get('selected_sql')); | ||
| 372 | $url->addParams(['database_restauration' => 'successful']); | ||
| 373 | } | ||
| 374 | catch(Exception $e){ | ||
| 375 | $url->addParams(['database_restauration' => $e->getMessage()]); | ||
| 376 | } | ||
| 377 | |||
| 378 | header('Location: ' . $url); | ||
| 379 | die; | ||
| 380 | } | ||
| 381 | |||
| 342 | // redirection page d'accueil | 382 | // redirection page d'accueil |
| 343 | else{ | 383 | else{ |
| 344 | header("Location: " . new URL(['error' => 'paramètres inconnus'])); | 384 | header("Location: " . new URL(['error' => 'paramètres inconnus'])); |
| 345 | die; | 385 | die; |
| 346 | } | 386 | } |
| 347 | } | 387 | } |
| 388 | |||
| 348 | // POST admin ne matchant pas | 389 | // POST admin ne matchant pas |
| 349 | else{ | 390 | else{ |
| 350 | echo json_encode(['success' => false]); | 391 | echo json_encode(['success' => false]); |
| @@ -393,5 +434,4 @@ else{ | |||
| 393 | http_response_code(500); | 434 | http_response_code(500); |
| 394 | echo "erreur côté serveur"; | 435 | echo "erreur côté serveur"; |
| 395 | } | 436 | } |
| 396 | } | 437 | } \ No newline at end of file |
| 397 | //die; // inutile \ No newline at end of file | ||
