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 Symfony Live, par Sensio Labs https://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/symfony-live-par-sensio-labs-290 https://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/symfony-live-par-sensio-labs-290#comments Mon, 08 Jun 2009 23:18:25 +0000 Didier https://www.php-experts.org/?p=290 Sensio Labs organise la 1ère édition du Symfony Live, conférence francophone dédiée au framework PHP open source Symfony. ( Rendez-vous les 11 & 12 juin, Cité Universitaire Internationale Paris 14° ).

Au programme de ces deux journées :
- Conférences inédites sur les thèmes : réseaux sociaux, stratégies de migration, gestion de médias, Symfony 2…
- Retours d’expériences : Dailymotion, Yahoo!, L’Express…
- Experts : Fabien Potencier, Créateur et Lead developer de Symfony et PDG de Sensio Labs, Dustin Whittle, évangéliste Yahoo!, Jonathan Wage, Lead developer de Doctrine ORM…

Programme complet ici : http://www.symfony-live.com/schedule

A noter, cette manifestation a aussi le soutien de la très sérieuse AFUP. Cette première conférence française entièrement consacrée au framework Symfony est très attendue dans la communauté et personnellement, si mon agenda l’avait permis, j’aurais beaucoup aimé pouvoir y montrer mon nez.
Vous pourrez suivre la conférence en direct sur Twitter (@sflive09fr)

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/symfony-live-par-sensio-labs-290/feed 0
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
Petit guide pour débuter avec Zend Framework: les bonnes pratiques https://www.php-experts.org/developpement-web/php-developpement-web/petit-guide-pour-debuter-avec-zend-framework-les-bonnes-pratiques-19 https://www.php-experts.org/developpement-web/php-developpement-web/petit-guide-pour-debuter-avec-zend-framework-les-bonnes-pratiques-19#comments Tue, 05 Aug 2008 15:51:03 +0000 Didier https://www.php-experts.org/?p=19 A l’occasion de la sortie de la version 1.6_rc1, j’ai récemment trouvé le courage de me lancer dans la découverte du Zend Framework. Le Framework Zend est une base de développement fiable, s’appuyant sur les bonnes pratiques de programmation orientée objet (POO). Le code subit des tests poussés afin de répondre aux exigences de fiabilité, de rapidité et de sécurité des applications web modernes. La force de frappe de Zend est telle que le framework intègre déjà des classes permettant de manipuler simplement la plupart des API majeures du marché, telles que celles de Google (dont Youtube), Amazon, Yahoo…

Au vu des documentations en ligne existantes, j’ai préféré utiliser pour le moment la version 1.5, plus stable que la 1.6_rc1 (je n’ai pas encore le niveau pour rectifier le tir en cas d’incompatibilité entre les tutoriaux et le code).
Voici un petit récapitulatif des tutoriaux m’ayant permis de faire le premier pas sereinement. J’espère qu’ils vous seront utiles; n’hésitez pas à me faire parvenir d’autres liens afin que je puisse compléter mes compétences, et la liste ci-dessous ;)

  • Michell Hashimoto nous livre ici une série de screencasts très bien réalisés, qui couvrent l’installation et les premiers pas sous Zend Framework. En anglais, ils détaillent l’arborescence de base d’un projet, l’utilisation des librairies, et la création du “bootstrapper”, script de démarrage qui sera appelé à chaque chargement de page (e oui, on code bel et bien en véritable MVC).
    Getting Started with Zend Framework, en anglais, par Mitchell Hashimoto
  • Premiers pas pratiques avec le Zend Framework (version 1.5) en approche MVC (modèle-vue-contrôleur) propre. Pas-à-pas, plein d’exemples: on apprendra ici à créer un répertoire de disques (albums) avec ajout, édition et suppression, en utilisant une base de données grâce à la couche PDO (Php Data Objects) et en utilisant un fichier ini contenant la configuration de l’application.
    Débuter avec Zend Framework 1.5 (approche MVC) en français, par Guillaume Rossolini
  • Après avoir repris brièvement les bases de la programmation PHP accompagnée du Zend Framework, Julien Pauli détaille les classes utiles du package: Zend_Db et le très important Mapping Objet Relationnel, qui permet d’utiliser les possibilités avancées de tout bon SGBDR moderne (bon, ok, pour du web, on se contente souvent de MySQL, mais cela concerne aussi, pour ne citer que lui, PostgreSQL…), ainsi que Zend_View, le gestionnaire de vues MVC du Zend Framework.
    Présentation du Zend Framework en français, par Julien Pauli
  • Vous pouvez aussi consulter le manuel Zend Framework officiel en français. Pensez à bien garder le Guide de référence du programmeur de Zend Framework sous les yeux, c’est une Bible à laquelle vous devrez souvent vous référer.
]]>
https://www.php-experts.org/developpement-web/php-developpement-web/petit-guide-pour-debuter-avec-zend-framework-les-bonnes-pratiques-19/feed 5
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
php-experts : un blog rempli de tutoriels PHP https://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/php-experts-272 https://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/php-experts-272#comments Sun, 15 May 2005 12:46:59 +0000 Didier https://www.php-experts.org/?p=272 Bonjour, ami lecteur.

Ce blog PHP me sert de bloc-notes dans mes développements, principalement en PHP mais aussi dans la gestion courantes des serveurs Unix/Linux (préférence pour la distribution Debian), les systèmes de bases de données relationnelles (SGBDR) comme MySQL, Oracle et Postgres (préférence pour MySQL).

Je poste régulièrement mes découvertes, et j’espère qu’elles vous seront utiles. En ce moment, mon attention se porte notamment sur :

  • le Perl, langage de script modulaire qui reprend des fonctionnalités du C et des langages de scripts sed, awk et sh (shell), très pratique en ce qui concerne l’automatisation de tâches sous Linux
  • L’Objective-C, utilisé notamment pour le développement sur iPhone et Mac OS X d’Apple (basé sur Cocoa, une bibliothèque de classes)
  • le développement MySQL avancé: fonctions et procédures stockées…

N’hésitez pas à vous abonner à mon flux RSS et/ou à me suivre sur Twitter. Vous pouvez aussi suivre PHP-Experts sur Facebook (NetworkedBlogs). A bientôt !

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/php-experts-272/feed 0