Я создаю сценарий установки для приложения, которое я разрабатываю, и вам нужно динамически создавать базы данных из PHP. У меня есть это, чтобы создать базу данных, но теперь мне нужно загрузить в несколько файлов .sql. Я планировал открыть файл и mysql_query, это строка за раз – пока я не посмотрел файлы схемы и не понял, что это не один запрос на строку.
Итак, как мне загрузить sql-файл из PHP (как phpMyAdmin делает с его командой импорта)?
У меня возникает ощущение, что все здесь, кто ответил на этот вопрос, не знают, каково это быть разработчиком веб-приложений, который позволяет людям устанавливать приложение на своих серверах. Общий хостинг, в частности, не позволяет использовать SQL, как упомянутый ранее запрос «LOAD DATA». Большинство общедоступных хостов также не позволяют использовать shell_exec.
Теперь, чтобы ответить на OP, вам лучше всего построить PHP-файл, содержащий ваши запросы в переменной, и вы можете просто запустить их. Если вы решите разбирать файлы .sql, вы должны изучить phpMyAdmin и получить некоторые идеи для получения данных из .sql-файлов таким образом. Посмотрите на другие веб-приложения, у которых есть инсталляторы, и вы увидите это, вместо того, чтобы использовать файлы .sql для своих запросов, они просто упаковывают их в файлы PHP и запускают каждую строку через mysql_query или что-то, что им нужно делать ,
$db = new PDO($dsn, $user, $password); $sql = file_get_contents('file.sql'); $qr = $db->exec($sql);
phpBB использует несколько функций для анализа своих файлов. Они довольно хорошо комментируются (какое исключение!), Поэтому вы можете легко узнать, что они делают (я получил это решение с http://www.frihost.com/forums/vt-8194.html ). вот решение, я использовал его много:
<php ini_set('memory_limit', '5120M'); set_time_limit ( 0 ); /*************************************************************************** * sql_parse.php * ------------------- * begin : Thu May 31, 2001 * copyright : (C) 2001 The phpBB Group * email : support@phpbb.com * * $Id: sql_parse.php,v 1.8 2002/03/18 23:53:12 psotfx Exp $ * ****************************************************************************/ /*************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * ***************************************************************************/ /*************************************************************************** * * These functions are mainly for use in the db_utilities under the admin * however in order to make these functions available elsewhere, specifically * in the installation phase of phpBB I have seperated out a couple of * functions into this file. JLH * \***************************************************************************/ // // remove_comments will strip the sql comment lines out of an uploaded sql file // specifically for mssql and postgres type files in the install.... // function remove_comments(&$output) { $lines = explode("\n", $output); $output = ""; // try to keep mem. use down $linecount = count($lines); $in_comment = false; for($i = 0; $i < $linecount; $i++) { if( preg_match("/^\/\*/", preg_quote($lines[$i])) ) { $in_comment = true; } if( !$in_comment ) { $output .= $lines[$i] . "\n"; } if( preg_match("/\*\/$/", preg_quote($lines[$i])) ) { $in_comment = false; } } unset($lines); return $output; } // // remove_remarks will strip the sql comment lines out of an uploaded sql file // function remove_remarks($sql) { $lines = explode("\n", $sql); // try to keep mem. use down $sql = ""; $linecount = count($lines); $output = ""; for ($i = 0; $i < $linecount; $i++) { if (($i != ($linecount - 1)) || (strlen($lines[$i]) > 0)) { if (isset($lines[$i][0]) && $lines[$i][0] != "#") { $output .= $lines[$i] . "\n"; } else { $output .= "\n"; } // Trading a bit of speed for lower mem. use here. $lines[$i] = ""; } } return $output; } // // split_sql_file will split an uploaded sql file into single sql statements. // Note: expects trim() to have already been run on $sql. // function split_sql_file($sql, $delimiter) { // Split up our string into "possible" SQL statements. $tokens = explode($delimiter, $sql); // try to save mem. $sql = ""; $output = array(); // we don't actually care about the matches preg gives us. $matches = array(); // this is faster than calling count($oktens) every time thru the loop. $token_count = count($tokens); for ($i = 0; $i < $token_count; $i++) { // Don't wanna add an empty string as the last thing in the array. if (($i != ($token_count - 1)) || (strlen($tokens[$i] > 0))) { // This is the total number of single quotes in the token. $total_quotes = preg_match_all("/'/", $tokens[$i], $matches); // Counts single quotes that are preceded by an odd number of backslashes, // which means they're escaped quotes. $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$i], $matches); $unescaped_quotes = $total_quotes - $escaped_quotes; // If the number of unescaped quotes is even, then the delimiter did NOT occur inside a string literal. if (($unescaped_quotes % 2) == 0) { // It's a complete sql statement. $output[] = $tokens[$i]; // save memory. $tokens[$i] = ""; } else { // incomplete sql statement. keep adding tokens until we have a complete one. // $temp will hold what we have so far. $temp = $tokens[$i] . $delimiter; // save memory.. $tokens[$i] = ""; // Do we have a complete statement yet? $complete_stmt = false; for ($j = $i + 1; (!$complete_stmt && ($j < $token_count)); $j++) { // This is the total number of single quotes in the token. $total_quotes = preg_match_all("/'/", $tokens[$j], $matches); // Counts single quotes that are preceded by an odd number of backslashes, // which means they're escaped quotes. $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$j], $matches); $unescaped_quotes = $total_quotes - $escaped_quotes; if (($unescaped_quotes % 2) == 1) { // odd number of unescaped quotes. In combination with the previous incomplete // statement(s), we now have a complete statement. (2 odds always make an even) $output[] = $temp . $tokens[$j]; // save memory. $tokens[$j] = ""; $temp = ""; // exit the loop. $complete_stmt = true; // make sure the outer loop continues at the right point. $i = $j; } else { // even number of unescaped quotes. We still don't have a complete statement. // (1 odd and 1 even always make an odd) $temp .= $tokens[$j] . $delimiter; // save memory. $tokens[$j] = ""; } } // for.. } // else } } return $output; } $dbms_schema = 'yourfile.sql'; $sql_query = @fread(@fopen($dbms_schema, 'r'), @filesize($dbms_schema)) or die('problem '); $sql_query = remove_remarks($sql_query); $sql_query = split_sql_file($sql_query, ';'); $host = 'localhost'; $user = 'user'; $pass = 'pass'; $db = 'database_name'; //In case mysql is deprecated use mysqli functions. mysql_connect($host,$user,$pass) or die('error connection'); mysql_select_db($db) or die('error database selection'); $i=1; foreach($sql_query as $sql){ echo $i++; echo "<br />"; mysql_query($sql) or die('error in query'); } ?>
эта<php ini_set('memory_limit', '5120M'); set_time_limit ( 0 ); /*************************************************************************** * sql_parse.php * ------------------- * begin : Thu May 31, 2001 * copyright : (C) 2001 The phpBB Group * email : support@phpbb.com * * $Id: sql_parse.php,v 1.8 2002/03/18 23:53:12 psotfx Exp $ * ****************************************************************************/ /*************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * ***************************************************************************/ /*************************************************************************** * * These functions are mainly for use in the db_utilities under the admin * however in order to make these functions available elsewhere, specifically * in the installation phase of phpBB I have seperated out a couple of * functions into this file. JLH * \***************************************************************************/ // // remove_comments will strip the sql comment lines out of an uploaded sql file // specifically for mssql and postgres type files in the install.... // function remove_comments(&$output) { $lines = explode("\n", $output); $output = ""; // try to keep mem. use down $linecount = count($lines); $in_comment = false; for($i = 0; $i < $linecount; $i++) { if( preg_match("/^\/\*/", preg_quote($lines[$i])) ) { $in_comment = true; } if( !$in_comment ) { $output .= $lines[$i] . "\n"; } if( preg_match("/\*\/$/", preg_quote($lines[$i])) ) { $in_comment = false; } } unset($lines); return $output; } // // remove_remarks will strip the sql comment lines out of an uploaded sql file // function remove_remarks($sql) { $lines = explode("\n", $sql); // try to keep mem. use down $sql = ""; $linecount = count($lines); $output = ""; for ($i = 0; $i < $linecount; $i++) { if (($i != ($linecount - 1)) || (strlen($lines[$i]) > 0)) { if (isset($lines[$i][0]) && $lines[$i][0] != "#") { $output .= $lines[$i] . "\n"; } else { $output .= "\n"; } // Trading a bit of speed for lower mem. use here. $lines[$i] = ""; } } return $output; } // // split_sql_file will split an uploaded sql file into single sql statements. // Note: expects trim() to have already been run on $sql. // function split_sql_file($sql, $delimiter) { // Split up our string into "possible" SQL statements. $tokens = explode($delimiter, $sql); // try to save mem. $sql = ""; $output = array(); // we don't actually care about the matches preg gives us. $matches = array(); // this is faster than calling count($oktens) every time thru the loop. $token_count = count($tokens); for ($i = 0; $i < $token_count; $i++) { // Don't wanna add an empty string as the last thing in the array. if (($i != ($token_count - 1)) || (strlen($tokens[$i] > 0))) { // This is the total number of single quotes in the token. $total_quotes = preg_match_all("/'/", $tokens[$i], $matches); // Counts single quotes that are preceded by an odd number of backslashes, // which means they're escaped quotes. $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$i], $matches); $unescaped_quotes = $total_quotes - $escaped_quotes; // If the number of unescaped quotes is even, then the delimiter did NOT occur inside a string literal. if (($unescaped_quotes % 2) == 0) { // It's a complete sql statement. $output[] = $tokens[$i]; // save memory. $tokens[$i] = ""; } else { // incomplete sql statement. keep adding tokens until we have a complete one. // $temp will hold what we have so far. $temp = $tokens[$i] . $delimiter; // save memory.. $tokens[$i] = ""; // Do we have a complete statement yet? $complete_stmt = false; for ($j = $i + 1; (!$complete_stmt && ($j < $token_count)); $j++) { // This is the total number of single quotes in the token. $total_quotes = preg_match_all("/'/", $tokens[$j], $matches); // Counts single quotes that are preceded by an odd number of backslashes, // which means they're escaped quotes. $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$j], $matches); $unescaped_quotes = $total_quotes - $escaped_quotes; if (($unescaped_quotes % 2) == 1) { // odd number of unescaped quotes. In combination with the previous incomplete // statement(s), we now have a complete statement. (2 odds always make an even) $output[] = $temp . $tokens[$j]; // save memory. $tokens[$j] = ""; $temp = ""; // exit the loop. $complete_stmt = true; // make sure the outer loop continues at the right point. $i = $j; } else { // even number of unescaped quotes. We still don't have a complete statement. // (1 odd and 1 even always make an odd) $temp .= $tokens[$j] . $delimiter; // save memory. $tokens[$j] = ""; } } // for.. } // else } } return $output; } $dbms_schema = 'yourfile.sql'; $sql_query = @fread(@fopen($dbms_schema, 'r'), @filesize($dbms_schema)) or die('problem '); $sql_query = remove_remarks($sql_query); $sql_query = split_sql_file($sql_query, ';'); $host = 'localhost'; $user = 'user'; $pass = 'pass'; $db = 'database_name'; //In case mysql is deprecated use mysqli functions. mysql_connect($host,$user,$pass) or die('error connection'); mysql_select_db($db) or die('error database selection'); $i=1; foreach($sql_query as $sql){ echo $i++; echo "<br />"; mysql_query($sql) or die('error in query'); } ?>
не<php ini_set('memory_limit', '5120M'); set_time_limit ( 0 ); /*************************************************************************** * sql_parse.php * ------------------- * begin : Thu May 31, 2001 * copyright : (C) 2001 The phpBB Group * email : support@phpbb.com * * $Id: sql_parse.php,v 1.8 2002/03/18 23:53:12 psotfx Exp $ * ****************************************************************************/ /*************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * ***************************************************************************/ /*************************************************************************** * * These functions are mainly for use in the db_utilities under the admin * however in order to make these functions available elsewhere, specifically * in the installation phase of phpBB I have seperated out a couple of * functions into this file. JLH * \***************************************************************************/ // // remove_comments will strip the sql comment lines out of an uploaded sql file // specifically for mssql and postgres type files in the install.... // function remove_comments(&$output) { $lines = explode("\n", $output); $output = ""; // try to keep mem. use down $linecount = count($lines); $in_comment = false; for($i = 0; $i < $linecount; $i++) { if( preg_match("/^\/\*/", preg_quote($lines[$i])) ) { $in_comment = true; } if( !$in_comment ) { $output .= $lines[$i] . "\n"; } if( preg_match("/\*\/$/", preg_quote($lines[$i])) ) { $in_comment = false; } } unset($lines); return $output; } // // remove_remarks will strip the sql comment lines out of an uploaded sql file // function remove_remarks($sql) { $lines = explode("\n", $sql); // try to keep mem. use down $sql = ""; $linecount = count($lines); $output = ""; for ($i = 0; $i < $linecount; $i++) { if (($i != ($linecount - 1)) || (strlen($lines[$i]) > 0)) { if (isset($lines[$i][0]) && $lines[$i][0] != "#") { $output .= $lines[$i] . "\n"; } else { $output .= "\n"; } // Trading a bit of speed for lower mem. use here. $lines[$i] = ""; } } return $output; } // // split_sql_file will split an uploaded sql file into single sql statements. // Note: expects trim() to have already been run on $sql. // function split_sql_file($sql, $delimiter) { // Split up our string into "possible" SQL statements. $tokens = explode($delimiter, $sql); // try to save mem. $sql = ""; $output = array(); // we don't actually care about the matches preg gives us. $matches = array(); // this is faster than calling count($oktens) every time thru the loop. $token_count = count($tokens); for ($i = 0; $i < $token_count; $i++) { // Don't wanna add an empty string as the last thing in the array. if (($i != ($token_count - 1)) || (strlen($tokens[$i] > 0))) { // This is the total number of single quotes in the token. $total_quotes = preg_match_all("/'/", $tokens[$i], $matches); // Counts single quotes that are preceded by an odd number of backslashes, // which means they're escaped quotes. $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$i], $matches); $unescaped_quotes = $total_quotes - $escaped_quotes; // If the number of unescaped quotes is even, then the delimiter did NOT occur inside a string literal. if (($unescaped_quotes % 2) == 0) { // It's a complete sql statement. $output[] = $tokens[$i]; // save memory. $tokens[$i] = ""; } else { // incomplete sql statement. keep adding tokens until we have a complete one. // $temp will hold what we have so far. $temp = $tokens[$i] . $delimiter; // save memory.. $tokens[$i] = ""; // Do we have a complete statement yet? $complete_stmt = false; for ($j = $i + 1; (!$complete_stmt && ($j < $token_count)); $j++) { // This is the total number of single quotes in the token. $total_quotes = preg_match_all("/'/", $tokens[$j], $matches); // Counts single quotes that are preceded by an odd number of backslashes, // which means they're escaped quotes. $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$j], $matches); $unescaped_quotes = $total_quotes - $escaped_quotes; if (($unescaped_quotes % 2) == 1) { // odd number of unescaped quotes. In combination with the previous incomplete // statement(s), we now have a complete statement. (2 odds always make an even) $output[] = $temp . $tokens[$j]; // save memory. $tokens[$j] = ""; $temp = ""; // exit the loop. $complete_stmt = true; // make sure the outer loop continues at the right point. $i = $j; } else { // even number of unescaped quotes. We still don't have a complete statement. // (1 odd and 1 even always make an odd) $temp .= $tokens[$j] . $delimiter; // save memory. $tokens[$j] = ""; } } // for.. } // else } } return $output; } $dbms_schema = 'yourfile.sql'; $sql_query = @fread(@fopen($dbms_schema, 'r'), @filesize($dbms_schema)) or die('problem '); $sql_query = remove_remarks($sql_query); $sql_query = split_sql_file($sql_query, ';'); $host = 'localhost'; $user = 'user'; $pass = 'pass'; $db = 'database_name'; //In case mysql is deprecated use mysqli functions. mysql_connect($host,$user,$pass) or die('error connection'); mysql_select_db($db) or die('error database selection'); $i=1; foreach($sql_query as $sql){ echo $i++; echo "<br />"; mysql_query($sql) or die('error in query'); } ?>
Самое простое решение – использовать shell_exec () для запуска клиента mysql со сценарием SQL в качестве входного. Это может работать немного медленнее, потому что оно должно развиваться, но вы можете написать код через пару минут, а затем вернуться к работе над чем-то полезным. Написание PHP-скрипта для запуска любого скрипта SQL может занять несколько недель.
Поддержка SQL-скриптов более сложна, чем то, что люди описывают здесь, если вы не уверены, что ваш скрипт содержит только часть функциональности скриптов. Ниже приведены некоторые примеры вещей, которые могут появляться в обычном сценарии SQL, которые делают его сложным для кодирования сценария для его интерпретации по строкам.
-- Comment lines cannot be prepared as statements -- This is a MySQL client tool builtin command. -- It cannot be prepared or executed by server. USE testdb; -- This is a multi-line statement. CREATE TABLE foo ( string VARCHAR(100) ); -- This statement is not supported as a prepared statement. LOAD DATA INFILE 'datafile.txt' INTO TABLE foo; -- This statement is not terminated with a semicolon. DELIMITER // -- This multi-line statement contains a semicolon -- but not as the statement terminator. CREATE PROCEDURE simpleproc (OUT param1 INT) BEGIN SELECT COUNT(*) INTO param1 FROM foo; END //
Если вы поддерживаете только подмножество SQL-скриптов, исключая некоторые угловые случаи, такие как приведенные выше, относительно легко написать скрипт PHP, который читает файл и выполняет инструкции SQL в файле. Но если вы хотите поддерживать любой действительный SQL-скрипт, это намного сложнее.
См. Также мои ответы на следующие вопросы:
mysqli
может запускать несколько запросов, разделенных символом a ;
вы можете прочитать весь файл и запустить его сразу, используя mysqli_multi_query()
Но я буду первым, кто скажет, что это не самое элегантное решение.
В моих проектах я использовал следующее решение:
<?php /** * Import SQL from file * * @param string path to sql file */ function sqlImport($file) { $delimiter = ';'; $file = fopen($file, 'r'); $isFirstRow = true; $isMultiLineComment = false; $sql = ''; while (!feof($file)) { $row = fgets($file); // remove BOM for utf-8 encoded file if ($isFirstRow) { $row = preg_replace('/^\x{EF}\x{BB}\x{BF}/', '', $row); $isFirstRow = false; } // 1. ignore empty string and comment row if (trim($row) == '' || preg_match('/^\s*(#|--\s)/sUi', $row)) { continue; } // 2. clear comments $row = trim(clearSQL($row, $isMultiLineComment)); // 3. parse delimiter row if (preg_match('/^DELIMITER\s+[^ ]+/sUi', $row)) { $delimiter = preg_replace('/^DELIMITER\s+([^ ]+)$/sUi', '$1', $row); continue; } // 4. separate sql queries by delimiter $offset = 0; while (strpos($row, $delimiter, $offset) !== false) { $delimiterOffset = strpos($row, $delimiter, $offset); if (isQuoted($delimiterOffset, $row)) { $offset = $delimiterOffset + strlen($delimiter); } else { $sql = trim($sql . ' ' . trim(substr($row, 0, $delimiterOffset))); query($sql); $row = substr($row, $delimiterOffset + strlen($delimiter)); $offset = 0; $sql = ''; } } $sql = trim($sql . ' ' . $row); } if (strlen($sql) > 0) { query($row); } fclose($file); } /** * Remove comments from sql * * @param string sql * @param boolean is multicomment line * @return string */ function clearSQL($sql, &$isMultiComment) { if ($isMultiComment) { if (preg_match('#\*/#sUi', $sql)) { $sql = preg_replace('#^.*\*/\s*#sUi', '', $sql); $isMultiComment = false; } else { $sql = ''; } if(trim($sql) == ''){ return $sql; } } $offset = 0; while (preg_match('{--\s|#|/\*[^!]}sUi', $sql, $matched, PREG_OFFSET_CAPTURE, $offset)) { list($comment, $foundOn) = $matched[0]; if (isQuoted($foundOn, $sql)) { $offset = $foundOn + strlen($comment); } else { if (substr($comment, 0, 2) == '/*') { $closedOn = strpos($sql, '*/', $foundOn); if ($closedOn !== false) { $sql = substr($sql, 0, $foundOn) . substr($sql, $closedOn + 2); } else { $sql = substr($sql, 0, $foundOn); $isMultiComment = true; } } else { $sql = substr($sql, 0, $foundOn); break; } } } return $sql; } /** * Check if "offset" position is quoted * * @param int $offset * @param string $text * @return boolean */ function isQuoted($offset, $text) { if ($offset > strlen($text)) $offset = strlen($text); $isQuoted = false; for ($i = 0; $i < $offset; $i++) { if ($text[$i] == "'") $isQuoted = !$isQuoted; if ($text[$i] == "\\" && $isQuoted) $i++; } return $isQuoted; } function query($sql) { global $mysqli; //echo '#<strong>SQL CODE TO RUN:</strong><br>' . htmlspecialchars($sql) . ';<br><br>'; if (!$query = $mysqli->query($sql)) { throw new Exception("Cannot execute request to the database {$sql}: " . $mysqli->error); } } set_time_limit(0); $mysqli = new mysqli('localhost', 'root', '', 'test'); $mysqli->set_charset("utf8"); header('Content-Type: text/html;charset=utf-8'); sqlImport('import.sql'); echo "Peak MB: ", memory_get_peak_usage(true)/1024/1024;
В тестовом sql-файле (41 Мб) максимальное использование памяти: 3,25 Мб
Мое предложение – посмотреть исходный код PHPMyBackup. Это автоматический загрузчик PHP SQL. Вы обнаружите, что mysql_query загружает только один запрос за раз, а такие проекты, как PHPMyAdmin и PHPMyBackup, уже сделали вам тяжелую работу по правильному анализу SQL. Пожалуйста, не изобретайте это колесо: P
Обновленное решение решения Plahcinski. Кроме того, вы можете использовать fopen и fread для больших файлов:
$fp = file('database.sql', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $query = ''; foreach ($fp as $line) { if ($line != '' && strpos($line, '--') === false) { $query .= $line; if (substr($query, -1) == ';') { mysql_query($query); $query = ''; } } }
Поскольку я не могу прокомментировать ответ, остерегайтесь использовать следующее решение:
$db = new PDO($dsn, $user, $password); $sql = file_get_contents('file.sql'); $qr = $db->exec($sql);
В PHP PDO есть ошибка https://bugs.php.net/bug.php?id=61613
db->exec('SELECT 1; invalidstatement; SELECT 2');
не будет выходить из строя или возвращать false (проверено на PHP 5.5.14).
Работает на свалках Navicat. Может потребоваться сброс первого / * * / комментария navicat.
$file_content = file('myfile.sql'); $query = ""; foreach($file_content as $sql_line){ if(trim($sql_line) != "" && strpos($sql_line, "--") === false){ $query .= $sql_line; if (substr(rtrim($query), -1) == ';'){ echo $query; $result = mysql_query($query)or die(mysql_error()); $query = ""; } } }
Попробуй это:
// SQL File $SQLFile = 'YourSQLFile.sql'; // Server Name $hostname = 'localhost'; // User Name $db_user = 'root'; // User Password $db_password = ''; // DBName $database_name = 'YourDBName'; // Connect MySQL $link = mysql_connect($hostname, $db_user, $db_password); if (!$link) { die("MySQL Connection error"); } // Select MySQL DB mysql_select_db($database_name, $link) or die("Wrong MySQL Database"); // Function For Run Multiple Query From .SQL File function MultiQuery($sqlfile, $sqldelimiter = ';') { set_time_limit(0); if (is_file($sqlfile) === true) { $sqlfile = fopen($sqlfile, 'r'); if (is_resource($sqlfile) === true) { $query = array(); echo "<table cellspacing='3' cellpadding='3' border='0'>"; while (feof($sqlfile) === false) { $query[] = fgets($sqlfile); if (preg_match('~' . preg_quote($sqldelimiter, '~') . '\s*$~iS', end($query)) === 1) { $query = trim(implode('', $query)); if (mysql_query($query) === false) { echo '<tr><td>ERROR:</td><td> ' . $query . '</td></tr>'; } else { echo '<tr><td>SUCCESS:</td><td>' . $query . '</td></tr>'; } while (ob_get_level() > 0) { ob_end_flush(); } flush(); } if (is_string($query) === true) { $query = array(); } } echo "</table>"; return fclose($sqlfile); } } return false; } /* * * Use Function Like This: ** */ MultiQuery($SQLFile);
Вы уверены, что это не один запрос на строку? Ваш текстовый редактор может быть обертыванием строк, но на самом деле каждый запрос может быть в одной строке.
Во всяком случае, метод олля кажется лучшим. Если у вас есть причины для одновременного запуска запросов, вы должны иметь возможность читать в своем файле строку за строкой, а затем использовать точку с запятой в конце каждого запроса для разграничения. Вы гораздо лучше читаете файл в строке за строкой, чем пытаетесь разбить огромную строку, так как она будет намного добрее к памяти вашего сервера. Пример:
$query = ''; $handle = @fopen("/sqlfile.sql", "r"); if ($handle) { while (!feof($handle)) { $query.= fgets($handle, 4096); if (substr(rtrim($query), -1) == ';') { // ...run your query, then unset the string $query = ''; } } fclose($handle); }
Очевидно, что вам нужно будет рассмотреть транзакции и все остальное, если вы выполняете множество запросов в пакете, но, вероятно, это не очень важно для сценария новой установки.
mysql_query("LOAD DATA LOCAL INFILE '/path/to/file' INTO TABLE mytable");
Если вы не планируете импортировать огромные файлы .sql, просто прочитайте весь файл в памяти и запустите его как запрос.
Прошло некоторое время с тех пор, как я использовал PHP, поэтому, псевдокод:
all_query = read_file("/my/file.sql") con = mysql_connect("localhost") con.mysql_select_db("mydb") con.mysql_query(all_query) con.close()
Если файлы не огромны (скажем, более чем на несколько мегабайт), нет причин для его выполнения по принципу «время от времени» или попробуйте разбить его на несколько запросов (путем разбиения с помощью;, который, как я прокомментировал ответ Cam8001, будет break, если запрос имеет полуколоны внутри строк).
Этот лучший код Для восстановления sql php можно использовать 100% Goooood! Спасибо большое
$file_content = file('myfile.sql'); $query = ""; foreach($file_content as $sql_line){ if(trim($sql_line) != "" && strpos($sql_line, "--") === false){ $query .= $sql_line; if (substr(rtrim($query), -1) == ';'){ echo $query; $result = mysql_query($query)or die(mysql_error()); $query = ""; } } }
Самый простой и быстрый способ загрузить и проанализировать дамп phpmyadmin или файл mysql dump.
$ mysql -u username -p -h localhost dbname < dumpfile.sql
Вкратце, способ, которым я это сделал:
Прочитайте файл (db dump, например $ mysqldump db > db.sql
)
$sql = file_get_contents(db.sql);
Импортируйте его с помощью mysqli :: multi_query
if ($mysqli->multi_query($sql)) { $mysqli->close(); } else { throw new Exception ($mysqli->error); }
Остерегайтесь mysqli_query поддерживает асинхронные запросы. Подробнее здесь: http://php.net/manual/en/mysqli.multi-query.php и здесь https://stackoverflow.com/a/6652908/2002493
Ни одно из решений, которые я видел здесь, не требует изменения разделителя при создании хранимой процедуры на сервере, где я не могу рассчитывать на доступ к LOAD DATA INFILE. Я надеялся найти, что кто-то уже решил это, не пытаясь оценить код phpMyAdmin, чтобы понять это. Как и другие, я тоже искал чужой GPL-способ сделать это, так как сам пишу код GPL.
Некоторые библиотеки PHP могут анализировать SQL-файл из нескольких SQL-операторов, взорвать его правильно (не используя простой »,« взрывать », естественно) и выполнять их.
Например, проверьте PDOSQLExecTask Phing
Просто повторить проблему для всех:
PHP mysql_query автоматически ограничивает все команды SQL и, кроме того, очень расплывчато говорит об этом в своем руководстве. Все, кроме одной команды, приведет к ошибке.
На другой mysql_query отлично с строкой, содержащей комментарии в стиле SQL, \ n, \ r ..
Ограничение mysql_query проявляется в том, что синтаксический анализатор SQL сообщает о проблеме непосредственно в следующей команде, например
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO `outputdb:` (`intid`, `entry_id`, `definition`) VALUES...
Вот быстрое решение: (при условии, что форматированный SQL;
$sqlCmds = preg_split("/[\n|\t]*;[\n|\t]*[\n|\r]$/", $sqlDump);
Многие хосты не позволят вам создавать свою собственную базу данных через PHP, но вы, похоже, решили это.
После создания базы данных вы можете просто манипулировать и заполнять ее:
mysql_connect ( "локальный");
mysql_query ("SOURCE file.sql");
Это может быть полезно ->
Более или менее то, что он делает, это сначала взять строку, данную функции (значение file_get_contents () вашего файла.sql) и удалить все разрывы строк. Затем он разбивает данные на ";" персонаж. Затем он переходит в цикл while, просматривая каждую строку создаваемого массива. Если строка содержит символ “, она будет знать, что это запрос и вызывать функцию myquery () для данных данной строки.
Код:
function myquery($query) { mysql_connect(dbhost, dbuser, dbpass); mysql_select_db(dbname); $result = mysql_query($query); if (!mysql_errno() && @mysql_num_rows($result) > 0) { } else { $result="not"; } mysql_close(); return $result; } function mybatchquery ($str) { $sql = str_replace("\n","",$str) $sql = explode(";",$str); $x=0; while (isset($str[$x])) { if (preg_match("/(\w|\W)+`(\w|\W)+) { myquery($str[$x]); } $x++ } return TRUE; } function myrows($result) { $rows = @mysql_num_rows($result); return $rows; } function myarray($result) { $array = mysql_fetch_array($result); return $array; } function myescape($query) { $escape = mysql_escape_string($query); return $escape; } $str = file_get_contents("foo.sql"); mybatchquery($str);
Почему бы не взять код из phpMyAdmin и использовать его? Это открытый источник …
Я использую это все время:
$sql = explode(";",file_get_contents('[your dump file].sql'));// foreach($sql as $query) mysql_query($query);
Надеюсь, следующий код решит вашу проблему довольно хорошо.
//Empty all tables' contents $result_t = mysql_query("SHOW TABLES"); while($row = mysql_fetch_assoc($result_t)) { mysql_query("TRUNCATE " . $row['Tables_in_' . $mysql_database]); } // Temporary variable, used to store current query $templine = ''; // Read in entire file $lines = file($filename); // Loop through each line foreach ($lines as $line) { // Skip it if it's a comment if (substr($line, 0, 2) == '--' || $line == '') continue; // Add this line to the current segment $templine .= $line; // If it has a semicolon at the end, it's the end of the query if (substr(trim($line), -1, 1) == ';') { // Perform the query mysql_query($templine) or print('Error performing query \'<strong>' . $templine . '\': ' . mysql_error() . '<br /><br />'); // Reset temp variable to empty $templine = ''; } } ?>
это действительно сработало для меня:
/* load sql-commands from a sql file */ function loadSQLFromFile($url) { // ini_set ( 'memory_limit', '512M' ); // set_time_limit ( 0 ); global $settings_database_name; global $mysqli_object; global $worked; $worked = false; $sql_query = ""; // read line by line $lines = file($url); $count = count($lines); for($i = 0;$i<$count;$i++) { $line = $lines[$i]; $cmd3 = substr($line, 0, 3); $cmd4 = substr($line, 0, 4); $cmd6 = substr($line, 0, 6); if($cmd3 == "USE") { // cut away USE ``; $settings_database_name = substr($line, 5, -3); } else if($cmd4 == "DROP") { $mysqli_object->query($line); // execute this line } else if(($cmd6 == "INSERT") || ($cmd6 == "CREATE")) { // sum all lines up until ; is detected $multiline = $line; while(!strstr($line, ';')) { $i++; $line = $lines[$i]; $multiline .= $line; } $multiline = str_replace("\n", "", $multiline); // remove newlines/linebreaks $mysqli_object->query($multiline); // execute this line } } return $worked; } ?>
Некоторые ребята (Plahcinski) предложили этот код:
$file_content = file('myfile.sql'); $query = ""; foreach($file_content as $sql_line){ if(trim($sql_line) != "" && strpos($sql_line, "--") === false){ $query .= $sql_line; if (substr(rtrim($query), -1) == ';'){ echo $query; $result = mysql_query($query)or die(mysql_error()); $query = ""; } } }
но я бы обновил его тем, который работал на меня:
//selecting my database $database = 'databaseTitleInFile'; $selectDatabase = mysql_select_db($database, $con); if(! $selectDatabase ) { die('Could not select the database: ' . mysql_error()); } echo "The database " . $database . " selected successfully\n"; //reading the file $file_path='..\yourPath\to\File'; if(!file_exists($file_path)){ echo "File Not Exists"; } $file_content = file_get_contents($file_path); $array = explode("\n", $file_content) //making queries $query = ""; foreach($array as $sql_line){ $sql_line=trim($sql_line); if($sql_line != "" && substr($sql_line, 0, 2) === "--" && strpos($sql_line, "/*") === false){ $query .= $sql_line; if (substr(rtrim($query), -1) == ';'){ $result = mysql_query($query)or die(mysql_error()); $query = ""; } } }
потому что он более всеобъемлющий. 😉
У меня есть среда, в которой ни один инструмент mysql или phpmyadmin просто мое приложение php, подключающееся к серверу mysql на другом хосте, но мне нужно запустить скрипты, экспортированные mysqldump или myadmin. Чтобы решить проблему, я создал скрипт multi_query
как я упоминал здесь
Он может обрабатывать вывод mysqldump и экспорт phpmyadmin без инструмента командной строки mysql. Я также сделал несколько логических операций для обработки нескольких файлов миграции на основе временной метки, хранящейся в БД, например Rails. Я знаю, что для этого требуется больше обработки ошибок, но в настоящее время работает для меня.
Проверьте это: https://github.com/kepes/php-migration
Это чистый php и не нужны никакие другие инструменты. Если вы не обрабатываете вход пользователя с помощью только скриптов, созданных разработчиками или инструментами экспорта, вы можете безопасно использовать их.
Я заметил, что драйвер PostgreSQL PDO не позволяет запускать скрипты, разделенные точками с запятой. Для запуска файла .sql в любой базе данных с использованием PDO необходимо разделить операторы на PHP-код самостоятельно. Вот решение, которое, кажется, работает достаточно хорошо:
https://github.com/diontruter/migrate/blob/master/src/Diontruter/Migrate/SqlScriptParser.php
Связанный класс сделал трюк для меня независимым от базы данных, пожалуйста, сообщите мне, есть ли какие-либо проблемы. Вот как вы могли бы использовать скрипт после добавления его в свой проект:
$pdo = new PDO($connectionString, $userName, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $parser = new SqlScriptParser(); $sqlStatements = $parser->parse($fileName); foreach ($sqlStatements as $statement) { $distilled = $parser->removeComments($statement); if (!empty($distilled)) { $statement = $pdo->prepare($sql); $affectedRows = $statement->execute(); } }