Función de copias de seguridad PDO MySQL

esta función aquí http://davidwalsh.name/backup-mysql-database-php

ha estado flotando alrededor de las redes internas por un tiempo y es bastante famoso, pero está en mysql estándar. ¿Alguien tiene lo mismo pero en DOP? Si no, ¿alguien quiere hacer uno? ¿Es posible, leí en alguna parte que el DOP no hace MOSTRAR CREAR TABLA, es correcto?

finalmente, ¿alguien puede explicar qué diferencia hay entre esa función y el uso de SELECT * INTO OUTFILE?

(Por favor, no marque esto por contener demasiadas preguntas, todas están estrechamente relacionadas y estoy seguro de que las respuestas serán útiles para muchas personas)

Para cualquiera que esté buscando la función que actúa como el mysqldump, aquí está el último borrador, con las imperfecciones discutidas en los comentarios de arriba / abajo resueltos. Disfrutar.

require 'login.php'; $DBH = new PDO("mysql:host=$db_hostname;dbname=$db_database; charset=utf8", $db_username, $db_password); //put table names you want backed up in this array. //leave empty to do all $tables = array(); backup_tables($DBH, $tables); function backup_tables($DBH, $tables) { $DBH->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL ); //Script Variables $compression = false; $BACKUP_PATH = ""; $nowtimename = time(); //create/open files if ($compression) { $zp = gzopen($BACKUP_PATH.$nowtimename.'.sql.gz', "a9"); } else { $handle = fopen($BACKUP_PATH.$nowtimename.'.sql','a+'); } //array of all database field types which just take numbers $numtypes=array('tinyint','smallint','mediumint','int','bigint','float','double','decimal','real'); //get all of the tables if(empty($tables)) { $pstm1 = $DBH->query('SHOW TABLES'); while ($row = $pstm1->fetch(PDO::FETCH_NUM)) { $tables[] = $row[0]; } } else { $tables = is_array($tables) ? $tables : explode(',',$tables); } //cycle through the table(s) foreach($tables as $table) { $result = $DBH->query("SELECT * FROM $table"); $num_fields = $result->columnCount(); $num_rows = $result->rowCount(); $return=""; //uncomment below if you want 'DROP TABLE IF EXISTS' displayed //$return.= 'DROP TABLE IF EXISTS `'.$table.'`;'; //table structure $pstm2 = $DBH->query("SHOW CREATE TABLE $table"); $row2 = $pstm2->fetch(PDO::FETCH_NUM); $ifnotexists = str_replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS', $row2[1]); $return.= "\n\n".$ifnotexists.";\n\n"; if ($compression) { gzwrite($zp, $return); } else { fwrite($handle,$return); } $return = ""; //insert values if ($num_rows){ $return= 'INSERT INTO `'."$table"."` ("; $pstm3 = $DBH->query("SHOW COLUMNS FROM $table"); $count = 0; $type = array(); while ($rows = $pstm3->fetch(PDO::FETCH_NUM)) { if (stripos($rows[1], '(')) {$type[$table][] = stristr($rows[1], '(', true); } else $type[$table][] = $rows[1]; $return.= "`".$rows[0]."`"; $count++; if ($count < ($pstm3->rowCount())) { $return.= ", "; } } $return.= ")".' VALUES'; if ($compression) { gzwrite($zp, $return); } else { fwrite($handle,$return); } $return = ""; } $count =0; while($row = $result->fetch(PDO::FETCH_NUM)) { $return= "\n\t("; for($j=0; $j<$num_fields; $j++) { //$row[$j] = preg_replace("\n","\\n",$row[$j]); if (isset($row[$j])) { //if number, take away "". else leave as string if ((in_array($type[$table][$j], $numtypes)) && (!empty($row[$j]))) $return.= $row[$j] ; else $return.= $DBH->quote($row[$j]); } else { $return.= 'NULL'; } if ($j<($num_fields-1)) { $return.= ','; } } $count++; if ($count < ($result->rowCount())) { $return.= "),"; } else { $return.= ");"; } if ($compression) { gzwrite($zp, $return); } else { fwrite($handle,$return); } $return = ""; } $return="\n\n-- ------------------------------------------------ \n\n"; if ($compression) { gzwrite($zp, $return); } else { fwrite($handle,$return); } $return = ""; } $error1= $pstm2->errorInfo(); $error2= $pstm3->errorInfo(); $error3= $result->errorInfo(); echo $error1[2]; echo $error2[2]; echo $error3[2]; if ($compression) { gzclose($zp); } else { fclose($handle); } } 

Ese script de copia de seguridad es ridículo y nadie debería hacer otra versión de él. He visto ese script antes, así como bashs similares, y tienen muchos problemas:

  • No delimita los nombres de tablas en las marcas de retroceso
  • No maneja nulos
  • No maneja conjuntos de caracteres
  • No maneja datos binarios
  • No hace copia de seguridad de vistas
  • No hace una copia de seguridad de TRIGGER o PROCEDIMIENTOS ALMACENADOS o FUNCIONES O EVENTOS ALMACENADOS
  • Utiliza la extensión de mysql obsoleta (pero esta es la razón por la que desea una versión PDO, ¿no es así?)
  • Utiliza addlashes () en lugar de una función de escape MySQL adecuada.
  • Anexa todos los datos de todas las tablas en una cadena realmente larga, antes de enviar todo el contenido. Esto significa que tiene que poder almacenar toda su base de datos en una sola cadena, lo que casi con certeza agotará su límite máximo de memoria de PHP.

Vea también mi respuesta anterior sobre el desafortunado script de copia de seguridad de David Walsh:

  • ¿Por qué mi script de copia de seguridad de base de datos no funciona en php?

Re tu comentario:

Lee los comentarios en la página que has vinculado. Mucha gente ha identificado problemas y algunos tienen correcciones o al menos sugerencias.

El hecho de que esta secuencia de comandos agregue todo en una cadena es un factor decisivo, creo, pero no debería ser difícil cambiar la secuencia de comandos para abrir primero el archivo de salida, luego generar los datos de cada fila durante el ciclo y luego cerrar el archivo después del bucle. Eso es una especie de obviedad, no estoy seguro de por qué el guión no hace eso. Pero está bastante claro que el script no fue probado muy bien.

Pero de todos modos, no intentaría reinventar esta rueda. Mysqldump o mydumper hacen bien este trabajo. FWIW, no tiene que ejecutar mysqldump en el mismo servidor donde reside la base de datos. Mysqldump admite una opción para --host para que pueda ejecutar mysqldump en cualquier lugar para realizar una copia de seguridad de una base de datos remota, siempre que los firewalls no bloqueen la conexión de su cliente. Básicamente, si puede conectar una aplicación PHP a la base de datos desde algún host cliente, puede conectar mysqldump.

Si esa no es realmente una opción, entonces usaría la función de volcado de base de datos de phpmyadmin. Estos son maduros y bien probados y descargan todo correctamente. Aquí hay un artículo que describe cómo usar la función de volcado:

http://www.techrepublic.com/blog/smb-technologist/import-and-export-databases-using-phpmyadmin/


[Copiando mis comentarios de tu respuesta:]

Esto es entrar en la revisión de código, que no es el propósito de StackOverflow. Pero brevemente:

  • no hay soporte adecuado para NULL (los convierte a ”);
  • no delimitar constantemente los nombres de tablas;
  • el uso de comillas dobles no ANSI como delimitadores de cadena;
  • el uso de consultas en búfer en tablas enormes romperá el límite máximo de memoria de PHP;
  • la adición de todas las filas para una tabla enorme romperá el límite máximo de memoria de PHP;
  • utilizando addlashes () en lugar de PDO :: quote ();
  • comprobación de errores de consulta solo al final de la función;
  • no comprobando la creación de archivos fallidos;
  • La extensión gzip no puede ser cargada
  • Además, probablemente todavía no es compatible con los datos UTF8.

Pero está llegando, ¿no?

Sí, esto es mejor que el guión original de David Walsh. 🙂

¿Qué hay de malo con NULL para ”?

NULL no es lo mismo que ” en SQL (excepto en Oracle, pero en este caso no cumplen con el estándar SQL). Ver MySQL, mejor insertar NULL o cadena vacía?

La estructura de la tabla tiene que ser muy muy grande para la memoria máxima. cada fila de inserción se escribe en el archivo individualmente, así que, nuevamente, la fila debe ser muy grande para la memoria máxima.

He leído mal el código en el problema de límite de memoria. Estás escribiendo la salida para cada fila, así que está bien (a menos que la fila contenga un blob de 1GB o algo así).

Pero no solo debe generar una única instrucción INSERT con un conjunto de filas separadas por comas. Incluso mysqldump --extended-insert genera una longitud finita de datos, luego inicia una nueva instrucción INSERT. El criterio es si la longitud de la statement INSERT se ajusta al argumento de la opción para --net-buffer-length .

¿Qué pasa con “” delimitadores de cadena? ¿Cómo consigo el ANSI?

En ANSI SQL, las comillas simples ” se utilizan para delimitar literales de cadena o literales de fecha. Las comillas dobles “” se utilizan para delimitar identificadores como el nombre de tabla o los nombres de columna. Por defecto, MySQL los trata de la misma manera, pero esto no es estándar. Consulte ¿Las diferentes bases de datos utilizan diferentes citas de nombres? . Si intenta importar sus datos de respaldo en un servidor MySQL en el que tiene SET SQL_MODE=ANSI_QUOTES , la importación fallará.

¿Y qué tablas no están delimitadas?

Ejemplo: query('SELECT * FROM '.$table); y, de hecho, cada uno de los otros casos en los que usa $ table en una consulta. Solo delimitó la tabla una vez, en la instrucción INSERT sus resultados de script.

Todas las tablas $ no están delimitadas, ¿todas deben estar con “”?

MySQL siempre reconoce las marcas de retroceso como delimitadores de identificadores y comillas simples para cadenas / fechas. Pero las comillas dobles cambian de significado dependiendo del SQL_MODE que mencioné. No puede asumir qué SQL_MODE está en efecto en la instancia de MySQL que restaura, por lo que es mejor si usa las marcas de verificación para los identificadores y las comillas simples para las cadenas. La razón por la que los delimitaría al consultar su tabla es que puede tener nombres de tablas que son palabras reservadas de SQL, o que contienen caracteres especiales, etc.

¿Puede insertar flotadores sin delimitadores en mysql, o hacer la necesidad de ”? Gracias

Puede insertar todos los tipos numéricos sin delimitadores. Sólo cadenas y fechas necesitan delimitadores. Ver dev.mysql.com/doc/refman/5.6/en/literals.html

Todos los PDO y ext/mysql son comandos de envoltura a la base de datos subyacente (MySQL en este caso). Es decir, no hay nada que impida que PDO ejecute SHOW CREATE TABLE o los otros comandos.

Para todos los propósitos y propósitos, usted puede simplemente reemplazar:

 - $link = mysql_connect($host,$user,$pass); - mysql_select_db($name,$link); + $link = new PDO("mysql:host=$host;dbname=$name", $user, $pass); 

Y en lugar de

 $result = mysql_query($query); mysql_fetch_assoc($result); 

Utilizar

 $result = $link->query($query); $result->fetch(); 

Según lo recomendado por https://stackoverflow.com/a/18281687/2259391, use mysqldump con exec . Todo se reduce a esto:

  

Acabo de terminar de hacer la versión PDO de la función de copia de seguridad original de David Walsh.
también lo he mejorado para abordar los problemas mencionados en la respuesta de Bill Karwin ; maneja NULL, escribe líneas individuales para que no haya problemas de memoria, con comillas invertidas, etc.
Da casi exactamente lo que hace mysqldump.
Podría arreglarse un poco, pero aquí está, por favor avise sobre cualquier mejora.

 require 'login.php'; $DBH = new PDO("mysql:host=$db_hostname;dbname=$db_database; charset=utf8", $db_username, $db_password); //put table names you want backed up in this array. //leave empty to do all $tables = array(); backup_tables($DBH, $tables); function backup_tables($DBH, $tables) { $DBH->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_TO_STRING ); //Script Variables $compression = false; $BACKUP_PATH = ""; $nowtimename = time(); //create/open files if ($compression) { $zp = gzopen($BACKUP_PATH.$nowtimename.'.sql.gz', "w9"); } else { $handle = fopen($BACKUP_PATH.$nowtimename.'.sql','a+'); } //array of all database field types which just take numbers $numtypes=array('tinyint','smallint','mediumint','int','bigint','float','double','decimal','real'); //get all of the tables if(empty($tables)) { $pstm1 = $DBH->query('SHOW TABLES'); while ($row = $pstm1->fetch(PDO::FETCH_NUM)) { $tables[] = $row[0]; } } else { $tables = is_array($tables) ? $tables : explode(',',$tables); } //cycle through the table(s) foreach($tables as $table) { $result = $DBH->query('SELECT * FROM '.$table); $num_fields = $result->columnCount(); $num_rows = $result->rowCount(); $return=""; //uncomment below if you want 'DROP TABLE IF EXISTS' displayed //$return.= 'DROP TABLE IF EXISTS `'.$table.'`;'; //table structure $pstm2 = $DBH->query('SHOW CREATE TABLE '.$table); $row2 = $pstm2->fetch(PDO::FETCH_NUM); $ifnotexists = str_replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS', $row2[1]); $return.= "\n\n".$ifnotexists.";\n\n"; if ($compression) { gzwrite($zp, $return); } else { fwrite($handle,$return); } $return = ""; //insert values if ($num_rows){ $return= 'INSERT INTO `'.$table."` ("; $pstm3 = $DBH->query('SHOW COLUMNS FROM '.$table); $count = 0; $type = array(); while ($rows = $pstm3->fetch(PDO::FETCH_NUM)) { if (stripos($rows[1], '(')) {$type[$table][] = stristr($rows[1], '(', true); } else $type[$table][] = $rows[1]; $return.= $rows[0]; $count++; if ($count < ($pstm3->rowCount())) { $return.= ", "; } } $return.= ")".' VALUES'; if ($compression) { gzwrite($zp, $return); } else { fwrite($handle,$return); } $return = ""; } while($row = $result->fetch(PDO::FETCH_NUM)) { $return= "\n\t("; for($j=0; $j<$num_fields; $j++) { $row[$j] = addslashes($row[$j]); //$row[$j] = preg_replace("\n","\\n",$row[$j]); if (isset($row[$j])) { //if number, take away "". else leave as string if (in_array($type[$table][$j], $numtypes)) $return.= $row[$j] ; else $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; } if ($j<($num_fields-1)) { $return.= ','; } } $count++; if ($count < ($result->rowCount())) { $return.= "),"; } else { $return.= ");"; } if ($compression) { gzwrite($zp, $return); } else { fwrite($handle,$return); } $return = ""; } $return="\n\n-- ------------------------------------------------ \n\n"; if ($compression) { gzwrite($zp, $return); } else { fwrite($handle,$return); } $return = ""; } $error1= $pstm2->errorInfo(); $error2= $pstm3->errorInfo(); $error3= $result->errorInfo(); echo $error1[2]; echo $error2[2]; echo $error3[2]; if ($compression) { gzclose($zp); } else { fclose($handle); } } 
 function backupDB() { $db_config = getDbConfigFromWordPress(); if ($db_config === false) { unset($db_config); logMessage('Unable to get database configuration from WordPress', true, 'red'); return false; } $new_backup_file = __DIR__ . DIRECTORY_SEPARATOR . 'newbackup_xxx_date.sql'; if (is_file($new_backup_file) && is_writable($new_backup_file)) { @unlink($new_backup_file); } elseif (is_file($new_backup_file) && !is_writable($new_backup_file)) { logMessage('Unable to remove new backup SQL file. This is necessary to create backup SQL file.', true, 'red'); return false; } unset($new_backup_file); $dbh = new \PDO('mysql:dbname=' . $db_config['dbname'] . ';host=' . $db_config['dbhost'] . ';charset=' . $db_config['dbcharset'], $db_config['dbuser'], $db_config['dbpassword']); $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $dbh->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_OBJ); $dbh->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true); $sth = $dbh->prepare('SHOW TABLES'); $sth->execute(); $result = $sth->fetchAll(\PDO::FETCH_COLUMN); $tables = []; if (is_array($result) && !empty($result)) { foreach ($result as $row) { if (is_string($row) && stristr($row, $db_config['tableprefix']) !== false) { $tables[] = $row; } elseif (is_array($row) && array_key_exists(0, $row) && stristr($row[0], $db_config['tableprefix']) !== false) { $tables[] = $row[0]; } }// endforeach; natcasesort($tables); } $sth->closeCursor(); unset($result, $row, $sth); // begins export string header. $export_sql = '-- Manual backup SQL Dump'."\n\n"; $export_sql .= 'SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";'."\n\n\n"; $export_sql .= '--'."\n"; $export_sql .= '-- Database: `' . $db_config['dbname'] . '`'."\n"; $export_sql .= '--'."\n\n"; unset($db_config); writeDownBackupDB($export_sql); unset($export_sql); // starting to loop thru tables. if (isset($tables) && is_array($tables)) { foreach ($tables as $table) { $export_sql = '-- --------------------------------------------------------'."\n\n"; $export_sql .= '--'."\n"; $export_sql .= '-- Table structure for table `' . $table . '`'."\n"; $export_sql .= '--'."\n\n"; $export_sql .= 'DROP TABLE IF EXISTS `' . $table . '`;'."\n"; $sth = $dbh->prepare('SHOW CREATE TABLE `' . $table . '`'); $sth->execute(); $row = $sth->fetch(\PDO::FETCH_NUM); if (isset($row[1])) { $create_sql_string = $row[1]; $create_sql_string = str_replace(['CREATE TABLE `'], ['CREATE TABLE IF NOT EXISTS `'], $create_sql_string); if (substr($create_sql_string, -1) != ';') { $create_sql_string .= ' ;'; } } else { $create_sql_string = ''; } unset($row); $export_sql .= $create_sql_string."\n\n"; $sth->closeCursor(); unset($sth); writeDownBackupDB($export_sql); unset($export_sql); $export_sql = '--'."\n"; $export_sql .= '-- Dumping data for table `' . $table . '`'."\n"; $export_sql .= '--'."\n\n"; writeDownBackupDB($export_sql); unset($export_sql); // get fields $sth = $dbh->prepare('SELECT * FROM `' . $table . '` LIMIT 1'); $sth->execute(); $result = $sth->fetch(\PDO::FETCH_ASSOC); if (is_array($result)) { $fields = array_keys($result); } else { $fields = []; } $sth->closeCursor(); unset($result, $sth); // get fields type $sth = $dbh->prepare('DESCRIBE `' . $table . '`'); $sth->execute(); $table_columns = $sth->fetchAll(); $columns = []; if (is_array($table_columns)) { foreach ($table_columns as $column) { $columns[$column->Field] = [ 'field' => $column->Field, 'type' => $column->Type, 'null' => $column->Null, 'default' => $column->Default, ]; }// endforeach; unset($column); } $sth->closeCursor(); unset($sth, $table_columns); if (isset($fields) && is_array($fields) && !empty($fields)) { $select_string = 'SELECT '; $i_count_field = 1; foreach ($fields as $field) { $select_string .= 'IF (`' . $field . '` IS NULL, \'FIELD_VALUE_NULL\', `' . $field . '`) AS `' . $field . '`'; if ($i_count_field < count($fields)) { $select_string .= ', '; } $i_count_field++; }// endforeach; unset($i_count_field, $field); $select_string .= ' FROM `' . $table . '`'; $sth = $dbh->prepare($select_string); unset($select_string); $sth->execute(); $result = $sth->fetchAll(); $export_sql = ''; if (is_array($result) && !empty($result)) { // generate INSERT INTO `table_name` string. $export_sql .= 'INSERT INTO `' . $table . '` ('; $i_count = 1; foreach ($fields as $field) { $export_sql .= '`' . $field . '`'; if ($i_count < count($fields)) { $export_sql .= ', '; } $i_count++; }// endforeach; unset($field, $i_count); $export_sql .= ') VALUES'."\n"; writeDownBackupDB($export_sql); unset($export_sql); // generate VALUES of INSERT INTO. if (is_array($result)) { $i_count = 1; $i_count_break = 1; foreach ($result as $row) { $export_sql = '('; $i_count_fields = 1; foreach ($fields as $field) { $field_value = $row->{$field}; // escape slash $field_value = str_replace('\\', '\\\\', $field_value); // sanitize new line $field_value = str_replace(["\r\n", "\r", "\n"], ['\r\n', '\r', '\n'], $field_value); // escape single quote $field_value = str_replace('\'', '\'\'', $field_value); // change value to NULL if it is NULL. if ($field_value === 'FIELD_VALUE_NULL') { $field_value = 'NULL'; } // detect field value type and cloak with single quote. if (isset($columns[$field]['type']) && ( stristr($columns[$field]['type'], 'tinyint(') !== false || stristr($columns[$field]['type'], 'smallint(') !== false || stristr($columns[$field]['type'], 'mediumint(') !== false || stristr($columns[$field]['type'], 'int(') !== false || stristr($columns[$field]['type'], 'bigint(') !== false ) ) { // this field column type is int if (!is_numeric($field_value) && $field_value !== 'NULL') { $field_value = '\'' . $field_value . '\''; } } else { if ($field_value !== 'NULL') { $field_value = '\'' . $field_value . '\''; } } $export_sql .= $field_value; unset($field_value); if ($i_count_fields < count($fields)) { $export_sql .= ', '; } $i_count_fields++; }// endforeach; unset($field, $i_count_fields); $export_sql .= ')'; if ($i_count < count($result)) { if ($i_count_break >= 30) { $export_sql .= ';'."\n"; writeDownBackupDB($export_sql); unset($export_sql); $i_count_break = 0; $export_sql = 'INSERT INTO `' . $table . '` ('; $i_count_fields = 1; foreach ($fields as $field) { $export_sql .= '`' . $field . '`'; if ($i_count_fields < count($fields)) { $export_sql .= ', '; } $i_count_fields++; }// endforeach; unset($field, $i_count_fields); $export_sql .= ') VALUES'."\n"; writeDownBackupDB($export_sql); unset($export_sql); $export_sql = ''; } else { $export_sql .= ','."\n"; } } else { $export_sql .= ';'."\n\n"; } $i_count++; $i_count_break++; writeDownBackupDB($export_sql); unset($export_sql); }// endforeach; unset($i_count, $i_count_break, $result, $row); } } else { $export_sql .= "\n"; writeDownBackupDB($export_sql); unset($export_sql); } unset($fields); $sth->closeCursor(); unset($result, $sth); } else { $export_sql = "\n"; writeDownBackupDB($export_sql); unset($export_sql); } unset($export_sql); }// endforeach; unset($table); } unset($tables); unset($dbh); logMessage('Backup DB completed. Max memory usage is ' . formatBytes(memory_get_peak_usage(true)) . '.', true, 'green'); return true; }// backupDB /** * Write content to backup SQL file by append. * * @param string $content */ function writeDownBackupDB($content) { $new_backup_file = __DIR__ . DIRECTORY_SEPARATOR . 'newbackup_xxx_date.sql'; $handle = fopen($new_backup_file, 'a+'); fwrite($handle, $content); fclose($handle); unset($handle, $new_backup_file); }// writeDownBackupDB logMessage('Beginning backup DB.', true, 'light_gray'); backupDB(); 

Tenga en cuenta que…

  1. Faltan algunas funciones, como logMessage() , getDbConfigFromWordPress() . Por favor, retire de antes de usarlo.
  2. Algo como $db_config['tableprefix'] o $db_config[...] debe cambiar.
  3. Hay muchas cosas que no se pueden manejar como dijo @Bill Karwin .
  4. No estoy seguro de si es compatible con datos UTF-8, pero como veo, es compatible con muchos idiomas y también con emoji (😂😭😍).
  5. Exportar usando el comando mysql es siempre una mejor idea.

Implementé la última versión de Lan con algunas modificaciones (ver código a continuación):

  • Las tablas se guardan en una carpeta cuyo nombre es la fecha de hoy; Las versiones anteriores del mismo día se sobrescriben.
  • Es compatible con varios formatos, incluyendo CSV separados por comas
  • Muestra los tamaños de tabla en bytes y números de filas.
  • Usando mis tabulaciones (ciertamente anticuadas)

Una razón para agregar la opción csv es que me resultó imposible importar datos de archivos sql en formato TEXTO (UTF8) cuando es multibyte (scripts asiáticos). Funciona de hecho con el formato BLOB, pero luego no podemos indexarlo como FULLTEXT. Probablemente me haya perdido un punto al formatear las tablas …

Aquí está el código de todos modos:

 function backup_tables($DBH,$tables,$compression,$format) { $DBH->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL ); //Script Variables $BACKUP_PATH = DUMP; $date = date("Ymd"); $olddir = getcwd(); chdir($BACKUP_PATH); if(!file_exists($date)) { echo "Created '".$date."' folder
"; $cmd = "mkdir ".$date; exec($cmd); } chdir($date); //array of all database field types which just take numbers $numtypes = array('tinyint', 'smallint', 'mediumint', 'int', 'bigint', 'float', 'double', 'decimal', 'real'); //get all of the tables if(empty($tables)) { $pstm1 = $DBH->query('SHOW TABLES'); while($row = $pstm1->fetch(PDO::FETCH_NUM)) { $tables[] = $row[0]; } } else { $tables = is_array($tables) ? $tables : explode(',',$tables); } //cycle through the table(s) echo "Dumping tables to DB_DUMP:"; echo "
    "; foreach($tables as $table) { //create/open files if($format == "csv") { $filename = $table.".csv"; $handle = fopen($filename,"w"); } else { if($compression) { $filename = $table.".sql.gz"; $zp = gzopen($filename,"wb9"); } else { $filename = $table.".sql"; $handle = fopen($filename,"w"); } } echo "
  • ".$filename.""; $result = $DBH->query("SELECT * FROM $table"); $num_fields = $result->columnCount(); $num_rows = $result->rowCount(); $return = ""; $return .= 'DROP TABLE IF EXISTS `'.$table.'`;'; //table structure $pstm2 = $DBH->query("SHOW CREATE TABLE $table"); $row2 = $pstm2->fetch(PDO::FETCH_NUM); $ifnotexists = str_replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS', $row2[1]); $return .= "\n\n".$ifnotexists.";\n\n"; if($format <> "csv") { if($compression) gzwrite($zp, $return); else fwrite($handle,$return); } $return = ""; //insert values if($num_rows) { $return = 'INSERT INTO `'."$table"."` ("; $pstm3 = $DBH->query("SHOW COLUMNS FROM $table"); $count = 0; $type = array(); while($rows = $pstm3->fetch(PDO::FETCH_NUM)) { if(stripos($rows[1], '(')) { $type[$table][] = stristr($rows[1], '(', true); } else $type[$table][] = $rows[1]; $return .= "`".$rows[0]."`"; $count++; if($count < ($pstm3->rowCount())) { $return .= ", "; } } $return .= ")".' VALUES'; if($format <> "csv") { if($compression) gzwrite($zp, $return); else fwrite($handle,$return); } $return = ""; } $count = 0; while($row = $result->fetch(PDO::FETCH_NUM)) { if($format <> "csv") $return = "\n\t("; for($j=0; $j < $num_fields; $j++) { //$row[$j] = preg_replace("\n","\\n",$row[$j]); if(isset($row[$j])) { if($format == "csv") $return .= '"'.$row[$j].'"'; else { //if number, take away "". else leave as string if((in_array($type[$table][$j],$numtypes)) && (!empty($row[$j]))) $return .= $row[$j]; else $return .= $DBH->quote($row[$j]); } } else { if($format == "csv") $return .= ''; else $return .= 'NULL'; } if($j < ($num_fields-1)) $return .= ','; } $count++; if($format == "csv") $return .= "\n"; else { if($count < ($result->rowCount())) $return .= "),"; else $return .= ");"; } if($format == "csv") fwrite($handle,$return); else { if($compression) gzwrite($zp, $return); else fwrite($handle,$return); } $return = ""; } $return = "\n\n-- ------------------------------------------------ \n\n"; echo " (".$count." records)"; if($format <> "csv") { if($compression) gzwrite($zp, $return); else fwrite($handle,$return); } $return = ""; $error1 = $pstm2->errorInfo(); $error2 = $pstm3->errorInfo(); $error3 = $result->errorInfo(); echo $error1[2]; echo $error2[2]; echo $error3[2]; if($format == "csv") fclose($handle); else { if($compression) gzclose($zp); else fclose($handle); } $filesize = filesize($filename); echo " - ".$filesize." bytes
  • "; } echo "
"; chdir($olddir); return; }