【问题标题】:Running MySQL *.sql files in PHP在 PHP 中运行 MySQL *.sql 文件
【发布时间】:2011-04-30 23:27:10
【问题描述】:

我有两个*.sql 文件,用于创建新的网站数据库。第一个文件创建所有表。第二个文件填充了一些默认记录。我想从 PHP 执行这些文件。我也使用 Zend_Framework,如果这有助于实现这一点。

其他信息

  1. 我没有控制台访问权限
  2. 我正在尝试从我们的应用程序中自动生成网站。

解决方案

使用shell_exec()...

$command = 'mysql'
        . ' --host=' . $vals['db_host']
        . ' --user=' . $vals['db_user']
        . ' --password=' . $vals['db_pass']
        . ' --database=' . $vals['db_name']
        . ' --execute="SOURCE ' . $script_path
;
$output1 = shell_exec($command . '/site_db.sql"');
$output2 = shell_exec($command . '/site_structure.sql"');

...我从来没有得到有用的输出,但在another thread 上关注some suggestions 并最终让它全部工作。我将命令切换到--option=value 格式并使用--execute="SOURCE ..." 而不是< 来执行文件。

另外,我从来没有很好地解释shell_exec()exec() 之间的区别。

【问题讨论】:

  • 不能使用控制台?就这么简单....
  • @Pekka - 更新了我的帖子
  • 在 linux 上非常适合我。还没有在 windows xampp 上尝试过,但它怀疑它会起作用:)
  • shell_exec()exec() 的区别在于shell_exec 将所有输出流作为字符串返回。 exec 返回输出的最后一行。通过stackoverflow.com/a/7093892/557358
  • 这是我想出的一个很好的解决方案stackoverflow.com/a/41404203/627473

标签: php mysql zend-framework scripting


【解决方案1】:

只是想添加到上面给出的@Bill Karwin 答案。

您可以导入 |重新初始化 |执行自定义 SQL;数据库使用 sql 脚本文件,只需单击按钮。该按钮将使用 ajax 执行 sql 脚本文件。

例如。


前端代码

  <input type="button" value="Execute SQL Script" id="btnExecuteScript" />
  <input type="button" value="reset" onclick="clearDiv('divExecuteScript')" />
  <div id="divExecuteScript" style='display: none'></div>
  <br />

调用ajax的jQuery代码

  $('#btnExecuteScript').click(function (event) {
    if ($('#divExecuteScript').html() == '') {
      $('#divExecuteScript').html("<b style='font-family: sans-serif;font-size: larger'>Please Wait, It might take a few minutes</b>");
      $('#divExecuteScript').show();
      $.get("../controller/Controller.php?executeScript=TRUE", function (data) {
        // alert("$" + data + "$");
        $('body').css('cursor', 'default');
        $('#divExecuteScript').html(data);
        $('#divExecuteScript').show();
      });
    } else
      $('#divExecuteScript').toggle();
  });

连接文件

class Conn {

    protected $databaseURL; // const
    protected $databaseName;
    protected $databaseUName;
    protected $databasePWord;
    public $mysqli;

        public function __construct($args = null) {
        if (stripos($_SERVER['SERVER_NAME'], "localhost") !== FALSE) {
                $this->databaseURL = "host"; 
                $this->databaseName = "database";
                $this->databaseUName = "user";
                $this->databasePWord = "password";
            } 
            $this->mysqli = new mysqli($this->databaseURL, $this->databaseUName, $this->databasePWord, $this->databaseName) or die('Could not connect to the database server' . mysqli_connect_error());

             if (empty($this->mysqli))
               die("Error while connecting to host"); 
    }

    function get_databaseURL() {
        return $this->databaseURL;
    }

    function get_databaseUName() {
        return $this->databaseUName;
    }

    function get_databasePWord() {
        return $this->databasePWord;
    }

    function get_databaseName() {
        return $this->databaseName;
    }

}    

执行命令的控制器代码

$con = new Conn();
  $mysqli = new mysqli($con->get_databaseURL(), $con->get_databaseUName(), $con->get_databasePWord(), $con->get_databaseName()) or die('Could not connect to the database server' . mysqli_connect_error());

if (isset($_GET['executeScript'])) {
  $script_path = '/path-to-script-file/filename.sql';
  $command = "mysql --user={$con->get_databaseUName()} --password='{$con->get_databasePWord()}' "
  . "-h {$con->get_databaseURL()} -D {$con->get_databaseName()} < {$script_path}";
  $output = shell_exec($command);

  if (!empty($output))
    echo "<b style='font-family: sans-serif;font-size: large'>Execute the SQL script<br />";
  else
    echo "<b style='font-family: sans-serif;font-size: large'>Unable to execute the SQL script</b><br />";

  return;
}

【讨论】:

    【解决方案2】:

    这个问题不时出现。直接从 PHP 运行 .sql 脚本没有好的解决方案。在某些极端情况下,.sql 脚本中的常见语句无法作为 SQL 语句执行。例如,mysql 工具有 builtin commands 未被 MySQL 服务器识别,例如CONNECTTEESTATUSDELIMITER

    所以我给@Ignacio Vazquez-Abrams 的answer +1。您应该通过调用mysql 工具在PHP 中运行您的.sql 脚本,例如使用shell_exec()


    我得到了这个测试:

    $command = "mysql --user={$vals['db_user']} --password='{$vals['db_pass']}' "
     . "-h {$vals['db_host']} -D {$vals['db_name']} < {$script_path}";
    
    $output = shell_exec($command . '/shellexec.sql');
    

    另请参阅我对这些相关问题的回答:

    【讨论】:

    • 我正在尝试 shell_exec() 路由,但我没有找到指定要执行的文件的示例。这是我到目前为止所拥有的:shell_exec('mysql' . ' -u ' . $vals['db_user'] . ' -p ' . $vals['db_pass'] . ' -D ' . $vals['db_name']);
    • 您读取文件以使用 shell 重定向执行:mysql ... &lt; mysqldump.sql
    • 我想我会对阅读本文但无法使其工作的任何人提供一些见解,shell_exec 可能出现的一个问题是mysql 不在路径上。这很容易通过在受影响机器的控制台中运行命令mysql 来测试。在这种情况下,需要将 MySQL 添加到路径中,或者需要其他方法。
    • @AaronNewton,好主意。与路径相关的问题非常基本,但我忘记了还有多少人还在为它们苦苦挣扎。
    • 如果我也需要创建数据库怎么办?
    【解决方案3】:

    这是我的解决方案,下面的代码解释了它的作用。 其原理是逐行读取文件,构建查询并执行每个查询。我看到许多使用“file_get_contents”的解决方案,这不是一个好的解决方案,因为它可能会导致缓冲区问题,因为它将整个文件内容读取到字符串变量。 我的解决方案还考虑了触发器的查询。 没有数组分配,注释和空行被剥离。

    <?php
     /**
     * Get a connection from database
     * @param type $db_host database hostname
     * @param type $db_user database username
     * @param type $db_password database password
     * @param type $db_name database name
     * @return \PDO
     */
     function get_db_connection($db_host, $db_user, $db_password, $db_name)
    {
        $dns = "mysql:host=$db_host;dbname=$db_name";
        try
        {
            return new PDO($dns, $db_user, $db_password);
        } catch (PDOException $ex)
        {
            return null;
        }
    }
    
    /**
     * Runs SQL queries from file
     */
    
     function exec_sql_queries_from_file($script_file, $db_host, $db_user, $db_password, $db_name)
    {
        // to increase the default PHP execution time
        set_time_limit ( 60 ); // Max time = 60 seconds
    
        // Connect to database
        $connection = get_db_connection($db_host, $db_user, $db_password, $db_name);
    
        // If the connection is acquired
        if($connection != null){
    
            // Open sql file
            $f = fopen($script_file, 'r');
    
            // sql query
            $query = '';
    
            // Default delimiter for queries
            $delimiter = ';';
    
            // read line by line
            while (!feof($f))
            {           
                $line = str_replace(PHP_EOL, '', fgets($f)); // read a line and remove the end of line character
    
                /* if the current line contains the key word 'DELIMITER'. Ex: DELIMITER ;; or DELIMITER $$
                 * mostly used for TRIGGERS' queries
                 */
                if(strpos($line, 'DELIMITER') !== false)
                {
                    // change the delimiter and read the next line
                    $delimiter = str_replace('DELIMITER ', '', $line);
                    continue;
                }   
    
                // Consider the line as part of a query if it's not empty and it's not a comment line
                if (!empty($line) && !starts_with($line, '/*') && !starts_with($line, '--'))
                {
                    // the query hasn't reach its end: concatenate $line to $query if $line is not a delimiter
                    $query .= $line !== $delimiter ? $line : '';
    
                    // if the current line ends with $delimiter: end of current query
                    if (ends_with($line, $delimiter))
                    {                
                        // exec the query
                        $connection->exec($query) or die($connection->errorInfo());
                        // start new query
                        $query = '';
                    }
                }                    
            }
    
            fclose($f);
        }
    }
    
     /**
     * Starts with function
     */
    function starts_with($haystack, $needle)
    {
        return $haystack{0} === $needle{0} ? stripos($haystack, $needle) === 0 : false;
    }
    
    /**
     * Ends with function
     */
    function ends_with($haystack, $needle)
    {
        $pos = stripos($haystack, $needle);
        return $pos === FALSE ? FALSE : substr($haystack, $pos) === $needle;
    

    }

    【讨论】:

      【解决方案4】:

      您可以使用此脚本来运行 MySQL 脚本文件。当然,您需要设置 $hostName、$userName、$password、$dataBaseName、$port 和 $fileName。

      <?php
      
      function parseScript($script) {
      
        $result = array();
        $delimiter = ';';
        while(strlen($script) && preg_match('/((DELIMITER)[ ]+([^\n\r])|[' . $delimiter . ']|$)/is', $script, $matches, PREG_OFFSET_CAPTURE)) {
          if (count($matches) > 2) {
            $delimiter = $matches[3][0];
            $script = substr($script, $matches[3][1] + 1);
          } else {
            if (strlen($statement = trim(substr($script, 0, $matches[0][1])))) {
              $result[] = $statement;
            }
            $script = substr($script, $matches[0][1] + 1);
          }
        }
      
        return $result;
      
      }
      
      function executeScriptFile($fileName, $dbConnection) {
        $script = file_get_contents($scriptFleName);
        $statements = parseScript($script);
        foreach($statements as $statement) {
          mysqli_query($dbConnection, $statement);
        }
      }
      
      $hostName = '';
      $userName = '';
      $password = '';
      $dataBaseName = '';
      $port = '';
      $fileName = '';
      
      if ($connection = @mysqli_connect($hostName, $userName, $password, $dataBaseName, $port)) {
        executeScriptFile($fileName, $connection);
      } else {
        die('Can not connect to MySQL');
      }
      

      【讨论】:

      • 在为自己的问题写答案时,能否请您发布解释和代码。没有解释,我们仍然不知道为什么没有研究很多无用的代码就解决了问题。
      • 这不是我自己的问题。 TC 询问“我想从 PHP 执行这些文件”。我给了脚本如何做到这一点。如果您无法阅读这么小的代码(没有太多要研究的东西,它太小而且太明显了),并且如果您不需要解决方案 - 为什么您可以跳过我的答案而不是如此粗鲁? :)
      • 我并不想变得粗鲁。看到上面的否决票(其他人把它放在那里,以防你认为是我)?我试图告诉你为什么你会得到它,并建议你可以做些什么来获得赞成票。我只是想帮忙。它也在 3 分钟前被编辑过,现在看起来更好了。不幸的是,对于新手用户来说,这里期望一个很棒的答案(和问题)以及工作代码。这是一个诀窍。拥有它后,您将能够做出好的答案(和问题)并获得支持。
      • 希望我没有冒犯,我不是故意的。正如我上面所说,我试图通过帮助您改进答案和问题来为您赢得一些声誉。
      【解决方案5】:

      要从应用程序中执行表生成,您可能需要创建一个 php 文件,以便在您运行它时执行此操作。

      $hostname  = "localhost";
      $database  = "databasename";
      $username  = "rootuser";
      $UserPassword  = "password";
      
      $myconnection = mysql_pconnect($hostname, $username , $UserPassword) or trigger_error(mysql_error(),E_USER_ERROR); 
      mysql_connect($hostname , $username , $UserPassword ) or die(mysql_error());
      mysql_select_db($database) or die(mysql_error());
      
      if ( !$myconnection ){ echo "Error connecting to database.\n";}
      
      
      $userstableDrop = " DROP TABLE IF EXISTS `users`";
      $userstableCreate = " CREATE TABLE IF NOT EXISTS `users` (
      `UserID` int(11) NOT NULL,
        `User_First_Name` varchar(50) DEFAULT NULL
      ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=15" ;
      
      $userstableInsert = "INSERT INTO `users` (`UserID`, `User_First_Name`) VALUES
      (1, 'Mathew'),
      (2, 'Joseph'),
      (3, 'James'),
      (4, 'Mary')";
      
      $userstableAlter1 = "ALTER TABLE `users` ADD PRIMARY KEY (`UserID`)";
      $userstableAlter2 = " ALTER TABLE `users` MODIFY `UserID` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=15";
      
      $createDb_sql = $userstableDrop;
      $insertSite = mysql_query($createDb_sql);
      
      $createDb_sql = $userstableCreate;
      $insertSite = mysql_query($createDb_sql);
      
      $createDb_sql = $userstableInsert;
      $insertSite = mysql_query($createDb_sql);
      
      $createDb_sql = $userstableAlter1;
      $insertSite = mysql_query($createDb_sql);
      
      $createDb_sql = $userstableAlter2;
      $insertSite = mysql_query($createDb_sql);
      
      echo "Succesful!";
      mysql_close($myconnection );
      

      【讨论】:

      【解决方案6】:
      $commands = file_get_contents($location);   
      $this->_connection->multi_query($commands);
      

      【讨论】:

      • 您的解决方案适用于mysqli。我正在使用 PDO。你的回答促使我进行搜索,我发现了这个:stackoverflow.com/questions/6346674/…
      • 我正在使用 mysqli,但无法使用此解决方案。 $commands 只是作为一个空字符串返回。对于 $location 我尝试了相对本地路径(脚本文件与 php 文件位于同一文件夹中)和完全限定的超链接。无论哪种方式,我都会得到相同的结果。
      • 这对于某些类型的高级查询似乎失败了,例如创建一个过程并执行它。
      【解决方案7】:

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

      查看:https://github.com/kepes/php-migration

      我认为,如果您不使用它仅处理由开发人员制作的脚本或导出工具来处理用户输入,那么您可以安全地使用它。

      【讨论】:

        【解决方案8】:

        我知道我参加聚会已经很晚了,但 PHP Mini Admin 曾多次成为救命稻草。它基本上是一个“精简版”PHPMyAdmin,全部包含在一个文件中,因此无需复杂的安装,只需上传并登录即可。简单!

        【讨论】:

          【解决方案9】:

          这是我使用的:


          function run_sql_file($location){
              //load file
              $commands = file_get_contents($location);
          
              //delete comments
              $lines = explode("\n",$commands);
              $commands = '';
              foreach($lines as $line){
                  $line = trim($line);
                  if( $line && !startsWith($line,'--') ){
                      $commands .= $line . "\n";
                  }
              }
          
              //convert to array
              $commands = explode(";", $commands);
          
              //run commands
              $total = $success = 0;
              foreach($commands as $command){
                  if(trim($command)){
                      $success += (@mysql_query($command)==false ? 0 : 1);
                      $total += 1;
                  }
              }
          
              //return number of successful queries and total number of queries found
              return array(
                  "success" => $success,
                  "total" => $total
              );
          }
          
          
          // Here's a startsWith function
          function startsWith($haystack, $needle){
              $length = strlen($needle);
              return (substr($haystack, 0, $length) === $needle);
          }
          

          【讨论】:

          • 在某些极端情况下这会失败,而且不是错误消息,而是(可能)意外行为。例如,SQL 语句中的多行字符串文字可能以字符串 '--' 开头,或者字符串文字可能包含 ; 字符。如果你打算走这条路,你真的应该使用完整的 SQL 解析器。
          【解决方案10】:

          我从来没有使用过它,但是 mysqli 类有一个 multi_query 方法:

          http://php.net/manual/en/mysqli.multi-query.php

          【讨论】:

            【解决方案11】:

            不要忘记phpMyAdmin。与 MySQL 交互的非常可靠的界面。

            我不知道它是否解决了你的问题,因为我不知道你是否可以直接从代码中与之交互,但只是想把它扔在那里。

            【讨论】:

            • 好建议。用纯 PHP sucks 解析 mySQL 转储,phpMyAdmin 可以轻松解决(虽然不是自动化的)。
            【解决方案12】:

            一个建议:

            // connect to db.
            if (mysql_query("SOURCE myfile.sql")) {
            
              echo "Hello Sonny";
            
            } 
            

            【讨论】:

            【解决方案13】:

            您需要为此创建一个完整的 SQL 解析器。我建议您使用 mysql 命令行工具来代替,从 PHP 外部调用它。

            【讨论】:

              猜你喜欢
              • 2010-11-11
              • 1970-01-01
              • 1970-01-01
              • 2014-04-12
              • 2023-04-10
              • 1970-01-01
              • 1970-01-01
              • 2021-11-12
              • 1970-01-01
              相关资源
              最近更新 更多