Pourquoi est-PDO mieux pour échapper à des requêtes MySQL / querystrings que mysql_real_escape_string?

StackOverflow https://stackoverflow.com/questions/1742066

Question

On m'a dit que je serais mieux en utilisant PDO pour échapper à MySQL, plutôt que mysql_real_escape_string.

Peut-être que je vais avoir une journée de mort cérébrale (ou peut-être le fait que je ne suis pas du bout droit de l'imagination d'un programmeur naturel, et je suis encore très au stade débutant en matière de PHP) , mais après avoir vérifié le manuel PHP et lisez l'entrée sur AOP , Je ne suis toujours pas clair quant à ce que PDO est en fait et pourquoi il vaut mieux que d'utiliser mysql_real_escape_string. Cela peut être parce que je ne l'ai pas vraiment réussi à maîtriser la complexité de la POO encore (je suppose que c'est quelque chose à voir avec la POO), mais à part le fait que les variables et les valeurs du tableau semblent avoir un Infront du côlon d'entre eux, Je ne suis toujours pas sûr de ce qu'il est en réalité et comment vous l'utiliser (et pourquoi il vaut mieux que mysql_real_escape_string. (il a aussi peut-être quelque chose à voir avec le fait que je n'ai pas vraiment une compréhension claire de ce que « les classes » sont , alors quand je lis « classe AOP » Je suis vraiment pas plus sage).

Après avoir lu un article ou deux sur le « développeur bit « zone du site MySQL, je ne suis toujours pas claire. Comme je ne peux même pas comprendre ce qu'il est à l'heure actuelle, je pense que probablement l'utiliser est un peu au-delà de moi en ce moment, mais je suis toujours intéressé à élargir mon éducation et de découvrir comment je pourrais améliorer les choses.

Quelqu'un pourrait-il me expliquer en « anglais simple » ce que l'AOP (ou me diriger dans la direction de quelque chose sur le sujet écrit en anglais ordinaire), et comment vous iriez à l'utiliser?

Était-ce utile?

La solution

Comme les réponses actuelles vont dans les détails alors que votre question est plus destiné à un aperçu général, je vais faire un essai:

Les classes AOP visent à encapsuler toutes les fonctionnalités nécessaires pour interagir avec une base de données. Ils le font en définissant « méthodes » (de salon de OO pour les fonctions) et « propriétés » (de société OO pour les variables). Vous souhaitez les utiliser comme remplacement complet pour toutes les fonctions « standard » que vous utilisez maintenant pour parler à une base de données.

Alors, au lieu d'appeler une série de «mysql_doSomething () fonctions, le stockage de leurs résultats dans vos propres variables, vous le feriez « instancier » un objet de la classe AOP ( « classe »= définition abstraite, « objet »= béton , instance utilisable d'une classe) et des méthodes appel sur cet objet à faire de même.

À titre d'exemple, sans AOP, 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 en utilisant 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();

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

Si vous avez besoin de parler à une base de données PostgreSQL à la place, vous feriez seulement changer mysql:to pgsql: dans le new PDO() d'appel instanciation. Avec l'ancienne méthode, vous auriez à passer par tout votre code, en remplaçant tous les 'mysql_doSomething () fonctions avec leur « pg_doSomthing () » contrepartie (toujours vérifier les différences potentielles dans la gestion des paramètres). La même chose serait le cas pour beaucoup d'autres moteurs de base de données pris en charge.

Donc, pour revenir à votre question, essentiellement PDO vous donne juste une autre façon d'atteindre les mêmes choses, tout en offrant des raccourcis / améliorations / avantages. Par exemple, Évasion se passerait-il automatiquement la bonne façon nécessaire pour le moteur de base de données que vous utilisez. Aussi la substitution paramètre (SQL empêche Injections, non représentés dans l'exemple) est beaucoup plus facile, ce qui rend moins sujette aux erreurs.

Vous devriez lire sur quelques notions de base de la POO pour avoir une idée d'autres avantages.

Autres conseils

Je ne suis pas super familier avec PDO, mais il y a une distinction entre les « préparées » et échappé à cordes. Échapper est d'environ suppression de chaînes de caractères non admissibles de la requête, mais les déclarations préparées sont sur dire la base de données quel genre de requête pour attendre .

Une requête comporte plusieurs parties

Pensez-y de cette façon: lorsque vous donnez une requête à la base de données, vous indiquez à plusieurs choses distinctes. Une chose peut être, par exemple, « Je veux que vous fassiez une sélection. » Une autre pourrait être « limiter à des lignes où le nom d'utilisateur est la valeur suivante. »

Si vous construisez une requête comme une chaîne et la main à la base de données, il ne sait pas non plus partie jusqu'à ce qu'il obtienne la chaîne terminée. Vous pouvez faire ceci:

'SELECT * FROM transactions WHERE username=$username'

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

Mise en pièces mélangées

Supposons qu'un utilisateur malveillant entrées leur nom d'utilisateur comme billysmith OR 1=1. Si vous ne faites pas attention, vous pourriez mettre cela dans votre chaîne, entraînant:

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

... qui renverrait toutes les transactions pour tous les utilisateurs , parce que 1 est toujours égal à 1. Whoops, vous avez été piraté!

Voir ce qui est arrivé? La base de données ne savait pas quelles sont les parties à attendre dans votre requête , donc juste analysé la chaîne. Il n'a pas été surpris que le WHERE avait un OR, avec deux conditions qui pourraient satisfaire.

Garder les parties droites

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

Avec une déclaration préparée, vous pouvez donner à cette attente correcte. . Vous vous pouvez dire à la base de données « Je vais vous envoyer un SELECT, et il va se limiter aux lignes WHERE username = une chaîne que je vais vous donner, c'est tout - il n'y a pas d'autres parties à la requête sont. 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ù la colonne username contient la chaîne réelle « billysmith OU 1 = 1. » Si personne n'a que le nom d'utilisateur, il retournerait rien.

Autres avantages de déclarations préparées

En plus des avantages de sécurité, des déclarations préparées ont deux avantages de vitesse:

  • Ils peuvent être réutilisés avec des paramètres différents, ce qui devrait être plus rapide que la construction d'une nouvelle requête à partir de zéro, parce que la base de données connaît déjà essentiellement ce que vous êtes sur le point de demander. Il a déjà construit son « plan de requête ».
  • Certaines bases de données (Postgres est un, je pense) va commencer à faire un plan de requête dès qu'ils obtiennent la déclaration préparée - avant que vous avez réellement envoyé les paramètres à utiliser avec elle. Ainsi, vous pouvez voir un speedup même sur la première requête.

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

Contrairement à mysql_real_escape_string, AOP vous 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 nombre entier (PDO :: PARAM_INT).

En second lieu, 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 ne devez pas vous assurer que vous citez 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 vous permet de transférer votre application à une autre db sans changer vos appels de données PHP.

imaginez que vous écrivez quelque chose le long des lignes de:

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

ne vous sauvera pas d'injections, parce que $ id pourrait être 1 OR 1=1 et vous obtiendrez tous les enregistrements de la table. vous auriez à jeter $ id à droite datatype (int dans ce cas)

pdo a un autre avantage, et qui est l'interchangeabilité de backends base de données.

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 n'est pas toujours le cas sur les anciennes versions de MySQL). La préparation / Procédé de liaison est plus en ligne avec d'autres langues que j'ai travaillé.

  

Pourquoi est-PDO mieux pour échapper à des requêtes MySQL / querystrings que mysql_real_escape_string?

Tout simplement parce que « échapper » seul n'a pas de sens.
De plus, il est différent incomparable questions.

Le seul problème est que avec Escaping tout le monde prend mal, en supposant comme une sorte de « protection ».
Tout le monde dit: «J'échappai mes variables » avec le sens « je protégé ma requête ».
Alors que échapper seul n'a rien à voir avec la protection du tout.

La protection peut être à peu près atteint en cas de je me suis évadé et a cité mes données , mais ce n'est pas applicable partout, pour les identifiants par exemple (ainsi que AOP, par la voie).

Alors, la réponse est:

  • AOP, lorsque vous faites échapper à des valeurs binded, applique non seulement échapper, mais aussi de citer -. Voilà pourquoi il vaut mieux
  • « échapper » n'est pas synonyme de la « protection ». "Échapper + citant" à peu près est plus.
  • mais pour certaines parties de la requête les deux méthodes inapplicables.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top