From 9021dc699874c46b72dcbe019ec1a4408fbf6d70 Mon Sep 17 00:00:00 2001 From: polo Date: Tue, 30 Jun 2026 22:05:06 +0200 Subject: =?UTF-8?q?restore=5Fdb.php=20n'exclue=20plus=20la=20table=20'user?= =?UTF-8?q?',=20possibilit=C3=A9=20de=20restaurer=20une=20BDD=20vide=20ou?= =?UTF-8?q?=20incompl=C3=A8te?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/MaintenanceController.php | 4 +-- src/service/Backup.php | 59 +++++++++++++++++++------------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/controller/MaintenanceController.php b/src/controller/MaintenanceController.php index 1f8fadd..5b67fa8 100644 --- a/src/controller/MaintenanceController.php +++ b/src/controller/MaintenanceController.php @@ -103,7 +103,7 @@ class MaintenanceController if(pathinfo($selected_file)['extension'] !== 'sql'){ // pas censé se produire en fait throw new Exception("charger un fichier au format SQL"); } - Backup::restoreDatabase($entityManager, $selected_file); + Backup::restoreDatabase($entityManager, $selected_file, ['user']); $_SESSION['flash_message'] = "La base de données a été restaurée avec succès !!"; } @@ -134,7 +134,7 @@ class MaintenanceController $uploaded_file->move(Backup::$backup_dir, $server_place); // s'en servir - Backup::restoreDatabase($entityManager, $server_place); + Backup::restoreDatabase($entityManager, $server_place, ['user']); $_SESSION['flash_message'] = "La base de données a été restaurée avec succès !!"; } diff --git a/src/service/Backup.php b/src/service/Backup.php index 45593bb..c30ce5b 100644 --- a/src/service/Backup.php +++ b/src/service/Backup.php @@ -156,8 +156,7 @@ class Backup } } - // pattern "template method" - static public function restoreDatabase(EntityManager $entityManager, string $file_name): void + static public function restoreDatabase(EntityManager $entityManager, string $file_name, array $exclusion_list = []): void { // création d'un backup de sécurité non écrasable $date = new DateTime; @@ -168,20 +167,10 @@ class Backup $version = $entityManager->getConnection()->fetchOne('SELECT VERSION()'); $engine = stripos($version, 'mariadb') !== false ? 'mariadb' : 'mysql'; - // choisir les tables à restaurer - $tables = $entityManager->getConnection()->createSchemaManager()->listTableNames(); - foreach($tables as $key => $elem){ - if($elem === TABLE_PREFIX . 'user'){ - unset($tables[$key]); - } - } - // sécurité cas pas normal - if(empty($tables)){ - throw new RuntimeException("Aucune table à supprimer"); - } + $tables = self::getDBListOfTables($entityManager, $exclusion_list); // choisir les tables à effacer et restaurer, exclure "user" - $tmp = tempnam('../var', 'tmp_db_codes_'); // crée un fichier avec un nom aléatoire et des droits 600 (concurrence) - file_put_contents($tmp, + $tmp_db_codes = tempnam('../var', 'tmp_db_codes_'); // crée un fichier avec un nom aléatoire et des droits 600 (concurrence) + file_put_contents($tmp_db_codes, "[client]\n user=" . Config::$user . "\n password=" . Config::$password . "\n @@ -191,31 +180,53 @@ class Backup $command = new Process([ $engine, // mariadb ou mysql - '--defaults-extra-file=' . $tmp, // pour ne pas enregistrer les codes dans l'historique de la console ou dans les processus de l'OS + '--defaults-extra-file=' . $tmp_db_codes, // pour ne pas enregistrer les codes dans l'historique de la console ou dans les processus de l'OS Config::$database ]); $command->setInput(file_get_contents(Backup::$backup_dir . '/' . $file_name)); // l'entrée < - + // utiliser une liste de tables à exclure dynamique try{ // tout effacer $tables_with_backquotes = array_map(fn($t) => '`' . $t . '`', $tables); - $sql = "SET FOREIGN_KEY_CHECKS=0; DROP TABLE " . implode(', ', $tables_with_backquotes) . "; SET FOREIGN_KEY_CHECKS=1;"; - $entityManager->getConnection()->executeStatement($sql); + if(!empty($tables_with_backquotes)){ + $sql = "SET FOREIGN_KEY_CHECKS=0; DROP TABLE " . implode(', ', $tables_with_backquotes) . "; SET FOREIGN_KEY_CHECKS=1;"; + $entityManager->getConnection()->executeStatement($sql); + } - // la table user restante va poser problème - $entityManager->getConnection()->executeStatement('RENAME TABLE `' . TABLE_PREFIX . 'user` TO `' . TABLE_PREFIX . 'user_dont_touch`;'); + // copie des tables à ne pas restaurer + foreach($exclusion_list as $excluded){ + $entityManager->getConnection()->executeStatement('RENAME TABLE `' . TABLE_PREFIX . $excluded . '` TO `' . TABLE_PREFIX . $excluded . '_dont_touch`;'); + } // restaurer $command->mustRun(); // comme run() mais lance une ProcessFailedException // remettre table user comme avant - $entityManager->getConnection()->executeStatement('DROP TABLE `' . TABLE_PREFIX . 'user`;'); - $entityManager->getConnection()->executeStatement('RENAME TABLE `' . TABLE_PREFIX . 'user_dont_touch` TO `' . TABLE_PREFIX . 'user`;'); + foreach($exclusion_list as $excluded){ + $entityManager->getConnection()->executeStatement('DROP TABLE `' . TABLE_PREFIX . $excluded . '`;'); + $entityManager->getConnection()->executeStatement('RENAME TABLE `' . TABLE_PREFIX . $excluded . '_dont_touch` TO `' . TABLE_PREFIX . $excluded . '`;'); + } } finally{ // exécuté même quand situé après "return" - unlink($tmp); + unlink($tmp_db_codes); } } + + static private function getDBListOfTables(EntityManager $entityManager, array $exclusion_list = []): array + { + $tables = $entityManager->getConnection()->createSchemaManager()->listTableNames(); + foreach($tables as $key => $elem){ + foreach($exclusion_list as $excluded){ + if(!is_string($excluded)){ // cas pas du tout censé arriver! + throw new LogicException("Un nom de table doit etre une chaîne de caractères."); + } + if($elem === TABLE_PREFIX . $excluded){ + unset($tables[$key]); + } + } + } + return $tables; + } } \ No newline at end of file -- cgit v1.2.3