TUTORIELS 
10 erreurs à ne pas commettre en Php (Seconde Partie)
Cinq nouveaux pièges dans lesquels il est facile de tomber: négligences de sécurité, accès sous-optimaux aux bases de données... Autant de problèmes en puissance.  (20 novembre 2001)
 

Dans la première partie de ce tutoriel dédié aux erreurs à ne pas commettre en Php, nous recensions cinq comportements à éviter :
- 1) Réinventer la roue
- 2) Oublier la convention de nommage
- 3) Ne pas commenter son code
- 4) Utiliser " printf " à toute occasion
- 5) Ne pas se limiter en variables temporaires

Nous rajoutons aujourd'hui cinq autres points clefs dont il faut se soucier afin de garder son code Php le plus propre et efficace possible.

Tutoriel mis à jour le 21/11/2001.

6) Négliger la sécurité de son application

La sécurité est un vaste domaine et une affaire de spécialiste. Etre exhaustif est donc hors de portée de cet article. Rassurez-vous, tout n'est pas perdu pour autant.
En effet, entre tenter d'obtenir un système fiable à 100% et permettre à son site d'éviter certains écueils connus, il y a une différence de taille. Nous évoquerons ici quelques-uns de ces dangers, et les moyens de les éviter.

"Prévoir le pire", voilà en résumé la conduite à adopter lors de la conception d'une application, écrite en Php ou non d'ailleurs.
Bien sûr, le niveau de sécurité requis et les conséquences d'un piratage ou d'une mauvaise action, parfois involontaire de la part d'un internaute, n'ont pas les mêmes conséquences sur un site de commerce électronique ou sur un site personnel. Toutefois, optimiser le site dont on s'occupe, personnel ou non, est une bonne chose.

Voyons où se situent certaines failles et comment y remédier.

Certaines étapes d'apparence anodine telle que l'inscription d'un internaute sur votre site, peuvent pourtant apporter leur lot de problèmes.
Si vous souhaitez par exemple recueillir l'adresse email d'un internaute avant de le laisser s'inscrire sur votre site, il se peut que celui-ci soit tenté de saisir une adresse invalide.
Que faire alors ? Vous pouvez toujours traiter la chaîne de caractères reçue grâce aux expressions régulières mais est-ce vraiment utile ? Au mieux vous détecterez que la syntaxe de l'email n'est pas correcte (pas de "@", pas de ".", etc) mais alors comment réagir face à un email syntaxiquement valide tel que :

toto@site-inconnu.com

Il reste à vérifier si le serveur existe ("socket validation"). Si celui-ci est temporairement en panne, vous rejettez l'email, pas de chance pour l'internaute...
Un internaute de perdu, dix de retrouvés pensez-vous ? Sans doute pas mais le problème n'est pas là. Il existe un cas plus vicieux encore :

nom.connu@site-connu.com

Le site existe, le compte "nom.connu" aussi... Bien sûr, ça n'est pas l'email de l'internaute, mais il est valide. Non, la seule solution vraiment fiable est de rallonger le processus d'inscription en obligeant l'internaute a cliquer sur un lien contenu dans un email que vous lui avez préalablement envoyé. Dans ce cas vous êtes sûr que celui-ci dispose d'un email et que c'est le sien (passons sur la mailbox familiale ou le compte piraté).
Rien ne vous dit par contre que ce n'est pas une de ces adresse "gratuites" créee pour l'occasion, mais qu'importe, vous avez votre email.

Convenons-en, ces problèmes d'emails ne mettent pas en péril la sécurité de votre application. A la rigueur quelques "mailer-daemon" vous reviennent après l'envoi de votre newsletter, mais c'est tout.
Leur "intérêt" principal est en fait ailleurs : vous mettre la puce à l'oreille quant à la fiabilité du contenu renseigné par l'internaute.

Celui-ci peut en effet se revéler être plus dramatique qu'un email invalide.
Lorsque vous récupérez une variable renseignée par un internaute, vous pouvez utiliser la commande "escapeshellcmd" afin "d'échapper" tous les caractères susceptibles d'activer une commande Shell.
En d'autres termes cette commande place le caractère "\" devant chaque caractère potentiellement "dangereux" (#, &, ´, ', \, ", |, *, etc...). Ce caractère n'est en effet pas ajouté automatiquement lorsque les chaînes de caractères sont stockées par Php, cela dépend notamment de l'utilisation de la variable "magic_quotes". Un "phpinfo()" sur votre site vous indiquera si elle est activée ou pas.

Attention : si le Php est capable de stocker certaines données comprenant des caractères spéciaux, il n'en est pas forcément de même pour la base de données. L'utilisation de la fonction "addslahes" peut alors aider.

Enfin, quelques règles simples sont à appliquer :

Ne pas transmettre de mot de passe en clair par URL ou formulaire.
Ceci est aussi valable pour des prix, ou d'autres informations sensibles. Afin de limiter les problèmes de piratage (soumission d'un prix issu d'un autre domaine par exemple), stockez ce type d'informations dans une base de données, effectuez les calculs du côté serveur (JavaScript ne suffit pas) !
De même, si l'utilisation de Javascript est souhaitable à des fins de vérification de formulaire (et éviter ainsi à l'internaute d'attendre la réponse du serveur), il faut systématiquement doubler tous les tests effectués du côté client par des traitements au moins équivalents du côté serveur. N'oubliez pas que JavaScript peut se désactiver...

D'autres éléments à prendre en compte au niveau sécurité se trouvent sur le site officiel de Php. Un autre article très intéressant est lui aussi à lire sur Phpbuilder.com.

7) "Copier / Coller" sans comprendre

A quoi bon s'appliquer à rendre son code Php le plus fiable et le plus propre possible si c'est pour inclure du code que vous ne maîtrisez pas dans votre application ?

Télécharger des scripts sur Internet doit d'abord être un moyen de comprendre comment d'autres programmeurs ont résolu votre problème. Une fois le travail de compréhension effectué, les modifications éventuellement apportées, alors seulement vous pouvez inclure le code (Open) source dans le vôtre.

Méfiez-vous des bouts de script qu'on croise parfois dans les forums de discussion, certains sont de vrais joyaux et sont fiables, d'autres ne vous apporteront peut-être que des ennuis !
Dans tous les cas il faut le comprendre, ne serait-ce que pour pouvoir maintenir par la suite votre application.

Enfin, "patcher" son code sans réellement refondre le script téléchargé dans son application casse la logique qui était celle de votre script. Cela ralentit votre application Php et la rend moins lisible. Qu'en est-il en effet des conventions de nommage adoptées par l'auteur des lignes de code que vous souhaitez réutiliser ? Si vous n'y prenez garde vous risquez un conflit de variable qui risque de ne pas être évident à détecter.

Bref, s'inspirer de la communauté et ne pas réinventer la roue, oui, mais à condition de comprendre comment elle tourne...

8) Ne pas gérer les erreurs éventuelles

Nous parlions tout à l'heure de sécurité, voici un type d'erreur qui peut conduire à des problèmes dans ce domaine.

Si l'erreur est parfois imprévisible, ne pensez pas qu'il soit pour autant impossible de l'intercepter. S'il est en effet difficile de prévoir tout ce qui peut se passer sur un site, vous pouvez néanmoins vérifier que les résultats que vous obtenez sont cohérents et correspondent à vos attentes.

Si vous ne faites rien, vous exposez vos utilisateurs à des messages d'erreurs déjà parfois difficilement compréhensibles par un informaticien... De plus, ces erreurs de script Php (parfois générés par la base de données) peuvent renseigner un pirate éventuel. Chaque bribe d'information récupérée peut constituer un point de départ pour un pirate : un message de debug que vous laissez affiché en cas de plantage, le type du SGBD, mieux encore le nom d'une table ou de la base...
Aussi, ces messages ne doivent pas apparaître sans un contrôle de votre part, c'est l'objectif de la gestion d'erreur ou "error handling".

Vous pouvez alors profiter des possibilités offertes par Php dans ce domaine (voir notre tutoriel) et indiquer à Php de remonter le maximum de "warning" possibles, un peu comme si vous descendiez la tolérance d'un compilateur. Pour cela, donnez la valeur "E_ALL" au "reporting level".

Afin de remonter le maximum d'erreurs, plusieurs éléments sont à tester : les connections aux bases de données, les valeurs retournées par les fonctions... Exemple :

$messerreur = "Veuillez nous excuser pour cet incident.";

$req="select nom, prenom from membres where id = 2";
$idreq=mysql_query($req,$idconnect);
if ($idreq == 0)
{
     print "Erreur selection nom, prenom.<br>";
     echo("$messerreur<br>");
     mysql_close($idconnect);
     exit;
}

Si votre requête est invalide, le script s'arrête ici (afin d'éviter un plantage certain un peu plus loin) et affiche un message d'erreur particulier "sélection nom, prénom" avec en plus un message plus générique défini dans une bibliothèque par exemple (ici $messerreur).

9) Ne pas faire relire son code

Sans pour autant adopter des méthodes dignes de "l'eXtreme programming", faire relire votre code par un oeil extérieur est une très bonne chose. Qui n'a jamais passé de (trop) longues minutes, heures (?) autour de quelques lignes de code qui ne fonctionnaient pas, pour s'apercevoir au final qu'il ne s'agissait que d'une grossière erreur ?
Imaginez le temps gagné si vous aviez appelé un collègue à la rescousse...

Faire relire son code par quelqu'un qui n'a pas été impliqué dans son processus de production permet d'obtenir une toute autre vue que la sienne sur l'ensemble de la chose. Des bugs peuvent ainsi être décelés bien plus rapidement que si c'est vous qui vous étiez relu. C'est aussi l'occasion de revoir sa documentation si celle-ci est jugée peu lisible.

10) Négliger les bases de données

Optimiser son code Php ne sert à rien si c'est pour saccager la partie "bases de données". Deux erreurs à éviter :

- La mauvaise utilisation de certaines fonctions d'accès aux bases de données
- Reporter sur le Php des traitements dont SQL peut s'acquitter.

Lister toutes les mauvaises utilisations possibles des fonctions Php dédiées aux bases de données n'a pas de sens, alors un conseil : lorsque vous avez besoin d'une de ces fonctions, choisissez celle qui parmi la liste disponible (ici MySQL) est celle qui correspond le mieux à votre cas. Inutile en effet de prendre un canon pour tuer une mouche.

Par exemple, n'utilisez pas "mysql_fetch_row" pour tester uniquement si votre requête a renvoyé des tuples mais plutôt "mysql_nums_row" qui est conçu pour cette tâche (si votre SGBD la supporte). Trouvez la fonction minimale pour effectuer ce dont vous avez besoin.

Idem pour stocker les données issues d'une requête, n'inventez pas de système complexe de votre cru alors que "mysql_fetch_array" vous propose par exemple un tableau associatif très pratique :

$req="select nom, prenom from membres where id = 2";
$idreq=mysql_query($req,$idconnect);
// On passe sur les tests de validité de la requête ici...
// La requête ne ramène qu'un seul tuple.

$row=mysql_fetch_array($idreq)
$nom_user = $row[nom];
$prenom_user = $row[prenom];

C'est lisible, court, que demander de plus ?

Passons au SQL... Maîtriser ce langage, tout du moins ses bases, est très important. La rapidité de votre site en dépend.
Véritable cauchemar des hébergeurs mutualisés, la clause " SELECT * " appliquée sur une large table est une aberration lorsque l'on souhaite ne récupérer que quelques champs.
Rappatriez uniquement ce dont vous avez besoin !
Indiquez les champs, un par un, que vous souhaitez ramener.
Admettons que votre table "membres" ne comprenne que deux champs aujourd'hui : Nom et prénom. Vous souhaitez récupérer les deux champs. Un "SELECT * " ne fera effectivement pas de dégât... pour cette fois-ci. Et si demain la structure de votre table change pour s'enrichir d'une dizaine de champ ?
Si vous ne modifiez pas votre SELECT, que vous auriez pu écrire correctement dès le départ, ce sont dix champs de trop que vous aller ramener...

De manière générale, le "SELECT * " est à proscrire, c'est une bonne habitude à prendre que de nommer, un par un, les champs dont vous avez besoin.

De même, utilisez la clause "WHERE" pour réduire encore le nombre de tuples à rappatrier de la base. Inutile de d'abord tout ramener et de faire le tri en Php, par exemple dans la boucle "while" de l'exemple ci-dessus... Utiliser des "if" pour identifier un enregistrement spécifique n'a pas lieu d'être quand on peut le ramener, seul, grâce à une clause WHERE.

Intéressez-vous à SQL si ça n'est pas encore le cas, il existe plusieurs tutoriels sur le web dédié à ce langage, en voici un où vous pouvez tester vos requêtes.

Ainsi s'achève notre série d'erreurs à ne pas commettre. Certains principes débordaient du seul langage Php mais il était bon de les rappeler. Cette liste d'erreurs n'est hélas pas exhaustive, il en existe d'autres, à vous de vous poser les bonnes questions lors de la conception de vos scripts futurs, discutez-en avec la communauté Php francophone, qui par chance est très active, et échangez vos expériences, c'est comme cela que l'on progresse le plus rapidement.

 
[ Arnaud GadalJDNet
 
Accueil | Haut de page