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

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

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

Не в последнюю очередь сам источник phpMyAdmin :)

Vinko Vrsalovic 29.09.2008 11:44

@ Аноним: Я искал «лучший» способ. Это место должно быть универсальным магазином для ответов (также и на будущее), и поэтому я считаю, что задавать вопросы, на которые есть ответы в другом месте, вполне нормально. Однако я сначала поискал в другом месте и не смог найти точного ответа.

Josh Smeaton 30.09.2008 13:51

RE: phpMyAdmin - этот источник в некоторой степени полезен, но очень зависит от других функций и не подходит для моих очень строгих временных рамок и требований сложности.

Josh Smeaton 30.09.2008 13:53

Всем тем, кто выступает за ответы помимо общепринятого: вопрос был в том, как загрузить скрипт из PHP. Решение LOAD DATA решает проблему на стороне MySQL. Кроме того, MySQL может работать на другом компьютере и не иметь доступа к файловой системе, в которой выполняется сценарий PHP, что следует учитывать.

tishma 13.11.2010 14:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
71
5
139 497
30
Перейти к ответу Данный вопрос помечен как решенный

Ответы 30

mysql_query("LOAD DATA LOCAL INFILE '/path/to/file' INTO TABLE mytable");

не работает, если апач и mysql это разные серверы

verybadbug 24.10.2012 06:03

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

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

$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);
}

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

Это не всегда сработает .. Что, если у вас есть запрос вроде .. ВЫБЕРИТЕ пример FROM blah WHERE something = "something;"

dbr 29.09.2008 12:35

if (substr (rtrim ($ query, -1) == ';') {неверно. Оно должно быть: if (substr (rtrim ($ query), -1) == ';') {

Josh Smeaton 29.09.2008 18:57

file () отлично читает файл, разбитый на строки, и код намного чище.

pilsetnieks 29.09.2008 20:06

Проблема с file () в том, что он считывает весь файл в память сразу, что не идеально для больших файлов.

cam8001 17.09.2011 16:17

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

К сожалению, mysql_query будет выполнять только один запрос за раз;)

SchizoDuckie 29.09.2008 13:48

$query = "SELECT * FROM posts LIMIT 1; SELECT * FROM posts LIMIT 1"; mysql_query($query); вроде нормально работает ..? Я думаю, вы не можете получить результаты каждого запроса, но если вы просто загружаете файл .sql, все, что вам нужно проверить, это ошибка запроса?

dbr 01.10.2008 02:58

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

FWIW, и phpMyBackup, и phpMyAdmin находятся под лицензией GPL. Если вы «заимствуете» какой-либо из их кода, вы также обязаны создать свой собственный проект под лицензией GPL.

Bill Karwin 06.12.2008 05:33

Да, я согласен. У вас есть хороший аргумент, но в духе GPL я полагаю, что просто смотрю, как это делали другие по-прежнему является допустимым вариантом, если кому-то нужно самостоятельно использовать воплощать в жизнь для такой функции. Иногда имеют воссоздает колесо, например, в обход ограничений GPL! Тем не менее, на мой взгляд, это часто стоит того, как не все колеса созданы равными. В данном случае это может сделать простой консольный 10-15 лайнер-скрипт.

stefgosselin 13.07.2011 11:10

Конечно, это делает ваш код GPL, но GPL не имеет значения, если вы не распространяете свое программное обеспечение - например, большинство веб-приложений. (AGPL является заметным исключением, хотя, AFAIK, он никогда не проверялся в суде.)

sneak 18.07.2011 08:18

Самое простое решение - использовать 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 может выполнять несколько запросов, разделенных ;

вы можете прочитать весь файл и запустить его сразу, используя mysqli_multi_query()

Но я первым скажу, что это не самое элегантное решение.

Ответ принят как подходящий

У меня такое ощущение, что все здесь, кто ответил на этот вопрос, не знают, каково быть разработчиком веб-приложений, который позволяет людям устанавливать приложение на свои собственные серверы. В частности, виртуальный хостинг не позволяет использовать SQL, как упомянутый ранее запрос «ЗАГРУЗИТЬ ДАННЫЕ». Большинство общих хостов также не позволяют использовать shell_exec.

Теперь, чтобы ответить на OP, лучше всего просто создать файл PHP, который содержит ваши запросы в переменной и может просто их запускать. Если вы полны решимости проанализировать файлы .sql, вам следует заглянуть в phpMyAdmin и получить некоторые идеи по получению данных из файлов .sql таким образом. Посмотрите на другие веб-приложения, у которых есть установщики, и вы увидите, что вместо того, чтобы использовать файлы .sql для своих запросов, они просто упаковывают их в файлы PHP и просто запускают каждую строку через mysql_query или что-то еще, что им нужно сделать. .

Хороший момент в том, что размещенные среды более строгие. В вопросе OP не упоминается, что приложение необходимо развернуть в размещенных средах. Хм. Вопрос о запуске сценариев SQL в PHP возникает достаточно часто, чтобы получился отличный небольшой проект.

Bill Karwin 01.10.2008 03:03

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

Till 17.10.2008 04:45

Я до сих пор не понимаю, почему он не может просто прочитать файл .sql в строке и выполнить его с помощью PDO или mysqli. Вот как я это делаю. PDO и mysqli поддерживают несколько запросов. По общему признанию, я еще не запускал ОГРОМНЫХ файлов .sql, но не могли бы вы просто увеличить или удалить максимальное время выполнения сценария PHP?

Lotus Notes 21.05.2010 01:32

Кодовая база phpMyAdmin - дерьмо. Файл, который выполняет импорт (phpMyAdmin/library/import/sql.php), интенсивно использует глобальные переменные, и многие комментарии содержат грамматические ошибки. Вы знаете другие примеры лучше?

Kendall Hopkins 23.01.2012 04:40

Ознакомьтесь с ответом Луиса Гранха ниже stackoverflow.com/a/7178917/80353

Kim Stacks 11.03.2013 14:27

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

Я случайно прочитал код, о котором говорил в этом вопросе на днях, так что он свежий. В итоге мы просто читали, пока не встретили; и выполнить это заявление, отметив в комментариях, что его следует улучшить. Проект никуда не денся, поэтому лучшего решения мы не придумали.

Josh Smeaton 01.06.2010 10:17

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

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

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

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

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

Это будет работать в большинстве случаев, но не в том случае, если строка содержит; символ.

Josh Smeaton 13.01.2011 01:58

Или если файл .sql больше, чем ваш лимит памяти PHP, или если файл .sql содержит некоторые встроенные клиентские команды, или множество других случаев.

Bill Karwin 03.03.2014 20:07

Работает на дампах 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 = "";
    }
  }
 }

выпадет на некоторых вроде этого: select id,any from some where any=='--'

msangel 31.07.2012 07:37

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                : [email protected]
*
*     $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');
}

?>

Это должен быть принятый вариант. Сработало как шарм, спасибо.

takeshin 03.09.2011 00:20

Это лучшее решение этой проблемы, с которой я столкнулся

Mazatec 15.03.2012 20:36

спасибо Группе phpBB и спасибо Абу Садату за то, что вы заметили, что этот фрагмент кода можно повторно использовать и в других проектах. еще раз спасибо

themhz 08.11.2012 22:50

Спасибо! Прекрасно работает и на моей стороне! Если ваш mysql устарел, просто перейдите на функцию mysqli. php.net/manual/en/mysqli.query.php

Mavichow 02.09.2014 19:16

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

Dewi Morgan 14.09.2018 00:05

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

Yasin 14.09.2018 19:12

$db = new PDO($dsn, $user, $password);

$sql = file_get_contents('file.sql');

$qr = $db->exec($sql);

Я использую этот ответ. У меня это хорошо сработало на скрипте размером 643 КБ. Все идет нормально.

Kim Stacks 11.03.2013 14:26

Как насчет того, когда размер скрипта составляет 643мб? Или в любом случае крупнее max_allowed_packet?

Bill Karwin 03.03.2014 19:57

Идеальный! У меня пока работает с файлом размером 1 МБ.

dualmon 08.05.2014 08:34

В основном это сработало для меня. Кажется, что он не импортирует хранимые процедуры или триггеры, но отлично работает с DROP, TRUNCATE, SELECT, INSERT, UPDATE.

mts7 08.04.2016 23:58

Просто сформулирую проблему для всех:

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 с помощью 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 = "";
  }
 }
}

Это пропускает строки с комментариями в конце, но настоящий оператор SQL перед комментарием в той же строке. Кроме того, сценарии SQL поддерживают комментарии в формате /* */. И разделитель операторов не всегда ;.

Bill Karwin 03.03.2014 20:01

Это хорошо работает с представлениями, функциями, вставкой, изменением ... но не для всех случаев, например, когда в вашей таблице есть строки с HTML с символом ";", но это можно обновить .. спасибо, я постараюсь обновить и репост ...

Henry Gabriel González Montejo 05.04.2017 17:43

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

mysql_connect("localhost");
mysql_query("SOURCE file.sql");

Попробуй это:

// 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);

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

//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 = '';
}
}

?>

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

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

Обновленное решение решения 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 = '';
        }
    }
}

Это пропускает строки с комментариями в конце, но настоящий оператор SQL перед комментарием в той же строке. Кроме того, сценарии SQL поддерживают комментарии в формате /* */. И разделитель операторов не всегда ;.

Bill Karwin 03.03.2014 20:00

Хорошее простое решение, когда у вас есть относительно пустой файл и вам нужен быстрый простой парсер. Мне пришлось изменить конкатенацию, добавив пробел в начало каждой строки для обработки ситуаций, когда в многострочном операторе не было пробелов (например, ON UPDATE CASCADE)\nENGINE = InnoDB; анализирует, а CASCADE)\nENGINE = InnoDB\nCOMMENT = 'stuff'; нет)

lee 12.07.2019 15:40

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

<?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', '', $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 МБ

@Graben Спасибо. Я искал решение и не смог найти ни одного, которое могло бы импортировать большие файлы SQL, кроме Sypex Dumper, но его нельзя использовать в ваших собственных проектах, поскольку это портативное готовое к использованию решение. Так что пришлось написать свой и выложить здесь, но вопрос был задан задолго до моего поста :).

Gromo 04.06.2014 11:39

это действительно сработало для меня:

/* 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;
}
?>

Некоторые ребята (Плахцински) предложили этот код:

$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 = "";
            }
          }
         }

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

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

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

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

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

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

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

Поскольку я не могу комментировать ответ, будьте осторожны, чтобы использовать следующее решение:

$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).

Как я недавно узнал, это потому, что вам нужно использовать PDOStatement::nextRowset.

lordg 06.05.2016 21:51

Вкратце, как я это сделал:

  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 и здесь https://stackoverflow.com/a/6652908/2002493

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

  /*
     ingestSql(string) : string

     Read the contents of a SQL batch file, stripping away comments and
     joining statements that are broken over multiple lines with the goal
     of producing lines of sql statements that can be successfully executed
     by PDO exec() or execute() functions.

     For example:
       -- My SQL Batch
       CREATE TABLE foo(
         bar VARCHAR(80),
         baz INT NOT NULL);

     Becomes:
       CREATE TABLE foo(bar VARCHAR(80), baz INT NOT NULL);
  */

  function ingestSql($sqlFilePath=__DIR__ . "/create-db.sql") {
    $sqlFile = file($sqlFilePath);
    $ingestedSql = "";
     $statement = "";
    foreach($sqlFile as $line) {

      // Ignore anything between a double-dash and the end of the line.
      $commentStart = strpos($line, "--");
      if ($commentStart !== false) {
        $line = substr($line, 0, $commentStart);
      }

      // Only process non-blank lines.
      if (strlen($line)) {

        // Remove any leading and trailing whitespace and append what's
        // left of the line to the current statement.
        $line = trim($line);
        $statement .= $line;

        // A semi-colon ends the current statement.  Otherwise what was a
        // newline becomes a single space;
        if (substr($statement, -1) == ";") {
          $ingestedSql .= $statement;
          $statement = "\n";
        }
        else {
          $statement .= " ";
        }
      }
    }

    return $ingestedSql;
  }

?>

    $sql = file_get_contents("sql.sql");

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

Это действительно самый простой ответ. Но люди здесь хотят усложнять себе жизнь. Единственное, что они умеют делать лучше всего, - это запретить пользователям публиковать вопросы!

Thanasis 31.01.2021 17:43

Другие вопросы по теме