web-dev-qa-db-fra.com

Quelle est la signification du point d'interrogation dans MySQL à "WHERE column =?"?

Je dissèque du code et je suis tombé sur ça,

$sql = 'SELECT page.*, author.name AS author, updator.name AS updator '
     . 'FROM '.TABLE_PREFIX.'page AS page '
     . 'LEFT JOIN '.TABLE_PREFIX.'user AS author ON author.id = page.created_by_id '
     . 'LEFT JOIN '.TABLE_PREFIX.'user AS updator ON updator.id = page.updated_by_id '
     . 'WHERE slug = ? AND parent_id = ? AND (status_id='.Page::STATUS_REVIEWED.' OR status_id='.Page::STATUS_PUBLISHED.' OR status_id='.Page::STATUS_HIDDEN.')';

Je me demande ce que le "?" fait dans l'instruction WHERE. Est-ce une sorte de support de paramètres?

41
Levi

Les relevés préparés utilisent le "?" dans MySQL pour permettre la liaison des paramètres à l'instruction. Hautement considéré comme plus sûr contre les injections SQL s'il est utilisé correctement. Cela permet également des requêtes SQL plus rapides car la requête ne doit être compilée qu'une seule fois et peut être réutilisée.

38
Jayrox

Le point d'interrogation représente un paramètre qui sera ultérieurement remplacé. L'utilisation de requêtes paramétrées est plus sécurisée que l'intégration des paramètres directement dans la requête.

SQL Server appelle cela des requêtes de paramétrage et Oracle l'appelle des variables de liaison.

L'utilisation varie selon la langue à partir de laquelle vous exécutez la requête.

Voici un exemple d'utilisation de PHP.

en admettant que $mysqli est une connexion à la base de données et people est une table à 4 colonnes.

$stmt = $mysqli->prepare("INSERT INTO People VALUES (?, ?, ?, ?)");

$stmt->bind_param('sssd', $firstName, $lastName, $email, $age);

Le 'sssd' est un indicateur identifiant le reste des paramètres, où s représente une chaîne et d représente des chiffres.

28
Steve Stedman

? n'a pas de signification particulière dans MySQL WHERE = instructions

Il n'a qu'une signification particulière pour plusieurs interfaces externes telles que PHP stdlib et les frameworks web comme Rails.

? n'est qu'une erreur de syntaxe sur:

CREATE TABLE t (s CHAR(1));
SELECT * FROM t WHERE s = ?;

car il n'est pas cité, et dans:

INSERT INTO t VALUES ('a');
INSERT INTO t VALUES ("?");
SELECT * FROM t WHERE s = '?';

il renvoie:

s
?

donc apparemment sans signification particulière.

Exemple de rails

Dans Rails par exemple, le point d'interrogation est remplacé par un argument donné par une variable du langage de programmation de la bibliothèque (Ruby), par exemple:

Table.where("column = ?", "value")

et il cite automatiquement des arguments pour éviter les bugs et l'injection SQL, générant une instruction comme:

SELECT * FROM Table WHERE column = 'value';

La citation nous sauverait en cas de quelque chose comme:

Table.where("column = ?", "; INJECTION")

Instructions préparées par MySQL 5.0

MySQL 5.0 a ajouté fonction de déclaration préparée qui a une sémantique similaire au point d'interrogation dans les frameworks Web.

Exemple de la documentation:

PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
SET @a = 3;
SET @b = 4;
EXECUTE stmt1 USING @a, @b;

Production:

hypotenuse
5

Ceux-ci échappent également aux caractères spéciaux comme prévu:

PREPARE stmt1 FROM 'SELECT ? AS s';
SET @a = "'";
EXECUTE stmt1 USING @a;

Production:

s
'

Ce sont des déclarations préparées, les déclarations préparées offrent deux avantages majeurs:

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 les mêmes paramètres ou des paramètres différents. Une fois la requête préparée, la base de données analysera, compilera et optimisera son plan d'exécution de la requête. Pour les requêtes complexes, ce processus peut prendre suffisamment de temps pour ralentir sensiblement une application s'il est nécessaire de répéter plusieurs fois la même requête avec des paramètres différents. En utilisant une instruction préparée, l'application évite de répéter le cycle d'analyse/compilation/optimisation. Cela signifie que les instructions préparées utilisent moins de ressources et s'exécutent donc plus rapidement.

Les paramètres des instructions préparées n'ont pas besoin d'être cités; le pilote s'en charge automatiquement. Si une application utilise exclusivement des instructions préparées, le développeur peut être sûr qu'aucune injection SQL ne se produira (cependant, si d'autres parties de la requête sont créées avec des entrées non échappées, l'injection SQL est toujours possible).

http://php.net/manual/en/pdo.prepared-statements.php

1
Raheel