J'ai récemment eu l'occasion occasionnelle de travailler avec plusieurs anciennes applications PHP. J'ai remarqué quelques anti-schémas communs qui devaient être corrigés. Cet article ne traite pas de la façon de réécrire une ancienne application PHP pour <insérer le nom du merveilleux framework ici>, mais comment la rendre plus facile à maintenir et moins de tracas à utiliser.
Antipattern # 1: les informations d'identification dans le code
C'est le plus courant des pires modèles que j'ai rencontrés. Dans de nombreux projets, le code versionné est codé en dur avec des informations importantes, telles que les noms et les mots de passe pour accéder à la base de données. C'est évidemment une mauvaise pratique, car elle ne permet pas de créer des environnements locaux, car le code est lié à un environnement spécifique. De plus, toute personne ayant accès au code peut voir les informations d'identification généralement appropriées pour l'environnement de production.
Pour résoudre ce problème, je préfère une méthode qui fonctionne pour n'importe quelle application: installez le package phpdotenv , qui vous permet de créer un fichier d'environnement et d'accéder aux variables à l'aide de super variables d'environnement.
Créons deux fichiers:
.env.example
un qui sera versionné et servira de modèle pour le fichier.env
, qui contiendra les informations d'identification. Le fichier n'est .env
pas versionné, alors ajoutez-le à .gitignore
. Ceci est bien expliqué dans la documentation officielle .
Votre fichier
.env.example
listera les informations d'identification:
DB_HOST=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
Et les données elles-mêmes seront dans le fichier
.env
:
DB_HOST=localhost
DB_DATABASE=mydb
DB_USERNAME=root
DB_PASSWORD=root
Dans un fichier normal, chargez
.env
:
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
Peut ensuite s'appliquer aux données comptables en utilisant, par exemple
$_ENV['DB_HOST']
.
Il n'est pas recommandé d'utiliser le package en fonctionnement "tel quel", pour cela il vaut mieux:
- Injectez des variables d'environnement dans l'environnement d'exécution de votre conteneur si vous avez un déploiement basé sur Docker, ou dans la configuration HTTP côté serveur si possible.
- Mettez en cache les variables d'environnement pour éviter la surcharge de lecture de .env à chaque demande. C'est ainsi que fait Laravel .
Les fichiers d'identification peuvent être supprimés de l'historique Git .
Antipattern # 2: n'utilisez pas Composer
Auparavant, il était très populaire d'avoir un dossier lib avec de grandes bibliothèques comme PHPMailer. Cela doit être évité de toutes les manières possibles en ce qui concerne la gestion des versions, donc ces dépendances doivent être gérées avec Composer . Ensuite, il vous sera très facile de voir quelle version du package est utilisée et de la mettre à jour si nécessaire.
Alors installez Composer et utilisez-le pour gérer.
Antipattern # 3: pas d'environnement local
La plupart des applications avec lesquelles j'ai travaillé n'avaient qu'un seul environnement: la production.
Mais en vous débarrassant de l'anti-pattern # 1, vous pouvez facilement personnaliser votre environnement local. Certaines de vos configurations ont peut-être été codées en dur, telles que les chemins de démarrage, mais vous pouvez maintenant la déplacer vers
.env
.
J'utilise Docker pour créer des environnements locaux. Cela fonctionne particulièrement bien pour les projets plus anciens car ils utilisent souvent des versions plus anciennes de PHP que vous ne voulez pas ou ne pouvez pas installer.
Vous pouvez utiliser un service comme PHPDocker ou utiliser un petit fichier
docker-compose.yml
.
Antipattern # 4: n'utilisez pas le dossier public
Il s'est avéré que la plupart de ces anciens projets sont accessibles à partir de leurs dossiers racine. Autrement dit, tout fichier à la racine sera disponible pour la lecture publique. Ceci est particulièrement grave lorsque des attaquants (comme un script pour enfants) tentent d'accéder directement aux fichiers inclus, car vous ne pourrez peut-être pas déterminer une sortie si le script accède directement à tous vos fichiers inclus.
De toute évidence, cette situation est incompatible avec l'utilisation de
.env
ou Composer, car ouvrir le dossier du fournisseur est une mauvaise idée . Oui, il existe quelques astuces pour faire cela; mais si possible, déplacez tous les fichiers PHP ouverts aux clients dans un dossier Public
et modifiez la configuration du serveur afin que ce dossier devienne le dossier racine de votre application.
Je fais généralement ceci:
- Créez un dossier
docker
pour les fichiers liés à Docker (configuration Nginx, PHP Dockerfile, etc.). - Je crée un dossier
app
dans lequel je stocke la logique métier (services, classes, etc.). - Je crée un dossier
public
dans lequel je stocke des scripts PHP et des ressources (JS / CSS) ouverts aux clients. Il s'agit du dossier racine de l'application du point de vue des clients. - Je crée des fichiers
.env
et.env.example
.
Antipattern # 5: problèmes de sécurité énormes
Les applications PHP, en particulier les plus anciennes qui n'utilisent pas de framework, souffrent souvent de problèmes de sécurité énormes:
- En raison du manque d'échappatoire des paramètres dans la requête, il existe un risque d'injection SQL. Pour les éviter, utilisez PDO!
- Il existe un risque d'injection XSS en raison de l'affichage de données utilisateur non échappées. Utilisez htmlspecialchars pour les éviter.
- … . , , , .
- - CSRF-. Anti-CSRF, .
- Mauvais cryptage du mot de passe. J'ai vu de nombreux projets utiliser encore SHA-1 et même MD5 pour le hachage de mot de passe. PHP 5.5 prêt à l'emploi a un bon support pour BCrypt, c'est dommage de ne pas l'utiliser. Pour transférer confortablement les mots de passe, je préfère mettre à jour les hachages dans la base de données lorsque les utilisateurs se connectent. L'essentiel est de s'assurer que la colonne
password
est suffisamment longue pour contenir les mots de passe BCrypt, VARCHAR (255) convient. Voici le pseudo-code pour le rendre plus clair:
<?php // : $ // : if (strpos($oldPasswordHash, '$') !== 0 && hash_equals($oldPasswordHash, sha1($clearPasswordInput))) { $newPasswordHash = password_hash($clearPasswordInput, PASSWORD_DEFAULT); // password // : } // if (password_verify($clearPasswordInput, $currentPasswordHash)) { // : } // :
Antipattern # 6: aucun test
Ceci est très courant dans les anciennes applications. Il n'est guère possible de commencer à écrire des tests unitaires pour l'ensemble de l'application, vous pouvez donc écrire des tests fonctionnels.
Ce sont des tests de haut niveau pour vous aider à vous assurer que la refactorisation ultérieure de votre application ne la casse pas. Les tests peuvent être simples, par exemple, nous lançons le navigateur et entrons dans l'application, puis attendons le code HTTP sur la réussite de l'opération et / ou le message correspondant sur la dernière page. Pour les tests, vous pouvez utiliser PHPUnit, ou Cypress , ou codeception .
Antipattern # 7: mauvaise gestion des erreurs
Si (ou très probablement quand) quelque chose se brise, vous devez le savoir rapidement. Mais de nombreuses applications plus anciennes ne gèrent pas bien les erreurs, s'appuyant sur PHP pour la clémence.
Vous devez être capable de détecter et d'enregistrer autant d'erreurs que possible afin de les corriger. Il y a de bons articles sur ce sujet .
En outre, il vous sera plus facile de trouver des endroits où des erreurs se produisent si le système lève des exceptions spécifiques.
Antipattern # 8: variables globales
Je pensais que je ne les reverrais jamais avant de commencer à travailler sur d'anciens projets. Les variables globales rendent la lecture et la compréhension du comportement du code imprévisibles. Bref, c'est mal .
Mieux vaut plutôt utiliser l' injection de dépendances , car cela vous permet de contrôler quels éléments sont utilisés et où. Par exemple, le package Pimple a bien fonctionné .
Quoi d'autre à améliorer?
En fonction du sort de l'application ou du budget, vous pouvez prendre plusieurs mesures supplémentaires pour améliorer votre projet.
Tout d'abord, si l'application s'exécute sur une ancienne version de PHP (inférieure à 7), essayez de la mettre à jour. Le plus souvent, cela ne pose pas de gros problèmes, et surtout, il faudra la plupart du temps pour se débarrasser des appels
mysql_ calls
, le cas échéant. Pour résoudre rapidement cela, vous pouvez utiliser une bibliothèque similaire , mais il est préférable de réécrire toutes les requêtes de PDO afin que tous les paramètres soient échappés en même temps.
Si l'application n'utilise pas le modèle MVC, c'est-à-dire que la logique métier et les modèles sont séparés, il est temps d'ajouter une bibliothèque de modèles (je sais que PHP est un langage de modèles, mais les bibliothèques modernes sont beaucoup plus pratiques), par exemple Smarty, Twig ou Blade.
Enfin, sur le long terme, il est préférable de réécrire votre application dans un framework PHP moderne comme Laravel ou Symfony. Vous aurez tous les outils dont vous avez besoin pour un développement PHP sûr et intelligent. Si l'application est volumineuse, je recommande d'utiliser le modèle d' étranglement pour éviter la réécriture du big bang , qui peut (et se terminera probablement) mal. Par conséquent, vous pouvez migrer vers le nouveau système les parties du code sur lesquelles vous travaillez actuellement, en gardant les anciennes parties de travail intactes jusqu'à ce qu'elles les atteignent.
Il s'agit d'une approche efficace qui vous permet de créer un environnement PHP moderne pour votre travail quotidien, sans geler les fonctionnalités pendant des semaines ou des mois, selon le projet.