Running MySQL *.sql files in PHP

PhpMysqlZend FrameworkScripting

Php Problem Overview


I have two *.sql files that I use when creating a new web site database. The first file creates all the tables. The second file populates some default records. I would like to execute these files from PHP. I also use the Zend_Framework, if that will help accomplish this.

Additional Info

  1. I don't have console access
  2. I'm trying to automate site generation from within our application.

SOLUTION

Using 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"');

...I never did get useful output, but followed some suggestions on another thread and finally got it all working. I switch to the --option=value format for the commands and used --execute="SOURCE ..." instead of < to execute the file.

Also, I never got a good explanation of the difference between shell_exec() and exec().

Php Solutions


Solution 1 - Php

This question comes up from time to time. There's no good solution for running a .sql script directly from PHP. There are edge cases where statements common in a .sql script can't be executed as SQL statements. For example, the mysql tool has builtin commands that are not recognized by the MySQL Server, e.g. CONNECT, TEE, STATUS, and DELIMITER.

So I give +1 to @Ignacio Vazquez-Abrams's answer. You should run your .sql script in PHP by invoking the mysql tool, for instance with shell_exec().


I got this test working:

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

See also my answers to these related questions:

Solution 2 - Php

$commands = file_get_contents($location);	
$this->_connection->multi_query($commands);

Solution 3 - Php

You'll need to create a full SQL parser for this. I recommend you use the mysql command line tool for this instead, invoking it externally from PHP.

Solution 4 - Php

Here is what I use:


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

Solution 5 - Php

I have never had to use it but the mysqli class has a multi_query method:

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

Solution 6 - Php

I know I'm pretty late to the party but [PHP Mini Admin][1] has been a lifesaver on a couple of occasions. It's basically a "lite" PHPMyAdmin all contained in one file so no need for complicated installs, just upload it and log in. Simples!

[1]: http://sourceforge.net/projects/phpminiadmin/ "PHP Mini Admin"

Solution 7 - Php

Don't forget about phpMyAdmin. Pretty solid interface for interacting with MySQL.

I don't know if it solves your problem, since I don't know if you can interact with it directly from code, but just wanted to throw it out there.

Solution 8 - Php

You can use this script to run MySQL script files. You'll need to set $hostName, $userName, $password, $dataBaseName, $port and $fileName of course.

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

Solution 9 - Php

I created a migration script with multi_query. It can process mysqldump output and phpmyadmin exports without mysql command line tool. I also made some logic to process multiple migration files based on timestamp stored in DB like Rails. I know it needs more error handling but currently does the work for me.

Check it out: https://github.com/kepes/php-migration

I think if you don't process user input with it only scripts made by developers or export tools you can use it safely.

Solution 10 - Php

Here is my solution and the below code explains what is does. The principle is to read the file line by line, build a query and execute each of them. I saw many solutions using the "file_get_contents" which is not a good solution because it could cause a buffer issue as it read the whole file contents to string variable. My solution takes also into account TRIGGERs' queries. There's no array allocation, comment and empty lines are stripped.

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

}

Solution 11 - Php

To execute table generation from within the application, you may want to create a php file that will do just that when you run it.

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

Solution 12 - Php

Just wanna to add to @Bill Karwin answer given above.

You can import | reinitialize | execute custom SQL; the database using sql script file, by simply clicking on button. That button would execute the sql script file using ajax.

eg.


Front end code

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

Jquery code calling the ajax

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

connection file

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

}    

controller code executing the command

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

Solution 13 - Php

One suggestion:

// connect to db.
if (mysql_query("SOURCE myfile.sql")) {

  echo "Hello Sonny";

} 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSonnyView Question on Stackoverflow
Solution 1 - PhpBill KarwinView Answer on Stackoverflow
Solution 2 - PhpFarid MovsumovView Answer on Stackoverflow
Solution 3 - PhpIgnacio Vazquez-AbramsView Answer on Stackoverflow
Solution 4 - PhpIbrahim LawalView Answer on Stackoverflow
Solution 5 - PhpDaveView Answer on Stackoverflow
Solution 6 - PhpMatthewView Answer on Stackoverflow
Solution 7 - PhpjocullView Answer on Stackoverflow
Solution 8 - PhpSergiy LavrykView Answer on Stackoverflow
Solution 9 - PhpkepesView Answer on Stackoverflow
Solution 10 - PhpN'faly KabaView Answer on Stackoverflow
Solution 11 - PhpKizito IkapelView Answer on Stackoverflow
Solution 12 - PhpAdeel Raza AzeemiView Answer on Stackoverflow
Solution 13 - PhpzerodinView Answer on Stackoverflow