48 votes

Pourquoi PDO est-il meilleur pour échapper aux requêtes / chaînes de requête MySQL qu'à mysql_real_escape_string?

J'ai dit que je serais mieux à l'aide d' PDO pour MySQL échapper, plutôt que d' mysql_real_escape_string.

Peut-être que je vais avoir un cerveau en état de mort jour (ou peut être le fait que je ne suis pas d'imagination naturel programmeur, et je suis encore très novice en scène quand il s'agit de PHP), mais après avoir vérifié le manuel PHP et de lire l'entrée sur le PDO, je ne suis toujours pas plus clair quant à ce que PDO est réellement et pourquoi c'est mieux que d'utiliser mysql_real_escape_string. Ce peut être parce que je n'ai pas vraiment réussi à maîtriser la complexité de la programmation orientée objet pour l'instant (je suis en supposant que c'est quelque chose à voir avec la programmation orientée objet), mais d'autres que le fait que les variables et les valeurs de tableau semblent avoir un côlon en face d'eux, je ne suis toujours pas sûr de ce qu'il est réellement et comment vous l'utilisez (et pourquoi c'est mieux que d' mysql_real_escape_string. (Il peut aussi avoir quelque chose à voir avec le fait que je n'ai pas vraiment avoir une compréhension claire de ce que les "classes" sont, donc quand j'ai lu "de la classe PDO" je ne suis pas plus sage vraiment).

Après avoir lu un article ou deux sur le "Developer Zone" bit du site web de MySQL, je ne suis toujours pas plus clair. Comme je ne peux même pas comprendre ce que c'est à l'heure actuelle, je pense que probablement son utilisation est un peu au-delà de moi, mais je suis toujours intéressé à l'élargissement de mes études et de trouver comment faire, j'ai pu améliorer les choses.

Quelqu'un pourrait-il m'expliquer en "plain English" ce que PDO est (ou me diriger dans la direction de quelque chose sur le sujet rédigée en anglais), et comment vous pouvez aller sur son utilisation?

57voto

Henrik Opel Points 16296

Comme le courant des réponses entrer dans les détails, tandis que votre question est plus destiné à un aperçu général, je vais faire un essai:

L'AOP cours a pour objectif de résumer toutes les fonctionnalités nécessaires pour interagir avec une base de données. Ils le font par la définition de "méthodes" (OO salon pour les fonctions) et 'propriétés' (OO salon pour les variables). Vous souhaitez utiliser comme un remplacement complet pour tous les "standards" des fonctions que vous utilisez aujourd'hui pour parler à une base de données.

Donc, au lieu d'appeler une série de " mysql_doSomething()' fonctions, le stockage de leurs résultats dans votre propre variables, vous 'instancier' un objet de la classe PDO ('class' = définition abstraite, 'objet' = concrètes, utilisables instance d'une classe) et appeler des méthodes sur l'objet pour en faire de même.

Comme un exemple, sans PDO, vous feriez quelque chose comme ceci:

// Get a db connection
$connection = mysql_connect('someHost/someDB', 'userName', 'password');
// Prepare a query
$query = "SELECT * FROM someTable WHERE something = " . mysql_real_escape_string($comparison) . "'";
// Issue a query
$db_result = mysql_query($query);
// Fetch the results
$results = array();
while ($row = mysql_fetch_array($db_result)) {
  $results[] = $row;
}

alors que ce serait l'équivalent de l'aide AOP:

// Instantiate new PDO object (will create connection on the fly)
$db = new PDO('mysql:dbname=someDB;host=someHost');
// Prepare a query (will escape on the fly)
$statement = $db->prepare('SELECT * FROM someTable WHERE something = :comparison');
// $statement is now a PDOStatement object, with its own methods to use it, e.g.
// execute the query, passing in the parameters to replace
$statement->execute(array(':comparison' => $comparison));
// fetch results as array
$results = $statement->fetchAll();

Donc, à première vue, il n'y a pas beaucoup de différence, sauf dans la syntaxe. Mais l'AOP version a certains avantages, le plus important étant la base de données de l'indépendance:

Si vous avez besoin de parler à une base de données PostgreSQL au lieu de cela, vous ne changez mysql:de pgsql: dans l'instanciation d'appel new PDO(). Avec l'ancienne méthode, vous auriez à passer à travers tout votre code, en remplaçant tous les " mysql_doSomething()' fonctions avec leur " pg_doSomthing (les) contrepartie (en vérifiant toujours des différences potentielles dans la gestion des paramètres). Le même se serait le cas pour de nombreux autres moteurs de base de données.

Donc, pour revenir à votre question, AOP, fondamentalement, vous donne juste une autre façon d'obtenir les mêmes choses, tout en offrant quelques raccourcis/améliorations/avantages. Par exemple, en échappant à se produirait automatiquement dans la bonne façon nécessaire pour le moteur de base de données que vous utilisez. Aussi le paramètre de substitution (empêche les Injections SQL, pas montré dans l'exemple) est beaucoup plus facile, ce qui rend moins sujettes à erreur.

Vous devriez lire sur certains POO bases pour avoir une idée de d'autres avantages.

40voto

Nathan Long Points 30303

Je ne suis pas super familier avec PDO, mais il y a une distinction entre "préparées" et s'est échappé des chaînes de caractères. L'échappement est à propos de la suppression rejeté les chaînes de caractères à partir de la requête, mais préparé déclarations de dire la base de données de ce genre de requête à attendre.

Une requête a plusieurs parties

Pensez-y de cette façon: lorsque vous faites une requête à la base de données, vous la raconter plusieurs choses distinctes. Une chose peut être, par exemple, "je veux vous faire une sélection." Une autre pourrait être de "limiter à des lignes OÙ le nom de l'utilisateur est la valeur suivante."

Si vous créez une requête comme une chaîne de caractères et le remettre à la base de données, il ne sait pas à propos de la partie jusqu'à ce qu'il obtient le formulaire de chaîne de caractères. Vous pourriez faire ceci:

'SELECT * FROM transactions WHERE username=$username'

Quand il obtient de cette chaîne, il doit analyser et décider "c'est un SELECT avec un WHERE".

Obtenir les pièces mélangées

Supposons qu'un utilisateur malveillant entrées de leur nom d'utilisateur de l' billysmith OR 1=1. Si vous n'êtes pas prudent, vous pourriez mettre dans votre chaîne, ce qui entraîne:

'SELECT * FROM transactions WHERE username=billysmith OR 1=1'

...qui permettrait le retour de toutes les transactions pour tous les utilisateurs, car 1 est toujours égal à 1. Oups, vous avez été piraté!

Voir ce qui s'est passé? La base de données ne sais pas quelles parties de la requête, donc il se contente d'analyser la chaîne. Il n'était pas surpris que l' WHERE avaient un OR, avec deux conditions qui pourrait la satisfaire.

En gardant les parties droites

Si seulement il avait su à quoi s'attendre, à savoir, un SELECT dont WHERE a une seule condition, l'utilisateur malveillant ne pouvais pas l'avoir trompé.

Avec une déclaration préparée, vous pouvez lui donner que de corriger d'attente. Vous, vous pouvez dire à la base de données "je suis sur le point de vous envoyer un SELECT, et ça va être limité aux lignes WHERE username = d'une chaîne que je m'apprête à vous donner. C'est tout - il n'y a pas d'autres parties à la requête. Êtes-vous prêt? OK, voici la chaîne à comparer au nom d'utilisateur."

Avec cette attente, la base de données ne serait pas dupe: il ne renvoie des lignes où l' username colonne contient la chaîne 'billysmith OU 1=1.' Si personne n'en a que le nom d'utilisateur, il serait de retour rien.

D'autres avantages de déclarations préparées à l'avance

En plus des prestations de la sécurité, les instructions préparées ont un couple de vitesse avantages:

  • Ils peuvent être réutilisés avec des paramètres différents, qui devrait être plus rapide que la construction d'une nouvelle requête à partir de zéro, car la base de données, on sait déjà ce que vous êtes sur le point de demander. Il a déjà construit son "plan de requête".
  • Certaines bases de données (Postgresql est un, je crois) va commencer à faire un plan de requête dès qu'ils obtenir le prêt de l'instruction avant que vous avez réellement envoyé les paramètres à utiliser avec elle. Ainsi, vous pouvez voir une accélération même lors de la première requête.

Pour une autre explication, voir Theo réponse ici.

16voto

Cory House Points 5014

Contrairement à mysql_real_escape_string, PDO permet d'appliquer un type de données.

<?php
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();
?>

Notez que dans l'exemple ci-dessus, le premier paramètre, les calories, doit être un entier (PDO::PARAM_INT).

Deuxièmement, pour moi, PDO requêtes paramétrées sont plus faciles à lire. Je préfère lire:

SELECT name FROM user WHERE id = ? AND admin = ? 

que

SELECT name FROM user WHERE id = mysql_real_escape_string($id) AND admin = mysql_real_escape_string($admin);

Troisièmement, vous n'avez pas à assurez-vous de citer les paramètres correctement. AOP prend soin de cela. Par exemple, mysql_real_query_string:

SELECT * FROM user WHERE name = 'mysql_real_escape_string($name)' //note quotes around param

vs

SELECT * FROM user WHERE name = ?

Enfin, PDO permet de porter votre application à une autre db sans changer votre PHP appels de données.

14voto

knittl Points 64110

imaginez que vous écrivez quelque chose comme:

 $query = 'SELECT * FROM table WHERE id = ' . mysql_real_escape_string($id);
 

cela ne vous évitera pas les injections, car $ id pourrait être 1 OR 1=1 et vous obtiendrez tous les enregistrements de la table. vous auriez à convertir $ id dans le bon type de données (int dans ce cas)

pdo présente un autre avantage, à savoir l’interchangabilité des bases de données.

3voto

Wes Points 572

En plus d'empêcher l'injection SQL, PDO vous permet de préparer une requête une fois et de l'exécuter plusieurs fois. Si votre requête est exécutée plusieurs fois (dans une boucle, par exemple), cette méthode devrait être plus efficace (je dis "devrait être", car il semble que ce ne soit pas toujours le cas sur les anciennes versions de MySQL). La méthode prepare / bind est également plus en ligne avec les autres langues avec lesquelles j'ai travaillé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X