Declaraciones preparadas PHP MySQL
Las declaraciones preparadas son muy útiles contra las inyecciones de SQL.
Declaraciones preparadas y parámetros enlazados
Una declaración preparada es una característica que se utiliza para ejecutar las mismas (o similares) declaraciones SQL repetidamente con alta eficiencia.
Las declaraciones preparadas básicamente funcionan así:
- Preparar: se crea una plantilla de declaración SQL y se envía a la base de datos. Ciertos valores se dejan sin especificar, llamados parámetros (etiquetados como "?"). Ejemplo: INSERTAR EN VALORES de MyGuests(?, ?, ?)
- La base de datos analiza, compila y realiza la optimización de consultas en la plantilla de declaración SQL y almacena el resultado sin ejecutarlo.
- Ejecutar: en un momento posterior, la aplicación vincula los valores a los parámetros y la base de datos ejecuta la instrucción. La aplicación puede ejecutar la sentencia tantas veces como quiera con diferentes valores
En comparación con la ejecución directa de sentencias SQL, las sentencias preparadas tienen tres ventajas principales:
- Las declaraciones preparadas reducen el tiempo de análisis ya que la preparación de la consulta se realiza solo una vez (aunque la declaración se ejecuta varias veces)
- Los parámetros vinculados minimizan el ancho de banda al servidor, ya que necesita enviar solo los parámetros cada vez, y no toda la consulta.
- Las declaraciones preparadas son muy útiles contra las inyecciones de SQL, porque los valores de los parámetros, que se transmiten más tarde usando un protocolo diferente, no necesitan escaparse correctamente. Si la plantilla de declaración original no se deriva de una entrada externa, no se puede producir la inyección SQL.
Declaraciones preparadas en MySQLi
El siguiente ejemplo usa declaraciones preparadas y parámetros enlazados en MySQLi:
Ejemplo (MySQLi con declaraciones preparadas)
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// prepare and bind
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
// set parameters and execute
$firstname = "John";
$lastname = "Doe";
$email = "[email protected]";
$stmt->execute();
$firstname = "Mary";
$lastname = "Moe";
$email = "[email protected]";
$stmt->execute();
$firstname = "Julie";
$lastname = "Dooley";
$email = "[email protected]";
$stmt->execute();
echo "New records created successfully";
$stmt->close();
$conn->close();
?>
Líneas de código para explicar del ejemplo anterior:
"INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)"
En nuestro SQL, insertamos un signo de interrogación (?) donde queremos sustituir un valor entero, cadena, doble o blob.
Luego, echa un vistazo a la función bind_param():
$stmt->bind_param("sss", $firstname, $lastname, $email);
Esta función vincula los parámetros a la consulta SQL y le dice a la base de datos cuáles son los parámetros. El argumento "sss" enumera los tipos de datos que son los parámetros. El carácter s le dice a mysql que el parámetro es una cadena.
El argumento puede ser de cuatro tipos:
- yo - entero
- d - doble
- s - cadena
- b - BLOB
Debemos tener uno de estos para cada parámetro.
Al decirle a mysql qué tipo de datos esperar, minimizamos el riesgo de inyecciones de SQL.
Nota: si queremos insertar datos de fuentes externas (como la entrada del usuario), es muy importante que los datos estén desinfectados y validados.
Declaraciones preparadas en PDO
El siguiente ejemplo usa declaraciones preparadas y parámetros enlazados en PDO:
Ejemplo (PDO con declaraciones preparadas)
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepare sql and bind parameters
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email)
VALUES (:firstname, :lastname, :email)");
$stmt->bindParam(':firstname', $firstname);
$stmt->bindParam(':lastname', $lastname);
$stmt->bindParam(':email', $email);
// insert a row
$firstname = "John";
$lastname = "Doe";
$email = "[email protected]";
$stmt->execute();
// insert another row
$firstname = "Mary";
$lastname = "Moe";
$email = "[email protected]";
$stmt->execute();
// insert another row
$firstname = "Julie";
$lastname = "Dooley";
$email = "[email protected]";
$stmt->execute();
echo "New records created successfully";
} catch(PDOException $e)
{
echo "Error: " . $e->getMessage();
}
$conn = null;
?>