Utilitaires
Scripts
Divers
Jeux
Rechercher
Quillevere.net
Réflexions informatiques

Sauvegarder les données de son site Internet

29/02/2020
Un site Internet doit être considéré comme la version de production d'un service et si son contenu peut être modifié par les utilisateurs (commentaires, articles, notes...), il convient de le sauvegarder à intervalles réguliers afin de ne pas perdre de données en cas de piratage, de défaillance ou de migration.

Une tâche de lancement

Il faut planifier une sauvegarde de toute la base de données et des fichiers envoyés par les utilisateurs. Il est inutile de sauvegarder les codes sources du site, les images et les styles puisque vous devezavoir la version de recette de votre site, comportant ces fichiers, et utilisant une autre procédure de sauvegarde, orientée projet (telle que SVN ou Git).

En ce qui me concerne, j'utilise un CRON système qui appelle l'ordonnanceur de tâches de mon CMS. L'ordonnanceur priorise certaines tâches par rapport aux autres, en les enchaînant si nécessaire. Certains CMS comme Wordpress ont leur propre ordonnanceur de tâches, qui est déclenché par la visite d'une personne sur le site. Le fonctionnement est similaire sauf que le processus d'exécution ne se fait pas en parallèle et exactement à l'heure prévue.

La tâche doit être paramétrée pour une date de lancement au moins journalière et à une heure où l'on estime qu'il y a peu d'utilisateurs afin de ne pas les gêner. Dans mon cas, les sauvegardes ont lieu très tôt le matin car c'est là qu'il y a le moins de visiteurs.

Le fichier de sauvegarde doit permettre de restaurer facilement une partie du site. Pour mon usage, j'ai créé une routine qui parcourt toutes les tables d'une base de données, récupère les champs de celles-ci puis crée les instructions de restauration sous la forme ci-dessous. L'ensemble des instructions est ensuite enregistré dans un fichier SQL présenté comme ci-dessous : 

DROP TABLE IF EXISTS matable;
CREATE TABLE matable (champ1 VARCHAR(10), champ2 VARCHAR(10));
INSERT INTO matable (champ1, champ2) VALUES
(val1, val2)
, (val3, val4)
, (val5, val6)

Les instructions SQL générées ainsi permettent de récupérer tout ou partie des valeurs d'une table, en copiant seulement les lignes intéressantes si l'import a besoin d'être partiel. Il faut cependant coder aussi la restauration de la base car si jamais la table est volumineuse, le moteur SQL ne pourra insérer toutes les lignes en une seule fois (il y a une limite sur la taille d'une instruction SQL).

Je vous oriente vers un autre article permettant de sauvegarder une base de données MySQL : Sauver et restaurer rapidement sa base MySQL

Gérer les fichiers de sauvegarde

Le fichier de sauvegarde pouvant être volumineux, il est utile de le compresser avec le taux le plus efficace. S'il s'agit de code SQL, les gains peuvent être très importants, vous permettant ainsi de stocker davantage de sauvegardes. Le nom de l'archive ainsi créée peut être au format "AAAA-MM-JJ HH-MM-SS nom du site" afin d'identifier tout de suite les sauvegardes les plus récentes.

Une purge de ces archives doit être faite pour ne pas encombrer le serveur inutilement : à la fin du code de sauvegarde, si tout s'est bien passé, je supprime les sauvegardes les plus anciennes pour n'en garder qu'un certain nombre, cela peut être sur une semaine, un mois...  Tout dépend du site Internet, selon qu'il soit très utilisé ou pas.

Sauvegarder... ailleurs

La sauvegarde doit être faite vers un autre serveur, afin d'anticiper une perte complète des données du serveur. Si on n'en dispose pas, on peut sauvegarder sur le serveur lui même et lancer une tâche planifiée sur son propre PC, sur un NAS ou vers un hébergement tiers pour récupérer régulièrement les sauvegardes. Il faudra aussi dans ces cas-là gérer une purge des fichiers les plus anciens. L'avantage de cette technique est aussi d'avoir de la redondance de sauvegarde.

J'ai écrit le script PHP ci-dessous pour récupérer les sauvegardes d'un ensemble de sites depuis un accès HTTPS. Il faut le modifier pour indiquer l'adresse renvoyant la dernière sauvegarde (celle-ci doit être en mesure de vous renvoyer le fichier de sauvegarde compressé, tout en étant masquée des utilisateurs). On peut également préciser la durée de conservation des fichiers :

<?php
/* Récupère une sauvegarde régulière des sites
Eric Quillévéré - 24/01/2019
*/

$sRep="/volume1/web/cron_sauvegarde";
$sRepArchives=$sRep . "/archives";
if (!is_dir($sRepArchives))
    mkdir($sRepArchives);
// Liste des adresses
$listeSources=Array();
$listeSources[]=Array(
        'url'=>'https://monsite1.fr/sauvegarde',
        'nb_sauvegardes'=>15,
        'destination'=>$sRepArchives . '/monsite1.fr'
        );
// Parcours les sauvegardes    
for ($i=0; $i<sizeof($listeSources); $i++) {
    $info=$listeSources[$i];
   
    if (!is_dir($info['destination']))
        mkdir($info['destination']);
       
    $sFichier= recupereNomFichier($info['url']);
   
    if ($sFichier!='')
        {
        echo "Télécharge " . $sFichier . ' depuis ' . $info['url'] . "";
       
        $sDesti=$info['destination'] . '/' . $sFichier;
       
        if (!file_exists($sDesti))
            {
            file_put_contents( $sDesti, file_get_contents($info['url']));
            purgeRepertoire($info['destination'], $info['nb_sauvegardes']);
            }
        else
            echo 'Fichier déjà présent' . "";
        }
    else
        echo 'Nom de fichier non récupéré depuis le serveur !' . "";
}  
   
   
   
   
// Purge : conserve X fichiers par adresse
function purgeRepertoire($sRepArchives, $iNbArchivesMaxi)
    {
    $listeFichiers=getlisteFichiers($sRepArchives);
    $iNbFichiersTrouves=sizeof($listeFichiers);
    if ($iNbFichiersTrouves > $iNbArchivesMaxi)
        {
        sort($listeFichiers);
        for ($i=0; $i<$iNbFichiersTrouves- $iNbArchivesMaxi; $i++) {
            echo 'Suppression de ' . $listeFichiers[$i] . "";;
            unlink($listeFichiers[$i]);
            }
        }
    }
// Récupère le nom du fichier
function recupereNomFichier($url)
    {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLOPT_NOBODY, 1);
    $data = curl_exec($ch);
    preg_match("#filename=([^]+)#is", $data, $matches);
    $sFichier=trim($matches[1]);
   
    // Supprime les éventuels guillemets début/fin
    if (substr($sFichier,0, 1)=='"')
        $sFichier=substr($sFichier,1, strlen($sFichier)-2);
    return $sFichier;
    }
// Renvoie la liste des fichiers d'un répertoire (sans sous-rep)
function getlisteFichiers($sRep)
    {
    $listeFichiers=Array();
    if (is_dir($sRep))
        {
        $resDir = opendir($sRep);
        if ($resDir)
            {
            $sFichier = readdir($resDir);
            while ($sFichier !==false)
                {
                if ($sFichier!="." && $sFichier!="..")
                    {
                    // Répertoire
                    if (is_file($sRep . '/' . $sFichier))
                        $listeFichiers[]=$sRep . '/' . $sFichier;
                    }
                $sFichier = readdir($resDir);
                }
            }
        closedir($resDir);
        }
    return $listeFichiers;
    }  
?>

Pour le lancer, une tâche planifiée sur un NAS permet de ne plus s'en soucier :

php70 -dextension=curl.so /volume1/web/cron_sauvegarde/recupere_sauvegarde_sql.php

Penser à la restauration

Si la sauvegarde est importante et la redondance une sécurité, la restauration des données est également une chose à ne pas négliger :   il faut pouvoir récupérer une sauvegarde rapidement ! La récupération d'une sauvegarde ne doit pas s'imposer comme une lourdeur administrative car quand on a besoin de restaurer, on est déjà pressé par le temps.

Sur mes sites, je gère la restauration d'une sauvegarde très simplement, en proposant dans le panneau d'administration une boîte déroulante listant les dernières sauvegardes, avec à côté le bouton "Restaurer". Au clic, celui-ci archive la base actuelle et restaure en quelques secondes la sauvegarde sélectionnée. L'algorithme de la procédure de restauration (sur MySQL) fonctionne en 2 parties :

  • Archivage de la base actuelle (le but est d'obtenir une base préfixée de la date du jour).
    • Création d'une nouvelle base (CREATE DATABASE y), qui sera au finale l'ancienne base
    • Récupération des noms des tables et renommage de chacune d'elles (RENAME TABLE x.matable TO y.matable)
  • Importation de la sauvegarde choisie dans la nouvelle base.
    • désactivation des clés étrangères : SET FOREIGN_KEY_CHECKS=0;
    • parcours de chaque table
      • suppression de chaque table : DROP TABLE x
      • création de chaque table : CREATE TABLE x (champ1 AS type)
      • insertion de chaque ligne : INSERT INTO x(champ1) VALUES ()  () ()
    • à la fin du parcours, activation des clés étrangères : SET FOREIGN_KEY_CHECKS=1;

Les hébergeurs proposent également de sauvegarder la machine ou la base de données. Il est intéressant de se renseigner sur cette option (souvent payante) mais la meilleure sauvegarde reste celle que l'on maîtrise et qui sait rester invisible.

Dernière modification le 29/02/2020 - Quillevere.net

Rechercher sur le site

rss RSS info Informations