Mysql PDO и LIKE

  • Автор темы Автор темы KorP
  • Дата начала Дата начала

KorP

Новичок
Господа, никак не могу одуплить, нужно сделать запрос типа
PHP:
SELECT `id` FROM `warning` WHERE `where` = 'test' AND `time` LIKE '2012-11-01 10:31%'
напрямую в базе всё работает отлично, а вот через PDO я никак не могу его заставить работать. т.е. запрос выполняется, но ничего не возвращает. пробовал:
PHP:
$date = date("Y-m-d H:i").'%';
$stmt = Database::getInstance()->dbh->prepare("SELECT `id` FROM `warning` WHERE `where` = :tracker AND `time` LIKE :date");
$stmt->bindParam(':tracker', $tracker);
$stmt->bindParam(':date', $date, PDO::PARAM_STR);
как тут описано
где я чего не понял, подскажите плиз
 
на первый взгляд должно работать
не пробовал писать
PHP:
$date = '2012-11-01 10:31%';
?
Но вообще дата лайками - моветон.
 
c0dex
сдаётся мне, ты не понял вопроса.

KorP
у тебя же в примере выше без двоеточия работало?
А КСТАААТИ...
emulate_prepares у тебя он или офф?
если он, то поставь в офф и попробуй без лишнего двоеточия.
если офф - то поставь в он, и сделай намеренную ошибку в запросе рядом с лайком. он тебе вывалит кусок запроса на посмотреть.
 
Фанат
Сдается мне, ты не понял, что я написал, ибо я об эту фичу PDO гугл стер, пока понял, что не мой фейл был)

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

KorP
про emulate_prepares я прогнал. у тебя ж именованные плейсхолдеры, то есть, они все равно по-любому парсятся пдошечкой.
Думаю, в ней всё и дело - если бы были нативные вопросеки, то всё бы нашлось.
Если не в лом - потестируй с ними (и при emulate_prepares=off )?
 
Фанат
Ну раз ты у нас такой знаток, то скажи мне почему имеем следующее:

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

Ну так вот, имеем код (налепил на скорую руку, для примера):

PHP:
error_reporting(E_ALL);
ini_set('display_errors', 1);

try {
	$config['hostname'] = 'localhost';
	$config['username'] = 'root';
	$config['password'] = 'password';
	$config['database'] = 'test';
	$config['init'] = array(\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'');
	$config['dsn'] = 'mysql:dbname=' . $config['database'] . ';host=' . $config['hostname'];

	/** @var PDO */
	$connection = new \PDO(
		$config['dsn'], $config['username'], $config['password'], $config['init']
	);
} catch (\PDOException $e) {
	throw new Exception('Connection failed: ' . $e->getMessage());
}

Далее пишем свой код, для получения данный юзера:

PHP:
$sth = $connection->prepare("SELECT * FROM users WHERE pswd LIKE '%:placeholder%' ");
$sth->execute(array(':placeholder' => 177));
print_r($sth->fetchAll());
// Код вернет мне Array()



$sth = $connection->prepare("SELECT * FROM users WHERE pswd LIKE CONCAT('%', :placeholder, '%') ");
$sth->execute(array(':placeholder' => 177));
print_r($sth->fetchAll());
// Код вернет мне данные юзера.

Почему?
 
PHP:
'%:placeholder%'
- надеюсь, ты это не всерьёз написал?
или ты действительно считаешь, что это "не твой фейл"?

Кстати, должен заметить, что к вопросу ТС твои страдания всё-таки отношения не имеют. Он изначально делал правильно, и вот у него, как раз - "не его фейл".
 
Фанат
объяснись уж, что в запросе не так?

Я о том, что синтаксис валиден, запрос при подстановке значения плейсхолдера руками вернет все как надо.

PS: я конечно понимаю, что влез не совсем с тем вопросом, но оно мне покоя не дает давно.
 
А не проще/правильнее вместо LIKE использовать BETWEEN
PHP:
 SELECT `id` FROM `warning` WHERE `where` = 'test' AND `time` BETWEEN '2012-11-01 10:31:00' AND '2012-11-01 10:31:59'
 
c0dex, у тебя в первом случае обычный строковой литерал, там нет плейсхолдера. Есть зависимость от контекста. Нельзя так просто взять и заменить
Код:
:placeholder
на 177. Нельзя рассматривать SQL-шаблон как самую примитивную строку, в которой мы
Код:
$query = str_replace(':placeholder', escape($value), $queryTemplate);
делаем, так ты как раз бы получил уязвимости.
 
Да с какой радости он валиден-то?
Ты не понимаешь принципиального смысла плейсхолдеров.
Это не тупо подстановка по типу printf-a. Оно в таком варианте в принципе не будет работать, потому что невозможно защитить данные.
Плейсхолдер - это переменная в запросе. Он может представлять собой только целый кусок данных, а не их часть.
Лайк в качестве параметра принимает строку. "процентики" - это часть строки, а не часть оператора LIKE.
Ты должен сформировать строку данных, и эту строку передать с помощью плейсхолдера в запрос.

Точно так же ты не можешь забиндить выражение "0,10" для LIKE. потому что здесь ДВЕ переменные, и они должны биндиться отдельно.
По ссылке, которую ты дал, это же как раз и объясняется.
 
c0dex
wildcard надо в подстановку пихать
PHP:
$sth->execute(array(':placeholder' => '%177%'));
 
Redjik
"как надо" он и сам вас научит.
он спрашивает, почему.
 
У меня и был вопрос как раз о том,
Нельзя рассматривать SQL-шаблон как самую примитивную строку

Мне это было неочевидно, так как я надеялся, что данный синтаксис должен по логике прокатить. Ибо кардинальных отличий в самом запросе нет.

Про замечание Redjik о
wildcard надо в подстановку пихать
я в курсе.
 
Ибо кардинальных отличий в самом запросе нет.
Не сочти за наезд, но отличий нет только если рассматривать запрос с ламерской позиции "пихаем всё что под руку попало (и искейпим "вредные" символы)".
Если же рассматривать запрос по частям, отделяя данные от кода, то отличия есть.

Агументом оператора лайк является строковый литерал. У строкового литерала есть простые правила форматирования:
- он должен быть ограничен кавычками
- внутре должны быть прослешены спецсимволы.

Следовательно, если мы хотим делать всё правильно, мы должны помещать в запрос уже отформатированный литерал. Целиком.
А не собирать его в запросе. Потому что такая сборка в итоге и ведет к инъекциям.
Именно поэтому разница есть
PHP:
:placeholder
- законный элемент синтаксиса. В режиме эмуляции будет трансформирован в строку в соответствии с вышеперечисленными правилами.
PHP:
'%:placeholder%'
- литерал, собранный из огрызков. Трансформировать в строку в соответствии с правилами невозможно

но дело всё равно даже не в этом
А в том, что плейсхолдер, как объяснено по твоей ссылке, не может являться частью литерала.
плейсхолдер - это отдельный элемент синтаксиса запроса. Ну как знак "+" в ПХП.
Если он стоит просто в коде - то это оператор "плюс".
Но если он стоит внутри строки - это просто символ!
Так и здесь:
Если плейсхолдер является самостоятельной частью запроса - это плейсхолдер. Если же частью строки - это всего лишь часть строки безо всякого специального значения.
обратно разница есть.
 
Сверху