Files
doc-fr/reference/pdo/prepared-statements.xml
2021-09-24 04:13:47 +01:00

216 lines
7.0 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 84e8f0960b841a5ebca9d81cd2c2311b6504a371 Maintainer: yannick Status: ready -->
<!-- Reviewed: yes -->
<chapter xml:id="pdo.prepared-statements" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Requêtes préparées et procédures stockées</title>
<para>
La plupart des bases de données supportent le concept des requêtes préparées.
Qu'est-ce donc ? Vous pouvez les voir comme une sorte de modèle compilé
pour le SQL que vous voulez exécuter, qui peut être personnalisé en utilisant
des variables en guise de paramètres. Les requêtes préparées offrent
deux fonctionnalités essentielles :
</para>
<itemizedlist>
<listitem>
<simpara>
La requête ne doit être analysée (ou préparée) qu'une seule fois, mais peut
être exécutée plusieurs fois avec des paramètres identiques ou différents.
Lorsque la requête est préparée, la base de données va analyser, compiler
et optimiser son plan pour exécuter la requête. Pour les requêtes complexes,
ce processus peut prendre assez de temps, ce qui peut ralentir vos applications
si vous devez répéter la même requête plusieurs fois avec différents paramètres.
En utilisant les requêtes préparées, vous évitez ainsi de répéter le cycle
analyse/compilation/optimisation. Pour résumer, les requêtes préparées
utilisent moins de ressources et s'exécutent plus rapidement.
</simpara>
</listitem>
<listitem>
<simpara>
Les paramètres pour préparer les requêtes n'ont pas besoin d'être entre
guillemets ; le pilote gère cela pour vous. Si votre application utilise exclusivement
les requêtes préparées, vous pouvez être sûr qu'aucune injection SQL
n'est possible (Cependant, si vous construisez d'autres parties de la requête
en vous basant sur des entrées utilisateurs, vous continuez à prendre un risque).
</simpara>
</listitem>
</itemizedlist>
<para>
Les requêtes préparées sont tellement pratiques que c'est l'unique fonctionnalité
que PDO émule pour les pilotes qui ne les prennent pas en charge. Ceci assure de pouvoir
utiliser la même technique pour accéder aux données, sans se soucier des capacités
de la base de données.
</para>
<para>
<example>
<title>Insertions répétitives en utilisant les requêtes préparées</title>
<simpara>
Cet exemple effectue une requête INSERT en y substituant un
<literal>nom</literal> et une <literal>valeur</literal> pour les marqueurs nommés.
</simpara>
<programlisting role="php">
<![CDATA[
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insertion d'une ligne
$name = 'one';
$value = 1;
$stmt->execute();
// insertion d'une autre ligne avec des valeurs différentes
$name = 'two';
$value = 2;
$stmt->execute();
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Insertions répétées en utilisant des requêtes préparées</title>
<simpara>
Cet exemple effectue une requête INSERT en y substituant un <literal>nom</literal>
et une <literal>valeur</literal> pour les marqueurs <literal>?</literal>.
</simpara>
<programlisting role="php">
<![CDATA[
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
// insertion d'une ligne
$name = 'one';
$value = 1;
$stmt->execute();
// insertion d'une autre ligne avec différentes valeurs
$name = 'two';
$value = 2;
$stmt->execute();
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Récupération des données en utilisant des requêtes préparées</title>
<simpara>
Cet exemple récupère des données basées sur la valeur d'une clé fournie
par un formulaire. L'entrée utilisateur est automatiquement échappée, il n'y a
donc aucun risque d'attaque par injection SQL.
</simpara>
<programlisting role="php">
<![CDATA[
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
$stmt->execute([$_GET['name']]);
foreach ($stmt as $row) {
print_r($row);
}
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Appel d'une procédure stockée avec un paramètre de sortie</title>
<simpara>
Si le pilote de la base de données le prend en charge, vous pouvez également lier
des paramètres aussi bien pour l'entrée que pour la sortie. Les paramètres de sortie
sont utilisés typiquement pour récupérer les valeurs d'une procédure stockée.
Les paramètres de sortie sont un peu plus complexes à utiliser que les paramètres d'entrée
car vous devez savoir la longueur qu'un paramètre donné pourra atteindre lorsque vous
le liez. Si la valeur retournée est plus longue que la taille qui vous aurez suggéré,
une erreur sera émise.
</simpara>
<programlisting role="php">
<![CDATA[
<?php
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// Appel de la procédure stockée
$stmt->execute();
print "La procédure a retourné : $return_value\n";
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Appel d'une procédure stockée avec un paramètre d'entrée/sortie</title>
<simpara>
Vous devez également spécifier les paramètres qui gèrent les valeurs
aussi bien pour l'entrée que pour la sortie ; la syntaxe est similaire aux
paramètres de sortie. Dans le prochain exemple, la chaîne 'Bonjour' est passée
à la procédure stockée et lorsqu'elle retourne la valeur, 'Bonjour' est remplacée
par la valeur retournée par la procédure.
</simpara>
<programlisting role="php">
<![CDATA[
<?php
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// appel de la procédure stockée
$stmt->execute();
print "La procédure a retourné : $value\n";
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Utilisation invalide de marqueur</title>
<programlisting role="php">
<![CDATA[
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute([$_GET['name']]);
// un marqueur doit être utilisé à la place d'une valeur complète
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(["%$_GET[name]%"]);
?>
]]>
</programlisting>
</example>
</para>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->