从PHP内加载.sql文件


68

我正在为正在开发的应用程序创建安装脚本,并且需要从PHP内部动态创建数据库。我已经创建了数据库,但是现在我需要加载几个.sql文件。我计划一次打开一个文件并用mysql_query一次一行-直到我查看了模式文件并意识到它们不仅仅是每行一个查询。

那么,如何从PHP内加载sql文件(就像phpMyAdmin的import命令一样)?


尤其是phpMyAdmin的来源本身:)
Vinko Vrsalovic

@匿名:我一直在寻找“最好的”方法。这个地方应该是一站式服务(包括将来的答案),因此我觉得在其他地方回答问题也很好。但是,我确实首先寻找其他地方,却找不到一个很好的答案。
Josh Smeaton

RE:phpMyAdmin-它的来源有些帮助,但非常依赖于它的其他功能,因此不适合我非常严格的时间范围和复杂性要求。
Josh Smeaton

1
对于所有认为除了答案之外都支持答案的人:问题是如何从PHP内加载脚本。LOAD DATA解决方案解决了MySQL方面的问题。同样,MySQL可能在另一台机器上运行,并且无法访问执行PHP脚本的文件系统,因此应予以考虑。
tishma 2010年

Answers:


51

我感觉到,回答这个问题的每个人都不知道成为一个Web应用程序开发人员是什么样的,它允许人们在自己的服务器上安装该应用程序。尤其是,共享主机不允许您像前面提到的“ LOAD DATA”查询那样使用SQL。大多数共享主机也不允许您使用shell_exec。

现在,要回答OP,最好的选择就是构建一个PHP文件,该文件将您的查询包含在一个变量中并可以运行它们。如果确定要解析.sql文件,则应该研究phpMyAdmin并获得一些想法,以这种方式从.sql文件中获取数据。看看其他具有安装程序的Web应用程序,您会看到,它们没有使用.sql文件进行查询,而是将它们打包到PHP文件中,并通过mysql_query或需要执行的任何操作来运行每个字符串。


2
很好的一点是托管环境的限制性更高。OP的问题没有提到应用程序需要在托管环境中进行部署。嗯 在PHP中运行SQL脚本的问题经常出现,因此这将是一个很小的项目。
Bill Karwin

是的,我要说的是-您不能期望别人认为您处于有史以来最严格的环境中。尤其是随着虚拟机的普及,每个人都可以以相对较低的成本拥有自己的服务器。
直到

4
我仍然不明白为什么他不能只将.sql文件读入字符串并用PDO或mysqli执行它。这就是我的方法。PDO和mysqli支持多个查询。诚然,我还没有运行任何巨大的.sql文件,但是您是否不能增加或删除PHP的最大脚本执行时间?
Lotus Notes 2010年

5
phpMyAdmin的代码库为sh * t。进行import(phpMyAdmin/library/import/sql.php)的文件大量使用了全局变量,并且许多注释都有语法错误。您知道其他更好的例子吗?
肯德尔·霍普金斯

2
通过Luis Granja签出以下答案stackoverflow.com/a/7178917/80353
Kim Stacks 2013年

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

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

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

我正在使用这个答案。对于643kb的脚本,它对我来说效果很好。到现在为止还挺好。
Kim Stacks 2013年

6
脚本何时为643mb呢?或在任何情况下大于max_allowed_packet
Bill Karwin 2014年

1
完善!到目前为止,我的文件大小为1MB。
dualmon 2014年

1
这主要为我工作。它似乎不导入存储过程或触发器,但是可以使用DROP,TRUNCATE,SELECT,INSERT,UPDATE进行操作。
mts7

59

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

?>

7
这应该是公认的。像魅力一样工作,谢谢。
Takehin 2011年

1
这是我遇到的这个问题的最佳解决方案
Mazatec 2012年

2
谢谢phpBB Group,感谢Abu Sadat,您设法注意到这段代码也可用于其他项目。再次
感谢

1
谢谢!我这边也很好!如果您的mysql被弃用,只需更改为mysqli函数即可。php.net/manual/en/mysqli.query.php
Mavichow 2014年

1
请注意,PhpBB是GPL许可的。因此,如果在项目中使用此代码,则还必须以GPL许可发布项目。
Dewi Morgan

29

最简单的解决方案是使用shell_exec()以SQL脚本作为输入来运行mysql客户端。这可能会慢一些,因为它必须分叉,但是您可以在几分钟内编写代码,然后重新开始进行有用的工作。编写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脚本,则要复杂得多。


另请参阅我对以下相关问题的回答:


10

mysqli 可以运行多个查询,并用 ;

您可以读取整个文件并使用一次运行所有文件 mysqli_multi_query()

但是,我将第一个说这不是最优雅的解决方案。


10

在我的项目中,我使用了下一个解决方案:

<?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文件(41Mb)上的内存峰值使用量:3.25Mb


@Graben谢谢。我一直在寻找解决方案,除了Sypex Dumper之外,找不到任何可以导入大型SQL文件的文件,但是由于它是可移植的即用型解决方案,因此无法在自己的项目中使用。因此,我不得不写我自己的文章并将其发布在这里,但是在我发表文章之前很久才提出问题:)。
Gromo 2014年

8

由于我无法评论答案,请注意使用以下解决方案:

$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 '16

4

我的建议是查看PHPMyBackup的源代码。这是一个自动化的PHP SQL加载程序。您会发现mysql_query一次仅加载一个查询,并且PHPMyAdmin和PHPMyBackup之类的项目已经为您以正确的方式解析SQL进行了艰苦的工作。请不要重新发明轮子:P


4
FWIW,phpMyBackup和phpMyAdmin均根据GPL许可。如果您“借用”他们的任何代码,那么您也必须制定自己的项目GPL。
比尔·卡文

1
是的我同意。您确实有一个好点,但是本着GPL的精神,我可以想象一下如果一个人必须自己实现这样的功能,那么偷看别人如何仍然是一个有效的选择。例如,有时必须重新创建轮子来规避GPL限制!不过,在我看来,这通常是值得的,因为并非所有轮子都是一样的。在这种情况下,一个简单的控制台10-15衬里脚本可以做到这一点。
stefgosselin 2011年

当然,它使您的代码成为GPL,但如果您不分发软件(例如,大多数Web应用程序),则GPL并不重要。(AGPL是一个明显的例外,尽管AFAIK从未在法庭上进行过测试。)
潜行

4

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 2014年

当文件相对较裸并且需要快速简单的解析器时,这是一个不错的简单解决方案。我必须通过在每行的开头添加一个空格来修改连接,以处理多行语句没有空格(例如,ON UPDATE CASCADE)\nENGINE = InnoDB;解析但CASCADE)\nENGINE = InnoDB\nCOMMENT = 'stuff';没有空格)的情况
lee Lee

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

2
如果apachemysql是不同的服务器,则无法正常工作
verybadbug 2012年


3

我注意到PostgreSQL PDO驱动程序不允许您运行用分号分隔的脚本。为了使用PDO在任何数据库上运行.sql文件,必须自己拆分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();
    }
}

3

您确定不是每行一个查询吗?您的文本编辑器可能会换行,但实际上每个查询可能都在一行中。

无论如何,olle的方法似乎是最好的。如果您有理由一次运行一个查询,则应该能够逐行读取文件,然后在每个查询的末尾使用分号定界。与尝试拆分一个巨大的字符串相比,逐行读取文件要好得多,因为这将对服务器的内存更加友好。例:

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

显然,如果要批量运行大量查询,则需要考虑事务和其余事务,但是对于新安装的脚本来说,这可能并不重要。


2
那将永远无法正常工作。如果您有类似的查询,该怎么办呢?
dbr

1
if(substr(rtrim($ query,-1)==';'){不正确。应该是:if(substr(rtrim($ query),-1)==';'){
Josh Smeaton

file()读取文件并分成几行很好,并且代码更简洁。
pilsetnieks

1
file()的问题是它一次将整个文件读入内存,这对于大型文件而言并不理想。
cam8001 2011年

2

除非您打算导入巨大的.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的回答所评论的那样)如果查询字符串中包含分号)。


3
不幸的是,mysql_query一次只会执行一个查询;)
SchizoDuckie 08/09/29

$query="SELECT * FROM posts LIMIT 1; SELECT * FROM posts LIMIT 1"; mysql_query($query);似乎运行得很好..?我猜您无法获取每个查询的结果,但是如果您只是加载.sql文件,那么肯定需要检查的所有内容是否都是查询错误?
dbr

2

适用于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 = "";
    }
  }
 }

3
会像这样掉落:select id,any from some where any=='--'
msangel 2012年

2

这是通过php恢复sql的最佳代码,可以使用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 = "";
  }
 }
}

1
这将跳过在末尾带有注释的行,但是会在同一行的注释之前添加一个真正的SQL语句。另外,SQL脚本支持/* */格式的注释。语句定界符并非总是如此;
Bill Karwin 2014年

这适用于视图,函数,插入,更改...,但不适用于所有情况,例如在您的表中具有带有字符“;”的HTML行时,但是可以更新..谢谢,我将尝试更新并重新发布...
亨利·加布里埃尔·冈萨雷斯·蒙特霍

2

尝试这个:

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

2

加载和解析phpmyadmin dump或mysql dump文件的最简单,最快的方法。

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

1

我在这里看到的所有解决方案都没有涉及在服务器上创建存储过程时需要更改定界符的问题,在该服务器上我不能指望可以访问LOAD DATA INFILE。我希望发现有人已经解决了这个问题,而不必搜寻phpMyAdmin代码来解决。与其他人一样,由于我自己编写GPL代码,因此我也在寻找别人采用GPL编写的方法。


前几天,我刚好阅读了我在此问题中所指的代码,因此很新鲜。我们最终只是阅读,直到遇到一个;。并执行该语句,并在注释中指出应对其进行改进。该项目没有进行到任何地方,因此我们没有提出比这更好的解决方案。
Josh Smeaton 2010年


1

只是为了向所有人重申这个问题:

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

1

许多主机不允许您通过PHP创建自己的数据库,但是您似乎已经解决了这一问题。
创建数据库后,您可以简单地对其进行操作和填充:

mysql_connect(“ localhost”);
mysql_query(“ SOURCE file.sql”);


1

有些人(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 = "";
            }
          }
         }

因为它更全面。;-)


1

这可能会有所帮助->

或多或少地要做的是首先获取赋予函数的字符串(file.sql的file_get_contents()值)并删除所有换行符。然后用“;”分割数据 字符。接下来,它进入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);

0

我经常用这个:

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

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

2
在大多数情况下,这是可行的,但如果字符串包含;,则无效。字符。
Josh Smeaton

或者.sql文件大于PHP的内存限制,或者.sql文件包含某些客户端内置命令,或者其他情况。
Bill Karwin

0

我希望以下代码能很好地解决您的问题。

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

?>

0

这实际上为我工作:

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

0

我在没有mysql工具或phpmyadmin的环境中,仅将我的php应用程序连接到其他主机上的mysql服务器,但是我需要运行mysqldump或myadmin导出的脚本。为了解决这个问题,我创建了一个脚本,multi_query就像我在这里提到的那样

它可以在没有mysql命令行工具的情况下处理mysqldump输出和phpmyadmin导出。我还根据基于存储在数据库中的时间戳(例如Rails)的时间戳制定了一些逻辑来处理多个迁移文件。我知道它需要更多错误处理,但目前为我完成了工作。

检查一下:https : //github.com/kepes/php-migration

它是纯PHP,不需要任何其他工具。如果您不使用它来处理用户输入,则只能安全地使用开发人员或导出工具编写的脚本。


0

这是我正在研究的项目。基本上获取任何文本文件并提取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;
  }

?>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.