如何使用PHP将.sql文件导入到MySQL数据库中?

88

我正在尝试通过PHP代码导入一个 .sql 文件。但是,我的代码显示了以下错误:

There was an error during import. Please make sure the import file is saved in the same folder as this script and check your values:

MySQL Database Name:    test
MySQL User Name:    root
MySQL Password: NOTSHOWN
MySQL Host Name:    localhost
MySQL Import Filename:  dbbackupmember.sql

这是我的代码:

<?php
//ENTER THE RELEVANT INFO BELOW
$mysqlDatabaseName ='test';
$mysqlUserName ='root';
$mysqlPassword ='';
$mysqlHostName ='localhost';
$mysqlImportFilename ='dbbackupmember.sql';
//DONT EDIT BELOW THIS LINE
//Export the database and output the status to the page
$command='mysql -h' .$mysqlHostName .' -u' .$mysqlUserName .' -p' .$mysqlPassword .' ' .$mysqlDatabaseName .' < ' .$mysqlImportFilename;
exec($command,$output=array(),$worked);
switch($worked){
    case 0:
        echo 'Import file <b>' .$mysqlImportFilename .'</b> successfully imported to database <b>' .$mysqlDatabaseName .'</b>';
        break;
    case 1:
        echo 'There was an error during import. Please make sure the import file is saved in the same folder as this script and check your values:<br/><br/><table><tr><td>MySQL Database Name:</td><td><b>' .$mysqlDatabaseName .'</b></td></tr><tr><td>MySQL User Name:</td><td><b>' .$mysqlUserName .'</b></td></tr><tr><td>MySQL Password:</td><td><b>NOTSHOWN</b></td></tr><tr><td>MySQL Host Name:</td><td><b>' .$mysqlHostName .'</b></td></tr><tr><td>MySQL Import Filename:</td><td><b>' .$mysqlImportFilename .'</b></td></tr></table>';
        break;
}
?>

我做错了什么?SQL文件与当前目录相同。


2
你确定 dbbackupmember.sql 文件存在于与你的脚本相同的目录中吗?执行 var_dump( file_exists('dbbackupmember.sql') ); 会输出什么? - Amal Murali
是的,这是同一个目录,但我不知道为什么它显示错误。 - msalman
Apache 进程是否可以访问转储文件所存放的文件夹/文件?exec('whoami') 命令是否返回您的用户名?有时由于权限问题,Apache 进程也可能无法正确执行 exec 命令。 - Benno
可能是从PHP内部加载.sql文件的重复问题。 - T.Todua
2
这个回答解决了你的问题吗?如何使用MySQL命令行导入SQL文件? - Dharman
17个回答

150
警告:mysql_*扩展自PHP 5.5.0版本起已被弃用,并在PHP 7.0.0版本中被删除。应改用mysqliPDO_MySQL扩展。在选择MySQL API时,还可以参考MySQL API概述获取更多帮助。
尽可能将文件导入MySQL委派给MySQL客户端。

我有另一种方法来做这件事,请尝试此方法。

<?php

// Name of the file
$filename = 'churc.sql';
// MySQL host
$mysql_host = 'localhost';
// MySQL username
$mysql_username = 'root';
// MySQL password
$mysql_password = '';
// Database name
$mysql_database = 'dump';

// Connect to MySQL server
mysql_connect($mysql_host, $mysql_username, $mysql_password) or die('Error connecting to MySQL server: ' . mysql_error());
// Select database
mysql_select_db($mysql_database) or die('Error selecting MySQL database: ' . mysql_error());

// 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 = '';
}
}
 echo "Tables imported successfully";
?>

这对我来说起作用了


4
哥们!救了我的命!:D 由于我有很大的转储文件,所以需要流式传输文件而不是一次性读取所有内容...看这里 https://dev59.com/emYr5IYBdhLWcg3w--0I#13246630 - v01pe
1
我也加了这个:if(substr($line,0,2) == "/*"){continue;}。有帮助。 - Relentless
1
不要使用它,否则你很快就会耗尽内存! - Alex Skrypnyk
1
@Enrique,你能更详细地解释一下吗:D 我应该先做什么,上传 .sql 文件然后继续上面的脚本! 我的问题是数据库更新还是替换为新的。 - Freddy Sidauruk
我只需要将所有的 mysql_ 更改为 mysqli_ 并提供连接参数... 然后它就像魔法般地运行了!非常感谢! - Louys Patrice Bessette
显示剩余3条评论

57

您可以按照以下方式使用mysqli multi_query函数:

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

$mysqli = new mysqli("localhost", "root", "pass", "testdb");

/* execute multi query */
$mysqli->multi_query($sql);

6
这比被接受的答案要快得多,确切地说快了100倍。(我进行了测量) - Snowball
1
如果由于某些原因无法使用命令行mysql命令,则这是首选选项。使用multi_query时要小心,因为它是异步的,必须在之后运行阻塞循环。 - Dharman
2
继Dharman所说的,这个问题的关键在于你需要能够将整个转储文件读入内存才能使其工作,因此它只适用于较小的文件。如果你有一个1GB的转储文件,由于缺乏内存,这将失败。大型转储文件只能通过MySQL命令行处理。 - Machavity

39

注意: mysql_* 扩展自 PHP 5.5.0 起已被弃用,并在 PHP 7.0.0 中被移除。应改用 mysqliPDO_MySQL 扩展。有关选择 MySQL API 的更多帮助,请参阅 MySQL API 概述
尽可能地,将文件导入 MySQL 应委托给 MySQL 客户端。

Raj的回答很有用,但是(由于 file($filename)),如果你的mysql-dump不符合内存,它将失败

如果您正在使用共享主机并且存在限制,例如30 MB和12秒的脚本运行时间,并且您必须恢复x00MB的mysql dump,则可以使用此脚本:

它会逐个查询遍历dump文件,如果脚本执行截止时间接近,则将当前文件位置保存在tmp文件中,自动浏览器重载将一次又一次地继续这个过程... 如果出现错误,则重载将停止并显示错误...

如果你从午餐回来,你的数据库将被恢复;-)

noLimitDumpRestore.php:

// your config
$filename = 'yourGigaByteDump.sql';
$dbHost = 'localhost';
$dbUser = 'user';
$dbPass = '__pass__';
$dbName = 'dbname';
$maxRuntime = 8; // less then your max script execution limit


$deadline = time()+$maxRuntime; 
$progressFilename = $filename.'_filepointer'; // tmp file for progress
$errorFilename = $filename.'_error'; // tmp file for erro

mysql_connect($dbHost, $dbUser, $dbPass) OR die('connecting to host: '.$dbHost.' failed: '.mysql_error());
mysql_select_db($dbName) OR die('select db: '.$dbName.' failed: '.mysql_error());

($fp = fopen($filename, 'r')) OR die('failed to open file:'.$filename);

// check for previous error
if( file_exists($errorFilename) ){
    die('<pre> previous error: '.file_get_contents($errorFilename));
}

// activate automatic reload in browser
echo '<html><head> <meta http-equiv="refresh" content="'.($maxRuntime+2).'"><pre>';

// go to previous file position
$filePosition = 0;
if( file_exists($progressFilename) ){
    $filePosition = file_get_contents($progressFilename);
    fseek($fp, $filePosition);
}

$queryCount = 0;
$query = '';
while( $deadline>time() AND ($line=fgets($fp, 1024000)) ){
    if(substr($line,0,2)=='--' OR trim($line)=='' ){
        continue;
    }

    $query .= $line;
    if( substr(trim($query),-1)==';' ){
        if( !mysql_query($query) ){
            $error = 'Error performing query \'<strong>' . $query . '\': ' . mysql_error();
            file_put_contents($errorFilename, $error."\n");
            exit;
        }
        $query = '';
        file_put_contents($progressFilename, ftell($fp)); // save the current file position for 
        $queryCount++;
    }
}

if( feof($fp) ){
    echo 'dump successfully restored!';
}else{
    echo ftell($fp).'/'.filesize($filename).' '.(round(ftell($fp)/filesize($filename), 2)*100).'%'."\n";
    echo $queryCount.' queries processed! please reload or wait for automatic browser refresh!';
}

你的脚本也解决了我的问题!我有一个2.4GB大小的SQL文件,无法控制增加允许的文件大小和查询大小。非常感谢! - Siniša
这段代码需要更新为mysqli- mysql_connect在php 5.5中已被弃用并在7中被移除。 - Chris Mccabe
使用这个脚本时,我遇到了一些特殊字符的问题(如ö、ä、²、³等),但并不是每个表格都有。使用上面ManojGeek的脚本就可以正常工作了。 - Harry
1
@user2355808 - 这很奇怪 - 因为两个脚本都使用相同的功能,没有字符集不可知函数(文件和mysql-query vs. fgets和mysql-query),也许您的数据库创建方式不同。 - Grain
注意客户端缓存。此外,刷新时间可以设置为1,因为计时器在页面加载之前不会运行。 - Sanquira Van Delbar

12
<?php
$host = "localhost";
$uname = "root";
$pass = "";
$database = "demo1"; //Change Your Database Name
$conn = new mysqli($host, $uname, $pass, $database);
$filename = 'users.sql'; //How to Create SQL File Step : url:http://localhost/phpmyadmin->detabase select->table select->Export(In Upper Toolbar)->Go:DOWNLOAD .SQL FILE
$op_data = '';
$lines = file($filename);
foreach ($lines as $line)
{
    if (substr($line, 0, 2) == '--' || $line == '')//This IF Remove Comment Inside SQL FILE
    {
        continue;
    }
    $op_data .= $line;
    if (substr(trim($line), -1, 1) == ';')//Breack Line Upto ';' NEW QUERY
    {
        $conn->query($op_data);
        $op_data = '';
    }
}
echo "Table Created Inside " . $database . " Database.......";
?>

非常感谢,节省了我的时间。你的代码完美地为我工作。 - Sumit patel

10
<?php
system('mysql --user=USER --password=PASSWORD DATABASE< FOLDER/.sql');
?>

2
这是推荐方案。将文件导入MySQL应始终委托给MySQL客户端。 - Dharman

4

Grain Script非常出色,帮我解决了很多问题。与此同时,mysql已经过时了,我使用PDO重写了Grain Script的答案。

    $server  =  'localhost'; 
    $username   = 'root'; 
    $password   = 'your password';  
    $database = 'sample_db';

    /* PDO connection start */
    $conn = new PDO("mysql:host=$server; dbname=$database", $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);         
    $conn->exec("SET CHARACTER SET utf8");     
    /* PDO connection end */

    // your config
    $filename = 'yourFile.sql';

    $maxRuntime = 8; // less then your max script execution limit


    $deadline = time()+$maxRuntime; 
    $progressFilename = $filename.'_filepointer'; // tmp file for progress
    $errorFilename = $filename.'_error'; // tmp file for erro



    ($fp = fopen($filename, 'r')) OR die('failed to open file:'.$filename);

    // check for previous error
    if( file_exists($errorFilename) ){
        die('<pre> previous error: '.file_get_contents($errorFilename));
    }

    // activate automatic reload in browser
    echo '<html><head> <meta http-equiv="refresh" content="'.($maxRuntime+2).'"><pre>';

    // go to previous file position
    $filePosition = 0;
    if( file_exists($progressFilename) ){
        $filePosition = file_get_contents($progressFilename);
        fseek($fp, $filePosition);
    }

    $queryCount = 0;
    $query = '';
    while( $deadline>time() AND ($line=fgets($fp, 1024000)) ){
        if(substr($line,0,2)=='--' OR trim($line)=='' ){
            continue;
        }

        $query .= $line;
        if( substr(trim($query),-1)==';' ){

            $igweze_prep= $conn->prepare($query);

            if(!($igweze_prep->execute())){ 
                $error = 'Error performing query \'<strong>' . $query . '\': ' . print_r($conn->errorInfo());
                file_put_contents($errorFilename, $error."\n");
                exit;
            }
            $query = '';
            file_put_contents($progressFilename, ftell($fp)); // save the current file position for 
            $queryCount++;
        }
    }

    if( feof($fp) ){
        echo 'dump successfully restored!';
    }else{
        echo ftell($fp).'/'.filesize($filename).' '.(round(ftell($fp)/filesize($filename), 2)*100).'%'."\n";
        echo $queryCount.' queries processed! please reload or wait for automatic browser refresh!';
    }

我认为你和Grain需要在完成后对文件指针文件执行unlink操作,不是吗?否则,如果您重新上传相同的文件名,它将继续尝试从该最终指针运行。 - Dss

3

我测试了你的代码,当你已经导入了数据库或有一些同名的表时,会显示这个错误,而且显示的数组错误是因为你在exec括号里添加了它,下面是修复版本:

<?php
//ENTER THE RELEVANT INFO BELOW
$mysqlDatabaseName ='test';
$mysqlUserName ='root';
$mysqlPassword ='';
$mysqlHostName ='localhost';
$mysqlImportFilename ='dbbackupmember.sql';
//DONT EDIT BELOW THIS LINE
//Export the database and output the status to the page
$command='mysql -h' .$mysqlHostName .' -u' .$mysqlUserName .' -p' .$mysqlPassword .' ' .$mysqlDatabaseName .' < ' .$mysqlImportFilename;
$output=array();
exec($command,$output,$worked);
switch($worked){
    case 0:
        echo 'Import file <b>' .$mysqlImportFilename .'</b> successfully imported to database <b>' .$mysqlDatabaseName .'</b>';
        break;
    case 1:
        echo 'There was an error during import.';
        break;
}
?> 

这是推荐的解决方案。将文件导入MySQL应始终委托给MySQL客户端。 - Dharman

2

如果您需要用户界面并且想要使用PDO

这是一个简单的解决方案

<form method="post" enctype="multipart/form-data">
    <input type="text" name="db" placeholder="Databasename" />
    <input type="file" name="file">
    <input type="submit" name="submit" value="submit">
</form>

<?php

if(isset($_POST['submit'])){
    $query = file_get_contents($_FILES["file"]["name"]);
    $dbname = $_POST['db'];
    $con = new PDO("mysql:host=localhost;dbname=$dbname","root","");
    $stmt = $con->prepare($query);
    if($stmt->execute()){
        echo "Successfully imported to the $dbname.";
    }
}
?>

在我的端上绝对可以工作。值得一试。


您确定这可以适用于多个查询吗?此外,如果没有任何参数,使用预处理语句的好处是什么? - Nico Haase

2
如果您使用的是 PHP 7 或更高版本,请尝试以下脚本:
// Name of the file
$filename = 'sql.sql';
// MySQL host
$mysql_host = 'localhost';
// MySQL username
$mysql_username = 'username';
// MySQL password
$mysql_password = 'password';
// Database name
$mysql_database = 'database';
// Connect to MySQL server
$con = @new mysqli($mysql_host,$mysql_username,$mysql_password,$mysql_database);
// Check connection
if ($con->connect_errno) {
   echo "Failed to connect to MySQL: " . $con->connect_errno;
   echo "<br/>Error: " . $con->connect_error;
}
// 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
$con->query($templine) or print('Error performing query \'<strong>' . $templine . '\': ' . $con->error() . '<br /><br />');
    // Reset temp variable to empty
    $templine = '';
}
}
echo "Tables imported successfully";
$con->close($con);

0

我推荐一个虽然有点老但仍然有效的工具bigdump


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接