Intereting Posts
многомерный массив array_sum Ошибка компиляции: «g ++: ошибка при попытке выполнить« cc1plus »: execvp: нет такого файла или каталога" как использовать переменную php в html? Ковариация типов параметров в специализациях Неопределенный индекс с сеансами PHP Указание числового идентификатора на целое число для предотвращения SQL-инъекции Добавление чата через websocket, к существующему веб-приложению PHP Как проверить, полностью ли один элемент массива существует в другом массиве в php PHP DateTime микросекунды всегда возвращает 0 Исключение JSON в Android Как изменить порядок сообщений по количеству просмотров, а не по дате в wordpress Дублированные записи в mySQL с помощью jQuery ajax и PHP динамическая переменная с циклом while Определите, как долго PHP выполняется до сих пор Используя PHP, произвольно соединяйте группу элементов, не связывая их с самим собой, без прямых пар

PDO отправляет необработанный запрос в MySQL, в то время как Mysqli отправляет подготовленный запрос, оба дают тот же результат

Я начал понимать, как подготовленный оператор работает при использовании MySQLi и PDO, для первого шага я включил мониторинг запросов MySQL, как упоминалось здесь: как просмотреть текущие запросы MySQL? , Затем я создал следующий тест:

Использование mysqli:

$stmt = $mysqli->prepare("SELECT * FROM users WHERE username =?")) { $stmt->bind_param("i", $user); $user = "''1''"; 

серверные журналы:

  130802 23:39:39 175 Connect ****@localhost on testdb 175 Prepare SELECT * FROM users WHERE username =? 175 Execute SELECT * FROM users WHERE username =0 175 Quit 

Использование PDO:

  $user = "''1''"; $sql = 'SELECT * FROM user WHERE uid =?'; $sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); $sth->bindParam(1, $user, PDO::PARAM_INT); 

Журналы сервера:

  130802 23:41:42 176 Connect ****@localhost on testdb 176 Query SELECT * FROM user WHERE uid ='\'\'1\'\'' 176 Quit 

Однако оба обеспечивают одинаковый результат:

 uid: 0 username: admin role: admin 

Примечание: uid = 0 правильно, потому что intval("''1''") = 0

Что здесь важно:

Как запрос PDO получает тот же результат, когда он отправляет другой запрос в MySQL?

SELECT * FROM user WHERE uid ='\'\'1\'\''

Я нашел только одно указание из руководства PHP: http://www.php.net/manual/en/pdo.prepare.php

Заметка:

Эмулированные подготовленные операторы не взаимодействуют с сервером базы данных, поэтому PDO :: prepare () не проверяет инструкцию.

Но я не уверен, как MySQL справляется с этим запросом и заменяет '\'\'1\'\'' на 0 . В этом случае запросы мониторинга не будут точными при использовании PDO, в то же время использование PDO лучше знать точные запросы, отправляемые в MySQL, но не MySQLi.

Обновление: после изменения типа параметра frm integer для строки:

Журнал MySQLi:

  188 Prepare SELECT * FROM awa_user WHERE username =? 188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\'' 188 Quit 

Журнал PDO:

  189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\'' 189 Quit 

Это означает, что MySQLi и PDO избегают данных перед отправкой в ​​MySQL при использовании строки, в то время как для целых чисел mysqli применяет intval () или что-то подобное перед отправкой запроса, что также отвечает Биллу, который является правильным.

Ваш PDO настроен для эмуляции подготовленных запросов, тогда как mysqli использует истинные подготовленные запросы.

Подготовленный запрос связывает строку ''1'' как целочисленное значение параметра. PHP принуждает его к целому числу, используя что-то вроде intval() . Любая строка с нечисловыми ведущими символами интерпретируется как 0 PHP, поэтому значение параметра, отправленное после подготовки, является значением 0.

Поддельный подготовленный запрос использует строчную интерполяцию (вместо привязки), чтобы добавить строку ''1'' в SQL-запрос до того, как MySQL проанализирует его. Но результат схож, потому что SQL также обрабатывает строку с нечисловыми ведущими символами в целочисленном контексте как значение 0.

Единственное различие заключается в том, что заканчивается в общем журнале запросов, когда параметр привязан перед подготовкой и после подготовки.

Вы также можете заставить PDO использовать реальные подготовленные запросы, поэтому в этом случае он должен действовать так же, как mysqli:

 $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 

PS: Это может показаться хорошей причиной, по которой принято начинать значения id в 1 вместо 0.