PHP : la bonne pratique

Apprendre les bonnes pratiques de programmation en PHP


précédentsommairesuivant

VII. Bases de données

Votre code PHP va souvent faire appel aux bases de données pour préserver l'information. Vous avez un certain nombre d'options pour vous connecter et interagir avec votre base de données. L'option recommandée avant PHP 5.1.0 était d'utiliser les pilotes natifs tels que mysql, mysqli, pgsql, etc.

Les pilotes natifs sont géniaux si vous n'utilisez qu'un seul type de bases de données dans votre application, mais si, par exemple, vous utilisez MySQL et un peu de MSSQL ou vous avez besoin de vous connecter à une base Oracle alors vous ne pourrez utiliser les mêmes pilotes. Vous aurez besoin d'apprendre une nouvelle API pour chaque type de BDD — ce qui peut devenir lourd.

VII-A. Extension MySQL

L'extension mysql pour PHP est aujourd'hui au point mort et est officiellement dépréciée depuis PHP 5.5.0 ce qui signifie qu'elle sera retirée dans les prochaines versions. Si vous utilisez n'importe quelles fonctions commençant par mysql_* (comme mysql_connect()) dans votre application, alors cela donnera des erreurs dans votre code. Vous serez donc obligé de faire la transition vers mysqli ou PDO.

Si vous venez de commencer votre projet, alors n'utilisez surtout pas l'extension mysql , mais préférez mysqli ou PDO

VII-B. PDO

Le PDO est une couche d'abstraction pour se connecter à une base de données — intégrée à PHP depuis la 5.1.0 — qui fournit une interface commune pour communiquer avec différentes bases de données. Le PDO ne va pas traduire vos requêtes SQL ou émuler les fonctionnalités manquantes, il ne gère que la connexion entre différents types de bases de données avec la même API.

Plus important encore, le PDO vous permet d'injecter en toute sécurité des entrées étrangères (par ex., les identifiants) dans vos requêtes SQL sans que vous ayez à vous soucier des attaques par injection SQL. Cela est rendu possible grâce à l'utilisation des fonctions de PDO et des paramètres liés.

Supposons qu'un script PHP reçoive un identifiant numérique en tant que paramètre d'entrée. Cet ID devrait être utilisé pour récupérer les enregistrements d'un utilisateur dans la base de données. Voici la mauvaise façon de s'y prendre :

 
Sélectionnez
1.
2.
3.
<?php
$pdo = new PDO('sqlite:users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NON!

Ce code est mauvais. Vous insérez un paramètre en brut directement dans une requête SQL. C'est la porte ouverte pour le piratage comme l'injection SQL. Imaginez un instant que si un pirate envoie un paramètre id en invoquant l'URL http://domain.com/?id=1%3BDELETE+FROM+users. Cela va définir la variable $_GET['id'] à 1;DELETE FROM users ce qui va effacer l'ensemble de vos utilisateurs ! Au lieu de faire ça, vous devriez nettoyer les entrées en utilisant la liaison des paramètres avec PDO.

 
Sélectionnez
1.
2.
3.
4.
5.
<?php
$pdo = new PDO('sqlite:users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); // <-- Nettoyé automatiquement par PDO
$stmt->execute();

Voici le code correct. Il utilise un paramètre lié à une expression PDO. Cela « échappe » les entrées étrangères avant qu'elles ne soient introduites à la base de données ce qui empêche les attaques potentielles d'injection SQL.

En savoir plus sur PDO

Vous devriez savoir que les connexions à la base de données utilisent pas mal de ressources et il arrivait souvent que les ressources finissent par tarir si les connexions n'étaient pas implicitement fermées, cependant c'était plus souvent le cas dans les autres langages. En utilisant PDO, vous pouvez implicitement fermer la connexion en détruisant l'objet et en vous assurant que toutes les références à cet objet ont été supprimées, c'est-à-dire, mise à NULL. Si vous ne le faites pas explicitement, PHP va automatiquement fermer la connexion quand votre script s'arrêtera - à moins bien sûr, que vous n'utilisiez une connexion persistante.

En savoir plus sur les connexions avec PDO

VII-C. Couches d'abstractions

Beaucoup de frameworks fournissent leur propre couche d'abstraction qui peut être ou non basée sur PDO. Cette couche va souvent émuler les fonctionnalités d'une base de données qui seraient manquantes dans une autre base en enveloppant vos requêtes dans des méthodes PHP vous donnant ainsi une réelle abstraction avec la base de données. Cela engendre évidemment un léger surplus, mais si vous voulez développer une application portable ayant besoin de communiquer avec MySQL, PostgreSQL et SQLite alors ce petit surplus en vaudra la peine par souci de propreté et de maintenance du code.

Plusieurs couches d'abstractions ont été construites en utilisant les standards d'espace de noms PSR-0 ou PSR-4, ils peuvent donc être installés dans n'importe quelle application qui vous plaira :

VII-D. Interagir avec les bases de données

Quand les développeurs commencent à utiliser PHP, ils finissent souvent par mélanger le code métier avec celui gérant la base de données et l'affichage ce qui donne quelque chose de ce genre-là :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
<ul>
<?php
foreach ($db->query('SELECT * FROM table') as $row) {
    echo "<li>".$row['field1']." - ".$row['field1']."</li>";
}
</ul>

Ceci est une mauvaise pratique pour toutes sortes de raisons, principalement dues au fait qu'il est plus difficile à déboguer, à lire et pour réaliser des tests.

Bien qu'il existe un certain nombre de solutions pour pallier ce problème comme l'utilisation de la POO ou bien la programmation fonctionnelle, les parties logiques de votre code doivent être clairement délimitées.

Considérez l'exemple suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
<?php
function getAllSomethings($db) {
    return $db->query('SELECT * FROM table');
}

foreach (getAllFoos() as $row) {
    echo "<li>".$row['field1']." - ".$row['field1']."</li>"; // MAUVAIS!!
}

C'est un bon début. La séparation entre l'interaction avec la base de données et l'affichage est déjà bien distincte.

Créez une classe où vous placerez les méthodes de votre code métier (votre « modèle »). Puis créez un fichier .php qui contient la logique d'affichage (votre « vue ») ce qui revient grosso modo à utiliser le pattern MVC - un modèle d'architecture très courant dans la plupart des frameworks.

foo.php

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<?php

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

// Rendre votre modèle accessible
include 'models/FooModel.php';

// Création d'une instance
$fooList = new FooModel($db);

// Affichage du résultat
include 'views/foo-list.php';

models/FooModel.php

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<?php
class Foo()
{
 protected $db;

 public function __construct(PDO $db)
 {
 $this->db = $db;
 }

 public function getAllFoos() {
 return $this->db->query('SELECT * FROM table');
 }
}

views/foo-list.php

 
Sélectionnez
1.
2.
3.
<? foreach ($fooList as $row): ?>
    <?= $row['field1'] ?> - <?= $row['field1'] ?>
<? endforeach ?>

C'est l'essentiel de ce que font les frameworks de façon plus manuelle. Vous n'avez pas forcément besoin de l'utiliser constamment, mais mélanger la présentation et la logique métier peut être un réel casse-tête si vous devez ensuite utiliser les tests unitaires dans votre application.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Licence Creative Commons
Le contenu de cet article est rédigé par Josh Lockhart et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2017 Developpez.com.