#php #mysql #sql
#php #mysql #sql
Вопрос:
Я хотел бы создать PHP-скрипт, который будет проверять SQL-запрос, но не выполняет его. Он не только должен проверять синтаксис, но и должен, по возможности, сообщать вам, может ли запрос быть выполнен с учетом команды, содержащейся в запросе. Вот псевдокод того, что я хотел бы, чтобы он делал:
<?php
//connect user
//connect to database
//v_query = $_GET['usrinput'];
if(validate v_query == true){
echo "This query can be executed";
}
else{
echo "This query can't be executed because the table does not exist.";
}
//disconnect
?>
Что-то вроде этого. Я хочу, чтобы он имитировал запрос без его выполнения. Это то, что я хочу, и я ничего не могу найти по этому поводу.
Примером того, почему мы не хотели бы, чтобы запрос выполнялся, является то, что запрос добавляет что-то в базу данных. Мы просто хотим, чтобы он имитировал его без изменения базы данных.
Любые ссылки или примеры были бы с благодарностью приняты!
Комментарии:
1. Мне любопытно, какой вариант использования здесь. Если запрос неверен, SQL в любом случае вернет ошибку… на самом деле единственное, чего вы избегаете, выполняя это в скрипте, — это время подключения к сети. Но вы теряете это преимущество из-за накладных расходов, создаваемых PHP при разборе запроса. (Сервер БД может анализировать его намного быстрее, чем PHP.) Все это для того, чтобы сказать, зачем вам это нужно?
2. Какой синтаксис SQL вы хотели бы проверить?
3. ПРИВЕТ, Мэтт, спасибо, что уделили минутку рассмотрению моего вопроса. Я пишу приложение, которое будет генерировать PHP-скрипты вокруг запроса. Пока пользователь пишет запрос, он или она хотели бы проверить, является ли запрос допустимым, вы знаете, убедитесь, что строка существует и, конечно, синтаксис, но не обязательно выполнять запрос. Примером того, почему мы не хотели бы, чтобы запрос выполнялся, является то, что запрос добавляет что-то в базу данных. Мы просто хотим, чтобы он имитировал его без изменения базы данных.
4. Привет, Игнасио, спасибо, что тоже нашел время. Запрос будет отличаться в зависимости от ввода пользователя.
Ответ №1:
Начиная с MySQL 5.6.3, вы можете использовать EXPLAIN для большинства запросов
Я сделал это, и это прекрасно работает:
function checkMySqlSyntax($mysqli, $query) {
if ( trim($query) ) {
// Replace characters within string literals that may *** up the process
$query = replaceCharacterWithinQuotes($query, '#', '%') ;
$query = replaceCharacterWithinQuotes($query, ';', ':') ;
// Prepare the query to make a valid EXPLAIN query
// Remove comments # comment ; or # comment newline
// Remove SET @var=val;
// Remove empty statements
// Remove last ;
// Put EXPLAIN in front of every MySQL statement (separated by ;)
$query = "EXPLAIN " .
preg_replace(Array("/#[^nr;]*([nr;]|$)/",
"/[Ss][Ee][Tt]s @[A-Za-z0-9_] s*:?=s*[^;] (;|$)/",
"/;s*;/",
"/;s*$/",
"/;/"),
Array("","", ";","", "; EXPLAIN "), $query) ;
foreach(explode(';', $query) as $q) {
$result = $mysqli->query($q) ;
$err = !$result ? $mysqli->error : false ;
if ( ! is_object($result) amp;amp; ! $err ) $err = "Unknown SQL error";
if ( $err) return $err ;
}
return false ;
}
}
function replaceCharacterWithinQuotes($str, $char, $repl) {
if ( strpos( $str, $char ) === false ) return $str ;
$placeholder = chr(7) ;
$inSingleQuote = false ;
$inDoubleQuotes = false ;
$inBackQuotes = false ;
for ( $p = 0 ; $p < strlen($str) ; $p ) {
switch ( $str[$p] ) {
case "'": if ( ! $inDoubleQuotes amp;amp; ! $inBackquotes ) $inSingleQuote = ! $inSingleQuote ; break ;
case '"': if ( ! $inSingleQuote amp;amp; ! $inBackquotes ) $inDoubleQuotes = ! $inDoubleQuotes ; break ;
case '`': if ( ! $inSingleQuote amp;amp; ! $inDoubleQuotes ) $inBackquotes = ! $inBackquotes ; break ;
case '\': $p ; break ;
case $char: if ( $inSingleQuote || $inDoubleQuotes || $inBackQuotes) $str[$p] = $placeholder ; break ;
}
}
return str_replace($placeholder, $repl, $str) ;
}
Он вернет False, если запрос в порядке (разрешено несколько разделенных операторов), или сообщение об ошибке, в котором указывается ошибка, если существует синтаксис или другой MySQL другой (например, несуществующая таблица или столбец).
ИЗВЕСТНЫЕ ОШИБКИ:
- Ошибки MySQL с номерами строк: номера строк в большинстве случаев не совпадают.
- Не работает для инструкций MySQL, отличных от SELECT, UPDATE, REPLACE, INSERT, DELETE
Ответ №2:
Вы могли бы попробовать эту библиотеку:http://code.google.com/p/php-sql-parser /. Я еще не использовал его, поэтому не могу этого гарантировать, но код выглядит так, как будто он сможет определить разницу между допустимым и недопустимым SQL.
Другим вариантом может быть использование транзакций, если ваш вариант SQL позволяет это. Транзакция позволила бы вам выполнить SQL, а затем отменить его после этого, устраняя любой нанесенный ущерб. Я думаю, что предпочел бы вариант 1, хотя.
Комментарии:
1. Я наткнулся на
SET NOEXEC ON
Звучит примерно так, как я ищу. Позвольте мне провести небольшое дополнительное исследование по этому вопросу.2. Обратите внимание, что некоторые инструкции SQL (например, изменения в таблице) автоматически фиксируют транзакцию, так что это может быть опасно.
Ответ №3:
Вы не можете просто проанализировать и подтвердить SQL, потому что вам нужно проверить наличие таблиц, действительность соединений и т.д. Единственный возможный способ выполнить полный интегративный тест — это фактически запустить запрос. Вы могли бы обернуть это в транзакцию, а затем выполнить откат. Однако плохо разработанный или вредоносный запрос все равно может поставить ваш сервер на колени или уничтожить данные.
Комментарии:
1. Я наткнулся на
SET NOEXEC ON
Звучит примерно так, как я ищу. Позвольте мне провести небольшое дополнительное исследование по этому вопросу.