2723 votes

Pourquoi ne devrais-je pas utiliser les fonctions mysql_* en PHP ?

Quelles sont les raisons techniques pour lesquelles on ne devrait pas utiliser mysql_* fonctions ? (par exemple mysql_query() , mysql_connect() o mysql_real_escape_string() )?

Pourquoi devrais-je utiliser autre chose, même si cela fonctionne sur mon site ?

S'ils ne fonctionnent pas sur mon site, pourquoi j'obtiens des erreurs telles que

Attention : mysql_connect() : Aucun fichier ou répertoire de ce type

3 votes

L'erreur doit être comme : Erreur fatale : Unecaught Error : Appel à une fonction non définie mysql_connect() ...

48 votes

Le fait qu'ils soient dépréciés est une raison suffisante pour les éviter.

2237voto

Quentin Points 325526

L'extension MySQL :

  • N'est pas en cours de développement actif
  • Est officiellement déprécié à partir de PHP 5.5 (publié en juin 2013).
  • A été supprimé entièrement à partir de PHP 7.0 (publié en décembre 2015)
    • Cela signifie qu'à partir de 31 décembre 2018 il n'existe pas dans les versions supportées de PHP. Si vous utilisez une version de PHP qui le supporte, c'est que vous utilisez une version dont les problèmes de sécurité ne sont pas corrigés.
  • Manque d'une interface OO
  • Ne supporte pas :
    • Requêtes non bloquantes et asynchrones
    • Déclarations préparées ou des requêtes paramétrées
    • Procédures stockées
    • Déclarations multiples
    • Transactions
    • La méthode d'authentification par mot de passe "nouveau" (activée par défaut dans MySQL 5.6 ; requise dans 5.7)
    • Toutes les nouvelles fonctionnalités de MySQL 5.1 ou supérieur

Comme il est déprécié, son utilisation rend votre code moins résistant à l'avenir.

L'absence de prise en charge des instructions préparées est particulièrement importante, car elles constituent une méthode plus claire et moins sujette aux erreurs pour l'échappement et la citation des données externes que l'échappement manuel avec un appel de fonction séparé.

Voir la comparaison des extensions SQL .

311 votes

Le fait qu'ils soient dépréciés est une raison suffisante pour les éviter. Ils n'existeront plus un jour, et vous ne serez pas heureux si vous comptez sur eux. Le reste n'est qu'une liste de choses que l'utilisation des anciennes extensions a empêché les gens d'apprendre.

124 votes

La dépréciation n'est pas la solution miracle que tout le monde semble croire. PHP lui-même ne sera plus là un jour, et pourtant nous nous appuyons sur les outils dont nous disposons aujourd'hui. Quand nous devrons changer d'outils, nous le ferons.

150 votes

@LightnessRacesinOrbit - La dépréciation n'est pas une solution miracle, c'est un drapeau qui dit "Nous reconnaissons que cela craint et nous n'allons pas le supporter plus longtemps". Bien que le fait d'avoir un code plus pérenne soit une bonne raison de s'éloigner des fonctionnalités dépréciées, ce n'est pas la seule (ni même la principale). Changez d'outil parce qu'il existe de meilleurs outils, pas parce que vous y êtes contraint. (Et changer d'outils avant d'y être contraint signifie que vous n'apprenez pas les nouveaux outils juste parce que votre code a cessé de fonctionner et doit être réparé hier ce qui est le pire moment pour apprendre de nouveaux outils).

1365voto

NullPoiиteя Points 23754

PHP propose trois API différentes pour se connecter à MySQL. Il s'agit des mysql (supprimé à partir de PHP 7), mysqli et PDO extensions.

El mysql_* étaient autrefois très populaires, mais leur utilisation n'est plus encouragée. L'équipe de documentation discute de la situation de la sécurité des bases de données, et éduquer les utilisateurs pour qu'ils s'éloignent de l'extension ext/mysql communément utilisée en fait partie (consultez le site de l'équipe de documentation). php.internals : dépréciation de ext/mysql ).

Et l'équipe de développeurs PHP ultérieurs a pris la décision de générer E_DEPRECATED des erreurs lorsque les utilisateurs se connectent à MySQL, que ce soit par le biais de mysql_connect() , mysql_pconnect() ou la fonctionnalité de connexion implicite intégrée dans ext/mysql .

ext/mysql était officiellement déprécié à partir de PHP 5.5 et a été supprimé à partir de PHP 7 .

Vous voyez la boîte rouge ?

Quand vous allez sur n'importe quel mysql_* Dans la page du manuel de la fonction, vous voyez une boîte rouge, expliquant qu'elle ne doit plus être utilisée.

Pourquoi


S'éloigner de ext/mysql n'est pas seulement une question de sécurité, mais aussi d'accès à toutes les fonctionnalités de la base de données MySQL.

ext/mysql a été construit pour MySQL 3.23 et n'a reçu que très peu d'ajouts depuis, tout en conservant la compatibilité avec cette ancienne version, ce qui rend le code un peu plus difficile à maintenir. Fonctions manquantes qui ne sont pas supportées par ext/mysql inclure : ( _du manuel PHP_ ).

*Raison de ne pas utiliser `mysql_` función** :

  • Pas en développement actif
  • Supprimé à partir de PHP 7
  • Manque d'une interface OO
  • Ne prend pas en charge les requêtes non bloquantes et asynchrones.
  • N'appuie pas les déclarations préparées ou requêtes paramétrées
  • Ne prend pas en charge les procédures stockées
  • Ne prend pas en charge les déclarations multiples
  • Ne prend pas en charge transactions
  • Ne supporte pas toutes les fonctionnalités de MySQL 5.1

Point ci-dessus cité dans la réponse de Quentin

L'absence de prise en charge des instructions préparées est particulièrement importante, car elles constituent une méthode plus claire et moins sujette aux erreurs pour l'échappement et la citation des données externes que l'échappement manuel avec un appel de fonction séparé.

Voir le comparaison des extensions SQL .


Suppression des avertissements de dépréciation

Pendant que le code est converti en MySQLi / PDO , E_DEPRECATED Les erreurs peuvent être supprimées en définissant error_reporting en php.ini d'exclure E_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED

Notez que cela cachera également autres avertissements de dépréciation qui, cependant, peut être pour d'autres choses que MySQL. ( _du manuel PHP_ )

L'article PDO ou MySQLi : lequel utiliser ? par Dejan Marjanovic vous aidera à choisir.

Et un meilleur moyen est PDO et j'écris maintenant un simple PDO tutoriel.


Un tutoriel simple et court sur PDO


Q. La première question qui m'est venue à l'esprit est : qu'est-ce que le `PDO` ?

A. " PDO - Objets de données PHP - est une couche d'accès aux bases de données fournissant une méthode uniforme d'accès à plusieurs bases de données".

alt text


Connexion à MySQL

Avec mysql_* ou on peut le dire à l'ancienne (déprécié en PHP 5.5 et plus)

$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);

Avec PDO : Tout ce que vous devez faire est de créer un nouveau PDO objet. Le constructeur accepte des paramètres pour spécifier la source de la base de données PDO Le constructeur de l'application prend principalement quatre paramètres, à savoir DSN (nom de la source de données) et éventuellement username , password .

Ici, je pense que vous êtes familier avec tout sauf DSN ce qui est nouveau dans PDO . A DSN est essentiellement une chaîne d'options qui indique PDO le pilote à utiliser et les détails de connexion. Pour plus d'informations, consultez PDO MySQL DSN .

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

Nota: vous pouvez également utiliser charset=UTF-8 mais parfois cela provoque une erreur, il est donc préférable d'utiliser utf8 .

S'il y a une erreur de connexion, un message d'erreur sera généré. PDOException qui peut être attrapé pour gérer Exception plus loin.

Bonne lecture : Connexions et gestion des connexions ¶

Vous pouvez également transmettre plusieurs options de pilote sous forme de tableau au quatrième paramètre. Je recommande de passer le paramètre qui met PDO en mode exception. Parce que certains PDO ne prennent pas en charge les déclarations préparées natives. PDO réalise l'émulation de la préparation. Il vous permet également d'activer manuellement cette émulation. Pour utiliser les instructions préparées natives côté serveur, vous devez explicitement définir la fonction false .

L'autre solution consiste à désactiver l'émulation de la préparation, qui est activée dans l'onglet "Préparation". MySQL par défaut, mais l'émulation de préparation doit être désactivée pour utiliser le pilote PDO en toute sécurité.

J'expliquerai plus tard pourquoi l'émulation de préparation doit être désactivée. Pour trouver la raison, veuillez vérifier ce poste .

Il est uniquement utilisable si vous utilisez une ancienne version de MySQL ce que je ne recommande pas.

Vous trouverez ci-dessous un exemple de la façon dont vous pouvez le faire :

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password',
              array(PDO::ATTR_EMULATE_PREPARES => false,
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

Peut-on définir des attributs après la construction de PDO ?

Oui nous pouvons également définir certains attributs après la construction de PDO avec la fonction setAttribute método:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Traitement des erreurs


La gestion des erreurs est beaucoup plus facile dans PDO que mysql_* .

Une pratique courante lors de l'utilisation de mysql_* est :

//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));

OR die() n'est pas une bonne façon de gérer l'erreur puisque nous ne pouvons pas gérer la chose en die . Cela mettra simplement fin au script de manière abrupte et fera ensuite écho de l'erreur à l'écran, ce que vous ne voulez généralement PAS montrer à vos utilisateurs finaux, et laissera des pirates sanguinaires découvrir votre schéma. Alternativement, les valeurs de retour de mysql_* peuvent souvent être utilisées en conjonction avec les fonctions mysql_error() pour gérer les erreurs.

PDO propose une meilleure solution : les exceptions. Tout ce que nous faisons avec PDO doit être enveloppé dans un try - catch bloc. Nous pouvons forcer PDO dans l'un des trois modes d'erreur en définissant l'attribut de mode d'erreur. Les trois modes de traitement des erreurs sont les suivants.

  • PDO::ERRMODE_SILENT . Il ne fait que définir des codes d'erreur et agit à peu près de la même manière que mysql_* où vous devez vérifier chaque résultat et ensuite regarder $db->errorInfo(); pour obtenir les détails de l'erreur.
  • PDO::ERRMODE_WARNING Soulevez E_WARNING . (Avertissements d'exécution (erreurs non fatales). L'exécution du script n'est pas interrompue).
  • PDO::ERRMODE_EXCEPTION : Lancer des exceptions. Elle représente une erreur soulevée par PDO. Vous ne devez pas lancer une PDOException à partir de votre propre code. Voir Exceptions pour plus d'informations sur les exceptions en PHP. Il se comporte de la même manière que or die(mysql_error()); quand on ne l'attrape pas. Mais contrairement à or die() El PDOException peut être attrapé et traité avec élégance si vous choisissez de le faire.

Bonne lecture :

Comme :

$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

Et vous pouvez l'emballer dans try - catch comme ci-dessous :

try {
    //Connect as appropriate as above
    $db->query('hi'); //Invalid query!
} 
catch (PDOException $ex) {
    echo "An Error occured!"; //User friendly message/message you want to show to user
    some_logging_function($ex->getMessage());
}

Vous n'avez pas à vous occuper de try - catch en ce moment. Vous pouvez l'attraper à n'importe quel moment approprié, mais je vous recommande vivement d'utiliser try - catch . De plus, il peut être plus judicieux de l'attraper en dehors de la fonction qui appelle la fonction PDO truc :

function data_fun($db) {
    $stmt = $db->query("SELECT * FROM table");
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

//Then later
try {
    data_fun($db);
}
catch(PDOException $ex) {
    //Here you can handle error and show message/perform action you want.
}

En outre, vous pouvez gérer par or die() ou nous pouvons dire comme mysql_* mais il sera très varié. Vous pouvez masquer les messages d'erreur dangereux dans la production en tournant display_errors off et en lisant votre journal d'erreurs.

Maintenant, après avoir lu tout ce qui précède, vous vous dites probablement : qu'est-ce que c'est que ça, alors que je veux juste commencer à m'adonner à la simplicité ? SELECT , INSERT , UPDATE ou DELETE déclarations ? Ne vous inquiétez pas, c'est parti :


Sélection des données

PDO select image

Donc ce que vous faites dans mysql_* est :

<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());

$num_rows = mysql_num_rows($result);

while($row = mysql_fetch_assoc($result)) {
    echo $row['field1'];
}

Maintenant dans PDO vous pouvez le faire comme ça :

<?php
$stmt = $db->query('SELECT * FROM table');

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo $row['field1'];
}

Ou

<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

//Use $results

Note : Si vous utilisez la méthode comme ci-dessous ( query() ), cette méthode renvoie un PDOStatement objet. Donc si vous voulez récupérer le résultat, utilisez-le comme ci-dessus.

<?php
foreach($db->query('SELECT * FROM table') as $row) {
    echo $row['field1'];
}

Dans les données PDO, elle est obtenue via la fonction ->fetch() une méthode de votre gestionnaire de déclaration. Avant d'appeler fetch, la meilleure approche est d'indiquer à PDO comment vous souhaitez que les données soient récupérées. Dans la section ci-dessous, je vous explique cela.

Modes de récupération

Notez l'utilisation de PDO::FETCH_ASSOC dans le fetch() y fetchAll() code ci-dessus. Cela indique PDO pour retourner les lignes sous la forme d'un tableau associatif avec les noms des champs comme clés. Il existe également de nombreux autres modes de récupération que je vais expliquer un par un.

Tout d'abord, j'explique comment sélectionner le mode fetch :

 $stmt->fetch(PDO::FETCH_ASSOC)

Dans ce qui précède, j'ai utilisé fetch() . Vous pouvez également utiliser :

Maintenant, je viens en mode "recherche" :

  • PDO::FETCH_ASSOC : renvoie un tableau indexé par le nom de la colonne tel qu'il apparaît dans votre jeu de résultats.
  • PDO::FETCH_BOTH (par défaut) : renvoie un tableau indexé à la fois par le nom de la colonne et par le numéro de colonne indexé à 0, tel qu'il apparaît dans votre jeu de résultats.

Il y a encore plus de choix ! Découvrez-les tous dans PDOStatement Récupérer la documentation. .

Obtenir le nombre de lignes :

Au lieu d'utiliser mysql_num_rows pour obtenir le nombre de rangs retournés, vous pouvez obtenir un PDOStatement et faire rowCount() comme :

<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';

Obtenir le dernier ID inséré

<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();

Insertion et mise à jour ou suppression de déclarations

Insert and update PDO image

Ce que nous faisons dans mysql_* la fonction est :

<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);

Et dans pdo, cette même chose peut être faite par :

<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;

Dans la requête ci-dessus PDO::exec exécute une instruction SQL et renvoie le nombre de lignes affectées.

<em>L'insertion et la suppression seront abordées plus tard.</em>

La méthode ci-dessus n'est utile que lorsque vous n'utilisez pas de variable dans la requête. Mais lorsque vous avez besoin d'utiliser une variable dans une requête, n'essayez jamais de faire comme ci-dessus et là pour déclaration préparée ou déclaration paramétrée est.


Déclarations préparées

Q. Qu'est-ce qu'une déclaration préparée et pourquoi en ai-je besoin ?
A. Une instruction préparée est une instruction SQL précompilée qui peut être exécutée plusieurs fois en envoyant uniquement les données au serveur.

Le déroulement typique de l'utilisation d'une déclaration préparée est le suivant ( cité dans Wikipedia trois 3 points ) :

  1. Préparer : Le modèle de relevé est créé par l'application et envoyé au système de gestion de base de données (SGBD). Certaines valeurs ne sont pas spécifiées, appelées paramètres, placeholders ou variables de liaison (étiquetées ? ci-dessous) :

    INSERT INTO PRODUCT (name, price) VALUES (?, ?)

  2. Le SGBD analyse, compile et optimise les requêtes sur le modèle d'instruction, puis stocke le résultat sans l'exécuter.

  3. Exécuter : Plus tard, l'application fournit (ou lie) des valeurs pour les paramètres, et le SGBD exécute l'instruction (en retournant éventuellement un résultat). L'application peut exécuter l'instruction autant de fois qu'elle le souhaite avec des valeurs différentes. Dans cet exemple, elle peut fournir 'Pain' pour le premier paramètre et 1.00 pour le deuxième paramètre.

Vous pouvez utiliser une instruction préparée en incluant des placeholders dans votre SQL. Il existe trois types d'instructions préparées : les instructions sans placeholders (n'essayez pas avec la variable ci-dessus), les instructions avec placeholders non nommés et les instructions avec placeholders nommés.

Q. Alors maintenant, qu'est-ce qu'un espace réservé nommé et comment l'utiliser ?
A. Des caractères de remplacement nommés. Utilisez des noms descriptifs précédés de deux points, plutôt que de points d'interrogation. Nous ne nous soucions pas de la position/ordre de la valeur dans le nom du placeholder :

 $stmt->bindParam(':bla', $bla);

bindParam(parameter,variable,data_type,length,driver_options)

Vous pouvez également lier en utilisant un tableau d'exécution :

<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

Une autre fonctionnalité intéressante pour OOP amis est que les placeholders nommés ont la possibilité d'insérer des objets directement dans votre base de données, en supposant que les propriétés correspondent aux champs nommés. Par exemple :

class person {
    public $name;
    public $add;
    function __construct($a,$b) {
        $this->name = $a;
        $this->add = $b;
    }

}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);

Q. Alors maintenant, que sont les caractères de remplacement sans nom et comment les utiliser ?
A. Prenons un exemple :

<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();

y

$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));

Dans l'image ci-dessus, vous pouvez voir les ? au lieu d'un nom comme dans un porte-nom. Dans le premier exemple, nous attribuons des variables aux différents espaces réservés ( $stmt->bindValue(1, $name, PDO::PARAM_STR); ). Ensuite, nous attribuons des valeurs à ces espaces et exécutons l'instruction. Dans le deuxième exemple, le premier élément du tableau est placé dans le premier emplacement de l'instruction ? et le second au second ? .

NOTE : Sur des espaces sans nom nous devons veiller à l'ordre correct des éléments du tableau que nous transmettons à la fonction PDOStatement::execute() método.


SELECT , INSERT , UPDATE , DELETE requêtes préparées

  1. SELECT :

    $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
    $stmt->execute(array(':name' => $name, ':id' => $id));
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  2. INSERT :

    $stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
    $stmt->execute(array(':field1' => $field1, ':field2' => $field2));
    $affected_rows = $stmt->rowCount();
  3. DELETE :

    $stmt = $db->prepare("DELETE FROM table WHERE id=:id");
    $stmt->bindValue(':id', $id, PDO::PARAM_STR);
    $stmt->execute();
    $affected_rows = $stmt->rowCount();
  4. UPDATE :

    $stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
    $stmt->execute(array($name, $id));
    $affected_rows = $stmt->rowCount();

NOTA:

Cependant PDO et/ou MySQLi ne sont pas totalement sûrs. Vérifiez la réponse Les instructions préparées de PDO sont-elles suffisantes pour empêcher les injections SQL ? par ircmaxell . Aussi, je cite une partie de sa réponse :

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));

317voto

Second Rikudo Points 59550

Tout d'abord, commençons par le commentaire standard que nous donnons à tout le monde :

*S'il vous plaît, n'utilisez pas `mysql_` fonctions dans le nouveau code** . Ils ne sont plus entretenus et sont officiellement dépréciés . Voir le boîte rouge ? Apprendre déclarations préparées à la place, et utiliser AOP o MySQLi - cet article vous aidera à choisir. Si vous choisissez PDO, voici un bon tutoriel .

Examinons cela, phrase par phrase, et expliquons :

  • Ils ne sont plus maintenus et sont officiellement dépréciés.

    Cela signifie que la communauté PHP abandonne progressivement le support de ces très anciennes fonctions. Il est probable qu'elles n'existeront plus dans une future version (récente) de PHP ! Si vous continuez à utiliser ces fonctions, vous risquez de casser votre code dans un avenir pas si lointain.

    NOUVEAU ! - ext/mysql est maintenant _officiellement déprécié à partir de PHP 5.5 !_

    Plus récent ! ext/mysql _a été supprimé en PHP 7_ .

  • Au lieu de cela, vous devriez apprendre des déclarations préparées

    mysql_* ne prend pas en charge l'extension déclarations préparées qui est (entre autres) une contre-mesure très efficace contre les Injection SQL . Il corrige une vulnérabilité très sérieuse dans les applications dépendantes de MySQL qui permet aux attaquants d'accéder à votre script et d'effectuer toute requête possible sur votre base de données.

    Pour plus d'informations, voir Comment prévenir l'injection SQL en PHP ?

  • Vous voyez la boîte rouge ?

    Quand vous allez dans n'importe quel mysql Dans la page du manuel de la fonction, vous voyez une boîte rouge, expliquant qu'elle ne doit plus être utilisée.

  • Utilisez soit PDO soit MySQLi

    Il existe des alternatives meilleures, plus robustes et mieux construites, PDO - Objet de base de données PHP qui offre une approche complète de la POO pour l'interaction avec les bases de données. MySQLi qui est une amélioration spécifique à MySQL.

6 votes

Il y a encore une chose : je pense que cette fonction existe toujours en PHP pour une seule raison - la compatibilité avec les vieux CMS, e-commerce, systèmes de babillard électronique, etc. Elle sera finalement supprimée et vous devrez réécrire votre application...

4 votes

@Kamil : C'est vrai, mais ce n'est pas vraiment une raison pour laquelle vous ne devriez pas l'utiliser. La raison de ne pas l'utiliser est qu'il est ancien, non sécurisé, etc. :)

4 votes

@Mario -- Les développeurs PHP ont un processus, et ils viennent de voter en faveur de la dépréciation formelle de ext/mysql à partir de la version 5.5. Ce n'est plus un problème hypothétique.

230voto

mario Points 76989

Facilité d'utilisation

Les raisons analytiques et synthétiques ont déjà été mentionnées. Pour les nouveaux arrivants, il y a une raison plus importante d'arrêter d'utiliser les fonctions mysql_ datées.

Les API de base de données contemporaines sont juste plus facile à utiliser.

C'est surtout le paramètres liés ce qui peut simplifier le code. Et avec d'excellents tutoriels (comme ci-dessus) la transition vers AOP n'est pas trop difficile.

La réécriture d'une base de code plus importante en une seule fois prend cependant du temps. Raison d'être de cette alternative intermédiaire :

Fonctions pdo_* équivalentes à la place de mysql_*

Utilisation de < pdo_mysql.php > vous pouvez passer des anciennes fonctions mysql_ avec effort minimal . Il ajoute pdo_ qui remplacent leur mysql_ contreparties.

  1. Tout simplement include_once("pdo_mysql.php"); dans chaque invocation script qui doit interagir avec la base de données.

  2. Retirer le mysql_ préfixe de fonction partout et le remplacer par pdo_ .

    • mysql_connect() devient pdo_connect()
    • mysql_query() devient pdo_query()
    • mysql_num_rows() devient pdo_num_rows()
    • mysql_insert_id() devient pdo_insert_id()
    • mysql_fetch_array() devient pdo_fetch_array()
    • mysql_fetch_assoc() devient pdo_fetch_assoc()
    • mysql_real_escape_string() devient pdo_real_escape_string()
    • et ainsi de suite...
  3. Votre code fonctionnera de la même façon et aura toujours la même apparence :

    include_once("pdo_mysql.php"); 
    
    pdo_connect("localhost", "usrABC", "pw1234567");
    pdo_select_db("test");
    
    $result = pdo_query("SELECT title, html FROM pages");  
    
    while ($row = pdo_fetch_assoc($result)) {
        print "$row[title] - $row[html]";
    }

Et voilà.
Votre code est en utilisant AOP.
Maintenant il est temps de réellement utiliser il.

Les paramètres liés peuvent être faciles à utiliser

Vous avez juste besoin d'une API moins lourde.

pdo_query() ajoute un support très simple pour les paramètres liés. La conversion de l'ancien code est simple :

Déplacez vos variables hors de la chaîne SQL.

  • Ajoutez-les en tant que paramètres de fonction délimités par des virgules à l'adresse suivante pdo_query() .
  • Placez des points d'interrogation ? en tant que placeholders où les variables étaient auparavant.
  • Débarrassez-vous de ' les guillemets simples qui entouraient auparavant les valeurs/variables de la chaîne.

L'avantage devient plus évident pour les codes plus longs.

Souvent, les variables de type chaîne ne sont pas simplement interpolées en SQL, mais concaténées avec des appels d'échappement entre les deux.

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

Avec ? appliquées, vous n'avez pas à vous en soucier :

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

Rappelez-vous que pdo_* permet toujours l'un ou l'autre .
N'échappez pas une variable y le lier dans la même requête.

  • La fonction de remplacement est fournie par le véritable PDO qui se cache derrière.
  • Ainsi, il est également permis :named des listes d'attente plus tard.

Plus important encore, vous pouvez passer les variables $_REQUEST[] en toute sécurité derrière n'importe quelle requête. Lorsque vous soumettez <form> correspondent exactement à la structure de la base de données, c'est encore plus court :

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);

Tant de simplicité. Mais revenons à d'autres conseils de réécriture et à des raisons techniques pour lesquelles vous pourriez vouloir vous débarrasser des éléments suivants mysql_ et s'échapper.

Corrigez ou supprimez tout ce qui est "oldschool sanitize() función

Une fois que vous avez converti tous les mysql_ appels à pdo_query avec des paramètres liés, supprimer toutes les redondances pdo_real_escape_string appels.

En particulier, vous devez corriger tout sanitize o clean o filterThis o clean_data fonctionne comme annoncé par les tutoriels datés, sous une forme ou une autre :

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

Le bug le plus flagrant ici est le manque de documentation. Plus important encore, l'ordre de filtrage était exactement le mauvais.

  • L'ordre correct aurait été : déprécié stripslashes comme l'appel le plus interne, alors trim après strip_tags , htmlentities pour le contexte de sortie, et seulement en dernier lieu le _escape_string car son application doit précéder directement l'interséparation SQL.

  • Mais comme première étape, il suffit de se débarrasser de la _real_escape_string appeler.

  • Vous devrez peut-être garder le reste de votre sanitize() pour l'instant si votre base de données et le flux de votre application attendent des chaînes de caractères sécurisées par le contexte HTML. Ajoutez un commentaire indiquant qu'elle n'applique dorénavant que l'échappement HTML.

  • La gestion des chaînes et des valeurs est déléguée à PDO et à ses instructions paramétrées.

  • S'il y avait une mention de stripslashes() dans votre fonction de désinfection, cela peut indiquer un oubli de plus haut niveau.

    • C'était généralement là pour réparer les dommages (double échappement) causés par la version dépréciée de magic_quotes . Ce qui est cependant mieux fixé au niveau central et non pas chaîne par chaîne.

    • Utilisez l'un des inversion de l'userland approches. Puis retirez le stripslashes() dans le sanitize fonction.

    Note historique sur les magic_quotes. Cette fonctionnalité est à juste titre dépréciée. Elle est souvent dépeinte à tort comme un échec. sécurité cependant. Mais les magic_quotes sont autant une fonctionnalité de sécurité ratée que les balles de tennis ont échoué comme source de nutrition. Ce n'était tout simplement pas leur but.

    L'implémentation originale de PHP2/FI l'introduit explicitement avec juste " les guillemets seront automatiquement échappés, ce qui facilitera la transmission des données du formulaire directement aux requêtes msql. ". Notamment, il était accidentellement sûr d'utiliser avec mSQL car il ne supporte que l'ASCII.
    Puis PHP3/Zend a réintroduit magic_quotes pour MySQL et l'a mal documenté. Mais à l'origine, c'était juste un fonction de commodité n'est pas destiné à la sécurité.

Comment les déclarations préparées diffèrent

Lorsque vous brouillez les variables de chaîne dans les requêtes SQL, cela ne devient pas seulement plus compliqué à suivre. C'est aussi un effort superflu pour MySQL de séparer à nouveau le code et les données.

Les injections SQL sont simplement quand les données débordent sur le code le contexte. Un serveur de base de données ne peut pas repérer plus tard où PHP a collé des variables entre les clauses de la requête.

Avec les paramètres liés, vous séparez le code SQL et les valeurs du contexte SQL dans votre code PHP. Mais tout cela n'est pas mélangé en coulisses (sauf avec PDO::EMULATE_PREPARES). Votre base de données reçoit les commandes SQL non-variées et les valeurs variables 1:1.

Bien que cette réponse insiste sur le fait que vous devriez vous préoccuper des avantages en termes de lisibilité de l'abandon de l'option mysql_ . Cette séparation visible et technique des données et du code permet parfois d'améliorer les performances (INSERTs répétés avec des valeurs différentes).

Attention, la liaison des paramètres n'est pas encore une solution magique et unique pour lutter contre la fraude. tous les injections SQL. Il gère l'utilisation la plus courante des données/valeurs. Mais il ne peut pas mettre sur liste blanche les noms de colonnes/identifiants de tables, ni aider à la construction de clauses dynamiques, ni simplement les listes de valeurs de tableaux.

Utilisation de l'AOP hybride

Ces pdo_* constituent une API provisoire facile à coder. (C'est à peu près ce que MYSQLI aurait pu l'être s'il n'y avait pas eu le décalage de la signature de la fonction idiosyncrasique). Ils exposent également le vrai PDO la plupart du temps.
La réécriture ne doit pas s'arrêter à l'utilisation des nouveaux noms de fonctions pdo_. Vous pouvez transformer chaque pdo_query() en un simple appel $pdo->prepare()->execute().

Il est toutefois préférable de recommencer à simplifier. Par exemple, le résultat courant de la recherche :

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

Peut être remplacé par une simple itération foreach :

foreach ($result as $row) {

Ou mieux encore, une récupération directe et complète du tableau :

$result->fetchAll();

Dans la plupart des cas, vous obtiendrez des avertissements plus utiles que ceux que PDO ou mysql_ fournissent habituellement après l'échec des requêtes.

Autres options

Donc, j'espère que cela a permis de visualiser pratique des raisons et un cheminement utile pour abandonner mysql_ .

Il suffit de passer à pdo ne suffit pas. pdo_query() n'est également qu'une façade sur celui-ci.

À moins que vous n'introduisiez également la liaison des paramètres ou que vous puissiez utiliser autre chose de l'API plus agréable, c'est un changement inutile. J'espère qu'il est représenté de manière suffisamment simple pour ne pas décourager davantage les nouveaux arrivants. (L'éducation fonctionne généralement mieux que la prohibition).

Bien qu'il puisse être classé dans la catégorie des choses les plus simples qui pourraient fonctionner, il s'agit toujours d'un code très expérimental. Je ne l'ai écrit que le week-end dernier. Il existe cependant une pléthore d'alternatives. Il suffit de chercher sur Google Abstraction des bases de données PHP et naviguer un peu. Il y a toujours eu et il y aura toujours d'excellentes bibliothèques pour ce genre de tâches.

Si vous souhaitez simplifier davantage votre interaction avec la base de données, des mappeurs tels que Paris/Idiorm valent la peine d'être essayées. Tout comme personne n'utilise plus le DOM en JavaScript, vous n'avez plus besoin de surveiller une interface de base de données brute de nos jours.

161voto

Alnitak Points 143355

El mysql_ fonctions :

  1. sont périmés - ils ne sont plus entretenus
  2. ne permettent pas de passer facilement à un autre backend de base de données
  3. ne supportent pas les déclarations préparées, d'où
  4. encourager les programmeurs à utiliser la concaténation pour construire des requêtes, ce qui conduit à des vulnérabilités d'injection SQL

22 votes

2 est également vrai pour mysqli_

18 votes

Pour être juste, étant donné les variations dans le dialecte SQL, même PDO ne vous donne pas #2 avec un certain degré de certitude. Vous avez besoin d'une enveloppe ORM appropriée pour cela.

0 votes

Le site mysql_* sont une coquille dans les fonctions mysqlnd pour les nouvelles versions de PHP. Ainsi, même si l'ancienne bibliothèque client n'est plus maintenue, mysqlnd est maintenu :)

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