From 2c47085b27253c4ad2d062d15c18c3a8c7591298 Mon Sep 17 00:00:00 2001 From: polo Date: Sun, 10 May 2026 13:50:30 +0200 Subject: =?UTF-8?q?mysqldump,=20t=C3=A9l=C3=A9chargement=20d'un=20.sql=20e?= =?UTF-8?q?t=20stockage=20des=20sauvegardes=20dans=20/var/backups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + composer.json | 3 +- config/index.php | 4 ++ public/js/maintenance.js | 4 +- src/controller/MaintenanceController.php | 19 +++++++++ src/service/Backup.php | 70 ++++++++++++++++++++++++++++++++ src/service/Installation.php | 47 ++++++++++++++------- src/service/router.php | 5 ++- src/view/templates/form.php | 3 +- src/view/templates/maintenance.php | 12 +++++- 10 files changed, 145 insertions(+), 23 deletions(-) create mode 100644 config/index.php create mode 100644 src/service/Backup.php diff --git a/.gitignore b/.gitignore index 7b51759..2856821 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ vendor/ +var/ config/config.ini public/js/tinymce public/js/tinymce-langs diff --git a/composer.json b/composer.json index dd8aa9c..caf5a8c 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "symfony/http-foundation": "^7.3", "twbs/bootstrap-icons": "^1.13", "symfony/var-exporter": "^7.0", - "mklkj/tinymce-i18n": "^25.11" + "mklkj/tinymce-i18n": "^25.11", + "symfony/process": "^8.0" }, "scripts": { "post-install-cmd": [ diff --git a/config/index.php b/config/index.php new file mode 100644 index 0000000..f2fdd42 --- /dev/null +++ b/config/index.php @@ -0,0 +1,4 @@ + { @@ -26,7 +26,7 @@ function cleanLogs(){ } const log_table = getElementOrThrow('log_table'); - let fetcher = new Fetcher({ + const fetcher = new Fetcher({ endpoint: 'index.php?action=erase_logs', method: 'POST', onSuccess: () => { diff --git a/src/controller/MaintenanceController.php b/src/controller/MaintenanceController.php index 3b804fc..fca45f1 100644 --- a/src/controller/MaintenanceController.php +++ b/src/controller/MaintenanceController.php @@ -5,6 +5,7 @@ declare(strict_types=1); use Doctrine\ORM\EntityManager; use App\Entity\log; +use Symfony\Component\Process\Exception\ProcessFailedException; class MaintenanceController { @@ -47,4 +48,22 @@ class MaintenanceController } die; } + + static public function getLastDump(EntityManager $entityManager): void + { + try{ + $file_path = Backup::mySQLdump($entityManager); + header('Content-Type: application/octet-stream'); // signifie fichier quelconque, du binaire quoi! + header('Content-Disposition: attachment; filename="' . basename($file_path) . '"'); // pour provoquer un téléchargement et non pour afficher + header('Content-Length: ' . filesize($file_path)); // peut servir côté client (barre de progression...) + readfile($file_path); + die; + } + // exeptions lancées dans Backup::mySQLdump + catch(ProcessFailedException $e){ // pas d'info $e pour le client + header('Location: ' . new URL(['page' => 'maintenance', 'error' => '500'])); + die; + } + die; + } } \ No newline at end of file diff --git a/src/service/Backup.php b/src/service/Backup.php new file mode 100644 index 0000000..d628c27 --- /dev/null +++ b/src/service/Backup.php @@ -0,0 +1,70 @@ +format('Y-m-d') . '.sql'; + + // les versions de mysql sont comme ci: 8.0.36 + // celles de mariadb sont comme ça: 10.11.6-MariaDB + $version = $entityManager->getConnection()->fetchOne('SELECT VERSION()'); + $engine = stripos($version, 'mariadb') !== false ? 'mariadb-dump' : 'mysqldump'; + + $tmp = tempnam('../var', 'tmp_db_codes_'); // crée un fichier avec un nom aléatoire et des droits 600 (concurrence) + file_put_contents($tmp, + "[client]\n + user=" . Config::$user . "\n + password=" . Config::$password . "\n + host=" . Config::$db_host . "\n"); + + $command = new Process([ + $engine, + '--defaults-extra-file=' . $tmp, // pour ne pas enregistrer les codes dans l'historique de la console ou dans les processus de l'OS + '--single-transaction', + '--quick', // évite d'exploser la RAM si beaucoup de données + '--result-file=' . $file_path, + Config::$database + ]); + + try{ + $command->mustRun(); // comme run() mais lance une ProcessFailedException + return $file_path; + } + finally{ + // exécuté même quand situé après "return" + unlink($tmp); + self::cleanBackups(); + } + + // compression gzip (gros gain de place sur le serveur), nécessite l'extension zlib + /*try{ + file_put_contents( + $file_path . '.gz', + gzencode(file_get_contents($file_path), 5), // plus rapide que 9 et taille identique d'après mes essais + ); + return $file_path . '.gz'; + } + finally{ + unlink($file_path); + }*/ + } + + static public function cleanBackups(): void { + $files = glob(self::$backup_dir . '/*.sql'); + usort($files, fn($a, $b) => filemtime($b) <=> filemtime($a)); // filemtime = date de dernière modification + $files_to_delete = array_slice($files, self::$amount_to_keep); + foreach($files_to_delete as $file){ + unlink($file); + } + } +} \ No newline at end of file diff --git a/src/service/Installation.php b/src/service/Installation.php index 059c093..eb4b6db 100644 --- a/src/service/Installation.php +++ b/src/service/Installation.php @@ -9,10 +9,9 @@ class Installation { $flag = false; $extensions = ['pdo_mysql', 'mbstring', 'ctype', 'json', 'tokenizer', 'imagick']; // les 5 premières sont pour doctrine - // ajouter plus tard zip pour les backup + // ajouter plus tard zlib pour la compression des backups foreach($extensions as $extension){ - if(!extension_loaded($extension)) - { + if(!extension_loaded($extension)){ echo("

l'extension " . $extension . ' est manquante

'); $flag = true; } @@ -34,8 +33,8 @@ class Installation static public function checkFilesAndFoldersRights(): void { // -- droits des fichiers et dossiers -- - $droits_dossiers = 0700; - $droits_fichiers = 0600; + $droits_dossiers = 0755; + $droits_fichiers = 0644; if(!file_exists('user_data')){ // créer le dossier user_data @@ -46,25 +45,43 @@ class Installation

Aide: "serveur web" se nomme "www-data" sur debian et ubuntu, il s\'appelera "http" sur d\'autres distributions.

'; die; } + if(!file_exists('../var')){ + mkdir('../var'); + chmod('../var', $droits_dossiers); + // + } + if(!file_exists('../var/backups')){ + mkdir('../var/backups'); + chmod('../var/backups', $droits_dossiers); + // + } + // droits 600 pour celui-ci if(!file_exists('../config/config.ini')){ // aide à la création du config.ini echo '

Le fichier config/config.ini est introuvable.

'; echo '

Il doit obligatoirement contenir les codes de la base de données, le protocole http ou https (et éventuellement le port) utilisé pour créer les liens internes.
Un modèle est disponible, il s\'agit du fichier config/config-template.ini

-

Quand vous aurez terminé votre config.ini, donnez-lui par sécurité des droits 600.

'; +

Ce fichier a une importance critique. Si vous le pouvez faites en sorte que le serveur en soit le propriétaire et donner lui des droits 600.

'; die; } - else{ - // droits du config.ini - /*if(substr(sprintf('%o', fileperms('../config/config.ini')), -4) != 600){ - chmod('../config/config.ini', $droits_fichiers); - }*/ + /*else{ + // propriétaire du fichier + if(fileowner('../config/config.ini') != posix_geteuid()){ + echo "

le fichier config/config.ini n'appartient pas au serveur.

"; + } + else{ + // droits du config.ini + if(substr(sprintf('%o', fileperms('../config/config.ini')), -4) != 600){ + echo '

Attention, le

'; + //chmod('../config/config.ini', $droits_fichiers); + } + } + }*/ - // tester les liens internes - // + // tester les liens internes + // - // le test de connexion à la BDD est dans le doctrine bootstrap - } + // le test de connexion à la BDD est dans le doctrine bootstrap } } \ No newline at end of file diff --git a/src/service/router.php b/src/service/router.php index 508721c..6973656 100644 --- a/src/service/router.php +++ b/src/service/router.php @@ -45,7 +45,10 @@ if($request->getMethod() === 'GET'){ } if(IS_ADMIN === true){ - // ... + if($request->query->has('action') && $request->query->get('action') === 'get_mysqldump'){ + MaintenanceController::getLastDump($entityManager); + die; + } } // construction d'une page diff --git a/src/view/templates/form.php b/src/view/templates/form.php index b3611c1..384bde9 100644 --- a/src/view/templates/form.php +++ b/src/view/templates/form.php @@ -31,7 +31,6 @@

- Une copie de votre e-mail (nom, adresse et message) sera conservée dans notre base de données dans le but de pouvoir répondre à votre demande et éventuellement dans un but de prospection. Ces données seront traitées automatiquement par notre serveur et conservées pendant au maximum mois à compter de votre dernier message.
- Ce traitement repose sur votre consentement. Vous pouvez consulter, modifier ou supprimer vos données en base de données sur simple demande. + Une copie de votre e-mail (nom, adresse et message) sera conservée dans notre base de données dans le but de pouvoir mieux répondre à votre demande et éventuellement dans d'autres buts (prospection). Ces données seront traitées automatiquement par notre serveur et conservées pendant au maximum mois à compter de votre dernier message. Ce traitement repose sur votre consentement. Vous pouvez consulter, modifier ou supprimer vos données sur simple demande.

\ No newline at end of file diff --git a/src/view/templates/maintenance.php b/src/view/templates/maintenance.php index 0118bbf..3501fa4 100644 --- a/src/view/templates/maintenance.php +++ b/src/view/templates/maintenance.php @@ -12,8 +12,16 @@

-
- Emails reçus depuis tous les formulaires de contact + + reçus depuis tous les formulaires de contact +

+
+
+

+ + +
+ Réalise un "mysqldump", vous obtiendrez un unique fichier contenant toute la BDD.

-- cgit v1.2.3