GNU/Linux, Open Source, Cloud Computing, DevOps y más...

Backup de bases de datos MySQL con PHP

47 comentarios

Este artículo muestra cómo realizar un backup parcial o completo de bases de datos MySQL utilizando tan sólo código PHP. Esto es muy útil por ejemplo cuando un cliente no nos facilita datos de acceso a la base de datos de una aplicación web y sólo disponemos de un acceso FTP, o cuando sí disponemos de los datos de conexión a la base de datos pero no podemos acceder a ella a través de la red (sólo disponible en localhost) y tampoco podemos utilizar herramientas como mysqldump para respaldar la información porque no disponemos de privilegios para ello, o simplemente porque no tenemos acceso a una shell a la que conectarnos y ejecutar comandos.

ACTUALIZACIÓN 28/08/2017: trasladado el código fuente de los scripts myphp-backup.php y myphp-restore.php a mi repositorio de GitHub daniloaz/myphp-backup: https://github.com/daniloaz/myphp-backup

Backup de las tablas de una base de datos MySQL

En cualquiera de los escenarios anteriores, simplemente copiando y ejecutando el script PHP myphp-backup.php como indico más abajo podremos hacer un export completo o parcial (sólo algunas tablas) de la base de datos a un fichero .sql o .sql.gz que podremos descargar después desde la misma cuenta FTP. El script incluye la clase Backup_Database que se encarga de realizar todas las operaciones necesarias y dispone de distintas opciones de configuración para controlar en qué subdirectorio queremos que se almacenen los ficheros de backup y si queremos que se compriman con gzip o no. También deberemos establecer las credenciales de usuario para acceder a la base de datos, así como el nombre de ésta:

/**
 * Define database parameters here
 */
define("DB_USER", 'your_username');
define("DB_PASSWORD", 'your_password');
define("DB_NAME", 'your_db_name');
define("DB_HOST", 'localhost');
define("BACKUP_DIR", 'myphp-backup-files'); // Comment this line to use same script's directory ('.')
define("TABLES", '*'); // Full backup
//define("TABLES", 'table1 table2 table3'); // Partial backup
define("CHARSET", 'utf8');
define("GZIP_BACKUP_FILE", true); // Set to false if you want plain SQL backup files (not gzipped)

Normalmente las aplicaciones PHP disponen de un fichero de configuración tipo config.php o similar en el que podremos encontrar el usuario y contraseña de la base de datos en caso de no recordarlas o si nuestro cliente no nos ha facilitado dicha información.

Si no disponemos de permisos suficientes para crear el subdirectorio donde se almacenarán nuestros ficheros de copia de seguridad (por defecto myphp-backup-files/), podremos utilizar un directorio existente. Normalmente las aplicaciones PHP disponen de algún subdirectorio con suficientes permisos para crear nuevos archivos (cache, tmp, temp, etc.), que es donde diremos a nuestro script myphp-backup.php que deje el fichero con el backup de la base de datos. También podremos usar el propio directorio raíz (DocumentRoot). Para ello asignaremos simplemente un punto (‘.’) a la constante BACKUP_DIR.

El fichero .sql.gz o .sql generado como resultado de utilizar la clase Backup_Database del script myphp-backup.php tendrá un nombre del tipo myphp-backup-{DB_NAME}-YYYYmmdd_HHMMSS.sql.gz:

$ ls myphp-backup-files/*.sql.gz
myphp-backup-files/myphp-backup-smf-20160131_111735.sql.gz

Restauración de las tablas de una base de datos MySQL

El fichero anterior contendrá el código SQL comprimido (o no) listo para reproducir la estructura y el contenido de la base de datos original en otra base de datos distinta o en la misma sustituyendo los datos existentes por los de nuestro fichero de backup. Para efectuar la restauración simplemente ejecutaremos el otro script de mi repositorio: myphp-restore.php. Lo único que tendremos que hacer para realizar la restauración es subir al servidor en el que queramos hacer la importación tanto el script myphp-restore.php como el propio fichero de backup, que indicaremos mediante la constante BACKUP_FILE a una carpeta en la que tengamos permisos de escritura y que indicaremos mediante la constante BACKUP_DIR.

Las opciones de configuración de las que dispone el script myphp-restore.php son las siguientes:

/**
 * Define database parameters here
 */
define("DB_USER", 'your_username');
define("DB_PASSWORD", 'your_password');
define("DB_NAME", 'your_db_name');
define("DB_HOST", 'localhost');
define("BACKUP_DIR", 'myphp-backup-files'); // Comment this line to use same script's directory ('.')
define("BACKUP_FILE", 'your-backup-file.sql.gz'); // Script will autodetect if backup file is gzipped or not based on .gz extension
define("CHARSET", 'utf8');

El script detectará automáticamente si el fichero de copia de seguridad está comprimido o no con gzip basándose en la extensión de éste, por lo que no tendremos que establecer ninguna configuración adicional para esto.


Error: Your Requested widget " ai_widget-6" is not in the widget list.
  • [do_widget_area above-nav-left]
    • [do_widget_area above-nav-right]
      • [do_widget_area footer-1]
        • [do_widget id="wpp-4"]
      • [do_widget_area footer-2]
        • [do_widget id="recent-posts-4"]
      • [do_widget_area footer-3]
        • [do_widget id="recent-comments-3"]
      • [do_widget_area footer-4]
        • [do_widget id="archives-4"]
      • [do_widget_area logo-bar]
        • [do_widget id="oxywidgetwpml-3"]
      • [do_widget_area menu-bar]
        • [do_widget id="search-3"]
      • [do_widget_area sidebar]
        • [do_widget id="search-4"]
        • [do_widget id="ai_widget-2"]
        • [do_widget id="categories-5"]
        • [do_widget id="ai_widget-3"]
        • [do_widget id="ai_widget-4"]
        • [do_widget id="ai_widget-5"]
      • [do_widget_area sub-footer-1]
        • [do_widget id="text-4"]
      • [do_widget_area sub-footer-2]
        • [do_widget_area sub-footer-3]
          • [do_widget_area sub-footer-4]
            • [do_widget_area upper-footer-1]
              • [do_widget id="search-2"]
              • [do_widget id="recent-posts-2"]
              • [do_widget id="recent-comments-2"]
              • [do_widget id="archives-2"]
              • [do_widget id="categories-2"]
              • [do_widget id="meta-2"]
            • [do_widget_area upper-footer-2]
              • [do_widget_area upper-footer-3]
                • [do_widget_area upper-footer-4]
                  • [do_widget_area widgets_for_shortcodes]
                    • [do_widget id="search-5"]
                    • [do_widget id="ai_widget-6"]
                  • [do_widget_area wp_inactive_widgets]
                    • [do_widget id="wpp-2"]
                    • [do_widget id="text-1"]
                    • [do_widget id="recent-posts-3"]
                    • [do_widget id="categories-3"]
                    • [do_widget id="archives-3"]
                    • [do_widget id="icl_lang_sel_widget-3"]

                  Código fuente de los scripts de respaldo y restauración

                  Puedes encontrar el código fuente de ambos scripts en mi repositorio de Github daniloaz/myphp-backup: https://github.com/daniloaz/myphp-backup.

                  daniloaz-myphp-backup: Simple and fast MySQL backups using PHP

                  Y nada más. Si se te ocurre alguna característica adicional que pueda ser útil y eches en falta no dudes en dejarme un comentario. ¡Suerte!

                   

                  Sobre el autor

                  Daniel López Azaña
                  Arquitecto de soluciones Cloud AWS & Linux Sysadmin Freelance

                  Emprendedor, generador de ideas y mente inquieta. Apasionado de las nuevas tecnologías, especialmente de los sistemas Linux y del software libre. Me gusta escribir además sobre actualidad tecnológica, Cloud Computing, AWSi, DevOps, DevSecOps, seguridad, desarrollo web y programación, SEO, ciencia, innovación, emprendimiento, etc.

                  DanielBackup de bases de datos MySQL con PHP

                  Artículos relacionados

                  47 comentarios

                  Unirte a la conversación
                  • Carlos Andrés Restrepo - 28/08/2012 responder

                    Hola me funciono perfecto en un crontab solo un detalle retire de la linea $handle = fopen($outputDir.’/db-backup-‘.$this->dbName.’-‘.date(«Ymd-His», time()).’.sql’,’w+’);
                    la variable $outputDir dado que agrega un directorio de nombre cache y se pierde la ruta
                    pero funciona de lujo + 10
                    ya solo falta meterle los detallitos que uno considere que hagan falta para cada necesidad especifica

                    saludos

                  • JOSE PASTOR - 07/09/2012 responder

                    El script para hacer copia de la base de Datos me parece magnifico, por favor me pueden colaborar con el script para restaurar la base de Datos a partir del archivo creado con el script Backup_Databese.php

                    Les quedo altamente agradecido

                    Daniel - 03/10/2012 responder

                    Muchas gracias José. Lamentablemente en este momento no dispongo de tiempo para publicar el script de restauración. No obstante, tengo intención de hacerlo. Lo subiré tan pronto como pueda. Un saludo.

                    Pierre - 25/11/2012 responder

                    Por favor, quien me puede a ayudar a restaurar mi base de datos ?
                    Gracias de ante mano !

                  • Pierre - 25/11/2012 responder

                    Hola, por favor quien puede decir porque tengo este error al intentar respaldar mi base de datos

                    Deprecated: Function ereg_replace() is deprecated in C:xampphtdocsictvttrespaldarbackup.php on line 133

                    Daniel - 27/11/2012 responder

                    Gracias por tu comentario Pierre, pero en realidad no se trata de un mensaje de error. Menciono la causa de ese mensaje en este mismo hilo, unos cuantos comentarios más arriba.

                    leonardo - 05/09/2014 responder

                    ayuda por favor se realizó bien el respaldo pero no se como encontrarlo mas o menos entiendo q esta en la cache …ayuda

                    Daniel - 05/09/2014 responder

                    El destino del respaldo se indica en la constante OUTPUT_DIR definida al principio del script. En mi caso era en el directorio cache, pero este directorio no tiene por qué existir en todas las instalaciones donde hagais funcionar el script. Por tanto, debes poner un directorio que sea válido en tu escenario concreto.

                  • Martin - 05/02/2013 responder

                    Hola Daniel, que pasa con valores NULL?, los escribe como «»?

                    Daniel - 02/04/2013 responder

                    Hola Martin. Pues sinceramente no lo sé, no lo he probado con valores nulos… 🙂

                    Este script lo escribí para un trabajo puntual con un par de bases de datos específicas de un cliente y no se dio el caso que comentas. Es seguro que mi script es bastante mejorable aún. De hecho gracias a comentarios como el tuyo podré ir afinándolo más para que sea de utilidad a más personas. El problema es que no encuentro el tiempo necesario para hacerlo… 🙁

                    Si pudieras publicar el cambio que sería necesario hacer para corregir el problema te estaría muy agradecido, al igual que todos los lectores de tu comentario 😉

                    ¡Gracias!

                  • Fernando - 22/03/2013 responder

                    Hola, agradecido por tu script. buen trabajo.
                    Te comento algunas cosas para quien llegue como yo a éste blog, pueda estar corregido.
                    – El nombre del constructor de la clase, debe llamarse __construct()
                    – El aviso que da de ereg_replace, se puede sustituir por str_replace.

                    Y creo que lo más importante, es que tu código exporta los datos a un fichero sql pero no tiene en cuenta las relaciones, por lo que para exportar está muy bien, pero para importarlo no es válido.

                    Por lo demás, buen trabajo. Perfecto.

                    Saludos y gracias por compartir tus conocimientos!

                    Daniel - 02/04/2013 responder

                    Gracias Fernando por tus aportaciones. Efectivamente, hay algunas cosas que se han quedado anticuadas en mi script, como el uso de ereg_replace y el nombre del constructor, que debe llamarse __construct() en PHP5, aunque por compatibilidad con versiones anteriores se siga aceptando el nombre de la propia clase.

                    Tengo pendiente hacer varias mejoras e implementar una nueva clase para realizar importaciones y para aceptar tablas InnoDB con sus relaciones y demás, pero lamentablemente no he encontrado el momento por falta de tiempo.

                    Tendré en cuenta tu comentario para esa futura versión. Gracias.

                  • Omar Hernandez - 09/04/2013 responder

                    Excelente Script, funciona a la perfeccion.

                  • felix - 09/07/2013 responder

                    hola esta muy bien tu código, pero no me funciona cuando tengo tablas relacionadas….

                  • alex - 18/07/2013 responder

                    por alguna razon no me carga nada con un base de datos en especifico, sabes que pudo haber pasado?

                    que tenga algun tipo de proteccion o algo parecido?

                  • Berdejo Humberto - 14/08/2013 responder

                    Al restaurar el archivo sql los acentos y caracteres Ñ o ñ desaparecen y truncan la cadena en MySQL ¿Sabes a que se debe?

                  • Bruce - 03/10/2013 responder

                    Funciona perfectamente,its a perfect work thank you so much

                  • Roberto Carlos Garcia Andino - 02/11/2013 responder

                    Gracias, me sirvió tu código, tuve que agregarle una línea encima de tu línea 108 y concatenar la siguente:
                    $sql = «nn»;
                    $sql .= ‘CREATE DATABASE IF NOT EXISTS ‘.$this->dbName.»;nn»;
                    pues a la hora de leer los datos con la función file() me pone dos caracteres al inicio y es necesario separarlos de la primera línea sql. Espero este código le sirva a alguien más. Saludos.

                    $url = «db-backup-nominaplus-20131102-083116.sql»;
                    $nowhost = «localhost»;
                    $nowdatabase = «nominaplus1»;
                    $nowuser = «root»;
                    $nowpass = «»;

                    $link = mysql_connect($nowhost, $nowuser, $nowpass);

                    $lines = file($url);
                    foreach ($lines as $line_num => $line) {
                    echo «Line #{$line_num} : » . $line . «n»;
                    mysql_query($line);
                    }

                  • Rama - 03/09/2014 responder

                    Hola, en algunos casos me informa que todas las tablas las pasa OK pero luego crea el archivo con longitud cero … y no informa ningun error

                  • zarith - 23/09/2014 responder

                    Muchas gracias amigo, me funciono muy bien. Solo que gustaria que el archivo se descargara al escritorio o a la carpeta de descargas del computador para que sea mas fácil para el cliente ubicarlo. Espero pueda ayudarme con eso. Gracias de antemano.

                    Daniel - 23/09/2014 responder

                    Lo siento, pero no es así como funciona. El script se ejecuta en el servidor y deja el resultado en el servidor para ser recogido mediante FTP. No obstante, gracias por la sugerencia. Lo tendré en cuenta como una mejora en la revisión del código que tengo pendiente.

                  • pandorasoft - 09/10/2014 responder

                    Hola, todos los resultados aparecen ok, pero el archivo que crea es ta a 0. ¿que puede ser?

                    Daniel - 09/10/2014 responder

                    Pues no te sabría decir, habría que meter un poco de código de depuración en el script e ir viendo si el valor de la variable $sql se queda vacío y por qué. Sin algo más de información no te puedo decir qué ocurre.

                  • Antonio Munguia - 20/02/2015 responder

                    Hola Daniel buen script muy útil, una pregunta, en: define(«TABLES», ‘*’); el asterisco * significa que respaldara todas las tablas de la base de datos que tu elijas, o se tienen que poner el nombre de las tablas de la bd, muchas gracias por tu tiempo, y sigue así….

                  • Mariana - 11/08/2015 responder

                    Muy buen script! Yo necesité hacer unos cambios, para conseguir un formato como el de phpmyadmin. No sé si es lo más correcto, pero a mí me funcionó así:

                    $row[$j] = str_replace( array(«r», «n») , array(‘\r’, ‘\n’) , $row[$j] );

                    Por empezar, cambié ereg_replace por str_replace, (que daba error en las versiones nuevas de PHP). Y pasé un array con las distintas formas en que puede venir guardado el salto de línea.

                    Usé comillas dobles en el primer argumento y simples en el segundo, porque necesito que el primero interprete los saltos de línea y el segundo los escriba como string. Como estaba en tu script me interpretaba los saltos de línea en el documento, en lugar de mostrarlos como string.

                  • Mariana - 11/08/2015 responder

                    Me olvidé, en el comentario anterior, de agregar las tabulaciones, quedaría así:

                    $row[$j] = str_replace( array(«r», «n», «t») , array(‘\r’, ‘\n’, ‘\t’) , $row[$j] );

                  • Diego Soto - 28/01/2016 responder

                    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.

                    Muchas gracias.

                    http://disientoconusted.blogspot.com.ar/2016/01/backup-de-bases-de-datos-mysql-con-php.html

                    This is an update of the excellent article by Daniel Lopez Azana, 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.

                    Thank you very much.

                  • mario - 07/04/2016 responder

                    como hago para hacer un respaldo de todas mis bases de datos

                    Daniel - 05/05/2016 responder

                    Me temo que con el script actual sólo puedes hacerlo una a una cambiando los datos de conexión que aparecen al principio.

                  • Jorge - 12/04/2016 responder

                    Excelente, no pudo hacer respaldo de todas mis tablas, se terminaba la memoria, no sé si de php o de mysql, pero hice un loop y lo tengo en un conjob, me ahorraste mucho tiempo. Gracias.

                  • Jorge Alejandro - 16/12/2016 responder

                    Muchas Gracias por este aporte Ing. Luego se ve la gente que se apasiona de verdad por la programación. Unos libros que me recomiendes de php y mysql

                    Daniel - 17/12/2016 responder

                    Gracias Jorge Alejandro. Echa un vistazo a este enlace para lo de los libros: https://www.cloudways.com/blog/best-books-to-help-you-learn-php/

                  • Priyankar Gayen - 21/02/2017 responder

                    fopen(cache/db-backup-ship_software-20170221-114447.sql) [function.fopen]: failed to open stream: No such file or directory in C:xampphtdocsship_softwaredatabase_bckup.php on line 182

                  • Aldo - 30/04/2017 responder

                    Hola Daniel gracias por el script funciona todo bien pero si necesito realizar el backup incluido los procedimientos, vistas, funciones, etc. que lo podría agregar al script? porque hasta ahora solo me devuelve las tablas.

                  • ralph - 23/01/2018 responder

                    excelente aporte, funciona muy bien
                    claro y preciso
                    saludos

                  • Natsumi Franco - 14/03/2018 responder

                    Buen día, estoy implementando el código pero me sale el error ob_flush(): failed to flush buffer. Si se hace el back up en el servidor y si lo descargo desde el servidor y al abrirlo me salen los datos.
                    En un sitio web creo un listado de todos los respaldo con la opción de descargar pero al intentar descargarlo me dice » Error: Ningún archivo encontrado» a alguien le ha pasado?

                    Joseph - 12/04/2018 responder

                    Hola Natsumi
                    Vieras que me pasa lo mismo con el código, en mi localhost sale sin problema pero en el servidor me sale el error ob_flush(): failed to flush buffer, si hace los backups bien y baje el ultimo backup hecho y el archivo generado sale bien.
                    Pero me preocupa ese error que me sale de ob_flush(): failed to flush buffer
                    Que puede ser

                  • Joseph - 16/03/2018 responder

                    Hola Daniel
                    Excelente el código… me sirvió a la perfección, oye una consulta.. como se haría para que el código se ejecute cada día, por ejemplo ??

                    Daniel - 17/03/2018 responder

                    Puedes usar cron en el propio servidor donde se vaya a hacer el backup ejecutando el script desde la línea de comandos, ya que este script de backup permite ser ejecutado indistintamente vía web a través de Apache o Nginx, o directamente desde la línea de comandos. Si no tienes acceso al cron del servidor puedes añadir una función que se ejecute cada vez que alguien visita una página de tu sitio y que compruebe la fecha y la hora, y si es aquella que tú has programado, entonces que ejecute el script. Es algo parecido a lo que hace el wp_cron de WordPress. Otra opción si no tienes acceso al servidor es programar mediante el cron de un ordenador al que sí tengas acceso una petición por medio de curl a la URL del script a la hora convenida.

                  • Yosmar - 28/12/2018 responder

                    El restore no me funciona me arroja el siguiente mensaje:
                    2018-12-28 06:46:16 – Gunzipping backup file myphp-backup-files/myphp-backup-your_db_name-20181022_164459.sql.gz…

                    Warning: gzopen(myphp-backup-files/myphp-backup-your_db_name-20181022_164459.sql.gz): failed to open stream: No such file or directory in C:\xampp\htdocs\sicpad\config\respaldos\myphp-restore.php on line 185
                    ERROR: couldn’t gunzip backup file myphp-backup-files/
                    2018-12-28 06:46:16 – Restoration result: KO

                    Daniel - 08/01/2019 responder

                    Asegúrate de que exista el fichero myphp-backup-your_db_name-20181022_164459.sql.gz en una carpeta llamada myphp-backup-files dentro de la carpeta donde está el script de restauración myphp-restore.php. Es decir, en tu caso debe existir el fichero C:\xampp\htdocs\sicpad\config\respaldos\myphp-backup-files\myphp-backup-your_db_name-20181022_164459.sql.gz y además debe ser un fichero válido generado con el otro script myphp-backup.php y comprimido con gzip.

                  • Alejandro Calderón Girón - 28/06/2019 responder

                    Muchisimas gracias me ha funcionado perfectamente. saludos!!!!

                  • Ant - 17/09/2019 responder

                    como podria traducirse el script de mysqli a PDO??

                  • Marbel - 10/12/2019 responder

                    Extrae la BD pero no utilizarlo otra vez osea que no puedo ver ni importar a otra BD
                    alguien tubo el mismo problema

                  • Francisco - 27/12/2019 responder

                    y como puedo respaldar también las vistas, procedimientos y triggers??? Ojalá me puedan ayudar

                    Daniel - 20/01/2020 responder

                    En este momento mi script no permite hacer backup de vistas, procedimientos y triggers. Para ello deberás usar una herramienta más sofisticada tipo mysqldump o phpMyAdmin.

                  • Jamarchi - 20/01/2020 responder

                    Hola, este código esta actualizado a la ultima versión de PHP ?

                    Saludos

                  Deja una respuesta

                  Tu dirección de correo electrónico no será publicada.