begin process at 2008 08 20 12:37:54
1 228 823 membres
193 nouveaux aujourd'hui
14 257 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

SAUVEGARDE AUTOMATISÉE DE VOS BASES DE DONNÉES


Information sur la source

Catégorie :Base de données Classé sous : sauvegarde, mysql, automatique Niveau : Débutant Date de création : 02/01/2008 Date de mise à jour : 06/01/2008 19:39:28 Vu : 5 448

Note :
8,33 / 10 - par 3 personnes
8,33 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (36)
Ajouter un commentaire et/ou une note

Description

N'ayant pas trouvé mon bonheur auparavant pour sauvegarder mes bases de données, je m'y suis mis.

Ce code a été fait pour créer automatiquement un fichier de sauvegarde avec une copie de vos bases de données, au format zip. Ce zip est ensuite stocké dans un répertoire protégé sur un site distant.  Un mail peut confirmer l'opération et le zip peut également être envoyé en fichier joint. Le tout, idéalement, doit être utiliser via CRON (ou webcron.org).

Vous devez bien sûr avoir accès à un site distant! Ceci dit, même si vous n'avez pas un accès, vous pouvez retirer la partie FTP du code et utiliser l'envoi par email du zip.

Pour ma part, tous les jeudis à 2h du matin, le fichier est exécuté et je reçois un email confirmant si tout s'est bien passé ou non.

En espérant que ce code vous soit utile... à moi il l'est :-)

Source

  • <?php
  • function saveDB($mysql_array,$ftp_array,$mail_array = array()){
  • // données de connexion au serveur où se trouvent les bases de données
  • $mysql_host = $mysql_array[0];
  • $mysql_user = $mysql_array[1];
  • $mysql_password = $mysql_array[2];
  • // données de connexion au serveur où sera mis la sauvegarde des bases de données
  • $ftp_server = $ftp_array[0];
  • $ftp_user_name = $ftp_array[1];
  • $ftp_user_pass = $ftp_array[2];
  • $ftp_dest_folder = $ftp_array[3];
  • // désactiver le rapport d'erreurs afin de ne pas les afficher
  • error_reporting(0);
  • $err_msg = '';
  • // nombre maximum d'INSERT écrit par fichier avant de libérer la variable sql_export
  • $maxinsert = 500;
  • // si on a demandé un mail à la fin...
  • if (!empty($mail_array)){
  • $mail = $mail_array[0];
  • // $attachement == 1 => la sauvegarde sera également envoyée par mail. ATTENTION au poids du fichier!
  • $attachement = $mail_array[1];
  • }
  • /*
  • PARTIE MYSQL - on dump toutes les bases et on les met dans un zip
  • */
  • // librairie pour zipper
  • include_once('pclzip.lib.php');
  • // test de connection
  • if(!$link = mysql_connect($mysql_host,$mysql_user,$mysql_password))
  • $err_msg .= 'Impossible de se connecter à '.$mysql_host."\n";
  • else{
  • // Vérification de la disponibilité en écriture du répertoire "sql/"
  • // is_writable() retourne TRUE seulement si le fichier testé existe et est accessible en écriture,
  • // ce qui ne convient pas ici puisque le répertoire est vide
  • $testfile = 'sql/'.uniqid(mt_rand()).'.tmp';
  • if (!$handle = fopen($testfile,'w'))
  • $err_msg .= 'Impossible d\'ouvrir un fichier en écriture dans le répertoire "sql/"'."\n";
  • else
  • fclose($handle);
  • if (file_exists($testfile)) unlink($testfile);
  • if ($err_msg == ''){
  • // liste des base de données
  • $db_list = mysql_list_dbs($link);
  • // tableau pour les noms des bases de données
  • $names = array();
  • // dump des bases de données
  • while ($row = mysql_fetch_object($db_list)) {
  • if ($row->Database != 'information_schema'){
  • $q = 'SHOW CREATE DATABASE `'.($row->Database).'`';
  • $r = mysql_query($q);
  • while ($s=mysql_fetch_object($r)){
  • // ouverture du fichier pour stocker la base en cours (une base de données par fichier)
  • $filename = ($row->Database).'_'.date('Ymd').'.sql';
  • $names[] = $filename;
  • // test d'écriture (ne devrait en principe pas échouer)
  • if (!$handle = fopen('sql/'.$filename, 'w'))
  • $err_msg .= 'Impossible d\'ouvrir en écriture le fichier sql de '.($row->Database)."\n";
  • else{
  • // en-tête du fichier d'export pour la base en cours
  • $sql_header = '###############################################'."\n";
  • $sql_header .= '## BASE DE '.($row->Database)."\n";
  • $sql_header .= '###############################################'."\n\n";
  • $sql_header .= $s->{'Create Database'}.";\n\n";
  • if (fwrite($handle, $sql_header) === FALSE)
  • $err_msg .= 'Impossible d\'écrire dans le fichier sql de '.($row->Database)."\n";
  • else{
  • mysql_select_db($row->Database, $link);
  • // listing des tables de la base de données courante
  • $q3 = 'SHOW TABLES';
  • $r3 = mysql_query($q3);
  • while ($s3 = mysql_fetch_object($r3)){
  • // structure de chaque table
  • $table = $s3->{'Tables_in_'.($row->Database)};
  • $q4 = 'SHOW CREATE TABLE `'.$table.'`;';
  • $r4 = mysql_query($q4);
  • while ($s4 = mysql_fetch_object($r4)){
  • $sql_export = '';
  • $sql_export .= '## TABLE `'.$table.'`'."\n\n";
  • $sql_export .= $s4->{'Create Table'}.";\n\n";
  • // construction des INSERT
  • $q5 = 'SELECT * FROM `'.$table.'`;';
  • $r5 = mysql_query($q5);
  • // slashes en fonction du type de colonne
  • $slashes = array();
  • $nbfields = mysql_num_fields($r5);
  • for($i=0; $i < $nbfields; $i++)
  • if (in_array(mysql_field_type($r5, $i), array('string','blob','date','timestamp')))
  • $slashes[$i] = '\'';
  • $count = 0;
  • while($s5 = mysql_fetch_array($r5)){
  • $count++;
  • $sql_export .= 'INSERT INTO `'.$table.'` VALUES(';
  • $sql_export .= $slashes[0].mysql_real_escape_string($s5[0]).$slashes[0];
  • for($i=1; $i < $nbfields; $i++)
  • $sql_export .= ', '.$slashes[$i].mysql_real_escape_string($s5[$i]).$slashes[$i];
  • $sql_export .= ");\n";
  • if($count == $maxinsert){
  • if (fwrite($handle, $sql_export) === FALSE){
  • $err_msg .= 'Erreur d\'exportation avec la '.$table.' de la base '.($row->Database)."\n";
  • // mettre un break 3 ici pour stopper le tout. Je ne préfère pas personnellement
  • }
  • else
  • $sql_export = '';
  • }
  • }
  • $sql_export .= "\n";
  • // Pour chaque table, on écrit le résultat dans le fichier
  • if (fwrite($handle, $sql_export) === FALSE)
  • $err_msg .= 'Erreur d\'exportation avec la '.$table.' de la base '.($row->Database)."\n";
  • }
  • }
  • }
  • fclose($handle);
  • }
  • }
  • }
  • }
  • }
  • }
  • // si on a pu dumper les bases
  • if ($err_msg == ''){
  • // création d'un zip avec les bases de données
  • chdir('sql/');
  • $archs = 'dbsave_'.date('Ymd').'.zip';
  • $archive = new PclZip($archs);
  • $cnames = implode(',', $names);
  • $v_list = $archive->create($cnames);
  • if ($v_list == 0)
  • $err_msg .= 'Impossible de créer le fichier ZIP "'.$archs.'"'."\n";
  • else
  • for ($i=0;$i<count($names);$i++) // on efface les fichiers temporaires
  • unlink($names[$i]);
  • }
  • /*
  • PARTIE FTP - on transfert le zip sur notre serveur de sauvegarde (on ne sauvegarde pas sur le même serveur, logique!)
  • */
  • // si on a pu zipper
  • if ($err_msg == ''){
  • // connection ftp au site distant
  • $conn_id = ftp_connect($ftp_server);
  • $login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
  • if ((!$conn_id) || (!$login_result))
  • $err_msg .= 'Impossible de se connecter au serveur '.$ftp_server."\n";
  • else{
  • $source_file = $archs;
  • $destination_file = $archs;
  • // copie du zip sur le serveur distant
  • if (!$upload = ftp_put($conn_id, $ftp_dest_folder.$destination_file, $source_file, FTP_BINARY))
  • $err_msg .= 'Impossible de transférer le fichier '.$archs.' sur '.$ftp_server."\n";
  • }
  • // Récupère la liste des fichiers sur le serveur distant
  • $contents = ftp_nlist($conn_id, $ftp_dest_folder);
  • // Vérifie l'espace disque utilisé par les sauvegardes
  • $size = '';
  • for ($i=0;$i<count($contents);$i++)
  • $size += ftp_size($conn_id, $contents[$i]);
  • if (1024 > $size && $size >=1)// si c'est compris entre 1B et 1KB
  • $sz = round($size,2).' octets';
  • if (1024 > ($size/1024) && ($size/1024) >=1)// si c'est compris entre 1KB et 1MB
  • $sz = round(($size/1024),2).' KB';
  • if (1024 > ($size/(1024*1024)) && ($size/(1024*1024)) >=1)// si c'est compris entre 1MB et 1GB
  • $sz = round(($size/(1024*1024)),2).' MB';
  • ftp_close($conn_id);
  • }
  • /*
  • PARTIE ENVOIE DE MAIL
  • */
  • if (!empty($mail_array)){
  • if (file_exists($archs)){
  • $fp = fopen($archs, 'rb');
  • $content = fread($fp, filesize($archs));
  • $checksum = md5($content);
  • fclose($fp);
  • }
  • $sujet = 'Sauvegarde journalière du '.date("d/m/Y");
  • if ($err_msg == ''){
  • $msg = $sujet.' terminée avec succès.'."\n\n".'Serveur : http://'.$_SERVER['SERVER_NAME']."\n".'Fichier : '.$archs."\n".'Checksum : '.$checksum."\n".'URL : http://'.$ftp_server.'/sql/'.$archs."\n";
  • $sujet = '[SUCCES] '.$sujet;
  • }
  • else{
  • $msg = 'La sauvegarde n\'a pas fonctionné sur le serveur http://'.$_SERVER['SERVER_NAME'].".\n\n".'Les erreurs suivantes ont été identifiées:'."\n\n".$err_msg;
  • $sujet = '[ERREURS] '.$sujet;
  • }
  • $headers = "From: DBSave<dbsave@pouet.com>\n";
  • $headers .= "MIME-Version: 1.0\n";
  • $stat = '';
  • if ($err_msg == ''){
  • $stat .= "\n\n".'####### STATISTIQUES'."\n";
  • $stat .= 'Le répertoire de sauvegarde contient '.count($contents).' fichiers (taille totale: '.$sz.')'."\n";
  • for ($i=0;$i<count($contents);$i++)
  • $stat .= '- '.substr($contents[$i],strlen($ftp_dest_folder))."\n";
  • }
  • $msg .= $stat;
  • if ($attachement == 1){
  • $boundary = '-----='.md5(uniqid(rand())); // création du fichier joint
  • if (file_exists($archs)){
  • $content_encode = chunk_split(base64_encode($content));
  • $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"";
  • $message = "\n\n";
  • $message .= "--" . $boundary . "\n";
  • $message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
  • $message .= "Content-Transfer-Encoding: 8bit\n\n";
  • $message .= $msg;
  • $message .= "--" . $boundary . "\n";
  • $message .= "Content-Type: application/zip; name=\"$archs\"\n";
  • $message .= "Content-Transfer-Encoding: base64\n";
  • $message .= "Content-Disposition: attachment; filename=\"$archs\"\n\n";
  • $message .= $content_encode . "\n";
  • $message .= "\n\n";
  • $message .= "--" . $boundary . "--\n";
  • }
  • else
  • $message = $msg;
  • }
  • }
  • // on purge le répertoire sql/
  • unlink($source_file);
  • // on envoit le mail
  • if (!empty($mail_array))
  • mail($mail,$sujet,$message,$headers);
  • }
  • // site destination
  • $ftp_data = array('www.abcdefg.com','abc','123','/abcdefg.com/sql/');
  • // site source
  • $mysql_data = array('localhost','yxcvbn','456');
  • // 0: mail de confirmation sans fichier joint, 1: mail de confirmation avec fichier joint (le zip)
  • $mail_data = array('mon@email.com',1);
  • // saveDB($mysql_data,$ftp_data) sauvegarde et n'envoit pas de mail
  • saveDB($mysql_data,$ftp_data,$mail_data);
  • ?>
<?php

function saveDB($mysql_array,$ftp_array,$mail_array = array()){

	// données de connexion au serveur où se trouvent les bases de données
	$mysql_host = $mysql_array[0];
	$mysql_user = $mysql_array[1];
	$mysql_password = $mysql_array[2];
	// données de connexion au serveur où sera mis la sauvegarde des bases de données
	$ftp_server = $ftp_array[0];
	$ftp_user_name = $ftp_array[1];
	$ftp_user_pass = $ftp_array[2];
	$ftp_dest_folder = $ftp_array[3];
	// désactiver le rapport d'erreurs afin de ne pas les afficher
	error_reporting(0);
	$err_msg = '';
	// nombre maximum d'INSERT écrit par fichier avant de libérer la variable sql_export
	$maxinsert = 500;
	
	// si on a demandé un mail à la fin...	
	if (!empty($mail_array)){
		$mail = $mail_array[0];
		// $attachement == 1 => la sauvegarde sera également envoyée par mail. ATTENTION au poids du fichier!
		$attachement = $mail_array[1];
	}
	
	/* 
		PARTIE MYSQL - on dump toutes les bases et on les met dans un zip 
	*/
	
	// librairie pour zipper
	include_once('pclzip.lib.php');
	
	// test de connection
	if(!$link = mysql_connect($mysql_host,$mysql_user,$mysql_password))
		$err_msg .= 'Impossible de se connecter à '.$mysql_host."\n";
	else{	
		// Vérification de la disponibilité en écriture du répertoire "sql/"
		// is_writable() retourne TRUE seulement si le fichier testé existe et est accessible en écriture,
		// ce qui ne convient pas ici puisque le répertoire est vide
		$testfile = 'sql/'.uniqid(mt_rand()).'.tmp';
		if (!$handle = fopen($testfile,'w'))
			$err_msg .= 'Impossible d\'ouvrir un fichier en écriture dans le répertoire "sql/"'."\n";
		else
			fclose($handle);
			
		if (file_exists($testfile)) unlink($testfile);
		
		if ($err_msg == ''){
			// liste des base de données
			$db_list = mysql_list_dbs($link);
			// tableau pour les noms des bases de données
			$names = array();
		
			// dump des bases de données
			while ($row = mysql_fetch_object($db_list)) {
			
				if ($row->Database != 'information_schema'){
			
					$q = 'SHOW CREATE DATABASE `'.($row->Database).'`';
					$r = mysql_query($q);
				
					while ($s=mysql_fetch_object($r)){
					
						// ouverture du fichier pour stocker la base en cours (une base de données par fichier)
						$filename = ($row->Database).'_'.date('Ymd').'.sql';
						$names[] = $filename;
						
						// test d'écriture (ne devrait en principe pas échouer)
						if (!$handle = fopen('sql/'.$filename, 'w'))
							$err_msg .= 'Impossible d\'ouvrir en écriture le fichier sql de '.($row->Database)."\n";
						else{
						
							// en-tête du fichier d'export pour la base en cours
							$sql_header  = '###############################################'."\n";
							$sql_header .= '## BASE DE '.($row->Database)."\n";
							$sql_header .= '###############################################'."\n\n";
							$sql_header .= $s->{'Create Database'}.";\n\n";
							
							if (fwrite($handle, $sql_header) === FALSE)
								$err_msg .= 'Impossible d\'écrire dans le fichier sql de '.($row->Database)."\n";
							else{
								mysql_select_db($row->Database, $link);
								
								// listing des tables de la base de données courante
								$q3 = 'SHOW TABLES';
								$r3 = mysql_query($q3);
								
								while ($s3 = mysql_fetch_object($r3)){
								
									// structure de chaque table
									$table = $s3->{'Tables_in_'.($row->Database)};
									$q4 = 'SHOW CREATE TABLE `'.$table.'`;';
									$r4 = mysql_query($q4);
									
									while ($s4 = mysql_fetch_object($r4)){
									
										$sql_export = '';
										$sql_export .= '## TABLE `'.$table.'`'."\n\n";
										$sql_export .= $s4->{'Create Table'}.";\n\n";
										
										// construction des INSERT										
										$q5 = 'SELECT * FROM `'.$table.'`;';
										$r5 = mysql_query($q5);
										
										// slashes en fonction du type de colonne
										$slashes = array();
									    $nbfields = mysql_num_fields($r5);
										for($i=0; $i < $nbfields; $i++)
											if (in_array(mysql_field_type($r5, $i), array('string','blob','date','timestamp')))
												$slashes[$i] = '\'';
												
										$count = 0;
										while($s5 = mysql_fetch_array($r5)){
										
											$count++;
										
											$sql_export .= 'INSERT INTO `'.$table.'` VALUES(';
											$sql_export .= $slashes[0].mysql_real_escape_string($s5[0]).$slashes[0];

											for($i=1; $i < $nbfields; $i++)
												$sql_export .= ', '.$slashes[$i].mysql_real_escape_string($s5[$i]).$slashes[$i];
											
											$sql_export .=  ");\n";	
											
											if($count == $maxinsert){
												if (fwrite($handle, $sql_export) === FALSE){
													$err_msg .= 'Erreur d\'exportation avec la '.$table.' de la base '.($row->Database)."\n";
													// mettre un break 3 ici pour stopper le tout. Je ne préfère pas personnellement
												}
												else
													$sql_export = '';
											}		
										}
										$sql_export .= "\n";
										
										// Pour chaque table, on écrit le résultat dans le fichier
										if (fwrite($handle, $sql_export) === FALSE)
											$err_msg .= 'Erreur d\'exportation avec la '.$table.' de la base '.($row->Database)."\n";			
									}
								}
							}
							fclose($handle);
						}
					}
				}
			}
		}
	}
	
	 // si on a pu dumper les bases
	if ($err_msg == ''){
	
		// création d'un zip avec les bases de données
		chdir('sql/');
		$archs = 'dbsave_'.date('Ymd').'.zip';
		$archive = new PclZip($archs);

		$cnames = implode(',', $names);
		$v_list = $archive->create($cnames);
		
		if ($v_list == 0)
			$err_msg .= 'Impossible de créer le fichier ZIP "'.$archs.'"'."\n";
		else
			for ($i=0;$i<count($names);$i++) // on efface les fichiers temporaires				
				unlink($names[$i]);
	}
	
	/*
		PARTIE FTP - on transfert le zip sur notre serveur de sauvegarde (on ne sauvegarde pas sur le même serveur, logique!)
	*/
	
	// si on a pu zipper
	if ($err_msg == ''){
	
		// connection ftp au site distant
		$conn_id = ftp_connect($ftp_server);
		$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
		
		if ((!$conn_id) || (!$login_result))
			$err_msg .= 'Impossible de se connecter au serveur '.$ftp_server."\n";
		else{		
			$source_file = $archs;
			$destination_file = $archs;
			// copie du zip sur le serveur distant
			if (!$upload = ftp_put($conn_id, $ftp_dest_folder.$destination_file, $source_file, FTP_BINARY))
				$err_msg .= 'Impossible de transférer le fichier '.$archs.' sur '.$ftp_server."\n";
		}
		
		// Récupère la liste des fichiers sur le serveur distant
		$contents = ftp_nlist($conn_id, $ftp_dest_folder);
		
		// Vérifie l'espace disque utilisé par les sauvegardes
		$size = '';
		for ($i=0;$i<count($contents);$i++)
			$size += ftp_size($conn_id, $contents[$i]);
		if (1024 > $size && $size >=1)// si c'est compris entre 1B et 1KB
			$sz = round($size,2).' octets';
		if (1024 > ($size/1024) && ($size/1024) >=1)// si c'est compris entre 1KB et 1MB
			$sz = round(($size/1024),2).' KB';
		if (1024 > ($size/(1024*1024)) && ($size/(1024*1024)) >=1)// si c'est compris entre 1MB et 1GB
			$sz = round(($size/(1024*1024)),2).' MB';
			
		ftp_close($conn_id);
	}
	
	/*
		PARTIE ENVOIE DE MAIL
	*/
	
	if (!empty($mail_array)){
		if (file_exists($archs)){
			$fp = fopen($archs, 'rb');
			$content = fread($fp, filesize($archs));
			$checksum = md5($content);
			fclose($fp);
		}
	
		$sujet = 'Sauvegarde journalière du '.date("d/m/Y");
		
		if ($err_msg == ''){
			$msg = $sujet.' terminée avec succès.'."\n\n".'Serveur  : http://'.$_SERVER['SERVER_NAME']."\n".'Fichier  : '.$archs."\n".'Checksum : '.$checksum."\n".'URL      : http://'.$ftp_server.'/sql/'.$archs."\n";
			$sujet = '[SUCCES] '.$sujet;
		}
		else{
			$msg = 'La sauvegarde n\'a pas fonctionné sur le serveur http://'.$_SERVER['SERVER_NAME'].".\n\n".'Les erreurs suivantes ont été identifiées:'."\n\n".$err_msg;
			$sujet = '[ERREURS] '.$sujet;			
		}

		$headers  = "From: DBSave<dbsave@pouet.com>\n";		
		$headers .= "MIME-Version: 1.0\n";
		
		$stat = '';
		if ($err_msg == ''){
			$stat .= "\n\n".'####### STATISTIQUES'."\n";
			$stat .= 'Le répertoire de sauvegarde contient '.count($contents).' fichiers (taille totale: '.$sz.')'."\n";

			for ($i=0;$i<count($contents);$i++)
				$stat .= '- '.substr($contents[$i],strlen($ftp_dest_folder))."\n";
		}
		
		$msg .= $stat;
		
		if ($attachement == 1){
			$boundary = '-----='.md5(uniqid(rand())); // création du fichier joint
			
			if (file_exists($archs)){
				$content_encode = chunk_split(base64_encode($content));
				$headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"";
				$message  = "\n\n";
				$message .= "--" . $boundary . "\n";
				$message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
				$message .= "Content-Transfer-Encoding: 8bit\n\n";
				$message .= $msg;
				$message .= "--" . $boundary . "\n";
				$message .= "Content-Type: application/zip; name=\"$archs\"\n";
				$message .= "Content-Transfer-Encoding: base64\n";
				$message .= "Content-Disposition: attachment; filename=\"$archs\"\n\n";
				$message .= $content_encode . "\n";
				$message .= "\n\n";
				$message .= "--" . $boundary . "--\n";
			}
			else
				$message = $msg;
		}
	}
	
	// on purge le répertoire sql/
	unlink($source_file);
	
	// on envoit le mail
	if (!empty($mail_array))
		mail($mail,$sujet,$message,$headers);
}

// site destination
$ftp_data = array('www.abcdefg.com','abc','123','/abcdefg.com/sql/');
// site source
$mysql_data = array('localhost','yxcvbn','456');
// 0: mail de confirmation sans fichier joint, 1: mail de confirmation avec fichier joint (le zip)
$mail_data = array('mon@email.com',1); 

// saveDB($mysql_data,$ftp_data) sauvegarde et n'envoit pas de mail
saveDB($mysql_data,$ftp_data,$mail_data);

?>

Conclusion

Pour utiliser ce code de manière optimale:

1. créer un fichier saveDB.php contenant le code.

2. créer un répertoire sur le site distant ftp avec les droits en écriture et créer un .htaccess et un .htpasswd pour le répertoire de sauvegarde ftp
Vous devriez avoir la structure suivante:
[path]/repertoire_de_sauvegarde_ftp/.htaccess et.htpasswd

3. adapter saveDB.php à vos besoins et le mettre sur le serveur contenant les bd à sauvegarder dans un répertoire ("sql/" ici):
$ftp_data = array('www.votresiteftp.com','votre_user_ftp','votre_mot_de_passe_ftp','/repertoire_de_sauvegarde_ftp/');
$mysql_data = array('localhost','votre_user','votre_mot_de_passe');
$mail_data = array('votre@email.com',0); // 0: juste envoyer un mail de confirmation, 1: mettre en fichier joint le zip

--> Ne pas oublier de remplacer dans le code "sql/" par le bon répertoire

4. protéger le répertoire "sql/" par un .htaccess et un .htpasswd
Vous devriez avoir la structure suivante:
[path]/repertoire_avec_saveDB.php/.htaccess et .htpasswd et saveDB.php et pclzip.lib.php et le répertoire sql/ (cf fichier joint)

5. si vous avez un accès à cron, ajouter la ligne "0 2  * * 4 php -f /chemin_a_saveDB/saveDB.php" par exemple pour exécuter ce script tous les jeudis à 2h du matin, sinon vous pouvez utiliser les services de webcron.org
02 janvier 2008 23:06:36 :
orthographe
03 janvier 2008 07:50:41 :
Petite correction dans l'envoi du mail
03 janvier 2008 12:10:40 :
- zip retiré car inutile - prise en compte des remarques de Jantosze - ajout de fioritures dans le mail envoyé :-) - ajout d'une capture d'écran
04 janvier 2008 12:40:38 :
prise en compte des remarques de yoman64
05 janvier 2008 14:22:16 :
correction sur l'envoi des mails si fichier joint (les stats n'apparaissaient pas)
06 janvier 2008 19:39:29 :
Ajout d'un ";" dans la ligne $sql_header .= $s->{'Create Database'}.";\n\n"; Ajout d'un ";" dans la ligne $sql_export .= $s4->{'Create Table'}."\n\n"; Ajout de date et de timestamp dans la ligne if (in_array(mysql_field_type($r5, $i), array('string','blob','date','timestamp')))
  • signaler à un administrateur
    Commentaire de webdeb le 03/01/2008 01:47:26 7/10

    Salut,

    J'aurais fait beaucoup plus simple :

    <?php

    shell_exec('mysqldump -h monServeurSql -u monUser -p monPassword --all-databases > chemin/mon/backup.sql');

    ?>

    ++

  • signaler à un administrateur
    Commentaire de malik7934 le 03/01/2008 07:39:35

    Salut Webdeb,

    Merci pour ta remarque, ceci dit tout le monde n'a pas accès à un shell. J'ai plusieurs sites chez le principal hébergeur suisse (Infomaniak pour ne pas le citer) et il ne donne pas cette possibilité.

  • signaler à un administrateur
    Commentaire de malik7934 le 03/01/2008 07:55:01

    et si je peux encore ajouter quelque chose: ma source ne se borne pas à faire un mysqldump (--all-databases est d'ailleur une mauvaise idée :-)). Elle dump séparément les bases, crée un zip avec autant de fichiers à l'intérieur qu'il y a de bases, envoit le tout par ftp dans un répertoire protégé sur un autre serveur et envoit un email pour dire que tout s'est bien passé (ou non) avec le zip en fichier joint si demandé... le tout avec un petit appel en cron.

    Ta commande shell est donc un chouilla réductrice ;-)

  • signaler à un administrateur
    Commentaire de webdeb le 03/01/2008 09:13:56

    Oui c'est limité mais c'est une autre façon de dumper ^^

  • signaler à un administrateur
    Commentaire de jantosze le 03/01/2008 10:58:39

    Salut,

    L'objectif de ton code est de manipuler des volumes importants de données j'ai 2 remarques:
    - Structurer ton test d'échec fopen du $handle avant les 3 boucles while d'extraction de la base ,
    -  Ne serait-il pas judicieux de vider la variable $sql_export (par exemple en fin du while $s5)  pour éviter en cas de volume important un overflow de la limite mémoire accorder par l'administrateur du serveur.

    cdt
    JAN.

  • signaler à un administrateur
    Commentaire de malik7934 le 03/01/2008 11:09:15

    Salut Jantosze,

    "Structurer ton test d'échec fopen du $handle avant les 3 boucles while d'extraction de la base ": effectivement, cela permettrait d'éviter de tout dumper pour rien en cas d'échec! Bonne remarque.

    "Ne serait-il pas judicieux de vider la variable $sql_export (par exemple en fin du while $s5)": remarque également intéressante. Si je comprends bien ton point de vue, il s'agirait de stocker une table dans $sql_export, de l'écrire dans le fichier, puis de vider $sql_export avant de s'attaquer à la prochaine table?

    Je vais m'y repencher...

  • signaler à un administrateur
    Commentaire de jantosze le 03/01/2008 16:42:07

    Pour la rem 2 , il s'agit de traiter un dysfonctionnement risquant d'apparaître lors d'un transfert important, car les Ing Syst pour gérer les machines utilisent des règles de quotas: cpu, mémoire, io.... et comme au niveau d'un simple compte il n'y a pas d'engagement de niveaux de service de la part de l' hébergeur (c'est du best effort), la stratégie de sécurité de l'IS risque de pénaliser les perfs des comptes gourmands. Je pense que $sql_export (variable volatile) devrait se vider au fil de l'eau.
    Cdt
    JAN

  • signaler à un administrateur
    Commentaire de yoman64 le 03/01/2008 22:42:01

    Salut,
    Le code est loin d'être optimisé autant du coté php que mysql. Par exemple tu crée une requete INSERT par enregistrement, t'imagine si la table a un million d'enregistrements lors de la restauration ça fait 1 million de query.. ? Tu devrais mettre plusieurs enregistrements par insert, par exemple 500 pour chaque INSERT.

    Je pense que mysql_real_escape_string est plus approprié que addslashes.

    Pour vérifier si tu as accès en écriture à un fichier utilise la fonction is_writable au lieu de créé un fichier et de l'effacer ensuite.

    Dans le coin ou il y a (dans ta boucle for):
    #  if($i != 0) $sql_export .= ', ';
    # if(mysql_field_type($r5, $i) == 'stri
    .......

    Tu devrais sortir le if $i, une comparaison à chaque colone de chaque ligne c'est lourd pour rien.

    Ensuite tes deux comparaisons pour savoir si tu dois mettre une quote ou pas tu devrais encore une fois le faire juste une fois et stocké la colonne et son type dans un array, après suffit d'appeler un array au lieu d'appeler 4 fonctions plus deux comparaisons a chaque colonne de chaque ligne :|.


    Je ne note pas tout de suite, mais bravo l'envois par mail et par ftp est une bonne idée, par contre faut garder dans l'idée que ce script la avec les deux envois peut être très long si en plus tu fais 7-8 comparaisons inutiles par cycle (ex: tu as 12 lignes de 8 colonnes * 8 comparaisons= 768 comparaisons qui peuvent être évités).

    Bonne continuation!

  • signaler à un administrateur
    Commentaire de malik7934 le 04/01/2008 10:48:44

    Salut Yoman64,

    Merci pour tes remarques, je vais m'y pencher.

    Ceci dit, quelqu'un qui a une base de données avec un million d'entrées a son propre serveur ou a en tous cas un accès ssh, cela me semble évident, et utilisera un code tout a fait différent (je dirais même un script .sh qui s'exécutera en quelques instants et fera tout ce que fais ce code ci-dessus! - expérience faite, 1.6GB zippés en moins d'une seconde en console, alors qu'avec un script PHP ce serait impossible).

    Quoi qu'il en soit, pour le côté ludique de la chose, je vais réfléchir à tes remarques.

    Merci,
    Malik

  • signaler à un administrateur
    Commentaire de LiTtLeBuBu le 05/01/2008 12:21:39

    Pour moi celà fonctionne très bien et c'est même la première source qui a réellement fonctionné pour dumper ma petite base.

    Il faudrait juste pouvoir sauvegarder la valeur de AUTO INCREMENT.
    Si tu as le bout de code à rajouter ce serait cool.

    @+

  • signaler à un administrateur
    Commentaire de malik7934 le 05/01/2008 14:26:05

    Salut LiTtLeBuBu,

    Content que ça te serve :-)

    Je ne comprends pas ton problème d'auto-increment. Je viens de vérifier un export et je l'ai bien (il vaut 22 dans l'exemple suivant):

    CREATE TABLE `demo_cat` (
      `id` int(10) unsigned NOT NULL auto_increment,
      `creation_date` date default NULL,
      `name` text NOT NULL,
      `internal_name` text NOT NULL,
      `rang` int(11) NOT NULL default '0',
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM AUTO_INCREMENT=22 DEFAULT CHARSET=latin1

  • signaler à un administrateur
    Commentaire de LiTtLeBuBu le 05/01/2008 17:05:23

    Eh bien chez moi il ne sauvegarde pas AUTO_INCREMENT
    donc sinon dans quelle ligne du code fait il cette sauvegarde ?

  • signaler à un administrateur
    Commentaire de LiTtLeBuBu le 05/01/2008 20:51:06

    # SQL Dump par script PHP
    # http://www.monsite.com
    #
    # Serveur: sql.******.fr
    # Généré le 05-01-2008 à 20:45:14
    # Version du serveur PHP: 4.3.11
    # Version de Mysql: 4.1.16-Max
    #
    # Base de données: `base`
    #
    #

    CREATE DATABASE `base` /*!40100 DEFAULT CHARACTER SET latin1 */

    # ---------------------------------------------------

    #
    # Structure de la table `referer`
    #

    CREATE TABLE `referer` (
      `id` smallint(4) NOT NULL auto_increment,
      `nom` varchar(100) NOT NULL default '',
      `ville` varchar(100) NOT NULL default '',
      `date` date NOT NULL default '0000-00-00',
      `photo1` varchar(255) NOT NULL default '',
      `text1` varchar(60) NOT NULL default '',
      `photo2` varchar(255) NOT NULL default '',
      `text2` varchar(60) NOT NULL default '',
      `photo3` varchar(255) NOT NULL default '',
      `text3` varchar(60) NOT NULL default '',
      `photo4` varchar(255) NOT NULL default '',
      `text4` varchar(60) NOT NULL default '',
      `photo5` varchar(255) NOT NULL default '',
      `text5` varchar(60) NOT NULL default '',
      `photo6` varchar(255) NOT NULL default '',
      `text6` varchar(60) NOT NULL default '',
      `description` text NOT NULL,
      KEY `id` (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8

  • signaler à un administrateur
    Commentaire de LiTtLeBuBu le 06/01/2008 13:50:55

    #1064 - Erreur de syntaxe pr?s de 'CREATE TABLE `referer` (
      `id` smallint(4) NOT NULL auto_inc' ? la ligne 21

    En plus le backup ne fonctionne pas ?
    Tu as une idée ?

  • signaler à un administrateur
    Commentaire de malik7934 le 06/01/2008 19:21:17

    Je ne vois pas d'erreur... Essaie en console de faire "SHOW CREATE TABLE `referer`" et compare le résultat de l'export.

  • signaler à un administrateur
    Commentaire de malik7934 le 06/01/2008 19:26:50

    Là, je n'ai pas le temps de tester, mais je suis quasi sûr que le problème vient de la ligne 78.

    Remplace
    $sql_header .= $s->{'Create Database'}."\n\n";

    par
    $sql_header .= $s->{'Create Database'}.";\n\n"; // <- il y a un ";" en plus

  • signaler à un administrateur
    Commentaire de malik7934 le 06/01/2008 19:30:07

    et 100!

  • signaler à un administrateur
    Commentaire de alphanono le 07/01/2008 11:29:38 9/10

    Merci pour ce code. J'ai peu en faire quelques adaptations pour mon usage personnel et ça fonctionne super bien.
    J'ai juste un soucis de Notices qui est dû aux lignes 110-111 :

    if (in_array(mysql_field_type($r5, $i), array('string','blob','date','timestamp')))
    $slashes[$i] = '\'';

    Est-ce que ça peut poser problème au niveau de la sauvegarde SQL de remplacer par ceci :

    if (in_array(mysql_field_type($r5, $i), array('string','blob','date','timestamp'))){
    $slashes[$i] = '\'';
    } else {
    $slashes[$i] = '';
    }

    Avec cette modif, plus d'erreur PHP de rapportée ... et donc des lignes en moins dans les logs ...

  • signaler à un administrateur
    Commentaire de malik7934 le 07/01/2008 11:32:35

    Salut,

    C'est même plus propre ce que tu as mis! moi j'ai eu la flême :-)

    Ceci dit, c'est étonnant que tu aies eu une notice car j'ai mis error_reporting(0)!

  • signaler à un administrateur
    Commentaire de alphanono le 07/01/2008 11:36:33

    Bon tant mieux !

    Pour les notices ... je n'aime pas travailler en error_reporting(0). Je préfère coder avec l'affichage des erreurs et corriger tout ce qui est nécessaire.

    Ca me permet de garder des rapports d'erreurs sur d'autres problèmes plus ponctuels que je ne pouvais pas prévoir lors du codage par exemple.

  • signaler à un administrateur
    Commentaire de malik7934 le 07/01/2008 11:38:02

    OK, ceci dit, si j'ai enlevé le rapport d'erreur, c'est dans un souci de protection du script si qqun trouve le login/pwd pour accéder au répertoire. Anyway...

  • signaler à un administrateur
    Commentaire de alphanono le 07/01/2008 11:42:51

    outch ... là je suis largué ! error_reporting(0) pour une protection du script ? Tu peux m'en dire plus ?

  • signaler à un administrateur
    Commentaire de malik7934 le 07/01/2008 11:45:59

    Ben en 2 mots: si tu as une erreur et qu'elle s'affiche dans le navigateur, c'est des infos sur ton système que tu donnes à qui veut et qui peuvent servir pour de mauvaises intentions suivant quoi.

    En principe, un site en production ne devrait jamais avoir d'erreurs qui s'affichent directement dans le browser.

  • signaler à un administrateur
    Commentaire de alphanono le 07/01/2008 11:51:09

    OK

    Ca fait 6 ans que je code en ASP et je suis passé à PHP il y a peu. Donc question de débutant PHP :
    error_reporting(0) désactive les rapports d'erreur dans le navigateur mais les bloque-t'il aussi dans les fichiers de logs du serveur ?

  • signaler à un administrateur
    Commentaire de malik7934 le 07/01/2008 11:59:53

    Pas sûr, mais pour ce que je viens de voir sur gg, il semblerait qu'il est conseillé d'avoir

    error_reporting(E_ALL);
    error_log(...);

  • signaler à un administrateur
    Commentaire de alphanono le 07/01/2008 12:03:35

    Super, je vais regarder ça d'un peu plus prêt.

    Merci pour le code ... et les réponses ! ;)

  • signaler à un administrateur
    Commentaire de johann1 le 09/01/2008 01:11:45 9/10

    Fabuleux Malik,

    Je vais placer ce super code sur tous mes sites !

    Merci !

  • signaler à un administrateur
    Commentaire de christobal le 17/01/2008 21:38:35

    Bonjour,
    j'ai du remplacer error_log(0); par error_reporting(E_ALL); pour avoir les erreurs car je n'arrive pas a faire fonctionner le script.


    Warning: fopen(sql/106750348478fbbea7e075.tmp) [function.fopen]: failed to open stream: No such file or directory in /home.10.2/xxxxx/www/tst/sql/saveDB.php on line 40
    Notice: Undefined variable: archs in /home.10.2/xxxxx/www/tst/sql/saveDB.php on line 206
    Notice: Undefined variable: archs in /home.10.2/xxxxxx/www/tst/sql/saveDB.php on line 239
    Notice: Undefined variable: source_file in /home.10.2/xxxxx/www/tst/sql/saveDB.php on line 261
    Warning: unlink() [function.unlink]: No such file or directory in /home.10.2/xxxxx/www/tst/sql/saveDB.php on line 261

    Merci de votre aide

  • signaler à un administrateur
    Commentaire de alphanono le 17/01/2008 21:42:08

    Tu as un problème avec ta connexion à ton FTP. Il faut que tu revois tes paramètres.

  • signaler à un administrateur
    Commentaire de malik7934 le 18/01/2008 07:24:52

    Warning: fopen(sql/106750348478fbbea7e075.tmp) [function.fopen]: failed to open stream: No such file or directory in /home.10.2/xxxxx/www/tst/sql/saveDB.php on line 40

    => le script s'attend à trouver un répertoire sql/ dans sql/

  • signaler à un administrateur
    Commentaire de LiTtLeBuBu le 18/01/2008 09:50:46

    Moi j'ai toujours cette erreur quand je veux restaurer les tables. Mais comme j'ai modifié un peu le script il y a peut être une erreur qqpart....

    // DUMP SQL
    function saveDB($mysql_array = array()){

    $mysql_host = $mysql_array[0];
    $mysql_user = $mysql_array[1];
    $mysql_password = $mysql_array[2];

    error_reporting(0);
    $err_msg = '';
    $maxinsert = 500;

    if (!empty($mail_array)){
    $mail = $mail_array[0];
    $attachement = $mail_array[1];
    }

    if(!$link = mysql_connect($mysql_host,$mysql_user,$mysql_password))
    $err_msg .= 'Impossible de se connecter à '.$mysql_host."\n";
    else{
    $testfile = 'backup_sql/'.uniqid(mt_rand()).'.tmp';
    if (!$handle = fopen($testfile,'w'))
    $err_msg .= 'Impossible d\'ouvrir un fichier en écriture dans le répertoire "backup_sql/"'."\n";
    else
    fclose($handle);

    if (file_exists($testfile)) unlink($testfile);

    if ($err_msg == ''){
    $db_list = mysql_list_dbs($link);
    $names = array();

    while ($row = mysql_fetch_object($db_list)) {
    if ($row->Database != 'information_schema'){
    $q = 'SHOW CREATE DATABASE `'.($row->Database).'`';
    $r = mysql_query($q);

    while ($s=mysql_fetch_object($r)){
    $filename = 'BackupSQL_'.($row->Database).'_'.date('d-m-Y').'.sql';
    $names[] = $filename;
    if (!$handle = fopen('backup_sql/'.$filename, 'w'))
    $err_msg .= 'Impossible d\'ouvrir en écriture le fichier sql de '.($row->Database)."\n";
    else{

    $sql_header .= '# SQL Dump par script PHP'."\n";
    $sql_header .= '# http://www.******.com'."\n";
    $sql_header .= '#'."\n";
    $sql_header .= '# Serveur: sql.*****.fr'."\n";
    $sql_header .= '# Généré le '.date('d-m-Y à H:i:s').''."\n";
    $sql_header .= '# Version du serveur PHP: '.phpversion().''."\n";
    $sql_header .= '# Version de Mysql: '.mysql_get_server_info().''."\n";
    $sql_header .= '#'."\n";
    $sql_header .= '# Base de données: `'.($row->Database).'`'."\n";
    $sql_header .= '#'."\n";
    $sql_header .= '#'."\n\n";
    $sql_header .= $s->{'Create Database'}.";\n\n";

    if (fwrite($handle, $sql_header) === FALSE)
    $err_msg .= 'Impossible d\'écrire dans le fichier sql de '.($row->Database)."\n";
    else{
    mysql_select_db($row->Database, $link);

    $q3 = 'SHOW TABLES';
    $r3 = mysql_query($q3);

    while ($s3 = mysql_fetch_object($r3)){
    $table = $s3->{'Tables_in_'.($row->Database)};
    $q4 = 'SHOW CREATE TABLE `'.$table.'`;';
    $r4 = mysql_query($q4);

    while ($s4 = mysql_fetch_object($r4)){
    $sql_export = '';
    $sql_export .= '# ---------------------------------------------------'."\n\n";
    $sql_export .= '#'."\n";
    $sql_export .= '# Structure de la table `'.$table.'`'."\n";
    $sql_export .= '#'."\n\n";
    $sql_export .= $s4->{'Create Table'}."\n\n";

    $q5 = 'SELECT * FROM `'.$table.'`;';
    $r5 = mysql_query($q5);

    $slashes = array();
        $nbfields = mysql_num_fields($r5);
    for($i=0; $i < $nbfields; $i++)
    if (in_array(mysql_field_type($r5, $i), array('string','blob')))
    $slashes[$i] = '\'';

    $count = 0;

    while($s5 = mysql_fetch_array($r5)){
    $count++;

    $sql_export .= '#'."\n";
    $sql_export .= '# Contenu de la table `'.$table.'`'."\n";
    $sql_export .= '#'."\n\n";

    $sql_export .= 'INSERT INTO `'.$table.'` VALUES(';
    $sql_export .= $slashes[0].mysql_real_escape_string($s5[0]).$slashes[0];
    for($i=1; $i < $nbfields; $i++)
    $sql_export .= ', '.$slashes[$i].mysql_real_escape_string($s5[$i]).$slashes[$i];

    $sql_export .=  ");\n";

    if($count == $maxinsert){
    if (fwrite($handle, $sql_export) === FALSE){
    $err_msg .= 'Erreur d\'exportation avec la '.$table.' de la base '.($row->Database)."\n";

    }
    else
    $sql_export = '';
    }
    }
    $sql_export .= "\n";


    if (fwrite($handle, $sql_export) === FALSE)
    $err_msg .= 'Erreur d\'exportation avec la '.$table.' de la base '.($row->Database)."\n";
    }
    }
    }
    fclose($handle);
    }
    }
    }
    }
    }
    }
    }

    $mysql_data = array(SERVEUR,NAME,PASS);

  • signaler à un administrateur
    Commentaire de malik7934 le 18/01/2008 09:53:06

    T'aurais pu mettre ça dans le forum... :-/

  • signaler à un administrateur
    Commentaire de LiTtLeBuBu le 18/01/2008 10:30:02

    OK je vais le faire lol....

  • signaler à un administrateur
    Commentaire de christobal le 25/01/2008 19:05:25

    hello, je suis de retour et je n'arrive tj pas a faire marcher cette source :(
    voici les erreurs que j'ais :

    Warning: mysql_list_dbs() [function.mysql-list-dbs]: Unable to save MySQL query result in /home.10.2/zzzxzzz/www/xxxxx/sql/saveDB.php on line 50

    Warning: mysql_fetch_object(): supplied argument is not a valid MySQL result resource in /home.10.2/zzzxzzz/www/xxxxx/sql/saveDB.php on line 55

    Warning: chdir() [function.chdir]: No such file or directory (errno 2) in /home.10.2/zzzxzzz/www/xxxxx/sql/saveDB.php on line 153

    Warning: ftp_put() [function.ftp-put]: Could not create file. in /home.10.2/zzzxzzz/www/xxxxx/sql/saveDB.php on line 182

    mais que faire ??
    et que l'on ne me dise pas que c'est un pb FTP car ce sont les code quie j'utilie pour mettre me fichier en ligne.

    Merci de votre aide

  • signaler à un administrateur
    Commentaire de christobal le 26/01/2008 11:23:47

    Hello, retour sur mon dernier poste.
    j'ai tj les erreurs suivantes :

    Warning: mysql_list_dbs() [function.mysql-list-dbs]: Unable to save MySQL query result in /home.10.2/zzzxzzz/www/xxxxx/sql/saveDB.php on line 50
    Warning: mysql_fetch_object(): supplied argument is not a valid MySQL result resource in /home.10.2/zzzxzzz/www/xxxxx/sql/saveDB.php on line 55
    Warning: chdir() [function.chdir]: No such file or directory (errno 2) in /home.10.2/zzzxzzz/www/xxxxx/sql/saveDB.php on line 153
    Warning: fread() [function.fread]: Length parameter must be greater than 0. in /home.10.2/zzzxzzz/www/xxxxx/sql/saveDB.php on line 209

    La différence est le dernier message et oui je n'avais pas spésifier le chemin absolu du FTP mais relatif donc ca marchait pas.
    Autre chose j'ai bien le mail avec le fichier zip en PJ mais winzip me dit que le fichier est endomagé. C'est pas étonnant vue que le pois est de 71 Octets au lieux des 76 K)
    De plus l'archive ne se trouve pas dans mon rep /sql/ elle est ... nulpart.

    Une idée ?!

  • signaler à un administrateur
    Commentaire de malik7934 le 27/01/2008 12:07:40

    essaie déjà de régler "mysql_fetch_object(): supplied argument is not a valid MySQL result resource". A vue de nez, t'as peut-être pas les droits suffisants pour lire toutes les bases?! Faut un peu analyser! Regarde ce qui se passe autour de la ligne 55...

Ajouter un commentaire

</