Выполнение подготовленного оператора PDO с предложением like - PullRequest
5 голосов
/ 08 октября 2010

Я новичок в PHP и пытаюсь научиться использовать PDO для подключения к тестовой базе данных MySQL.У меня есть следующее:

try {
    $db = new PDO('mysql:dbname=MYDBNAME;host=MYHOST', 'USERNAME', 'PASSWORD');

    $query = "select * from books where ? like '%?%'";
    $stmt = $db->prepare($query);
    $stmt->execute(array($searchtype, $searchterm));  
} catch(PDOException $e) {
    echo 'PDOException: ' . $e->getMessage();
}

Когда я пытаюсь это сделать, я получаю следующее предупреждение: Предупреждение: PDOStatement :: execute () [pdostatement.execute]: SQLSTATE [HY093]: Неверный номер параметра: номер привязкипеременные не соответствуют количеству токенов

Когда я удаляю предложение like и параметр $ searchterm, он возвращает результат должным образом.Я подумал - например, «%?%» - возможно, это недопустимый способ создания этого запроса в двойных кавычках, поэтому я попытался уйти », но это не сработало.Я искал решение и обнаружил, что кто-то переместил «% и%» туда, где $ searchterm:

$query = "select * from books where ? like ?";
...
$stmt->execute(array($searchtype, '\'%'.$searchterm.'%\'')); 

Я получил тот же результат.
Любая помощь приветствуется.Спасибо!

/ ОБНОВЛЕНИЕ **** / Я нашел в примере 12 из http://us3.php.net/manual/en/pdo.prepared-statements.php

Пример #12 Неправильное использование заполнителя

<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));

// Below is What they suggest is the correct way.
// placeholder must be used in the place of the whole value 
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?> 

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

Ответы [ 3 ]

3 голосов
/ 08 октября 2010

Не добавляйте кавычки при привязке подготовленных переменных и не привязывайте имя столбца

$query = sprintf( "select * from books where %s like ?", $searchtype );
...
$stmt->execute(array($searchtype, '%'.$searchterm.'%')); 
2 голосов
/ 15 мая 2012

Проблема, которую я вижу, состоит в том, что если бы вы написали оболочку для PDO, то вам пришлось бы как-то обрабатывать это отдельно.Ответ, который я нашел и полюбил, - напиши свой запрос и сопоставь% с параметром.то есть "ГДЕ столбец как concat ('%',: что-то, '%')"

2 голосов
/ 08 октября 2010
$stmt->execute(array($searchtype, '\'%'.$searchterm.'%\'')); 

Это не так, как работают параметризованные запросы.Вставленные параметры уже действуют как буквальные строки, вам не нужно добавлять разделители кавычек вокруг них или экранировать их (в этом вся суть), и если вы попытаетесь, вы буквально сравниваете со строкой single-quote-searchterm-single-quote.

Следовательно, если вы (как я подозреваю) намереваетесь сравнить определенный столбец с литеральной строкой, вы не параметризуете имя столбца.В данный момент вы сравниваете литеральную строку с другой литеральной строкой, поэтому она всегда будет истинной или всегда ложной независимо от данных в строке!

Так что я думаю, что вы, вероятно, имеете в виду:

$query= "SELECT * FROM books WHERE $searchtype LIKE ?";
$like= "%$searchterm%";
$stmt->execute(array($like)); 

Естественно, вы должны быть очень осторожны, так как $searchtype хорошо известно, чтобы избежать SQL-инъекций.Обычно вы сравниваете его со списком допустимых имен столбцов перед его использованием.

(Кроме того: - это способ помещения произвольных строк в имя схемы, которые вы можете использовать для столбца, но это раздражает, варьируется в зависимости от базы данных, и для него нет стандартной функции перехода. В MySQL вы используете обратную косую черту, символ обратной кавычки, кавычки и обратную косую черту и окружаете имя обратными кавычками. В ANSI SQL вы используете двойные кавычки сdoubled-double-quotes изнутри. В SQL Server вы используете квадратные скобки. Однако в действительности вам редко приходится делать что-либо из этого, потому что на самом деле вы всегда хотите разрешить только несколько предопределенных имен столбцов.)

(Другойв сторону: если вы хотите разрешить $searchterm значения с буквальным процентом, подчеркиванием или обратным слешем в - так, чтобы пользователи могли искать «100%», не сопоставляя любую строку с 100 в - у вас естьиспользовать явный escape-символ, что немного утомительно:)

$query= "SELECT * FROM books WHERE $searchtype LIKE ? ESCAPE '+'";
$like= str_replace(array('+', '%', '_'), array('++', '+%', '+_'), $searchterm);
$stmt->execute(array("%$like%")); 
...