<?php
/**
 * Sauvegarde MySQL 
 * Travail initié par :
 *
 * @package	BackupMySQL
 * @author	Benoit Asselin
 * @version	backup.php, 2013/01/13
 *
 */
 
$_SESSION['prefix'] = $prefix;

if($_SESSION['save_auto']=='0') {
	$_SESSION['count_sess']=($_SESSION['nb_tables']+1);
}
else if($_SESSION['save_auto']=='1') {
	$_SESSION['count_sess']=($_SESSION['nb_tables']+2);
}
else if($_SESSION['save_auto']=='2') {
	$_SESSION['count_sess']=($_SESSION['nb_tables']+3);
}

/**
 * Sauvegarde MySQL
 */
class BackupMySQL extends mysqli {
	
	/**
	 * Dossier des fichiers de sauvegardes
	 * @var string
	 */
	protected $dossier;
	
	/**
	 * Nom du fichier
	 * @var string
	 */
	protected $nom_fichier;
	
	/**
	 * Ressource du fichier GZip
	 * @var ressource
	 */
	protected $fichier;
	
	
	/**
	 * Constructeur
	 * @param array $options
	 */
	public function __construct($options = array()) {
		$default = array(
			'host' => ini_get('mysqli.default_host'),
			'username' => ini_get('mysqli.default_user'),
			'passwd' => ini_get('mysqli.default_pw'),
			'dbname' => '',
			'port' => ini_get('mysqli.default_port'),
			'socket' => ini_get('mysqli.default_socket'),
			// autres options
			'dossier' => './',
			'nbr_fichiers' => 10,
			'nom_fichier' => 'backup'
			);
		$options = array_merge($default, $options);
		extract($options);
		
		// Connexion de la connexion DB
		@parent::__construct($host, $username, $passwd, $dbname, $port, $socket);
		if($this->connect_error) {
			$this->message(SAVERROR1.' (' . $this->connect_errno . ') '. $this->connect_error);
			return;
		}
		
		// Controle du dossier
		$this->dossier = $dossier;
		if(!is_dir($this->dossier)) {
			$this->message(SAVERROR2.' &quot;' . htmlspecialchars($this->dossier) . '&quot;');
			return;
		}
		
		// Indication si la sauvegarde est partielle ou non
		$array = array_keys($_POST);
		
		if(count($array)==$_SESSION['count_sess']||$_SESSION['save_auto']!='0') { $part = ''; }
		else { $part = '-partial'; }
		
		// Controle du fichier
		$this->nom_fichier = $nom_fichier.date('Ymd-His').$part.'.sql';
		$this->fichier = @fopen($this->dossier . $this->nom_fichier, 'w');
		if(!$this->fichier) {
			$this->message(SAVERROR3.' &quot;' . htmlspecialchars($this->nom_fichier) . '&quot;');
			echo $dossier;
			return;
		}
		
		// Demarrage du traitement
		$this->sauvegarder();
		$this->purger_fichiers($nbr_fichiers);
	}
	
	/**
	 * Message d'information ( commenter le "echo" pour rendre le script invisible )
	 * @param string $message HTML
	 */
	protected function message($message = '&nbsp;') {
		echo '<p style="padding:0; margin:1px 10px; font-family:Liberation Sans, Arial;">'. $message .'</p>';
	}
	
	/**
	 * Protection des quot SQL
	 * @param string $string
	 * @return string
	 */
	protected function insert_clean($string) {
		// Ne pas changer l'ordre du tableau !!!
		$s1 = array( "\\"	, "'"	, "\r", "\n", );
		$s2 = array( "\\\\"	, "''"	, '\r', '\n', );
		return str_replace($s1, $s2, $string);
	}
	
	/**
	 * Sauvegarder les tables
	 */
	protected function sauvegarder() {
		if(!isset($_POST['hidden_save'])) {
			$this->message(SAVE.'...');
		}
		
		$sql  = '--' ."\n";
		$sql .= '-- '. $this->nom_fichier ."\n";
		$encoding = mb_detect_encoding($sql, mb_detect_order(), true);
		if ($encoding) {
		    $sql_utf8 = mb_convert_encoding(addcslashes($sql, '‰'), 'UTF-8', $encoding);
		} else {
		    $sql_utf8 = addcslashes($sql, '‰');
		}
		fwrite($this->fichier, $sql_utf8);
		
		// Liste les tables
		$result_tables = $this->query("SHOW TABLE STATUS LIKE '".$_SESSION['prefix']."_%'");
		if($result_tables && $result_tables->num_rows) {
			while($obj_table = $result_tables->fetch_object()) {
				if(isset($_POST[''.$obj_table->{'Name'}.''])) {
					if(!isset($_POST['hidden_save'])) {
						$this->message('- ' . htmlspecialchars($obj_table->{'Name'}));
					}
					
					// DROP ...
					$sql  = "\n\n";
					$sql .= 'DROP TABLE IF EXISTS `'. $obj_table->{'Name'} .'`' .";\n";

					// CREATE ...
					$result_create = $this->query('SHOW CREATE TABLE `'. $obj_table->{'Name'} .'`');
					if($result_create && $result_create->num_rows) {
						$obj_create = $result_create->fetch_object();
						$sql .= $obj_create->{'Create Table'} .";\n";
						$result_create->free_result();
					}

					// INSERT ...
					$result_insert = $this->query('SELECT * FROM `'. $obj_table->{'Name'} .'`');
					if($result_insert && $result_insert->num_rows) {
						$sql .= "\n";
						while($obj_insert = $result_insert->fetch_object()) {
							$virgule = false;
							
							$sql .= 'INSERT INTO `'. $obj_table->{'Name'} .'` VALUES (';
							foreach($obj_insert as $val) {
								$sql .= ($virgule ? ',' : '');
								if(is_null($val)) {
									$sql .= 'NULL';
								} else {
									$sql .= '\''. $this->insert_clean($val) . '\'';
								}
								$virgule = true;
							} // for
							
							$sql .= ')' .";\n";
							
						} // while
						$result_insert->free_result();
					}
					
					$trans = array(
					    "\xc2\x80" => "\xe2\x82\xac", /* EURO SIGN */
					    "\xc2\x82" => "\xe2\x80\x9a", /* SINGLE LOW-9 QUOTATION MARK */
					    "\xc2\x83" => "\xc6\x92",     /* LATIN SMALL LETTER F WITH HOOK */
					    "\xc2\x84" => "\xe2\x80\x9e", /* DOUBLE LOW-9 QUOTATION MARK */
					    "\xc2\x85" => "\xe2\x80\xa6", /* HORIZONTAL ELLIPSIS */
					    "\xc2\x86" => "\xe2\x80\xa0", /* DAGGER */
					    "\xc2\x87" => "\xe2\x80\xa1", /* DOUBLE DAGGER */
					    "\xc2\x88" => "\xcb\x86",     /* MODIFIER LETTER CIRCUMFLEX ACCENT */
					    "\xc2\x89" => "\xe2\x80\xb0", /* PER MILLE SIGN */
					    "\xc2\x8a" => "\xc5\xa0",     /* LATIN CAPITAL LETTER S WITH CARON */
					    "\xc2\x8b" => "\xe2\x80\xb9", /* SINGLE LEFT-POINTING ANGLE QUOTATION */
					    "\xc2\x8c" => "\xc5\x92",     /* LATIN CAPITAL LIGATURE OE */
					    "\xc2\x8e" => "\xc5\xbd",     /* LATIN CAPITAL LETTER Z WITH CARON */
					    "\xc2\x91" => "\xe2\x80\x98", /* LEFT SINGLE QUOTATION MARK */
					    "\xc2\x92" => "\xe2\x80\x99", /* RIGHT SINGLE QUOTATION MARK */
					    "\xc2\x93" => "\xe2\x80\x9c", /* LEFT DOUBLE QUOTATION MARK */
					    "\xc2\x94" => "\xe2\x80\x9d", /* RIGHT DOUBLE QUOTATION MARK */
					    "\xc2\x95" => "\xe2\x80\xa2", /* BULLET */
					    "\xc2\x96" => "\xe2\x80\x93", /* EN DASH */
					    "\xc2\x97" => "\xe2\x80\x94", /* EM DASH */

					    "\xc2\x98" => "\xcb\x9c",     /* SMALL TILDE */
					    "\xc2\x99" => "\xe2\x84\xa2", /* TRADE MARK SIGN */
					    "\xc2\x9a" => "\xc5\xa1",     /* LATIN SMALL LETTER S WITH CARON */
					    "\xc2\x9b" => "\xe2\x80\xba", /* SINGLE RIGHT-POINTING ANGLE QUOTATION*/
					    "\xc2\x9c" => "\xc5\x93",     /* LATIN SMALL LIGATURE OE */
					    "\xc2\x9e" => "\xc5\xbe",     /* LATIN SMALL LETTER Z WITH CARON */
					    "\xc2\x9f" => "\xc5\xb8"      /* LATIN CAPITAL LETTER Y WITH DIAERESIS*/
					);
					$encoding = mb_detect_encoding($sql, mb_detect_order(), true);
					if ($encoding && $encoding !== 'UTF-8') {
					    $sql_utf8 = mb_convert_encoding($sql, 'UTF-8', $encoding);
					} else {
					    $sql_utf8 = $sql;
					}
					$result = strtr($sql_utf8, $trans);
					fwrite($this->fichier, $result);
				}
			} // while
			$result_tables->free_result();
		}
		fclose($this->fichier);
		$this->message('<strong style="color:#04B404;">' . htmlspecialchars($this->nom_fichier) . '</strong>');
		
		$this->message(SAVEFINI);
	}
	
	/**
	 * Purger les anciens fichiers
	 * @param int $nbr_fichiers_max Nombre maximum de sauvegardes
	 */
	protected function purger_fichiers($nbr_fichiers_max) {
		$this->message();
		$this->message(PURGE);
		$fichiers = array();
		
		// On recupere le nom des fichiers sql
		if($dossier = dir($this->dossier)) {
			while(false !== ($fichier = $dossier->read())) {
				if($fichier != '.' && $fichier != '..') {
					if(is_dir($this->dossier . $fichier)) {
						// Ceci est un dossier ( et non un fichier )
						continue;
					} else {
						$fichiers[] = $fichier;
					}
				}
			} // while
			$dossier->close();
		}
		
		// On supprime les  anciens fichiers
		$nbr_fichiers_total = count($fichiers);
		if($nbr_fichiers_total >= $nbr_fichiers_max) {
			// Inverser l'ordre des fichiers gz pour ne pas supprimer les derniers fichiers
			rsort($fichiers);
			
			// Suppression...
			for($i = $nbr_fichiers_max; $i < $nbr_fichiers_total; $i++) {
				$this->message('<strong style="color:#D90606;">' . htmlspecialchars($fichiers[$i]) . '</strong>');
				unlink($this->dossier . $fichiers[$i]);
			}
		}
		$this->message(PURGEFINI);
	}
	
}



// Instance de la classe ( a copier autant que necessaire, mais attention au timeout )
// Rq: pour les parametres, reprendre une ou plusieurs cles de $default ( dans la methode __construct() )
new BackupMySQL(array(
	'host' => $server,
	'username' => $user,
	'passwd' => $pwd,
	'dbname' => $base,
	'dossier' => './db/backup/'.$prefix.'/'
	));

?>
