Bonjour,
J’ai un scénario pour faire le backup de la conf de mon IPX800V4 dans /var/www/html/backup/ipx/
///////////////////////////////////////////////////////////
// PhpSaveIPX : script php //
// permettant la sauvegarde automatique //
// des données et de la configuration //
// des matériels GCE //
// (IPX800, EcoDevice, EcoDevice RT2,... ) //
// @fgtoul 2018 pour la communauté //
///////////////////////////////////////////////////////////
// Tableau $materiel avec les IPX800 V3, IPX800 V4, EDRT2
// structure d'une table à n matériels
// $materiel[0..n][0]: nom du matériel
// $materiel[0..n][1]: Type de matériel (IPX800V3, IPX800V4, EDRT2, ED),
// $materiel[0..n][2]: adresse IP locale ou distante,
// $materiel[0..n][3]: port TCP,
// $materiel[0..n][4]: securisation interface administrateur(true/false),
// $materiel[0..n][5]: utilisateur administrateur,
// $materiel[0..n][6]: password administrateur,
// $materiel[0..n][7]: nombre de cycles de sauvegarde à conserver. Illimité si 0
//remarque : si un seul matériel, ne laisser qu'une ligne et supprimer la virgule qui la termine
// si plusieurs matériels, chaque ligne doit se terminer par une virgule, sauf la dernière
$materiel=array
(
array('IPX800','IPX800V4','192.168.1.250','80',true,'admin','xxxxxx',1),
);
//sous-dossier temporaire pour download des fichiers sur le NAS
// ce sous-dossier sera créé dans le répertoire web de cette application
$dwnload="sauvegardesGCE";
// dossier de destination des sauvegardes (les sous-dossiers y seront créés).
// ce dossier doit exister au préalable et doit permettre à tout le monde de lire/écrire/exécuter -> chmod(0777)
$destination="/var/www/html/backup/ipx/"; //dossiers de destination des sauvegardes. renseigner le chemin absolu (complet)
// par défaut, un jeu de sauvegarde réputé incomplet (ayant rencontré des erreurs pendant son déroulement) ne sera pas préservé
// et sera remplacé lors du cycle suivant.
// si vous souhaitez préserver les jeux incomplets, passez le paramètre ci-dessous à true.
// Dans ce cas, il est conseillé de régler la rétention à 0 pour tous les matériels dans la table $materiel
$preserveIncomplets=false; //true ; false;
//Notifications
$NotificationsMail=true; //true : envoie d'un mail à la fin du traitement
$NotificationsLimitees=true; //si activés, les mails seront envoyés uniquement lorsque le script se terminera avec des erreurs.
$NotificationsDestinataire="";
//********************************************************************************************************************
//********************************************************************************************************************
//********************************************************************************************************************
// ne rien modifier sous cette ligne
//********************************************************************************************************************
// Tableau $fichiersXML contient le nom (sans extension) des fichiers XML à sauvegarder, par type de matériel
// structure d'une table à n types de matériels
// $fichiersXML[0..n][0] : chemin
// $fichiersXML[0..n][1] : nom du fichier
// $fichiersXML[0..n][2] : extension du fichier
$fichiersXML=array
(
'IPX800V4'=>array('/admin/','status', 'xml',
'/admin/','io', 'xml',
'/admin/','graph', 'xml',
'/admin/','analog','xml'
),
'IPX800V3'=>array('/','status', 'xml',
'/','globalstatus', 'xml'
),
'EDRT2'=>array('/admin/','status','xml'
),
'ED'=>array('/protect/download/','xdata','csv'
)
);
// Tableau $fichiersConfig contient le nom (sans extension) des fichiers de configuration à sauvegarder, par type de matériel
// structure d'une table à n types de matériels
// $fichiersConfig[0..n][0] : /chemin/
// $fichiersConfig[0..n][1] : type
// $fichiersConfig[0..n][2] : nom du fichier
// $fichiersConfig[0..n][3] : extension
$fichiersConfig=array
(
'IPX800V4'=>array('/admin/download/','config','gce'),
'IPX800V3'=>array('/protect/download/','config','gce'),
'EDRT2'=>array('/admin/download/','config','gce'),
'ED'=>array('/protect/download/','config','gce')
);
//gestionnaire d'erreurs
$erreurs=false; //gestionnaire d'erreurs => global script
$detailsExecutionErreurs='';
$avertissements=0;//gestionnaire d'avertissements => global script
set_time_limit(0);
//façonnage des données d'éxécution (contenu web)
$detailsExecution='';
////////////////////////////////////////////////////////////////////////////////
//initialisation à 0 des cycles pour tous les types de matériels
// permet l'initialisation en cas de nouveau matériel dans la table $materiels
$cycles=array();
for ($i = 0; $i < count($materiel); $i++) {
//$detailsExecution .= $materiel[$i][0] . "\r\n";
$cycles[$materiel[$i][0]] = 0;
}
// Cycles : liste lue à partir du fichier CyclesOUT.txt
if (is_readable ( './CyclesOUT.txt' ))
{
$cycles = unserialize ( urldecode ( file_get_contents ( './CyclesOUT.txt' ) ) );
}
//fseek($cyclesOut, 0); // On remet le curseur au début du fichier
//fclose($cyclesOut);
//ouverture du journal des sauvegardes
$journal=fopen('./Journal.txt', 'a+');
fputs($journal, '//////////////////////////////////////////'. "\n");
fputs($journal, "cycle du " . date("d/m/Y H:i:s") . "\n");
fputs($journal, '//////////////////////////////////////////'. "\n");
//création du sous-dossier pour download des fichiers
//if(!is_dir('./' . $dwnload )){
//if (!mkdir('./' . $dwnload ,0777,true)){
// fputs($journal, '***Création sous-dossier download ' . $dwnload . " : ECHEC \n");
// fputs($journal, "***Abandon du programme \n");
// $detailsExecutionErreurs .= 'ERREUR : Création sous-dossier download ' . $dwnload . ' : ECHEC'. "\r\n";
// $detailsExecutionErreurs .= "Abandon du programme. \r\n";
// $erreurs=true;
// goto fin;
//} else {
// fputs($journal, ' Création sous-dossier download "' . $dwnload . '" : OK'. "\n");
//}
//} else {
//fputs($journal, ' Sous-dossier download "' . $dwnload . '" déjà existant.'. "\n");
//}
////////////////////////////////////////////
//boucle principale //
////////////////////////////////////////////
$d= date("Ymd");
//traitement pour chaque matériel référencé
for ($i = 0; $i < count($materiel); $i++) {
$nommat=$materiel[$i][0];
$typmat=$materiel[$i][1];
$ipmat=$materiel[$i][2];
$portmat=$materiel[$i][3];
$securemat=$materiel[$i][4];
$usermat=$materiel[$i][5];
$pwdmat=$materiel[$i][6];
$retention=$materiel[$i][7];
if ($securemat==true){
$materiel_secure=$usermat . ':' . $pwdmat . '@';
} else {
$materiel_secure='';
}
$nberreurs=0; //gestionnaire d'erreurs par matériel
//entête matériel dans le journal
fputs($journal, '============== ' . $nommat . '(' . $typmat . ') =============='. "\n");
//création du sous-dossier destination pour ce matériel
$do=$destination . '/' . $nommat;
$er = "Création sous-dossier '" . $do . "'";
if(!is_dir($do)){
if (!mkdir($do,0777,true)){
fputs($journal, " ***" . $er. " : ECHEC \n");
$detailsExecutionErreurs .= "ERREUR : " . $er . " : ECHEC \r\n";
fputs($journal, " ***Sauvegarde ignorée. \n");
$detailsExecutionErreurs .= "Sauvegarde ignorée \r\n";
$erreurs=true;
goto MaterielSuivant;
} else {
fputs($journal, " " . $er . "' : OK". "\n");
}
} else {
fputs($journal, " Sous-dossier '" . $do . "' déjà existant.". "\n");
}
//détermination jeu de sauvegarde
$jeu=$cycles[$nommat];
$jeu += 1;
if ($jeu > $retention && $retention>0) {
$jeu=1;
}
//création du sous-dossier destination selon jeu de sauvegarde
$do=$destination . '/' . $nommat . '/' . $jeu;
$er='Création du dossier de destination "' . $do;
if(!is_dir($do)){
//création dossier destination Jeu de ce matériel
if (!mkdir($do ,0777,true)){
//échec création
fputs($journal,' ***' . $er . '" en échec.' . "\n");
fputs($journal,' ***sauvegarde ignorée.'. "\n");
$detailsExecutionErreurs .= 'ERREUR : ' . $er . '" en échec.' . "\r\n";
$detailsExecutionErreurs .= "sauvegarde ignorée. \r\n";
$erreurs=true;
goto MaterielSuivant;
} else {
//création réussie
fputs($journal,' création du dossier de destination "' . $do . '" réussie.'. "\n");
}
} else {
//dossier destination Jeu de ce matériel existe déjà
fputs($journal," Sous-dossier de destination '" . $do . "' déjà existant.". "\n");
//vidage dossier destination. "\n");
//$ret=vidage($destination . '/' . $nommat . '/' . $jeu);
$repertoire = opendir($destination . '/' . $nommat . '/' . $jeu);
fputs($journal, " Vidage du dossier '" . $destination . '/' . $nommat . '/' . $jeu . "'". "\n");
$old = getcwd(); // Save the current directory
chdir($destination . '/' . $nommat . '/' . $jeu);
while (false !== ($fichier = readdir($repertoire)))
{
$chemin = $destination . '/' . $nommat . '/' . $jeu ."/".$fichier; // On définit le chemin du fichier à effacer.
// Si le fichier n'est pas un répertoire…
if ($fichier != ".." AND $fichier != "." AND !is_dir($fichier))
{
if (!unlink($chemin)){; // On efface.
fputs($journal, " - Suppression du fichier " . $fichier . "' en échec\n");
$avertissements += 1 ; //ne remet pas en cause l'intégrité du jeu de sauvegarde
$detailsExecutionErreurs .= "Avertissement : Suppression du fichier " . $fichier . "' en échec \r\n";
} else {
fputs($journal, " - Suppression du fichier " . $fichier . "' réussie \n");
}
}
}
fputs($journal, " Vidage du dossier '" . $destination . "/" . $nommat . "/" . $jeu . "' terminé" . "\n");
closedir($repertoire);
chdir($old); // Restore the old working directory
}
//création dossier $nomat pour download
$do=$dwnload . '/' . $nommat;
$er='Création sous-dossier ' . $do ;
if(!is_dir($do)){
if (!mkdir($do,0777,true)){
fputs($journal, ' ***' . $do . ' : ECHEC'. "\n");
fputs($journal, " ***Sauvegarde ignorée.\n");
$detailsExecutionErreurs .= "ERREUR : " . $er . " : ECHEC \r\n";
$detailsExecutionErreurs .= "Sauvegarde ignorée";
$erreurs=true;
goto MaterielSuivant;
} else {
fputs($journal, ' Création sous-dossier "' . $do . '" : OK'. "\n");
}
} else {
fputs($journal, ' Sous-dossier "' . $do . '" déjà existant.'. "\n");
$detailsExecutionErreurs .="Avertissement : le dossier " . $do . " existe déjà \r\n";
}
// Boucle download des datas (boucle fichiers data)
for ($j = 0; $j < count($fichiersXML[$typmat]); $j+=3) {
$cheminMat=$fichiersXML[$typmat][$j]; //lecture chemin vers fichiers xml
if (substr($cheminMat, 0,1)!=="/"){$cheminMat="/".$cheminMat;}
if (substr($cheminMat, -1)!=='/'){$cheminMat=$cheminMat . '/';}
$dwnFic=false; //gestionnaire d'erreur au niveau du fichier
$fic=$fichiersXML[$typmat][$j+1];
$ext=$fichiersXML[$typmat][$j+2];
$RenameSource = getcwd() . "/" . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . "." . $ext;
$RenameDest = $destination . '/' . $nommat . '/' . $jeu . '/' . $fic . '_' . $d . "." . $ext;
//dwnload du fichier source
//echo $fic . "\r\n" . $RenameSource . "\r\n" . $RenameDest . "\r\n" . $fichiersXML[$typmat][$j] . "\r\n";
$ficcible=fopen ('./' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . "." . $ext, 'w+');
$url = curl_init('http://' . $materiel_secure . $ipmat . ':' . $portmat . $cheminMat . $fic . "." . $ext);
curl_setopt($url, CURLOPT_TIMEOUT, 50);
curl_setopt($url, CURLOPT_FILE, $ficcible);
curl_setopt($url, CURLOPT_FOLLOWLOCATION, true);
if (curl_exec($url)){
fputs($journal, ' Download du fichier http://' . $materiel_secure . $ipmat . ':' . $portmat . $cheminMat . $fic . "." . $ext . ' vers ' . $RenameSource . ' réussi.'. "\n");
$dwnFic=true;
} else {
fputs($journal, ' *Download du fichier http://' . $materiel_secure . $ipmat . ':' . $portmat . $cheminMat . $fic . "." . $ext . ' vers ' . $RenameSource . ' en échec'. "\n");
$detailsExecutionErreurs .= ' ERREUR : Download du fichier http://' . $materiel_secure . $ipmat . ':' . $portmat . $cheminMat . $fic . "." . $ext . ' vers ' . $RenameSource . ' en échec'. "\r\n";
$erreurs=true;
$nberreurs += 1;
}
curl_close($url);
fclose($ficcible);
if (filesize ( './' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . "." . $ext )<100){
echo "le fichier " . './' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . "." . $ext . " semble corrompu ! <br>";
$detailsExecutionErreurs .= "le fichier " . './' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . "." . $ext . " semble corrompu ! \r\n";
fputs($journal, " *le fichier " . './' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . "." . $ext . " semble corrompu ! \n");
}
//déplacement du fichier vers sa destination finale si dwnl ok
if ($dwnFic==true){
if (!rename($RenameSource, $RenameDest)){
// le déplacement a échoué
fputs($journal,' *Déplacement du fichier ' . $renameSource . ' vers ' . $RenameDest . ' en échec.'. "\n");
$detailsExecutionErreurs .= " ERREUR : Déplacement du fichier " . $renameSource . " vers " . $RenameDest . " en échec. \r\n";
$erreurs=true;
$nberreurs += 1;
} else {
// le déplacement a échoué
fputs($journal,' Déplacement du fichier ' . $RenameSource . ' vers ' . $RenameDest . ' réussi.'. "\n");
}
} else {
//supprime fichier créé à blanc si download échoué
//unlink('./' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . "." . $ext);
}
}
// sauvegarde du fichier de configuration (fichier .gce)
$cheminMat=$fichiersConfig[$typmat][0]; //lecture chemin vers fichiers config
if (substr($cheminMat, 0,1)!=="/"){$cheminMat="/".$cheminMat;}
if (substr($cheminMat, -1)!=='/'){$cheminMat=$cheminMat . '/';}
$dwnFic=false; //gestionnaire d'erreur au niveau du fichier
$fic=$fichiersConfig[$typmat][1];
$extension=$fichiersConfig[$typmat][2];
$RenameSource=getcwd() . "/" . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . '.' . $extension;
$RenameDest=$destination . '/' . $nommat . '/' . $jeu . '/' . $fic . '_' . $d . '.' . $extension;
//upload du fichier source
$ficcible=fopen ('./' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . '.' . $extension, 'w+');
$url = curl_init('http://' . $materiel_secure . $ipmat . ':' . $portmat . $cheminMat . $fic . '.' . $extension);
curl_setopt($url, CURLOPT_TIMEOUT, 50);
curl_setopt($url, CURLOPT_FILE, $ficcible);
curl_setopt($url, CURLOPT_FOLLOWLOCATION, true);
if (curl_exec($url)){
fputs($journal, ' Download du fichier http://' . $materiel_secure . $ipmat . ':' . $portmat . $cheminMat . $fic . '.' . $extension . " vers " . $RenameSource . " réussi\n");
$dwnFic=true;
} else {
fputs($journal, ' *Download du fichier ' . 'http://' . $materiel_secure . $ipmat . ':' . $portmat . $cheminMat . $fic . '.' . $extension . ' vers ' . $RenameSource . " en échec \n");
$detailsExecutionErreurs .= ' ERREUR : Download du fichier http://' . $materiel_secure . $ipmat . ':' . $portmat . $cheminMat . $fic . '.' . $extension . ' vers ' . $RenameSource . " en échec\r\n";
$erreurs=true;
$nberreurs += 1;
}
curl_close($url);
fclose($ficcible);
if (filesize ( './' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . '.' . $extension )<100){
echo "le fichier " . './' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . '.' . $extension . " semble corrompu ! <br>";
$detailsExecutionErreurs .= "le fichier " . './' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . '.' . $extension . " semble corrompu ! \r\n";
fputs($journal, " *le fichier " . './' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . '.' . $extension . " semble corrompu ! \n");
}
if ($dwnFic==true){
//déplacement du fichier vers sa destination finale
if (!rename($RenameSource, $RenameDest)){
// le déplacement a échoué
fputs($journal,' *Déplacement du fichier ' . $RenameSource . " vers " . $RenameDest . "en échec.\n");
$detailsExecutionErreurs .= ' ERREUR : Déplacement du fichier ' . $RenameSource . " vers " . $RenameDest . "en échec.\r\n";
$erreurs=true;
$nberreurs += 1;
} else {
// le déplacement a échoué
fputs($journal,' Déplacement du fichier ' . $RenameSource . " vers " . $RenameDest . " réussi. \n");
}
} else {
//supprime fichier créé à blanc si download échoué
unlink('./' . $dwnload . '/' . $nommat . '/' . $fic . '_' . $d . '.' . $extension);
}
MaterielSuivant:
//incrément du jeu de sauvegarde si sauvegarde complète
if ($nberreurs==0 || $preserveIncomplets==true){
$cycles[$nommat]=$jeu;
}
if ($nberreurs==0 ){
$ficOK=fopen ($destination . '/' . $nommat . '/' . $jeu . '/Sauvegarde_complete.txt', 'w+');
fclose($ficOK);
} else {
$ficOK=fopen ($destination . '/' . $nommat . '/' . $jeu . '/Sauvegarde_partielle.txt', 'w+');
fclose($ficOK);
}
// matériel suivant
}
fin:
// écriture cyclesOut.txt
file_put_contents ( './CyclesOUT.txt' , urlencode ( serialize ( $cycles ) ) );
// conclusion cycle de sauvegarde dans le $journal
fputs($journal,' -------------------------------------------------------'. "\n");
if ($erreurs==true){
fputs($journal,' Le cycle de sauvegarde a rencontré des problèmes. Lisez ce qui précède.'. "\n");
} else if ($avertissements>0) {
fputs($journal,' Cycle de sauvegarde terminé avec des avertissements. Lisez ce qui précède.'. "\n");
} else {
fputs($journal,' Le cycle de sauvegarde terminé normalement.'. "\n");
}
fputs($journal,' -------------------------------------------------------'. "\n");
fclose($journal);
// façonnage des détails d'exécution
$detailsExecutionErreurs = "===================================== \r\nRESUME DU CYCLE DE SAUVEGARDE DU JOUR : \r\n===================================== \r\n" . $detailsExecutionErreurs;
$detailsExecutionErreurs .= "===================================== \r\nJEUX DE SAUVEGARDE VALIDES DU JOUR : \r\n===================================== \r\n";
for ($i = 0; $i < count($materiel); $i++)
{
$detailsExecutionErreurs .= 'Materiel : ' . $materiel[$i][0] . " : Jeu ";
echo 'Materiel : ' . $materiel[$i][0] . " : Jeu ";
$detailsExecutionErreurs .= $cycles[$materiel[$i][0]] . "\r\n";
echo $cycles[$materiel[$i][0]] . "<br>";
}
// en cas d'erreur, le synology envoie une notification par mail
if ($NotificationsMail==true && ($erreurs==true || $NotificationsLimitees==false))
{
//trigger_error("Au moins une erreur est survenue. Merci de consulter le journal de l'application.", E_ERROR);
echo "Traitement terminé avec des erreurs. Veuillez consulter le journal de l'application." ;
mail($NotificationsDestinataire, "Sauvegarde Automatique GCE", "Au moins une erreur est survenue. Veuillez consulter le journal de l application.\r\n" . $detailsExecutionErreurs);
}
Ensuite une pause de 30 s puis la vérif que le backup s’est bien réalisé:
$directory = "/var/www/html/backup/ipx/IPX800/1/"; // Chemin du répertoire
$date_du_jour = date("Ymd"); // Format YYYYMMDD
$fichier_trouve = false; // Indicateur de présence du fichier
echo $scenario->setLog("Recherche de fichiers contenant : " . $date_du_jour . " avec extension .gce");
if (is_dir($directory)) {
$files = scandir($directory);
foreach ($files as $file) {
$filePath = $directory . $file;
$extension = pathinfo($filePath, PATHINFO_EXTENSION);
if ($file != "." && $file != ".." && strpos($file, $date_du_jour) !== false && $extension === "gce") {
echo $scenario->setLog("Fichier trouvé : " . $file);
$fichier_trouve = true;
$maCmd = cmd::byString('#[Système][Etatbkp][ipx]#');
$maCmd->event(0);
}
}
if (!$fichier_trouve) {
echo $scenario->setLog(" Aucun fichier .gce trouvé pour la date du jour.");
$maCmd = cmd::byString('#[Système][Etatbkp][ipx]#');
$maCmd->event(1);
}
} else {
echo $scenario->setLog("Le répertoire spécifié n'existe pas.");
$maCmd = cmd::byString('#[Système][Etatbkp][ipx]#');
$maCmd->event(1);
}
le script se lance tous les jours mais pas de sauvegarde présente:
------------------------------------
[2025-04-10 06:00:02][SCENARIO] -- Début : Scenario execute automatiquement sur programmation.
[2025-04-10 06:00:02][SCENARIO] - Exécution du sous-élément de type [action] : code
[2025-04-10 06:00:02][SCENARIO] Exécution d'un bloc code
[2025-04-10 06:00:02][SCENARIO] - Exécution du sous-élément de type [action] : action
[2025-04-10 06:00:02][SCENARIO] Pause de 30 seconde(s)
[2025-04-10 06:00:32][SCENARIO] - Exécution du sous-élément de type [action] : code
[2025-04-10 06:00:32][SCENARIO] Exécution d'un bloc code
[2025-04-10 06:00:32][SCENARIO] Recherche de fichiers contenant : 20250410 avec extension .gce
[2025-04-10 06:00:32][SCENARIO] Aucun fichier .gce trouvé pour la date du jour.
[2025-04-10 06:00:32][SCENARIO] Fin correcte du scénario
Je lance en manuel sans rien changer:
------------------------------------
[2025-04-10 14:36:56][SCENARIO] -- Début : Scenario lance manuellement.
[2025-04-10 14:36:56][SCENARIO] - Exécution du sous-élément de type [action] : code
[2025-04-10 14:36:56][SCENARIO] Exécution d'un bloc code
[2025-04-10 14:36:58][SCENARIO] - Exécution du sous-élément de type [action] : action
[2025-04-10 14:36:58][SCENARIO] Pause de 30 seconde(s)
[2025-04-10 14:37:28][SCENARIO] - Exécution du sous-élément de type [action] : code
[2025-04-10 14:37:28][SCENARIO] Exécution d'un bloc code
[2025-04-10 14:37:28][SCENARIO] Recherche de fichiers contenant : 20250410 avec extension .gce
[2025-04-10 14:37:28][SCENARIO] Fichier trouvé : config_20250410.gce
[2025-04-10 14:37:28][SCENARIO] Fin correcte du scénario
Franchement je ne comprends pas …