php-experts.org - développement php et internet » php https://www.php-experts.org Ressources sur le développement internet, PHP/MySQL, Ajax, marketing online, référencement... Sat, 19 Jun 2010 14:23:03 +0000 http://wordpress.org/?v=2.9.2 en hourly 1 Le tri bulle, ou tri par propagation https://www.php-experts.org/developpement-web/algoritmes/le-tri-bulle-ou-tri-par-propagation-382 https://www.php-experts.org/developpement-web/algoritmes/le-tri-bulle-ou-tri-par-propagation-382#comments Thu, 29 Oct 2009 13:09:14 +0000 Didier https://www.php-experts.org/?p=382 (en anglais: bubble sort)

Le tri bulle est un très bon algo au point de vue didactique mais mauvais en termes mathématiques (complexité trop grande). Son but est de trier une liste de valeurs pour la renvoyer en ordre croissant. Pour cela, l’algo parcours les éléments de la liste deux par deux, et les classe en ordre croissant (il les permute si le 2e élément est le plus petit). Une fois la liste finie, le tri-bulle recommence. Lorsqu’un parcours a été fait entièrement sans avoir besoin de faire une permutation, le tri est fini.

Attention, le tri-bulle n’est que très rarement utilisé lorsqu’on a besoin d’opérations de tri, car il n’est pas très performant.
Cet article est le premier d’une série consacrée aux algorithmes connus et utiles, et est à prendre comme une “introduction” à l’algorithmique.

Le code du tri-bulle en PHP

  1. function bubblesort(&$liste) {
  2.     $nbItems = count($liste);
  3.     $permutation = true;
  4.     $nbPermutations = 0;
  5. // on continue tant qu’on a eu à faire des permutations…
  6.     while($permutation == true) {
  7.         $permutation = false;
  8.         for($i=0;$i<$nbItems-1;$i++) {
  9.             // si l’élément de gauche est le plus grand,
  10.             if ($liste[$i] > $liste[$i+1]) {
  11.                 // on échange la place des éléments
  12.                 $temp = $liste[$i+1];
  13.                 $liste[$i+1] = $liste[$i];
  14.                 $liste[$i] = $temp;
  15.                 $permutation = true;
  16.                 $nbPermutations++;
  17.             }
  18.         }
  19.         print_r($liste);
  20.     }
  21.     return array(‘nbpermutations’=>$nbPermutations);
  22. }
  23.  
  24. $liste = array(4,9,13,5,17,2,-6);
  25. $bubble = bubblesort($liste);
  26.  
  27. echo ‘Liste triée en ‘.$bubble[‘nbpermutations’].‘ permutations.’;

Remarques sur le code: j’ai volontairement passé la liste de valeurs par référence. Dans ce cas, la variable de départ est utilisée directement au lieu d’être copiée dans la fonction puis modifiée. On n’a donc pas besoin d’utiliser return pour récupérer la liste triée.

]]>
https://www.php-experts.org/developpement-web/algoritmes/le-tri-bulle-ou-tri-par-propagation-382/feed 1
5 plugins indispensables pour coder en PHP avec l’IDE Eclipse https://www.php-experts.org/developpement-web/5-plugins-indispensables-pour-coder-en-php-avec-lide-eclipse-22 https://www.php-experts.org/developpement-web/5-plugins-indispensables-pour-coder-en-php-avec-lide-eclipse-22#comments Mon, 13 Apr 2009 11:55:21 +0000 Didier https://www.php-experts.org/?p=22 L’IDE Eclipse, conçu à l’origine pour développer en Java, s’est enrichi de fonctionnalités avancées, sous forme de plugins, qui lui permettent aujourd’hui de jouer dans la cours des grands des éditeurs de code PHP. Tour d’horizon de ceux que j’utilise.

1. Eclipse PDT

Vu ses parents, Zend et IBM, le projet Eclipse PDT est un “(Php) Development Tools framework” complet. Il étend les capacités natives de la plate-forme Eclipse pour permettre de développer calmement des applications solides en PHP. Pas vraiment besoin de le présenter, si ?
Eclipse PDT est téléchargeable en tant que plug-in ou en version “bundle” (PDT all-in-one), c’est à dire avec Eclipse et tous les composants de base. Ceci est très utile dans le cas d’une nouvelle installation.
Télécharger Eclipse PDT

Il existe d’autres plugins permettant d’ajouter à Eclipse le support du PHP, comme PHPEclipse ou Eclipse PHP IDE, développé par Zend.

2. RegEx Util

Editeur d’expressions régulières, toujours pratique de part le fait qu’il surligne les expressions qui matchent quand on sélectionne une partie du pattern. Il permet aussi de rationaliser ses expressions, notamment en utilisant les classes prédéfinies -comme [alphanum]

Site officiel : http://myregexp.com/eclipsePlugin.html
Update Site : http://regex-util.sourceforge.net/update/

RegexUtil pour Eclipse

RegexUtil pour Eclipse

3. SubClipse

SVN pour Eclipse avec Subclipse

SVN pour Eclipse avec Subclipse

Ajoute le support de SVN (SubVersion) à Eclipse. SVN est un système de gestion de versionning comme CVS intégrant quelques améliorations, comme la possibilité de déplacer et supprimer des fichiers, sans perdre leur historique.

Site officiel : http://subclipse.tigris.org/
Update Site (pour la branche 1.6) : http://subclipse.tigris.org/update_1.6.x

4. Remote System Explorer (RSE)

Permet notamment d’éditer ses fichiers directement via une connexion SSH. Je m’en sers pour les petites retouches de code PHP rapides qui ne peuvent “pas attendre”.

Site officiel : http://www.eclipse.org/dsdp/tm/tutorial/
Update Site : http://download.eclipse.org/dsdp/tm/updates

5. Azzuri Clay

azzurri clay

Azzurri Clay: bases de données sous Eclipse

Un peu difficile à prendre en mains, Azzuri Clay est un plugin commercial pour Eclipse qui permet d’ajouter un vrai support des bases de donnéees. Le système de licence adopté est un peu étrange: la version Pro ne peut être achetée qu’au Japon. Il n’en reste pas moins que l’édition classique, gratuite, est toujours intéressante.
La liste des SGBDR supportés est assez impressionnante vu qu’elle comprend, notamment, les classiques MySQL, PostGres, Oracle, MS SQL Server, DB2, Informix, mais aussi, beaucoup plus rare, SAP.

Pour se servir du Database Modeler d’Azzuri Clay, il faut créer un projet (ou utiliser un projet déjà existant) et faire File -> New -> Other -> Database Modeling -> Azzurri Clay Database Design Diagram.

Une fois cela fait, on peut créer ses premières tables, exporter les scripts SQL de création (selon le SGBDR choisi), et même faire du retro engineering sur des bases de données déjà crées.

Site officiel : http://www.azzurri.jp/en/clay/index.html
Update Site : http://www.azzurri.co.jp/eclipse/plugins

Références pour Eclipse

Installation minimale d’Eclipse, par Thierry Bothorel

]]>
https://www.php-experts.org/developpement-web/5-plugins-indispensables-pour-coder-en-php-avec-lide-eclipse-22/feed 3
Moteur de template : Smarty https://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80 https://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80#comments Sun, 08 Mar 2009 22:38:15 +0000 Didier https://www.php-experts.org/?p=80 Smarty est un moteur de template. Basiquement, l’utilité d’un moteur de templates est de séparer le code métier de l’affichage que génèrera votre application web. Smarty se présente sous la forme d’une classe qui gère un langage de balises permettant d’afficher dynamiquement du code. Ces templates sont compilés et mis en cache (les versions compilées étant en php, elles profitent d’éventuels accélérateurs comme APC). Le moteur de template Smarty est si riche de fonctionnalités que je lui consacrerai une série d’articles. Pour commencer, nous verrons l’utilisation basique de Smarty, l’utilisation du tag {literal} ainsi que la gestion des dates.

Principe de fonctionnement

Admettons que sur votre nouveau site social-2.0-multimedia (etc), vous avez une fiche utilisateur. Chaque fiche comportera, peu ou prou, les mêmes informations, notamment le login de l’utilisateur. Voici comment procéder. Créez d’abord un fichier user.tpl (Note sur les fichiers .tpl : l’extension est libre, mais l’usage du .tpl est une convention; la plupart des IDE possédent des plug-ins pour permettre l’analyse et la coloration syntaxique de ce language de balises. Pour les puristes -je ne parle pas pour moi-, on peut justifier l’emploi du “tpl” au lieu d’un “html” plus classique par le fait que les templates contiendront certes du HTML, mais aussi des instructions destinées au moteur de template… mais bref!) . Ce fichier contiendra :

  1. Login : <strong>{$login}</strong>

Le fichier php qui l’utilisera contiendra, lui :

  1. $smarty = new Smarty();
  2. $smarty->assign(‘login’,$user_login);
  3. $smarty->display(‘user.tpl’);

On instancie un objet de la classe Smarty (ligne 1) on déclare une variable de template appelée ‘login’ qui contiendra la valeur de la variable php $user_login (ligne 2). On demande ensuite à Smarty d’ “exécuter” et d’afficher le fichier user.tpl (ligne 3).
Vous l’aurez compris, le login de l’utilisateur apparaîtra en lieu et place du {$login} dans le fichier template. Les {} indiquent à Smarty que ce code doit être exécuté, et non directement reproduit en sortie (ce qui est le cas du HTML). Ces signes encadreront toutes les balises Smarty. Vous remarquerez que la variable se déclare en php sans le signe $, mais qu’il faut utiliser celui-ci lorsqu’on veut accéder à la valeur de la variable dans le fichier de template.

Gestion des tableaux sous Smarty

Si, en PHP, on assigne une tableau à une variable Smarty, on peut y accéder grâce au point, avec la syntaxe $tableau.index.

Fonctions prédéfinies

(lien vers la doc officielle)

Le tag {literal}

S’il vous arrive de devoir utiliser des accolades {} dans le code–source de votre template (par exemple pour y intégrer des fonctions JavaScript), il faut les entourer du tag Smarty {literal}{/literal}, afin d’indiquer au moteur de template de ne pas parser le contenu, ce qui provoquerait une erreur.

Gestion des dates avec Smarty

Smarty gère l’affichage des dates très efficacement grâce à un modificateur de variable (un filtre) nommé date_format. La syntaxe de date_format sous Smarty est la suivante :

  1. Date : {$date_user|date_format:"%A %d %B %Y à %Hh%M"}

Qui affiche :

  1. Date : Sunday 15 February 2009 à 13h59

Pour passer la date que Smarty va afficher en français, il suffit d’utiliser setlocale() en php, comme ceci:

  1. setlocale(LC_ALL, ‘fr_FR’)

(n’hésitez pas à me dire si vous voulez un post plus complet sur l’installation – au moins sous Debian – et l’utilisation des locales en php). La date affichée devient alors :

  1. Date : Dimanche 15 février 2009 à 13h59

Voici les options que vous pouvez passer à la fonction date_format de smarty :

  • %a – Abréviation du jour de la semaine, selon les paramètres locaux.
  • %A – Nom du jour de la semaine, selon les paramètres locaux.
  • %b – Abréviation du nom du jour, selon les paramètres locaux.
  • %B – Nom complet du mois, selon les paramètres locaux.%c – Préférences d’affichage selon les paramètres locaux.
  • %C – Siècle, (L’année divisée par 100 et tronquée comme un entier, de 00 à 99)
  • %d – Jour du mois, en tant que nombre décimal (de 01 à 31)
  • %D – même chose que %m/%d/%y
  • %e – Jour du mois en tant que nombre décimal. Un chiffre unique est précédé par un espace (de 1 à 31)
  • %g – Position de la semaine dans le siècle [00,99]
  • %G – Position de la semaine, incluant le siècle [0000,9999]
  • %h – identique à %b
  • %H – L’heure en tant que décimale, en utilisant une horloge sur 24 (de 00 à 23)
  • %I – L’heure en tant que décimale en utilisant une horloge sur 12 (de 01 to 12)
  • %j – jour de l’année (de 001 à 366)
  • %k – Heure (horloge sur 24). Les numéros à un chiffre sont précédés d’un espace. (de 0 à 23)
  • %l – Heure (horloge sur 12). Les numéros à un chiffre sont précédés d’un espace. (de 1 à 12)
  • %m – Mois en tant que nombre décimal (de 01 à 12)
  • %M – Minute en tant que nombre décimal
  • %n – Retour chariot (nouvelle ligne).
  • %p – soit am soit pm selon l’heure donnée, ou alors leurs correspondances locales.
  • %r – heure en notation a.m. et p.m.
  • %R – Heure au format 24 heures
  • %S – Secondes en tant que nombre décimal.
  • %t – Caractère tabulation.
  • %T – Heure courante, équivalent à %H:%M:%S
  • %u – Jour de la semaine en tant que nombre décimal [1,7], ou 1 représente le lundi.
  • %U – Le numéro de la semaine en nombre décimal, utilisant le premier dimanche en tant que premier jour de la première semaine.
  • %V – Le numéro de la semaine de l’année courante selon la norme ISO 8601:1988, de 01 à 53, ou la semaine 1 est la première semaine qui dispose au minimum de 4 jours dans l’année courante et ou Lundi est le premier jour de cette semaine.
  • %w – Jour de la semaine en tant que nombre décimal, dimanche étant 0
  • %W – Le numéro de la semaine de l’année courante en tant que nombre décimal, ou Lundi est le premier jour de la première semaine.
  • %x – Représentation préférée de la date selon les paramètres locaux.
  • %X – Représentation préférée de l’heure selon les paramètres locaux, sans la date.
  • %y – L’année en tant que nombre décimal, sans le siècle. (de 00 à 99)
  • %Y – L’année en tant que nombre décimal, avec le siècle.
  • %Z – Zone horraire, nom ou abréviation
  • %% – Un caractère litéral `%’

Lectures intéressantes sur Smarty:

Pour aider à la rédaction de ma série d’articles, n’hésitez pas à laisser un commentaire sur un sujet que vous voudriez voir abordé, ou à me signaler des docs intéressantes sur Smarty, je me ferais un plaisir de les rajouter dans les lectures intéressantes :)

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80/feed 5
Cache d’opcode: Alternative Php Cache (APC) https://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62 https://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62#comments Tue, 09 Dec 2008 17:23:58 +0000 Didier https://www.php-experts.org/?p=62 Pour accélerer les performances d’un site internet, il existe de nombreuses pistes à suivre. Outre les recommandations d’optimisation de Yahoo, qui concernent surtout l’architecture d’une application Web, on peut aussi s’attaquer à des couches plus transparentes (et souvent complètement ignorées par les développeurs), comme l’étape de “compilation” du script en exécutable. Nous allons voir comment APC (Alternative Php Cache) peut nous aider rapidement à accélérer des scripts php.

L’opcode ?

Oui, l’opcode. C’est le code généré par votre serveur Web (qui a dit Apache ?) à partir de vos scripts PHP, après leur interprétation et leur compilation. Ce code est exécutable, et sa génération prend un certain temps. A chaque exécution d’un script, le serveur régénère cet opcode, perdant ainsi un temps précieux: quand votre script n’a pas été modifié, cette étape est totalement inutile. On peut l’éviter en mémorisant l’opcode grâce à un cache d’opcode
Attention, il ne faut pas confondre les caches d’opcode et les caches HTML: un cache HTML servira à envoyer directement la sortie d’un script au client, sans traitement. Le cache d’opcode, lui, laisse place à l’exécution proprement dite du script dans des conditions normales: les données provenant d’une base de données MySQL, par exemple, seront rapatriées comme à l’accoutumée. On ne perd donc aucune réactivité au niveau de l’application, tout en améliorant ses temps de réponse.

APC ? (Alternative Php Cache)

Oui, APC. APC est un projet libre, implémenté comme une extension Zend. Cela permet de le compiler dans PHP ou de l’intégrer plus tard, comme un module classique. Le principal avantage d’APC (et des autres caches d’opcode) est qu’il n’y a aucun besoin en terme de modification des scripts: il suffit d’installer et d’activer le module pour que celui-ci accélère vos scripts PHP. De ce côté là, donc, rien de spécial à ajouter.
APC permet, par un script d’administration, de suivre quels opcodes sont mis en cache, le nombre de hits économisés, ainsi que les données utilisateur. Très pratique, la colonne “miss” vous indique combien de scripts ont été appelés sans profiter de l’accélération d’APC (Cela peut arriver car vous pouvez mettre des filtres en place pour ne stocker que certains répertoires, ou limiter la taille en mémoire occupée par l’ensemble des scripts “compilés”, par exemple…)

Le cache de données utilisateur

Mais là où réside, selon moi, la vraie puissance d’APC, est dans son cache de données utilisateur. En effet, imaginons le cas où nous avons une requête SQL assez lourde, suivie d’un traitement assez conséquent: sur la page d’accueil d’un forum (lien-copinage), on souhaite afficher les derniers connectés et le nombre de messages qu’ils ont posté. En théorie, à chaque affichage de la page, on va réexécuter la requête, et donc assassiner bêtement le serveur SQL.
On pourrait stocker les données dans une Session PHP ? Oui, mais d’une, les sessions ne sont pas faites pour ça, et de deux, on exécuterait quand même la requête SQL et le traitement associé pour chaque nouveau connecté.
La meilleure solution reste alors d’utiliser le cache de données d’APC. On va pour cela se servir de la fonction apc_store, qui prend 3 paramètres :
bool apc_store ( string $key , mixed $var [, int $ttl ] )

  • $key est le nom que l’on souhaite donner à la variable dans le “magasin” (store) d’APC. Je vous conseille de la préfixer du nom du site concerné si vous hébergez plusieurs sites sur le même serveur ; les variables sont accessibles à tous les scripts (attention donc à ce que vous faites dans le cas d’un hébergement partagé… ne stockez de préférence aucune donnée “sensible” à moins de savoir précisément ce que vous faites).
  • $var est la valeur à stocker, qui peut être un nombre, une chaîne, un tableau, ou même un objet complet (Attention, dans ce dernier cas, à bien inclure la déclaration de classe de l’objet avant d’essayer de le récupérer…).
  • $ttl est le “Time To Live” de la variable, c’est à dire le temps en secondes avant qu’APC ne l’efface de son store.

Par exemple, dans le cadre de notre forum, on aurait quelque chose comme :

  1. apc_store(‘forum_derniers_connectes’,$derniersConnectes,60);

Ce qui signifie qu’on stocke, tel quel, le tableau (array) $dernierConnectes, sous le nom forum_derniers_connectes, pour une durée de 60 secondes.

Pour accéder à la variable, on dispose de la fonction apc_fetch, qui prend le $key de la variable en paramètre, et renvoie soit la valeur stockée, soit FALSE en cas d’échec. On peut donc faire :

  1. if (!$derniersConnectes = apc_fetch(‘forum_derniers_connectes’)) {
  2. // forum_derniers_connectes n’est pas présent dans le cache: il faut le calculer
  3. $derniersConnectes = get_derniers_connectes(); // boum, on exécute
  4. apc_store(‘forum_derniers_connectes’,$derniersConnectes,60);
  5. }

C’est tout ! Si APC trouve la variable, il renseigne $derniersConnectes. Dans le cas contraire, on rapatrie les infos et on les stocke pour 60 secondes. La requête-de-la-mort ne sera plus exécutée qu’une fois par minute.

Bénéfices

Le bénéfice est donc double: on économise à la fois sur le temps d’exécution des scripts en ne les compilant qu’au besoin grâce au cache d’opcode (d’environ 50% selon les auteurs, sachant que cela dépendra de la complexité du script… on gagnera beaucoup plus sur des algorithmes récursifs, notamment), mais aussi sur le temps de processing de certaines ressources grâce au cache de données, qui est utilisé ici pour des requêtes SQL mais qui pourrait aussi bien l’être pour la lecture du fichier de configuration de votre application, par exemple (en stockant, au choix, un tableau associatif ou un objet $config), ou de n’importe quelle variable qui n’a pas vraiment besoin d’être mise à jour en temps réel.

Liens utiles

Manuel APC sur php.net (en français)

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62/feed 0
Parser des XML volumineux avec XMLReader https://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42 https://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42#comments Fri, 28 Nov 2008 17:25:20 +0000 Didier https://www.php-experts.org/?p=42 Avec des classes comme DomDocument ou SimpleXML, le parsing de fichiers XML s’est considérablement simplifié en PHP 5. Mais quand on doit parser des fichiers très volumineux (comme j’ai eu à le faire récemment pour le catalogue produits de mon comparateur d’électroménager), on se retrouve très rapidement avec des scripts très gourmands en mémoire. En effet, ces classes lisent et analysent la totalité du fichier XML avant de pouvoir agir dessus. Ce n’est pas le cas de XMLReader, qui elle, fonctionne en mode flux: le fichier est alors lu au fur et à mesure des besoins. Il en résulte des scripts plus rapides et très peu consommateurs de RAM.

Utiliser XMLReader et SimpleXML de concert

Voici comment on procède:

  1. $xml = new XMLReader();
  2. $xml->open(‘gros_fichier.xml’);
  3. while($xml->read()){
  4.     if ($xml->nodeType == XMLREADER::ELEMENT &amp;&amp; $xml->localName == "product") {
  5.         $product = $xml->expand();
  6.         $product = new SimpleXMLElement(‘<product>’.$xml->readInnerXML().‘</product>’);
  7.         $prod[‘name’] = utf8_decode($product->name);
  8.     }
  9. }

Ligne 1, on instancie classiquement un objet XMLReader. Le constructeur ne prend pas de paramètres. Ligne 2, on assigne le fichier que l’on souhaite parser.
C’est ensuite que les joyeusetés commencent : $xml->read() permet de passer au node suivant. Tant que XMLReader trouvera des nodes, on continuera à lire le fichier séquentiellement. L’intérieur de la boucle contiendra le traitement que je souhaite effectuer sur chaque node. Ici, si le nodeType est “ELEMENT” si le localName (le libellé du tag) est “product”, nous sommes en présence de l’un des produits que je souhaite traiter.
Dans ce cas, $xml->expand() permet de copier le node courant afin de le manipuler plus aisément. L’astuce ligne 6 (j’imagine bien qu’il doit y avoir un moyen de faire ça beaucoup plus proprement) consiste à recréer le node à partir de son localName et de la chaîne de caractères au format XML qu’il contient, récupérée grâce à $xml->readInnerXML(). Etant habitué à l’utilisation courante de SimpleXML, et pour des raisons de confort personnel, je passe la chaîne de caractères obtenue en paramètre au constructeur de SimpleXMLElement afin de récupérer un élement XML classique, que j’utilise ensuite simplement en accédant aux données qu’il contient.

Vérifier le bon déroulement des opérations

  1. $i++;
  2. if (($i % 500) == 0) {
  3.         echo "$i – Ok\r\n";
  4.         flush();
  5. }

Pour les imports de gros fichiers (1.2 giga-octets dans mon cas), mieux vaut savoir exactement ce qu’il se passe. J’ai donc déclaré avant mon while une variable $i=0, que j’incrémente à la fin de ma boucle, après avoir traité un produit. Ligne 2, je vérifie que $i (le nombre de produits traités) est un multiple de 500. Si oui, j’affiche le nombre courant et le flush() permet d’envoyer immédiatement le contenu du buffer à la sortie du script. Ici, le but était de faire tourner le script en ligne de commandes (CLI), mais cela aurait aussi bien marché avec un navigateur. (Il aurait fallu remplacer les \r\n par un <br /> classique.

Si cet article vous a intéressé, j’apprécierais un peu de promotion : ;)


]]>
https://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42/feed 4
erreur 404, redirection 301: headers et codes de réponse HTTP courants https://www.php-experts.org/developpement-web/php-developpement-web/erreur-404-redirection-301-headers-et-codes-de-reponse-http-courants-24 https://www.php-experts.org/developpement-web/php-developpement-web/erreur-404-redirection-301-headers-et-codes-de-reponse-http-courants-24#comments Fri, 05 Sep 2008 09:47:44 +0000 Didier https://www.php-experts.org/?p=24 Lorsqu’on se connecte à une page Web, le client (navigateur) envoie une requête, auquel le serveur qui traite la réponse, en suivant le protocole HTTP, renvoie un code de traitement à 3 chiffres.
Ce code se situe sur la première ligne de la réponse, et est de la forme :

  1. HTTP/1.1 200 OK

. En php, la fonction php header() permet, depuis vos scripts, d’adapter le code que le serveur renvoie, afin de “forcer” le comportement du navigateur client.
Petit tour d’horizon des codes les plus répandus.

200 OK

Le code 200, c’est le Nirvana. Tout s’est bien passé, rien à signaler. C’est le code par défaut.

301 Moved Permanently (aka Redirect Permanent)

Le code 301 ou “redirection permanente” est très utilisé en référencement. Il signale au client (navigateur ou crawler de moteur de recherche) que la ressource demandée (document, image, etc) a été déplacée de manière définitive.
Imaginons que je renomme un dossier. En l’état, les moteurs de recherche enverront les internautes vers des pages qui n’existent plus (ils recevront donc une erreur 404 – document not found), et les éventuels liens entrants dont bénéficiaient mes pages sont perdus puisqu’ils pointent aussi dans le vide.
Avec une redirection permanente, les moteurs étant prévenus que le document a été déplacé, mettront leur index à jour pour envoyer les visiteurs directement sur la bonne URL. Dans le même temps, la popularité amenée par les liens entrant sera reportée sur les nouvelles pages.

302 Moved Temporarily

Proche de la Redirection 301, le code 302 indique qu’un document a été déplacé temporairement. Moteurs comme navigateurs téléchargeront donc le document à sa nouvelle adresse, mais les références futures se feront à l’URL habituelle.

304 Not Modified

Quand ils ont un document dans le cache, les navigateurs envoient un entête If-Modified-Since, qui comprend la date à laquelle ils ont téléchargé le document pour la dernière fois. Si le document n’a pas été modifié depuis, le serveur envoie un code de réponse 304, “non modifié”, afin que le navigateur évite de retélécharger un contenu qui est à jour dans son cache.

404 Not Found

Le document auquel l’utilisateur essaye d’accéder a été déplacé, supprimé, ou l’URL fournie est simplement incorrecte. Le serveur n’a donc rien à renvoyer. On peut configurer Apache, au niveau du Virtual Host (ou d’un .htaccess) pour qu’il renvoie, dans ce cas, un document précis, grâce à la directive ErrorDocument 404 /fichier.html . En cas d’erreur 404, c’est fichier.html qui sera servi. Cela peut (et devrait toujours) servir à envoyer une page 404 personnalisée, qui comprend au minimum un mini-plan du site, afin que l’internaute puisse continuer sa visite sur le site.

500 Internal Server Error

Le code 500, c’est la fin du monde. Le serveur n’a pas pu répondre à la requête, très souvent à cause d’une erreur de configuration. Donc, vérifiez d’abord votre .htaccess, il suffit d’un point-virgule qui traine pour que le serveur ne s’en sorte plus.

Fonction header

La fonction header() en PHP permet d’envoyer un code de réponse autre que le 200 habituel. Vu qu’elle modifie les entêtes, elle doit être utilisée AVANT qu’un caractère imprimable soit envoyé au client. Dans le cas contraire, un warning “headers already sent” sera généré. Voici, pour exemple, la syntaxe complète de l’utilisation de la fonction header() pour envoyer une redirection 301 propre:

  1. header("HTTP/1.1 301 Moved Permanently");
  2. header("Location: http://www.nouvelle-url.com/");
]]>
https://www.php-experts.org/developpement-web/php-developpement-web/erreur-404-redirection-301-headers-et-codes-de-reponse-http-courants-24/feed 5
Site multilingue: déterminer la langue du visiteur https://www.php-experts.org/developpement-web/php-developpement-web/site-multilingue-determiner-la-langue-du-visiteur-17 https://www.php-experts.org/developpement-web/php-developpement-web/site-multilingue-determiner-la-langue-du-visiteur-17#comments Wed, 13 Aug 2008 13:38:29 +0000 Didier https://www.php-experts.org/?p=17 Sur les sites qui sont disponibles en plusieurs langues, il est fréquent de trouver une page “d’accueil” comportant plusieurs drapeaux ou un quelconque moyen de choisir son langage que l’on veut voir affiché. Cette pratique, aussi mauvaise pour le référencement qu’en termes d’ergonomie, peut facilement être évitée grâce au header “Accept-Language”.

Lors de chaque requête vers un serveur HTTP, le navigateur de l’internaute envoie un header “Accept-Language” contenant les langages qu’il accepte (ses favoris), dans l’ordre de préférence. Par exemple, chez moi, sa valeur est : “Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3″ (le q est un quality factor si on en croit la RFC 2616, on peut ne pas s’en occuper dans l’utilisation qui nous concerne)

Imaginons qu’on aie un site existant en français et anglais, avec un répertoire par version, placé à la racine (Encore une fois, je schématise, merci de ne pas trop m’en tenir rigueur… même remarque pour les noms des variables ci-dessous).

Plaçons le script PHP suivant sur la fameuse “page d’accueil” (qui est tout sauf accueillante) de notre site multilingue:

  1. $langagesSite = array(‘en’ => ‘English’, ‘fr’ => ‘Français’);
  2. $langageDefaut = ‘fr’;
  3. $langagesClient = split ([,;]‘, $_SERVER[‘HTTP_ACCEPT_LANGUAGE’]);
  4. $selected = null;
  5. foreach($langagesClient as $l) {
  6.       if (isset($langagesSite[$l]) && $selected == null) {
  7.            $selected = $l;
  8.       }
  9. }
  10. if ($selected == null) {
  11. $selected = $langageDefaut;
  12. }
  13. header(’Location:/’.$selected, true, 301);
  14. die();

Voyons ce qu’il se passe: on liste les langues disponibles pour le site (ligne 1), on détermine une langue comme étant celle par défaut (ligne 2), puis on récupère les langues que le visiteur a déclarées comme étant “recevables”. On parcourt cette liste à la recherche d’une correspondance… Dès qu’on l’obtient, on l’affecte à $selected, ce qui court-circuite les tests suivants. Dans le cas où on n’aurait aucune correspondance (si le visiteur demande du russe et/ou du chinois sur un site en anglais et français), on reprend la valeur de la langue par défaut.
Une fois cette affectation faite, on renvoie le visiteur, à l’aide d’une redirection 301 ou “redirection permanente”, vers le répertoire approprié.
Et dans le cas où le visiteur n’aurait pas envoyé l’entête magique dans sa requête (c’est le cas des crawlers des moteurs de recherche, en particulier de GoogleBot), la langue par défaut sert de

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/site-multilingue-determiner-la-langue-du-visiteur-17/feed 9
Coder une classe d’abstraction pour manipuler des objets en PHP5 https://www.php-experts.org/developpement-web/php-developpement-web/coder-une-classe-dabstraction-pour-manipuler-des-objets-en-php5-18 https://www.php-experts.org/developpement-web/php-developpement-web/coder-une-classe-dabstraction-pour-manipuler-des-objets-en-php5-18#comments Fri, 25 Jul 2008 20:38:22 +0000 Didier https://www.php-experts.org/?p=18 Sur chaque site, dans tous les projets, on a une base de données qui contient des tables, dont chaque ligne sont des items que l’on souhaitera manipuler à un moment où à un autre. Le code PHP à écrire pour effectuer les actions nécessaires – Ajouter des items, les modifier, les supprimer, récupérer leurs attributs… – varie peu, et pourtant ce travail est souvent répété d’un projet à l’autre. Il est possible de créer une classe générique d’abstraction, qui pourra manipuler toutes sortes d’objets de manière transparente.

Note: On m’a souvent déconseillé d’utiliser l’introspection (et donc notamment la méthode __get() ) pour des problèmes de performances. Or, et malheureusement, il est de nos jours nécessaire de se rappeler que l’hébergement d’un site, même si ses coûts pourraient être réduits par de l’optimisation poussée/poussive sur le code, coûtera bien moins cher qu’un développeur qualifié, à plein temps, occupé à maintenir du code “optimisé” mais dont on pourrait aisément se passer en achetant un serveur plus puissant. J’utilise donc __get et si ça vous choque, louez un serveur dédié (et en plus je me permets un lien d’affiliation…) et arrêtez de vous demander si vous devez utiliser echo ou print… Ce n’est pas là que sera votre valeur ajoutée en tant que développeur. Il est largement plus rentable à moyen et long terme de faire du code modulaire, réutilisable, en capitalisant sur les temps de développement.

Magic function : __get

Dans la programmation orientée objets en php5, il existe des méthodes de classes qui sont dites “magiques”. La plus célèbre, __construct(), est appélée à l’instanciation de la classe.
Une autre, moins connue, est appelée lorsqu’on tente d’accéder à une propriété qui n’est pas définie. C’est __get(). Cette méthode reçoit un argument, qui est le nom de la propriété en question. C’est celle-ci que nous allons utiliser pour réaliser notre classe d’abstraction. Pour l’exemple, nous assumerons que nous avons une variable globale (oui, je sais, encore quelque chose que je ne devrais pas faire… mais j’attends toujours qu’on m’explique pourquoi) $oDb qui est un objet Database capable de renvoyer la valeur d’une ligne (getRow) d’une table de la base de données.

Comme d’habitude, on va gérer une table Employes contenant des champs ID, nom, prenom et salaire (respectivement int, varchar, varchar et int…) :

  1. class GenericObject {
  2.     public function __get($var) {
  3.         print "Magic : get $var";
  4.     }
  5. }
  6. $emp = new GenericObject;
  7. print $emp->nom;

Comme on le voit, on essaye à la ligne 7 d’accéder à la propriété “nom”, alors que celle-ci n’existe pas. La méthode __get() est alors appelée et reçoit en argument le nom de la propriété inexistante (le script affichera donc bien Magic: get nom.

Dès lors, on peut imaginer construire une classe acceptant un nom de table (string) et un identifiant (integer) en argument et pouvant, déjà, rappatrier la valeur de n’importe quel champ. Imaginons le script suivant :

  1. class GenericObject {
  2.     public function __construct($table, $id) {
  3.         global $db;
  4.         // on charge la ligne de la base de données
  5.         $this->infos = $db->getRow("select * from $table where id = ‘$id’");
  6.     }
  7.     public function __get($var) {
  8.         // on renvoie la valeur tirée de la valeur (tableau) de la propriété $this->infos
  9.         return $this->infos[$var];
  10.     }
  11. }
  12. $emp = new GenericObject(‘emp’,1);
  13. var_dump(isset($emp->nom));
  14. print $emp->nom;

Ici, la classe est instanciée dans l’objet $emp. On lui passe l’ID (en base) de notre employé fictif. Dès lors, on peut, en une ligne, récupérer la totalité des informations le concernant. Pour preuve, la ligne 14 affiche bien “Dupont”. A noter, la ligne 13 qui renvoie bool(false) : $nom c’est vraiment pas défini avant le get.

Magic function : __set()

Bien sur, parralèlement à __get, on peut utiliser la méthode __set() pour changer la valeur d’une propriété qui n’est pas définie. Cette méthode accepte, cette fois, deux paramètres: le nom de la propriété en question et la valeur que l’on souhaite lui affecter. L’intérêt dans ce cas (pour différer du comportement “normal” de PHP, est, par exemple, de récupérer la liste des champs de la base dans une propriété, et de vérifier à chaque __set que la variable qu’on tente de déclarer aura bien une correspondance dans la table de la base de données.

Magic function : __destruct()

Quitte à utiliser des fonctions “magiques”, autant le faire jusqu’au bout. On peut, grâce à la méthode __destruct(), effectuer une action lorsque l’objet sera désinstancié. Cela peut se passer si on le unset, ou lorsque le script se terminera. Par exemple, pourquoi ne pas enregistrer les changements de notre objet dans la base de données ? Dans notre exemple, il suffit de faire une boucle foreach sur le tableau $this->infos et de formater une requête SQL UPDATE.

Bon, certes, j’ai pris pas mal de raccourcis, donc le code n’est pas vraiment exploitable “tel quel”, mais avouez que la classe est efficace dans le sens où elle peut gérer toutes sortes d’objets. Il faudrait notamment ajouter, avec __set, le système qui vérifie que le champ existera dans la table (en récupérant son type pour faire des contrôles avant d’insérer). Dans le __destruct, il faut faire en sorte de ne sauver que les champs ayant été modifiés. Et bien sur, éviter l’édition de l’ID sur un objet que l’on vient de charger. Tout un programme ;)
On pourrait par exemple utiliser ce système pour gérer les utilisateurs d’un site, avec gestion des droits en bit bashing.

On pourrait coder par-dessus tout ça un système d’itérateurs pour les gérer en lots. (et effectuer simplement des tâches comme “Afficher tous les employés”, “Augmenter tout le monde de 100 €”, etc).

Je tiens mon “work in progress” (WIP©) de la classe à disposition pour qui voudra, n’hésitez pas à me le demander dans les commentaires ou par mail. :)

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/coder-une-classe-dabstraction-pour-manipuler-des-objets-en-php5-18/feed 8
Coder un système d’authentification : Apache ET bases de données https://www.php-experts.org/developpement-web/php-developpement-web/coder-un-systeme-dauthentification-apache-et-bases-de-donnees-11 https://www.php-experts.org/developpement-web/php-developpement-web/coder-un-systeme-dauthentification-apache-et-bases-de-donnees-11#comments Wed, 09 Jul 2008 09:00:15 +0000 Didier https://www.php-experts.org/?p=11 Quand on veut gérer un système d’authentification en PHP pour un intranet (qui demande plus de rigueur et de sécurité qu’un site internet), on se retrouve à priori avec deux solutions valables: soit un formulaire relié à une base de données, le classique du Web/frontoffice, soit un fichier htpasswd, le classique du Backoffice, plus sûr mais moins flexible (notamment au niveau de l’ajout d’utilisateur ou de la gestion des droits d’accès). J’ai mis longtemps à me rendre compte qu’on pouvait mixer les deux pour avoir quelque chose de souple et de fiable.

En manipulant les headers Apache en PHP, on peut forcer le serveur à demander une authentification au visiteur, comme avec un .htaccess/htpasswd. Il suffit pour cela d’ajouter :

  1. header(‘WWW-Authenticate: Basic realm="Administration – Accès restreint"’);
  2. header(‘HTTP/1.0 401 Unauthorized’);

Quand on arrive sur la page, une “jolie” boite apparaît :
Exemple de boite de dialogue d\'authentification
C’est en faisant un var_dump($_SERVER) sur l’index du dossier qu’on remarque les deux variables qui vont nous servir : PHP_AUTH_USER et PHP_AUTH_PW. Celles-ci contiennent les valeurs des deux champs de la boîte de dialogue qu’Apache a fait remplir à votre visiteur. En y pluggant un système de login “classique”, qui va chercher une correspondance entre ces données et celles contenues dans une base de données, on se retrouve avec un module de login par headers http, envoyés par php, et couplé à une base de données dans laquelle on peut, notamment, stocker un niveau d’accès pour chaque utilisateur (et utiliser le Bit Bashing…)

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/coder-un-systeme-dauthentification-apache-et-bases-de-donnees-11/feed 2
Yahoo vous aide à accélérer votre site internet https://www.php-experts.org/developpement-web/yahoo-vous-aide-a-accelerer-votre-site-internet-8 https://www.php-experts.org/developpement-web/yahoo-vous-aide-a-accelerer-votre-site-internet-8#comments Mon, 30 Jun 2008 10:20:18 +0000 Didier https://www.php-experts.org/?p=8 Après avoir publié ses “Best Practices for Speeding Up Your Web Site” (comprendre: meilleures pratiques pour accélérer votre site internet”, Yahoo met désormais à disposition des développeurs YSlow!, une extension pour FireBug, célèbre plug-in Firefox, qui permet de faire un rapport d’optimisation pour la vitesse du site que vous visitez.

Le plug-in, très simple d’utilisation (un click dans la barre d’état lance l’analyse, qui apparait dans le panneau FireBug), recense toutes les modifications que vous pouvez apporter pour atteindre le fameux Speed Rank A, réservé à l’élite des sites rapides… (disons que les 34 critères définissent le « site rapide théorique parfait », mais ne sont pas tous applicables dans le monde réel. Par exemple, Yahoo recommande d’utiliser un CDN (Content Delivery Network), solution généralement assez chère pour ne pas être déployable sur des sites à moyen traffic et peu monétisés.

Voici un rappel de ce qu’il faut faire et éviter, aux yeux de Yahoo.


Les critères ont été classés en 7 catégories :

  1. Le contenu
  2. Le serveur
  3. Les cookies
  4. Les CSS (Cascading Style Sheets… les feuilles de style, quoi)
  5. Le Javascript
  6. Les images
  7. Version « mobile »

Tour d’horizon des critères que je trouve utiles parmi les 34 proposés :

Faire le moins de requêtes HTTP possible

Partant du principe que 80% du temps de rendu d’une page consiste en téléchargement (vu la source des données –Yahoo- je pense qu’on peut considérer ce chiffre comme fiable), Yahoo recommande clairement de « combiner » les fichiers : regroupez toutes vos classes CSS dans un seul fichier, toutes les fonctions Javascript dans un autre. A noter que, même si personnellement, je ne suis pas fan de la méthode, cela permet de maximiser l’effet des caches navigateur. Au premier chargement d’une page de votre site, l’utilisateur dispose de tous les éléments dont il aura besoin au fil de la navigation. On gagne donc pas mal de temps (et de bande passante) pour toutes les autres pages qu’il verra.

Dans la même optique, Yahoo recommande d’utiliser des « CSS Sprites » pour afficher les images (coins arrondis et compagnie) et des « Images Map », ce qui réduit le nombre de fichiers à télécharger.

Jouer avec les sous-domaines, mais en réduisant les DNS Lookups

Les navigateurs internet comme Internet Explorer ou Firefox, quand ils récupèrent les éléments d’une page, ne peuvent faire que deux téléchargements simultanés par nom de domaine. En gros, si vous mettez vos pages statiques (donc, le HTML) sur www.domain.tld, vos images sur img.domain.tld et vos feuilles de styles et javascripts sur elements.domain.tld, vous accélèrerez le téléchargement total de la page en multipliant les requêtes simultanées.

Attention, les DNS Lookups nécessaires pour récupérer l’adresse IP des sous-domaines prend du temps, donc n’en abusez pas. Yahoo considère que 2 à 4 sous-domaines est une fourchette acceptable.

Utiliser un Content Delivery Network ou CDN

Alors là, rien à redire : il est parfaitement logique qu’un CDN accélère votre site. C’est le but. Les Content Delivery Networks sont, en gros, des réseaux de serveurs qui vont « capturer » votre contenu statique (Javascript, CSS, images, mais aussi HTML) et le servir à votre place. Parmi les plus connus, Akamai comprend 20000 serveurs répartis dans 71 pays (données corporate). En effet, difficile de rivaliser ;)

Ajouter des headers « Expires » ou « Cache-control »

Là, deux cas :

  • Soit on parle de contenu statique et on peut utiliser un Expires, qui indique au navigateur quand est-ce qu’il devra recharger le composant au lieu de le piocher dans son cache,
  • Soit on parle de contenu dynamique, et on devra plutôt se servir de Cache-Control pour définir le comportement à adopter.

Le header « Expires » sert à spécifier au browser une date d’expiration pour le document visé. En gros, si j’ajoute à ma feuille de style un “Expires: Thu, 15 Apr 2010 20:00:00 GMT”, votre navigateur n’essaiera même pas de la télécharger avant cette date.

Bonne idée de Yahoo : utiliser une norme de nommage des fichiers qui consiste à suffixer le nom par le numéro de version (comme dans « yahoo_2.0.6.js ») : cela permet d’être sur que le fichier ne sera jamais modifié (sauf en cas de changement de version, où il sera renommé), et donc d’utiliser le plus souvent un Expires : aucun travail pour le serveur quand le document est déjà dans le cache du navigateur.

GZipper votre contenu

En compressant ce qui sort de votre serveur, vous améliorez le temps de chargement des éléments (logique). Il faut prendre en compte l’impact que la compression peut avoir sur les performances de votre site : le processeur de votre serveur sera plus sollicité, mais vous économiserez de la bande passante.

La plupart des clients qui suivent la norme HTTP/1.1 envoient un header « Accept-Encoding : gzip, deflate » auquel le serveur, s’il le peut, répondra par du contenu zippé avec un header « Content-Encoding : gzip ».

Pour que cela soit le cas, avec Apache 1.3, il faut installer et activer mod_gzip, remplacé pour Apache2 par mod_deflate.

Feuilles de style en haut et javascripts en bas, flush() fréquents

En embarquant vos feuilles de style dès le tag <head> de votre page, vous permettez au navigateur du client d’afficher celle-ci de manière progressive au cours de son chargement. Même si techniquement, cela ne change en rien la vitesse de chargement, l’impact psychologique de voir la page de remplir est tel qu’on a une impression de vitesse. Vous pouvez lire l’étude UseIt sur le “progressive rendering. Dans la même idée, utiliser un flush() après votre header (fonction qui ordonne au serveur d’envoyer le HTML déjà généré sans attendre la fin de la création de la page) permettra à la page de s’afficher plus rapidement, puisque les téléchargements connexes pourront commencer avant que le serveur n’aie fini ses calculs.

Selon la norme HTTP/1.1, les navigateurs ne doivent télécharger que deux éléments en parallèle par hostname. Si vous placez vos Javascripts en haut de votre code-source, le navigateur les téléchargera et donc bloquera l’un des deux téléchargements pour eux, qui n’ont pas d’impact visuel. A choisir, mettez les donc vers le bas du document, après que la structure de la page, les feuilles de styles et les images aient été chargées.

Minifier le code Javascript et les CSS (feuilles de style)

Minifier le code revient à en enlever les espaces inutiles, tabulations, retours à la ligne… On se retrouve avec une bouillie illisible mais beaucoup plus rapidement chargée qu’un code propre et indenté. Regardez le code-source de la home de Google… Il faudra bien évidemment garder une version « non-minifiée » de vos scripts, pour pouvoir les retoucher en cas de besoin. Yahoo propose 2 outils de minification : JsMin et YUI Compressor. J’en ai développé un aussi, mais je pense que le leur marchera mieux ;)

Gérer intelligemment les tailles d’images

Il ne faut jamais utiliser une image carrée de 500px de côté avec un width= »100 » pour la redimensionner en HTML. Le navigateur devra toujours télécharger l’image dans sa taille originale. Faites une copie plus petite de l’image !

Pensez à ajouter une favicon à votre site. Dans tous les cas, les navigateurs la demandent, et auront donc à télécharger votre page d’erreur 404 personnalisée (vous en avez une, n’est ce pas ? … Yahoo recommande d’éviter pour ne pas gaspiller de ressources serveur, mais Yahoo n’est pas référenceur…) en lieu et place de la petite icône qui apparaitra dans les favoris de vos utilisateurs et dans les onglets de leur navigateur. Même combat pour le robots.txt : il sera de toute façon demandé, donc autant en avoir un.

D’après Yahoo, le meilleur format d’images actuel est PNG (« Give PiNG a Chance », qu’ils disaient…) : tout ce qu’un GIF peut faire, un PNG8 peut le faire aussi, pour une taille de fichier souvent moindre. A essayer :)

Voici une rapide présentation des points qui m’ont semblés être des “quick-win” dans ce que propose Yahoo. La liste est loin d’être exhaustive, j’ai volontairement “oublié” des items de la liste qui avaient l’air moins importants (ou plus complexes à mettre en place) pour un site de taille raisonnable.

Un peu de lecture pour aller plus loin :

Et vous, quelles sont vos habitudes ?

]]>
https://www.php-experts.org/developpement-web/yahoo-vous-aide-a-accelerer-votre-site-internet-8/feed 10