miércoles, 27 de enero de 2016

Backup de bases de datos MySQL con PHP

El presente es una actualización del excelente artículo de Daniel Lopez Azaña quien se merece todos los créditos por el trabajo.

Lo que yo hice fue recopilar e incorporar todas las sugerencias propuestas por los que comentaron en el blog original y agregué de mi parte la especificación de la zona horaria para que el archivo de backup tenga el nombre acorde a la hora real de la zona.


Actualizado al 27/01/2016

  • Cambiado el nombre del constructor a __construct().
  • Cambiado ereg_replace() por str_replace(). 
  • Agregado "\n\n" antes de CREATE DATABASE.
  • Cambiadas comillas dobles a comillas simples.
  • Cambiado NULL en lugar de "" cuando corresponde.
  • Cambiado en str_replace(), comillas dobles en parámetro search, comillas simples en parámetro replace.
  • Cambiado el nombre del destino, carpeta "_backup" en lugar de "cache".
  • Corregido para versión PHP 5.5 usando mysqli_ en lugar de mysql_.
  • Corregido el problema de parámetros faltantes en mysqli_. 
  • Agregado el parámetro date_default_timezone_set(). Puedes cambiarlo según la Lista de Zonas horarias soportadas.

Using PHP to backup MySQL databases

This is an update of the excellent article by Daniel Lopez Azana (Using PHP to backup MySQL databases), who deserves all the credit for the work.

What I did was collect and incorporate all suggestions made by those who commented on the original blog, and added specifying the time zone in order the backup file has the name according to the real time in your zone.

Updated to 27-jan-2016
  • Changed the name of the constructor to __construct ().
  • Changed ereg_replace () to str_replace ().
  • Added "\n\n" before CREATE DATABASE.
  • Changed double quotes to single quotes.
  • Changed NULL rather than "" when appropriate.
  • Changed in str_replace(), double quotes in search parameter, single quotes. in replace parameter.
  • Changed the name of the destination, "_backup" instead of "cache" folder.
  • Fixed for PHP 5.5 version using mysqli_ instead of mysql_.
  • Fixed problem with missing parameters in mysqli_.
  • Added the date_default_timezone_set() parameter. You can change it according to the List of time zones supported.

Como se usa / How to use

  1. Edita el archivo y configura las variables de la base de datos, la carpeta destino y opcionalmente configura la zona horaria.
  2. Sube por FTP el archivo a la carpeta raíz del sitio.
  3. Ejecuta desde la barra de dirección del navegador.
  4. Tu archivo quedará generado en la carpeta destino que definiste y podrás descargarlo vía FTP.


  1. Edit the file and set database variables, destination folder and optionally set the time zone.
  2. Upload via FTP the file to the root folder on the site.
  3. Run from the browser address bar.
  4. The backup file will be generated in the destination folder you have defined, and you can download it via FTP.

Código / Code



<?php
/**
* This file contains the Backup_Database class wich performs
* a partial or complete backup of any given MySQL database
* @author Daniel López Azaña <http://www.azanweb.com-->
* @version 1.1 updated 27.jan.2016 by Diego Soto twitter: @diesoto (Thanks to Daniel and all)
*
*/
// Report all errors
error_reporting(E_ALL);
/**
* Define database parameters here
*/
define("DB_USER", '');
define("DB_PASSWORD", '');
define("DB_NAME", '');
define("DB_HOST", 'localhost');
define("OUTPUT_DIR", '_backup'); // DO NOT FORGET to set your destination folder
define("TABLES", '*');
/**
* Default time zone
*
* List of Supported Timezones: http://php.net/manual/en/timezones.php
*/
date_default_timezone_set('America/Argentina/Buenos_Aires');
/**
* Instantiate Backup_Database and perform backup
*/
$backupDatabase = new Backup_Database(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
$status = $backupDatabase->backupTables(TABLES, OUTPUT_DIR) ? 'OK' : 'KO';
echo "
Backup result: ".$status;
/**
* The Backup_Database class
*/
class Backup_Database {
/**
* Host where database is located
*/
var $host = '';
/**
* Username used to connect to database
*/
var $username = '';
/**
* Password used to connect to database
*/
var $passwd = '';
/**
* Database to backup
*/
var $dbName = '';
/**
* Database charset
*/
var $charset = '';
var $conn = null;
/**
* Constructor initializes database
*/
function __construct($host, $username, $passwd, $dbName, $charset = 'utf8')
{
$this->host = $host;
$this->username = $username;
$this->passwd = $passwd;
$this->dbName = $dbName;
$this->charset = $charset;
$this->initializeDatabase();
}
protected function initializeDatabase()
{
$this->conn = mysqli_connect($this->host, $this->username, $this->passwd);
mysqli_select_db($this->conn, $this->dbName);
if (! mysqli_set_charset ($this->conn, $this->charset))
{
mysqli_query($this->conn, 'SET NAMES '.$this->charset);
}
}
/**
* Backup the whole database or just some tables
* Use '*' for whole database or 'table1 table2 table3...'
* @param string $tables
*/
public function backupTables($tables = '*', $outputDir = '.')
{
try
{
/**
* Tables to export
*/
if($tables == '*')
{
$tables = array();
$result = mysqli_query($this->conn, 'SHOW TABLES');
while($row = mysqli_fetch_row($result))
{
$tables[] = $row[0];
}
}
else
{
$tables = is_array($tables) ? $tables : explode(',',$tables);
}
$sql = "\n\n";
$sql .= 'CREATE DATABASE IF NOT EXISTS '.$this->dbName.";\n\n";
$sql .= 'USE '.$this->dbName.";\n\n";
/**
* Iterate tables
*/
foreach($tables as $table)
{
echo "Backing up ".$table." table...";
$result = mysqli_query($this->conn, 'SELECT * FROM '.$table);
$numFields = mysqli_num_fields($result);
$sql .= 'DROP TABLE IF EXISTS '.$table.';';
$row2 = mysqli_fetch_row(mysqli_query($this->conn, 'SHOW CREATE TABLE '.$table));
$sql.= "\n\n".$row2[1].";\n\n";
for ($i = 0; $i < $numFields; $i++)
{
while($row = mysqli_fetch_row($result))
{
$sql .= 'INSERT INTO '.$table.' VALUES(';
for($j=0; $j<$numFields; $j++)
{
$row[$j] = addslashes($row[$j]);
$row[$j] = str_replace(array("\r", "\n", "\t"), array('\\r', '\\n', '\\t'), $row[$j]);
if (isset($row[$j]))
{
if($row[$j] != NULL) {
$sql .= "'".$row[$j]."'" ;
}
else {
$sql .= "NULL" ;
}
}
else
{
$sql.= "''";
}
if ($j < ($numFields-1))
{
$sql .= ',';
}
}
$sql.= ");\n";
}
}
$sql.="\n\n\n";
echo " OK" . "
";
}
}
catch (Exception $e)
{
var_dump($e->getMessage());
return false;
}
return $this->saveFile($sql, $outputDir);
}
/**
* Save SQL to file
* @param string $sql
*/
protected function saveFile(&$sql, $outputDir = '.')
{
if (!$sql) return false;
try
{
$handle = fopen($outputDir.'/db-backup-'.$this->dbName.'-'.date("Ymd-His", time()).'.sql','w+');
fwrite($handle, $sql);
fclose($handle);
}
catch (Exception $e)
{
var_dump($e->getMessage());
return false;
}
return true;
}
}

2 comentarios:

  1. Diego soto antes que nada te agradezco mucho por haber mejorado el codigo, revise tambien el aporte de Daniel y los dos han creado algo magnifico. Tengo dos dudas querido amigo. 1. Puedo utilizar este codigo para implementarlo en mi aplicación comercial? 2. La segunda pregunta es crees que podría corregirse el que no genere ningun problema cuando las tablas esten relacionadas, esta ultima duda también la hisieron en el post anterior de Daniel. Mil gracias amigo por tomarte el tiempo en mejorar el codigo. Saludos desde Guatemala Att: Abrahnns Hernández

    ResponderEliminar
    Respuestas
    1. Hola Abrahanns. Muchas gracias por tus halagos, me alegra que te haya sido útil. Discúlpame que recién veo tu mensaje. De mi parte, siéntete libre de usar lo que yo hice en donde lo necesites, pero no está en mi autorizar lo que hizo Daniel Lopez. Debes preguntarle a él. Sobre las tablas relacionadas, no tengo claro lo que me planteas, pero lamentablemente no pude dedicarle tiempo. Espero que estés muy bien. Saludos desde Argentina!

      Eliminar