Accès à la base de données PHP le faites-vous correctement?

Nous avons couvert l'API PDO de PHP à quelques reprises ici sur Nettuts +, mais, en général, ces articles étaient davantage axés sur la théorie et moins sur l'application. Cet article corrigera ça!

Pour le dire clairement, si vous utilisez toujours le vieux PHP mysql API pour se connecter à vos bases de données, lisez la suite!

À la recherche d'un raccourci?

Si vous travaillez avec PHP ou MySQL et avez besoin d'une solution rapide pour une erreur dans votre code, vous pouvez réparer n'importe quelle erreur, rapidement et à moindre coût, par le développeur PHP Araneux sur Envato Studio..


Quoi?

Il est possible que, à ce stade, la seule pensée dans votre esprit soit la suivante: "Qu'est-ce que c'est que le PDO?" C'est l'une des trois API disponibles de PHP pour la connexion à une base de données MySQL. "Trois", vous dites? Oui; beaucoup de gens ne le savent pas, mais il y a trois API différentes pour se connecter:

  • mysql
  • mysqli - MySQL amélioré
  • pdo - Objets de données PHP

Le traditionnel mysql L'API fait certainement le travail et est devenu si populaire en grande partie parce qu'elle rend le processus de récupération de certains enregistrements d'une base de données aussi simple que possible. Par exemple:

/ * * Anti-Pattern * / # Connectez mysql_connect ('localhost', 'nom d'utilisateur', 'mot de passe') ou die ('Connexion impossible:'. Mysql_error ()); # Choisissez une base de données mysql_select_db ('someDatabase') ou die ('impossible de sélectionner la base de données'); # Effectuer une requête dans la base de données $ query = "SELECT * from someTable"; $ result = mysql_query ($ query) ou die ('Échec de la requête:'. mysql_error ()); # Filtrer à travers les lignes et faire écho aux informations souhaitées while ($ row = mysql_fetch_object ($ result)) echo $ row-> name; 

Oui, le code ci-dessus est assez simple, mais il comporte une part importante d'inconvénients..

  • Obsolète Bien qu’elle n’ait pas été officiellement déconseillée - en raison de son utilisation généralisée - en termes de meilleures pratiques et d’éducation, elle pourrait tout aussi bien être:.
  • S'échapper: Le processus qui consiste à échapper les entrées de l'utilisateur est laissé au développeur - beaucoup d'entre eux ne comprennent pas ou ne savent pas comment purifier les données..
  • La flexibilité: L'API n'est pas flexible. le code ci-dessus est fait sur mesure pour travailler avec une base de données MySQL. Et si vous changez?

PDO, ou PHP Data Objects, fournit une API plus puissante qui ne se soucie pas du pilote que vous utilisez; c'est agnostique de base de données. En outre, il offre la possibilité d’utiliser des instructions préparées, ce qui élimine pratiquement tout problème d’injection SQL. Découvrez la gamme de scripts PDO et d'applications disponibles sur Envato Market pour avoir une idée de ce qui est possible..


Comment?

Lorsque je me suis renseigné pour la première fois sur l’API PDO, je dois admettre que c’était un peu intimidant. Ce n’était pas parce que l’API était trop compliquée (ce n’est pas) - c’est que le vieux Myqsl L'API était tellement facile à utiliser!

Ne vous inquiétez pas, cependant; suivez ces étapes simples et vous serez opérationnel en un rien de temps.

Relier

Donc, vous connaissez déjà l’ancien moyen de se connecter à une base de données MySQL:

# Connectez mysql_connect ('localhost', 'nom d'utilisateur', 'mot de passe') ou die ('Impossible de se connecter:'. Mysql_error ());

Avec PDO, nous créons une nouvelle instance de la classe et spécifions le pilote, le nom de la base de données, le nom d'utilisateur et le mot de passe - comme suit:

$ conn = new PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ password);

Ne laissez pas cette longue chaîne vous dérouter; c'est vraiment très simple: nous spécifions le nom du pilote (mysql, dans ce cas), suivi des détails requis (chaîne de connexion) pour la connexion.

Le point positif de cette approche est que si nous souhaitons utiliser une base de données sqlite, nous mettons simplement à jour le DSN, ou "Nom de la source de données", en conséquence; nous ne dépendons pas de MySQL comme nous le faisons lorsque nous utilisons des fonctions telles que mysql_connect.

les erreurs

Mais que se passe-t-il s'il y a une erreur et que nous ne pouvons pas nous connecter à la base de données? Eh bien, enveloppons tout dans un essayer / attraper bloc:

try $ conn = new PDO ('mysql: hôte = localhost; nombase = maBase de données', $ nomutilisateur, $ mot de passe); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION);  catch (PDOException $ e) echo 'ERROR:'. $ e-> getMessage (); 

C'est mieux! Veuillez noter que, par défaut, le mode d'erreur par défaut pour PDO est PDO :: ERRMODE_SILENT. Avec ce paramètre laissé inchangé, vous devrez extraire manuellement les erreurs, après avoir effectué une requête.

echo $ conn-> errorCode (); echo $ conn-> errorInfo ();

Au lieu de cela, un meilleur choix, lors du développement, consiste à mettre à jour ce paramètre sur PDO :: ERRMODE_EXCEPTION, qui déclenchera des exceptions à mesure qu’elles se produisent. De cette façon, toute exception non interceptée arrêtera le script.

Pour référence, les options disponibles sont:

  • PDO :: ERRMODE_SILENT
  • PDO :: ERRMODE_WARNING
  • PDO :: ERRMODE_EXCEPTION

Chercher

À ce stade, nous avons créé une connexion à la base de données. allons chercher des informations. Il existe deux méthodes principales pour accomplir cette tâche: question et exécuter. Nous allons examiner les deux.

Question

/ * * La méthode de requête * Anti-Pattern * / $ name = 'Joe'; # données fournies par l'utilisateur, essayez $ conn = new PDO ('mysql: hôte = localhost; nombase = ma base de données', $ nomutilisateur, $ motdepasse); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ data = $ conn-> query ('SELECT * FROM maTable WHERE name ='. $ conn-> quote ($ name)); foreach ($ data as $ row) print_r ($ row);  catch (PDOException $ e) echo 'ERROR:'. $ e-> getMessage (); 

Bien que cela fonctionne, notez que nous échappons toujours manuellement les données de l'utilisateur avec le AOP :: citation méthode. Pensez à cette méthode comme, plus ou moins, l’équivalent PDO à utiliser mysql_real_escape_string; il échappera et citera la chaîne que vous lui transmettez. Dans certains cas, lorsque vous liez des données fournies par l'utilisateur à une requête SQL, il est vivement recommandé d'utiliser des instructions préparées. Cela dit, si vos requêtes SQL ne dépendent pas des données de formulaire, le question Cette méthode est un choix utile et rend le processus de bouclage des résultats aussi simple qu’un pour chaque déclaration.

Déclarations préparées

/ * * La méthode des instructions préparées * Meilleure pratique * / $ id = 5; try $ conn = new PDO ('mysql: hôte = localhost; nombase = maBase de données', $ nomutilisateur, $ mot de passe); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ conn-> prepare ('SELECT * FROM maTable WHERE id =: id'); $ stmt-> execute (array ('id' => $ id)); while ($ row = $ stmt-> fetch ()) print_r ($ row);  catch (PDOException $ e) echo 'ERROR:'. $ e-> getMessage (); 

Dans cet exemple, nous utilisons le préparer méthode pour, littéralement, préparer la requête, avant que les données de l'utilisateur aient été attachées. Avec cette technique, l'injection SQL est pratiquement impossible, car les données ne sont jamais insérées dans la requête SQL elle-même. Notez que nous utilisons plutôt des paramètres nommés (: id) pour spécifier des espaces réservés.

Alternativement, vous pouvez utiliser ? paramètres, cependant, il en fait une expérience moins lisible. Stick avec des paramètres nommés.

Ensuite, nous exécutons la requête en passant un tableau contenant les données devant être liées à ces espaces réservés..

$ stmt-> execute (array ('id' => $ id));

Une autre solution, mais parfaitement acceptable, consisterait à utiliser le bindParam méthode, comme si:

$ stmt-> bindParam (': id', $ id, PDO :: PARAM_INT); $ stmt-> execute ();

Spécifier le résultat

Après avoir appelé le exécuter méthode, il existe différentes manières de recevoir les données: un tableau (valeur par défaut), un objet, etc. Dans l'exemple ci-dessus, la réponse par défaut est utilisée: PDO :: FETCH_ASSOC; ceci peut facilement être annulé, cependant, si nécessaire:

while ($ row = $ stmt-> fetch (PDO :: FETCH_OBJ)) print_r ($ row); 

Maintenant, nous avons spécifié que nous souhaitons interagir avec le jeu de résultats d'une manière plus orientée objet. Les choix disponibles incluent, sans toutefois s'y limiter:

  • PDO :: FETCH_ASSOC: Retourne un tableau.
  • PDO :: FETCH_BOTH: Retourne un tableau, indexé par nom de colonne et indexé par 0.
  • PDO :: FETCH_BOUND: Renvoie VRAI et affecte les valeurs des colonnes de votre jeu de résultats aux variables PHP auxquelles elles étaient liées..
  • PDO :: FETCH_CLASS: Renvoie une nouvelle instance de la classe spécifiée.
  • PDO :: FETCH_OBJ: Renvoie un objet anonyme, avec des noms de propriétés correspondant aux colonnes..

Un problème avec le code ci-dessus est que nous ne fournissons aucun retour si aucun résultat n'est renvoyé. Réglons cela:

$ stmt-> execute (array ('id' => $ id)); # Obtenir un tableau contenant toutes les lignes de résultat $ result = $ stmt-> fetchAll (); # Si une ou plusieurs lignes ont été retournées… if (count ($ result)) foreach ($ result as $ row) print_r ($ row);  else echo "Aucune ligne retournée."; 

À ce stade, notre code complet devrait ressembler à ceci:

 $ id = 5; try $ conn = new PDO ('mysql: hôte = localhost; nombase = base de données', $ nomutilisateur, $ mot de passe); $ stmt = $ conn-> prepare ('SELECT * FROM maTable WHERE id =: id'); $ stmt-> execute (array ('id' => $ id)); $ resultat = $ stmt-> fetchAll (); if (count ($ result)) foreach ($ result as $ row) print_r ($ row);  else echo "Aucune ligne retournée.";  catch (PDOException $ e) echo 'ERROR:'. $ e-> getMessage (); 

Exécutions multiples

L’extension PDO devient particulièrement puissante lorsqu’une même requête SQL est exécutée plusieurs fois, mais avec des paramètres différents.

try $ conn = new PDO ('mysql: hôte = localhost; nombase = base de données', $ nomutilisateur, $ mot de passe); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); # Prépare la requête UNE FOIS $ stmt = $ conn-> prepare ('INSERT INTO someTable VALUES (: name)'); $ stmt-> bindParam (': name', $ name); # Première insertion $ name = 'Keith'; $ stmt-> execute (); # Deuxième insertion $ name = 'Steven'; $ stmt-> execute ();  catch (PDOException $ e) echo $ e-> getMessage (); 

Une fois la requête préparée, elle peut être exécutée plusieurs fois, avec des paramètres différents. Le code ci-dessus insère deux lignes dans la base de données: l’une portant le nom "Kevin" et l’autre "Steven".


CRUD

Maintenant que le processus de base est en place, passons rapidement en revue les différentes tâches de CRUD. Comme vous le constaterez, le code requis pour chacun est pratiquement identique.

Créer (insérer)

try $ pdo = new PDO ('mysql: hôte = localhost; nombase = base de données', $ nomutilisateur, $ mot de passe); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('INSERT INTO someTable VALUES (: name)'); $ stmt-> execute (array (': name' => 'Justin Bieber')); Nombre de lignes affectées? echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Erreur:'. $ e-> getMessage ();

Mettre à jour

$ id = 5; $ name = "Joe le plombier"; try $ pdo = new PDO ('mysql: hôte = localhost; nombase = base de données', $ nomutilisateur, $ mot de passe); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('UPDATE unTable SET nom =: nom WHERE id =: id'); $ stmt-> execute (array (': id' => $ id, ': name' => $ name)); echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Erreur:'. $ e-> getMessage (); 

Effacer

$ id = 5; // À partir d'un formulaire ou de quelque chose de similaire, essayez $ pdo = new PDO ('mysql: host = localhost; nombase = base_de_données', $ nomutilisateur, $ mot_passe); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('DELETE FROM someTable WHERE id =: id'); $ stmt-> bindParam (': id', $ id); // cette fois, nous allons utiliser la méthode bindParam $ stmt-> execute (); echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Erreur:'. $ e-> getMessage (); 

Cartographie d'objets

L'un des aspects les plus intéressants de PDO (mysqli, également) est qu'il nous permet de mapper les résultats de la requête sur une instance de classe ou un objet. Voici un exemple:

utilisateur de classe public $ first_name; public $ last_name; fonction publique full_name () return $ this-> first_name. ". $ this-> last_name; try $ pdo = new PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ resultat = $ pdo-> query ('SELECT * FROM une table'); # Associe les résultats à l'objet $ result-> setFetchMode (PDO :: FETCH_CLASS, 'User'); while ($ user = $ result-> fetch ()) # Appelez notre méthode personnalisée nom_complet echo $ utilisateur-> nom_complet (); catch (PDOException $ e) echo 'Erreur:'. e-> getMessage ();

Pensées finales

En bout de ligne: si vous utilisez toujours ce vieux mysql API pour la connexion à vos bases de données, arrêtez. Même s’il n’est pas encore obsolète, en termes d’éducation et de documentation, il pourrait tout aussi bien l’être. Votre code sera nettement plus sécurisé et simplifié si vous adoptez l'extension PDO. Vérifiez les articles AOP sur Envato Market pour voir ce que vous pouvez faire..