it-swarm.com.ru

Загрузка файлов .sql изнутри PHP

Я создаю сценарий установки для приложения, которое я разрабатываю, и мне нужно динамически создавать базы данных из PHP. У меня есть это для создания базы данных, но теперь мне нужно загрузить в несколько файлов .sql. Я планировал открывать файл и mysql_query по одной строке за раз - пока я не посмотрел на файлы схемы и не понял, что это не просто один запрос на строку.

Итак, как мне загрузить файл sql из PHP (как phpMyAdmin с его командой import)?

59
Josh Smeaton

У меня возникает ощущение, что все, кто здесь ответил на этот вопрос, не знают, каково это быть разработчиком веб-приложений, который позволяет людям устанавливать приложение на своих собственных серверах. В частности, виртуальный хостинг не позволяет использовать SQL, как, например, запрос «LOAD DATA», упомянутый ранее. Большинство общих хостов также не позволяют использовать Shell_exec.

Теперь, чтобы ответить на OP, лучше всего создать файл PHP, содержащий ваши запросы в переменной и просто запустить их. Если вы полны решимости проанализировать файлы .sql, вам следует заглянуть в phpMyAdmin и получить некоторые идеи для получения данных из файлов .sql таким образом. Посмотрите на другие веб-приложения, в которых есть установщики, и вы увидите, что вместо того, чтобы использовать файлы .sql для своих запросов, они просто упаковывают их в файлы PHP и просто запускают каждую строку через mysql_query или что-то еще они должны сделать.

46
Jeremy Privett
$db = new PDO($dsn, $user, $password);

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

$qr = $db->exec($sql);
65
Luis Granja

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                : [email protected]
*
*     $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');
}

?>
58
Yasin

Самое простое решение - использовать Shell_exec () для запуска клиента mysql со сценарием SQL в качестве входных данных. Это может работать немного медленнее, потому что оно должно быть разветвленным, но вы можете написать код за пару минут и затем вернуться к работе над чем-то полезным. Написание скрипта 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, это намного сложнее.


Смотрите также мои ответы на эти связанные вопросы:

27
Bill Karwin

В своих проектах я использовал следующее решение:

<?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 (41 МБ) пиковое использование памяти: 3,25 МБ

10
Gromo

mysqli может выполнять несколько запросов, разделенных ; 

вы можете прочитать весь файл и запустить все сразу, используя mysqli_multi_query()

Но я буду первым, кто скажет, что это не самое элегантное решение.

10
phatduckk

Поскольку я не могу комментировать ответ, остерегайтесь использовать следующее решение:

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

5
zstate

Обновленное решение Плахчинского. В качестве альтернативы вы можете использовать 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 = '';
        }
    }
}
4
sanneo

Мое предложение было бы посмотреть на исходный код PHPMyBackup. Это автоматический PHP загрузчик SQL. Вы обнаружите, что mysql_query загружает только один запрос за раз, а такие проекты, как PHPMyAdmin и PHPMyBackup, уже проделали тяжелую работу по правильному разбору SQL. Пожалуйста, не изобретайте это колесо: P

4
SchizoDuckie

Работает на свалках 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
Plahcinski
mysql_query("LOAD DATA LOCAL INFILE '/path/to/file' INTO TABLE mytable");
3
olle

Попробуй это:

// 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);
3
Neeraj Singh

Вы уверены, что это не один запрос на строку? Ваш текстовый редактор может переносить строки, но в действительности каждый запрос может быть в одной строке.

В любом случае, метод Олле кажется лучшим. Если у вас есть причины выполнять запросы по одному, вы должны иметь возможность читать в файле строку за строкой, а затем использовать точку с запятой в конце каждого запроса для разделения. Вы гораздо лучше читаете файл за строкой, чем пытаетесь разбить огромную строку, так как это будет намного лучше для памяти вашего сервера. Пример:

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

Очевидно, что вам нужно будет учитывать транзакции и все остальное, если вы выполняете большое количество запросов в пакете, но это, вероятно, не имеет большого значения для сценария новой установки.

3
cam8001

Вкратце, способ, которым я сделал это:

  1. Прочитать файл (дамп базы данных, например, $ mysqldump db > db.sql)

    $sql = file_get_contents(db.sql);
    
  2. Импортируйте его используя mysqli :: multi_query

    if ($mysqli->multi_query($sql)) {
        $mysqli->close();
    } else {
        throw new Exception ($mysqli->error);
    }
    

Остерегайтесь mysqli_query поддерживает асинхронные запросы. Подробнее здесь: http://php.net/manual/en/mysqli.multi-query.php и здесь https://stackoverflow.com/a/6652908/2002493

3
Portmanteau

Если вы не планируете импортировать огромные .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, прерывать, если в запросе есть точки с запятой в строках) ..

2
dbr

Это лучший код для восстановления sql php может использовать 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 = "";
  }
 }
}
2
Ricky

Самый простой и быстрый способ загрузить и проанализировать дамп phpmyadmin файла дампа mysql.

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

Просто чтобы сформулировать проблему для всех:

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
Lorenz Lo Sauer

Ни одно из решений, которые я видел здесь, не связано с необходимостью изменения разделителя при создании хранимой процедуры на сервере, где я не могу рассчитывать на доступ к LOAD DATA INFILE. Я надеялся обнаружить, что кто-то уже решил это, не прибегая к помощи кода phpMyAdmin, чтобы понять это. Как и другие, я тоже находился в процессе поиска чужого GPL-способа сделать это, так как сам пишу GPL-код.

1
K B

Некоторые библиотеки PHP могут анализировать файл SQL, состоящий из нескольких операторов SQL, правильно его анализировать (без использования простого ";", конечно) и выполнять их. 

Например, проверьте Phing 's PDOSQLExecTask

1
Francois Zaninotto

Многие хосты не позволят вам создать собственную базу данных через PHP, но вы, похоже, решили это.
После того, как БД была создана, вы можете просто манипулировать ею и заполнять ее:

mysql_connect ( "локальный");
mysql_query ("SOURCE file.sql");

1
SamGoody

Это может быть полезно ->

Более или менее он сначала берет строку, заданную функции (значение file_get_contents () вашего file.sql), и удаляет все разрывы строк. Затем он разбивает данные на ";" персонаж. Затем он входит в цикл 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);
1
White Rabbit

Некоторые ребята (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
Darius Miliauskas

Это из проекта, над которым я работаю. В основном берет любой текстовый файл и извлекает операторы 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;
  }

?>
0
Dave H.

У меня есть среда, в которой нет ни инструмента mysql, ни phpmyadmin, а только мое приложение php, подключающееся к серверу mysql на другом хосте, но мне нужно запускать сценарии, экспортированные mysqldump или myadmin. Чтобы решить эту проблему, я создал скрипт multi_query, как я уже упоминал здесь

Он может обрабатывать вывод mysqldump и экспорт phpmyadmin без инструмента командной строки mysql. Я также сделал некоторую логику для обработки нескольких файлов миграции на основе метки времени, хранящейся в БД, таких как Rails. Я знаю, что требуется больше обработки ошибок, но в настоящее время делает работу для меня.

Проверьте это: https://github.com/kepes/php-migration

Это чистый php и не требует никаких других инструментов. Если вы не обрабатываете пользовательский ввод с помощью только сценариев, созданных разработчиками или инструментами экспорта, вы можете использовать его безопасно.

0
kepes

Почему бы не взять код из phpMyAdmin и использовать его? Это с открытым исходным кодом в конце концов ...

0
Mez

это на самом деле работает для меня:

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

Я заметил, что драйвер PostgreSQL PDO не позволяет запускать сценарии, разделенные точками с запятой. Чтобы запустить файл .sql в любой базе данных с использованием PDO, необходимо разделить операторы в коде 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();
    }
}
0
Dion Truter

Я надеюсь, что следующий код решит вашу проблему довольно хорошо.

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

Я использую это все время:

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

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