tabla - Ejecutar archivos MySQL*.sql en PHP
php mysql (12)
Tengo dos archivos *.sql
que uso al crear una nueva base de datos de sitios web. El primer archivo crea todas las tablas. El segundo archivo llena algunos registros predeterminados. Me gustaría ejecutar estos archivos desde PHP. También uso Zend_Framework, si eso ayuda a lograr esto.
Información adicional
- No tengo acceso a la consola
- Intento automatizar la generación de sitios desde dentro de nuestra aplicación.
SOLUCIÓN
Usando 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"'');
... Nunca obtuve resultados útiles, pero seguí algunas sugerencias sobre otro hilo y finalmente conseguí que todo funcionara. --option=value
formato --option=value
para los comandos y uso --execute="SOURCE ..."
lugar de <
para ejecutar el archivo.
Además, nunca obtuve una buena explicación de la diferencia entre shell_exec()
y exec()
.
Aquí está mi solución y el siguiente código explica lo que hace. El principio es leer el archivo línea por línea, crear una consulta y ejecutar cada una de ellas. Vi muchas soluciones usando el "archivo_contenido_contenido", que no es una buena solución porque podría causar un problema de búfer al leer todo el contenido del archivo en la variable de cadena. Mi solución también tiene en cuenta las consultas de TRIGGER. No hay asignación de matriz, los comentarios y las líneas vacías se eliminan.
<?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;
}
Esta pregunta surge de vez en cuando. No hay una buena solución para ejecutar un script .sql directamente desde PHP. Hay casos límite en los que los enunciados comunes en un script .sql no se pueden ejecutar como sentencias SQL. Por ejemplo, la herramienta mysql tiene comandos incorporados que no son reconocidos por el servidor MySQL, por ejemplo CONNECT
, TEE
, STATUS
y DELIMITER
.
Entonces doy +1 a la respuesta de @Ignacio Vazquez-Abrams. Debe ejecutar su script .sql en PHP invocando la herramienta mysql
, por ejemplo con shell_exec()
.
Tengo esta prueba funcionando:
$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'');
Ver también mis respuestas a estas preguntas relacionadas:
Esto es lo que uso:
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);
}
Necesitarás crear un analizador SQL completo para esto. Recomiendo usar la herramienta de línea de comandos mysql
para esto, invocándola externamente desde PHP.
No te olvides de phpMyAdmin . Interfaz bastante sólida para interactuar con MySQL.
No sé si resuelve tu problema, ya que no sé si puedes interactuar con él directamente desde el código, pero solo quería tirarlo allí.
Nunca tuve que usarlo, pero la clase mysqli tiene un método multi_query:
Para ejecutar la generación de tablas desde dentro de la aplicación, es posible que desee crear un archivo php que haga exactamente eso cuando lo ejecute.
$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 );
Puede usar esta secuencia de comandos para ejecutar archivos de script MySQL. Tendrá que configurar $ hostName, $ userName, $ password, $ dataBaseName, $ port y $ fileName, por supuesto.
<?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'');
}
Sé que llego bastante tarde a la fiesta, pero PHP Mini Admin ha sido un salvavidas en un par de ocasiones. Básicamente es un PHPMyAdmin "lite" todo contenido en un archivo, por lo que no es necesario realizar instalaciones complicadas, solo cárguelo e inicie sesión. ¡Simples!
Una sugerencia:
// connect to db.
if (mysql_query("SOURCE myfile.sql")) {
echo "Hello Sonny";
}
multi_query
un script de migración con multi_query
. Puede procesar exportaciones de mysqldump y phpmyadmin sin la herramienta de línea de comandos mysql. También hice un poco de lógica para procesar múltiples archivos de migración basados en la marca de tiempo almacenada en DB como Rails. Sé que necesita más manejo de errores, pero actualmente hace el trabajo por mí.
Compruébelo: https://github.com/kepes/php-migration
Creo que si no procesas la entrada del usuario con solo scripts creados por desarrolladores o herramientas de exportación, puedes usarla de forma segura.
$commands = file_get_contents($location);
$this->_connection->multi_query($commands);