Consultas preparadas emuladas en MySQL
Para conectarnos a diversas bases de datos en PHP usamos la clase PDO y consultas preparadas para evitar ataques de inyección de SQL.
Una consulta con PDO tiene un aspecto similar a este:
$dsn = ‘mysql:host=’ . $host . ’;port=’ . $port . ’;dbname=’ . $dbName’;
$options = [
\PDO::MYSQL_ATTR_INIT_COMMAND => ‘SET NAMES utf8’
];
$connection = new \PDO($dsn, $user, $password, $options);
$stmt = $connection->prepare(‘SELECT * FROM users WHERE id = ?’);
$stmt->execute([
$id
]);
$user = $stmt->fetch(\PDO::FETCH_ASSOC);
Las consultas preparadas pueden ser emuladas, lo que significa que el trabajo se realiza en PHP y se pasa a MySQL una consulta SQL con los datos en la propia cadena. Cuando no son emuladas, se pasan a MySQL las consultas y los datos por separado, y MySQL se encarga de todo el trabajo. Existe alguna diferencia:
El método “prepare” puede devolver “false” en lugar de “execute” lanzar una excepción.
Cuando las consultas son emuladas, todos los datos recuperados de la base de datos son cadenas, pero cuando no son emuladas cada campo mantiene su tipo de dato.
Cuando las consultas preparadas son emuladas, se pueden ejecutar varias consultas con una única llamada a “execute”. Es decir, si alguien del equipo escribe una sentencia SQL tal que:
‘SELECT * FROM users WHERE id = ’ . $id
sin que se haya filtrado el valor de $id correctamente, la llamada sería vulnerable a una inyección de SQL. Sin embargo, cuando las consultas preparadas no son emuladas $stmt sería “false” cuando $id se trata de una inyección de sql o es una consulta no válida.
Las consultas preparadas son, por defecto, emuladas y para hacer que no lo sean hay que proporcionar un parámetro, \PDO::ATTR_EMULATE_PREPARES. En nuestro ejemplo quedaría así:
$options = [
\PDO::MYSQL_ATTR_INIT_COMMAND => ‘SET NAMES utf8’,
\PDO::ATTR_EMULATE_PREPARES => false
];