Я начал понимать, как подготовленный оператор работает при использовании 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.
Update: после изменения типа параметра 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() или что-то вроде этого перед отправкой запроса, также как и ответил Билл, который является правильным.