Note for MySQL: to use input/output parameters for stored procedures with PDO use PDO.Query() statement.
For example:
<?php
$dbh->query("CAST SomeStoredProcedure($someInParameter1, $someInParameter2, @someOutParameter)");
$dbh->query("SELECT @someOutParameter");
?>
Or, if you want very much to use PDO.Prepare(), insert "SELECT @someOutParameter" in your stored procedure and then use:
<?php
$stmt = $dbh->prepare("CAST SomeStoredProcedure(?, ?)");
$stmt ->execute(array($someInParameter1, $someInParameter2));
?>
Sentencias preparadas y procedimientos almacenados
Muchas de las bases de datos más maduras soportan el concepto de sentencias preparadas. Pueden definirse como un tipo de plantillas compiladas para SQL que las aplicaciones desean ejecutar, que pueden ser personalizadas usando parámetros variables. Las sentencias preparadas ofrecen dos grandes beneficios:
- La consulta sólo necesita ser interpretada (o preparada) una vez, pero puede ser ejecutada en múltiples ocasiones con los mismos o diferentes parámetros. Cuando la consulta es preparada, la base de datos analizará, compilará y optimizará su plan para ejecutar la consulta. Para consultas complejas este proceso puede tomar suficiente tiempo como para que ralentice notablemente una aplicación si se necesita repetir la misma consulta muchas veces con los mismos parámetros. Usando una sentencia preparada la aplicación evita repetir el ciclo de análisis/compilación/optimización. Esto significa que las sentencias preparadas usan menos recursos y se ejecutan más rápidamente.
- Los parámetros para las sentencias preparadas no necesitan estar entrecomillados; el driver automáticamente se encarga de esto. Si una aplicación usa exclusivamente sentencias preparadas, el desarrollador puede estar seguro de que no ocurrirán inyecciones SQL (sin embargo, si otras partes de la consulta se construyen con datos de entrada sin escapar, las inyecciones SQL pueden ocurrir).
Las sentencias preparadas son tan útiles que son la única característica que PDO emulará para drivers que no las soporten. Esto asegura que una aplicación será capaz de usar el mismo paradigma de acceso a datos independientemente de las capacidades de la base de datos.
Ejemplo #1 Múltiples inserts usando sentencias preparadas
Este ejemplo realiza dos consulta de tipo INSERT sustituyendo name y value por los valores equivalentes.
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insertar una fila
$name = 'one';
$value = 1;
$stmt->execute();
// insertar otra fila con diferentes valores
$name = 'two';
$value = 2;
$stmt->execute();
?>
Ejemplo #2 Múltiples inserts usando sentencias preparadas
Este ejemplo realiza dos consultas de tipo INSERT sustituyendo name y value por el parámetro de sustitución?.
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
// insertar una fila
$name = 'one';
$value = 1;
$stmt->execute();
// insertar otra fila con diferentes valores
$name = 'two';
$value = 2;
$stmt->execute();
?>
Ejemplo #3 Buscar datos usando sentencias preparadas
Este ejemplo busca datos basándose en un valor clave proporcionado por un formulario. Los datos de usuario son automáticamente entrecomillados, con lo cual no hay riesgo de un ataque por inyección SQL.
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
?>
Si el driver de la base de datos lo soporta, una aplicación puede también enlazar parámetros de salida al igual que para entrada. Los parámetros de salida son típicamente usados para recuperar valores de procedimientos almacenados. Los parámetros de salida son ligeramente más complejos de usar que los de entrada, de manera que el desarrollador debe saber cuánto de grande puede ser un parámetro cuando se enlaza. Si el valor resulta ser más grande que el tamaño que se ha supuesto, se eleva un error.
Ejemplo #4 Llamar a un procedimiento almacenado con un parámetro de salida
<?php
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// llamar al procedimiento almacenado
$stmt->execute();
print "procedure returned $return_value\n";
?>
Los desarrolladores pueden también especificar parámetros que contendrán valores tanto de entrada como de salida; la sintaxis es similar a la de los parámetros de salida. En el siguiente ejemplo, la cadena 'hello' es pasada al procedimiento almacenado, y cuando éste finaliza, 'hello' es reemplazada con el valor de retorno del procedimiento.
Ejemplo #5 Llamar a un procedimiento almacenado con un parámetro de entrada/salida
<?php
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// llamar al procedimiento almacenado
$stmt->execute();
print "procedure returned $value\n";
?>
Ejemplo #6 Uso inválido de un parámetro de sustitución
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));
// los parámetros de sustitución deben ser usados en el lugar del valor completo
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>
Note for MySQL: to use input/output parameters for stored procedures with PDO use PDO.Query() statement.
For example:
<?php
$dbh->query("CAST SomeStoredProcedure($someInParameter1, $someInParameter2, @someOutParameter)");
$dbh->query("SELECT @someOutParameter");
?>
Or, if you want very much to use PDO.Prepare(), insert "SELECT @someOutParameter" in your stored procedure and then use:
<?php
$stmt = $dbh->prepare("CAST SomeStoredProcedure(?, ?)");
$stmt ->execute(array($someInParameter1, $someInParameter2));
?>
Note that when using name parameters with bindParam, the name itself, cannot contain a dash '-'.
example:
<?php
$stmt = $dbh->prepare ("INSERT INTO user (firstname, surname) VALUES (:f-name, :s-name)");
$stmt -> bindParam(':f-name', 'John');
$stmt -> bindParam(':s-name', 'Smith');
$stmt -> execute();
?>
The dashes in 'f-name' and 's-name' should be replaced with an underscore or no dash at all.
See http://bugs.php.net/43130
Adam
You have to make attention to the parameters send to the method.
We can imagine that a request like that can work:
<?php
$query = 'SELECT ? FROM ? WHERE id = ?';
?>
But in fact, it's a hijack of prepared query, which MUST be used *ONLY* to change the condition (here the last '?' ).
You do not send my_table.my_row or my_scheme.my_table because this parameters are essentials to optimize the query before execution.
Other thing: prepared query can not be serialized to reuse it some time later. For that you can use a mask (http://fr2.php.net/singleton)
A prepared query is temporary.
