PDO MySQL функция резервного копирования
Эта функция здесь http://davidwalsh.name/backup-mysql-database-php
Уже некоторое время плавает по интернету и довольно известен, но его в стандартном mysql. есть ли у кого-нибудь то же самое, но в PDO? если нет, то кто-нибудь хочет его сделать? возможно ли это вообще, я где - то читал, что PDO не делает SHOW CREATE TABLE-это так?
Наконец, может ли кто-нибудь объяснить, в чем разница между этой функцией и использованием SELECT * в OUTFILE?
(пожалуйста не отмечайте это за то, что содержит слишком много вопросов, все они тесно связаны, и я уверен, что ответ(ы) будет полезен для многих людей)
7 ответов:
Для тех, кто ищет функцию, которая действует как mysqldump, вот последний проект, с недостатками, обсуждаемыми в комментариях выше / ниже, сглаженными. Наслаждаться.
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); } }
Этот сценарий резервного копирования смешон, и никто не должен делать другую его версию. Я видел этот сценарий раньше, а также подобные попытки, и у них есть много проблем:
- не разделяет имена таблиц в обратных ТИКах
- не обрабатывает нули
- не обрабатывает наборы символов
- не обрабатывает двоичные данные
- не создает резервные копии представлений
- не создает резервные копии триггеров, хранимых процедур, хранимых функций или событий
- использует устаревший mysql расширение (но именно поэтому вы хотите версию PDO, не так ли?)
- использует addslashes () вместо правильной функции экранирования MySQL.
- добавляет все данные для всех таблиц в одну действительно длинную строку, прежде чем выводить все содержимое. Это означает, что вы должны иметь возможность хранить всю вашу базу данных в одной строке,что почти наверняка приведет к потере вашего максимального лимита памяти PHP.
Смотрите также мой прошлый ответ о неудачном резервном копировании Дэвида Уолша сценарий:
Ваш комментарий:
Прочитайте комментарии на странице, на которую вы ссылаетесь. Многие люди выявили проблемы, а у некоторых есть исправления или, по крайней мере, предложения.
Тот факт, что этот скрипт добавляет все в одну строку, я думаю, является нарушением сделки, но не должно быть трудно изменить сценарий, чтобы открыть выходной файл сначала, а затем вывести данные каждой строки во время цикла, затем закройте файл после цикла. Я не понимаю, почему сценарий этого не делает. Но совершенно ясно, что сценарий был протестирован не очень хорошо.
Но в любом случае, я бы не стал пытаться изобрести это колесо. Mysqldump или mydumper прекрасно справляются с этой работой. FWIW, вам не нужно запускать mysqldump на том же сервере, где находится база данных. Mysqldump поддерживает опцию для--host
, так что вы можете запустить mysqldump в любом месте для резервного копирования удаленной базы данных, пока брандмауэры не блокируют подключение клиента. В принципе, если вы можете подключить PHP-приложение к базе данных с какого-то клиентского хоста, вы можете подключить mysqldump.Если это действительно не вариант, то я бы использовал функцию дампа базы данных phpmyadmin. Они зрелые и хорошо проверенные, и они сбрасывают все правильно. Вот статья, в которой описывается, как использовать дамп характеристика:
Http://www.techrepublic.com/blog/smb-technologist/import-and-export-databases-using-phpmyadmin/
[копирование моих комментариев из вашего ответа:]
Это попадание в обзор кода, который не является целью StackOverflow. Но кратко:
- нет надлежащей поддержки NULL (вы преобразуете их в");
- не последовательно разделяющие имена таблиц;
- использование двойных кавычек не-ANSI в качестве разделителей строк;
- использование буферизации запросы к огромным таблицам нарушат максимальный лимит памяти PHP;
- добавление всех строк для огромной таблицы нарушит максимальный лимит памяти PHP;
- использование addslashes () вместо PDO:: quote ();
- проверка ошибок запроса только в конце функции;
- не проверяется на неудачное создание файла;
- расширение gzip не может быть загружено
- также, вероятно, все еще не поддерживает данные UTF8.
Но ведь он туда добирается, не так ли?
Да, это так. лучше, чем оригинальный сценарий Дэвида Уолша. :- )
Что не так с NULLs to?
NULL-это не то же самое, что " в SQL (за исключением Oracle, но в данном случае они не соответствуют стандарту SQL). Смотрите MySQL, лучше вставить NULL или пустую строку?
Структура таблицы должна быть очень и очень большой для максимальной памяти. каждая строка вставки записывается в файл индивидуально, так что опять же, строка должна быть очень очень большой для максимальной памяти.
I неправильно истолковал код по вопросу ограничения памяти. Вы пишете выходные данные для каждой строки, так что все в порядке (если только строка не содержит большой двоичный объект размером 1 ГБ или что-то еще).
Но вы не должны просто выводить один оператор INSERT с набором строк, разделенных запятыми. Even
mysqldump --extended-insert
выводит конечную длину данных,а затем запускает новый оператор INSERT. Критерием является то, соответствует ли длина инструкции INSERT аргументу option для--net-buffer-length
.Что не так с разделителями строк""? как мне получить ANSI one?
В ANSI SQL одинарные кавычки " используются для разграничения строковых литералов или литералов даты. Двойные кавычки "" используются для разграничения идентификаторов, таких как имя таблицы или имя столбца. По умолчанию MySQL обрабатывает их одинаково, но это нестандартно. См. используют ли разные базы данных разные названия цитат?. Если вы попытаетесь импортировать данные резервной копии на сервер MySQL, где у вас есть
SET SQL_MODE=ANSI_QUOTES
, импорт завершится неудачей.А какие таблицы не разделены?
Пример:
query('SELECT * FROM '.$table);
и фактически каждый из других случаев, когда вы используете $table в запросе. Вы разделили таблицу только один раз, в инструкции INSERT, которую выводит ваш скрипт.Все $таблицы не разделены, они все должны быть с " "?
MySQL всегда распознает обратные тики как разделители идентификаторов и одинарные кавычки для строк / дат. Но двойные кавычки меняют значение в зависимости от упомянутого мною SQL_MODE. Вы не можете предположить, какой SQL_MODE находится в влияние на экземпляр MySQL, который вы восстанавливаете, поэтому лучше всего использовать обратные тики для идентификаторов и одинарные кавычки для строк. Причина, по которой вы разделяете их при запросе таблицы, заключается в том, что у вас могут быть имена таблиц, которые являются зарезервированными словами SQL или содержат специальные символы и т. д.
Можете ли вы вставить поплавки без разделителей в mysql, или вам нужно "? спасибо
Можно вставить все числовые типы без разделителей. Нужны только строки и даты ограничители. Видишь dev.mysql.com/doc/refman/5.6/en/literals.html
Все
PDO
иext/mysql
являются командами переноса в базовую базу данных (в данном случае MySQL). Это означает, что ничто не мешаетPDO
выполнятьSHOW CREATE TABLE
или другие команды.Для всех намерений и целей вы можете в значительной степени просто заменить:
- $link = mysql_connect($host,$user,$pass); - mysql_select_db($name,$link); + $link = new PDO("mysql:host=$host;dbname=$name", $user, $pass);
И вместо
$result = mysql_query($query); mysql_fetch_assoc($result);
Использовать
$result = $link->query($query); $result->fetch();
Как рекомендовано https://stackoverflow.com/a/18281687/2259391 Используйте
mysqldump
сexec
. Она сводится к следующему:<?php function importDatabase($host, $user, $password, $database, $backupFilePath) { //returns true iff successfull return exec('mysqlimport --host '. $host .' --user '. $user .' --password '. $password .' '. $database .' '.targetFilePath) === 0; } function exportDatabase($host, $user, $password, $database, $targetFilePath) { //returns true iff successfull return exec('mysqldump --host '. $host .' --user '. $user .' --password '. $password .' '. $database .' --result-file='.targetFilePath) === 0; }
Я только что закончил создание PDO-версии оригинальной резервной функции Дэвида Уолша.
я также улучшил его для решения проблем, упомянутых в ответе Билла Карвина ; обрабатывает NULL, пишет отдельные строки, поэтому нет проблем с памятью, с обратными указателями и т. д.
Выдает в значительной степени именно то, что делает mysqldump.
Можно было бы немного прибраться, но вот он, пожалуйста, посоветуйте о каких-либо улучшениях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();
- некоторые функции отсутствуют, такие как
logMessage()
,getDbConfigFromWordPress()
. Пожалуйста, удалите из, прежде чем использовать его.- что-то вроде
$db_config['tableprefix']
или$db_config[...]
должно быть изменено.- есть много вещей, которые не могут справиться, как сказал @Bill Karwin.
- я не уверен, что он поддерживает данные UTF-8, но, как я вижу, он поддерживает многие языки, а также поддерживает emoji ().
- экспорт с помощью команды mysql всегда лучше.
Я реализовал последнюю версию Lan с несколькими модификациями (см. код ниже):
- таблицы сохраняются в папке, имя которой-сегодняшняя дата; предыдущие версии того же дня перезаписываются
- он поддерживает несколько форматов, в том числе CSV через запятую
- он отображает размеры таблиц в байтах и количество строк
- используя мои (по общему признанию старомодные) таблицы
Причиной добавления опции csv является то, что я обнаружил невозможность импорта из sql хранит данные в текстовом формате (UTF8), если он многобайтовый (азиатские скрипты). Он действительно работает с форматом BLOB, но тогда мы не можем индексировать его как полнотекстовый. Возможно, я упускаю какой-то момент в форматировании таблиц...
Вот код в любом случае:
function backup_tables($DBH,$tables,$compression,$format) { $DBH->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL ); //Script Variables $BACKUP_PATH = DUMP; $date = date("Y-m-d"); $olddir = getcwd(); chdir($BACKUP_PATH); if(!file_exists($date)) { echo "<font color=red>Created ‘".$date."’ folder</font><br />"; $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 "<font color=blue>Dumping tables to DB_DUMP:</font>"; echo "<ul>"; 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 "<li><small><font color=blue>".$filename."</font>"; $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</small></li>"; } echo "</ul>"; chdir($olddir); return; }