Загрузка файлов.sql из PHP

Я создаю сценарий установки для приложения, которое я разрабатываю, и мне нужно динамически создавать базы данных из PHP. У меня есть это для создания базы данных, но теперь мне нужно загрузить в несколько файлов.sql. Я планировал открывать файл и mysql_query по одной строке за раз - пока я не посмотрел на файлы схемы и не понял, что это не один запрос на строку.

Итак, как мне загрузить файл sql из PHP (как phpMyAdmin с его командой import)?

32 ответа

Решение

У меня такое ощущение, что все, кто здесь ответил на этот вопрос, не знают, каково это быть разработчиком веб-приложений, который позволяет людям устанавливать приложение на своих собственных серверах. В частности, виртуальный хостинг не позволяет использовать 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 &lt; $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 &lt; $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 &lt; $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("/(?&lt;!\\\\)(\\\\\\\\)*\\\\'/", $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 &lt; $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("/(?&lt;!\\\\)(\\\\\\\\)*\\\\'/", $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. 
mysqli_connect($host,$user,$pass) or die('error connection');
mysqli_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, это намного сложнее.


Смотрите также мои ответы на эти связанные вопросы:

В своих проектах я использовал следующее решение:

<?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 МБ

mysqli может выполнять несколько запросов, разделенных ;

Вы можете прочитать весь файл и запустить все сразу, используя mysqli_multi_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).

Мое предложение было бы посмотреть на исходный код PHPMyBackup. Это автоматический загрузчик PHP SQL. Вы обнаружите, что mysql_query загружает только один запрос за раз, и такие проекты, как PHPMyAdmin и PHPMyBackup, уже проделали тяжелую работу по правильному разбору SQL. Пожалуйста, не изобретайте это колесо:P

Обновленное решение Плахчинского. В качестве альтернативы вы можете использовать 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 = '';
        }
    }
}
mysql_query("LOAD DATA LOCAL INFILE '/path/to/file' INTO TABLE mytable");

Вкратце, способ, которым я сделал это:

  1. Прочитать файл (например, дамп базы данных) $ mysqldump db > db.sql)

    $sql = file_get_contents(db.sql);
    
  2. Импортируйте его, используя 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 и здесь /questions/42521112/php-mysqli-neskolko-zaprosov-asinhronnyij/42521116#42521116

Работает на свалках 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() &gt; 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);
}

Очевидно, что вам нужно будет учитывать транзакции и все остальное, если вы выполняете много запросов в пакете, но это, вероятно, не имеет большого значения для сценария новой установки.

Я заметил, что драйвер 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();
    }
}

Если вы не планируете импортировать огромные файлы.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, прервется, если запрос содержит точки с запятой в строках)..

Самый простой и быстрый способ загрузить и проанализировать дамп phpmyadmin или файл дампа mysql.

$ mysql -u username -p -h localhost dbname < dumpfile.sql 

Это лучший код для восстановления 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 = "";
  }
 }
}

Некоторые ребята (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 = "";
            }
          }
         }

потому что это более всеобъемлющее.;-)

Некоторые библиотеки PHP могут анализировать файл SQL, состоящий из нескольких операторов SQL, правильно анализировать его (без использования простого символа ";" и выполнять).

Например, проверьте Phos's PDOSQLExecTask

Ни одно из решений, которые я видел здесь, не связано с необходимостью изменения разделителя при создании хранимой процедуры на сервере, где я не могу рассчитывать на доступ к LOAD DATA INFILE. Я надеялся обнаружить, что кто-то уже решил это, не прибегая к помощи кода phpMyAdmin, чтобы понять это. Как и другие, я тоже находился в процессе поиска чужого GPL-способа сделать это, так как сам пишу GPL-код.

Это может быть полезно ->

Более или менее он сначала берет строку, заданную функции (значение file_get_contents() вашего file.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);

Просто чтобы сформулировать проблему для всех:

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);
    $sql = file_get_contents("sql.sql");

Кажется, самый простой ответ

Многие хосты не позволят вам создать собственную базу данных через PHP, но вы, похоже, решили это.
После того, как БД была создана, вы можете просто манипулировать ею и заполнять ее:

mysql_connect ("локальный");
mysql_query ("SOURCE file.sql");

У меня есть среда, в которой нет ни инструмента mysql, ни phpmyadmin, а просто мое php-приложение, подключающееся к серверу mysql на другом хосте, но мне нужно запускать сценарии, экспортированные mysqldump или myadmin. Для решения проблемы я создал скрипт multi_query как я уже говорил здесь

Он может обрабатывать вывод mysqldump и экспорт phpmyadmin без инструмента командной строки mysql. Я также сделал некоторую логику для обработки нескольких файлов миграции на основе метки времени, хранящейся в БД, таких как Rails. Я знаю, что требуется больше обработки ошибок, но в настоящее время делает работу для меня.

Проверьте это: https://github.com/kepes/php-migration

Это чистый php и не требует никаких других инструментов. Если вы не обрабатываете пользовательский ввод с помощью только сценариев, созданных разработчиками или инструментами экспорта, вы можете использовать его безопасно.

Я использую это все время:

$sql = explode(";",file_get_contents('[your dump file].sql'));// 

foreach($sql as $query)
 mysql_query($query);

PHP-код

Код, который я нашел на этой странице, работал у меня. Этот код может загрузить указанный файл SQL и импортировать его в базу данных MySQL. Я протестировал этот код с базой данных WordPress , экспортированной в SQL с помощью phpMyAdmin , и он работал нормально. (Прокрутите вниз, чтобы увидеть версию с комментариями)

      <?php
$conn = new mysqli('localhost', 'root', '' , 'sql_auto_test_table');

$query = ''; 
$sqlScript = file('sqlFileName.sql');

foreach ($sqlScript as $line)   {

    $startWith = substr(trim($line), 0 ,2);
    $endWith = substr(trim($line), -1 ,1);
    
    if (empty($line) || $startWith == '--' || $startWith == '/*' || $startWith == '//') {
        continue;
    }
    
    $query = $query . $line . "/*<br>*/"; 
    if ($endWith == ';') {
        mysqli_query($conn,$query) or die('<div>Problem in executing the SQL query <b>,<br><br>' . $query. '</b><br><br>'.$conn->error.'</div>');
        $query= '';     
    }
}
echo '<div>SQL file imported successfully</div>';
?>

Возможные исправления

Мне пришлось добавить следующие строки вверху файла .sql, чтобы избежать нескольких ошибок DEFAULT VALUE в некоторых столбцах DATE. В качестве альтернативы вы можете попробовать выполнить следующие запросы перед выполнением вашего файла SQL, если вы получите аналогичную ошибку.

      SET GLOBAL sql_mode = 'NO_ENGINE_SUBSTITUTION';
SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION';

Кроме того, замените насильственную функцию die() на более совершенный механизм обработки ошибок.


Объяснение

Если хотите, я добавил несколько строк комментариев, объясняющих поведение.

      <?php
$conn = new mysqli('localhost', 'root', '' , 'db_name');

$query = ''; //Set an empty query variable to hold the query
$sqlScript = file('mySqlFile.sql'); //Set the sql file location

//Read each line of the file
foreach ($sqlScript as $line)   {

    //Get the starting character and the ending character of each line
    $startWith = substr(trim($line), 0 ,2);
    $endWith = substr(trim($line), -1 ,1);
    
    //Check for empty or comment lines. (If the line starts with --,/*,// or the line is empty, skip to the next line)
    if (empty($line) || $startWith == '--' || $startWith == '/*' || $startWith == '//') {
        continue;
    }
    
    //Add the line to the query. (Additional optional commented out <br> tag added to query for easy error identification)
    $query = $query . $line . "/*<br>*/"; 
    //If the line end with a ";" assume the last query has ended in this line
    if ($endWith == ';') {
        //Therefore, try to execute the query. Upon failure, display the last formed query with the SQL error message
        mysqli_query($conn,$query) or die('<div>Problem in executing the SQL query <b>,<br><br>' . $query. '</b><br><br>'.$conn->error.'</div>');
        //Reset the query variable and continue to loop the next lines
        $query= '';     
    }
}
//If nothing went wrong, display a success message after looping through all the lines in the sql file
echo '<div>SQL file imported successfully</div>';

/*
If failed with an invalid DEFAULT value for a DATE column error, try adding the following lines to the top of your SQL file. Otherwise, execute these lines before executing your .sql file.
SET GLOBAL sql_mode = 'NO_ENGINE_SUBSTITUTION';
SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION';
*/
?>

Я надеюсь, что следующий код решит вашу проблему довольно хорошо.

//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;
}
?>
Другие вопросы по тегам