Kamelot Blog

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 29 juillet 2010

jeu
29
juil '10

PHP-FPM (FastCGI Process Manager)

PHP-FPM est disponible dans le dernier php (5.3)... mais qu'est-ce-que c'est ?

PHP-FPM (FastCGI Process Manager) est une alternative à PHP FastCGI avec toute une série d'amélioration.

Principalement utile pour les sites à fort taux d'utilisation.

Plusieurs VHosts avec un UID/GID différent et des PHP.ini différents.

FPM permet de faire tourner plusieurs VHosts avec un UID/GID différent et des PHP.ini différents.

Support de l'upload accéléré

Statistique de base

similaire à mod_status d'apache.

Redémarrage de secours en cas de destruction accidentelle de l'opcode

Un header d'erreur

une config style

[ini]
 fastcgi.error_header = "HTTP/1.0 550 Server Made Big Boo"

... provoquera l'envoi de cette erreur au lieu d'en "200 tout va bien" avec une page blanche.

amélioration de la gestion des processus en cas de graceful stop/start

En pratique ca permet de prendre en compte une nouvelle config qui nécessite un redémarrage sans interrompre ce qui avait commencé avec l'ancienne configuration.

Journalisation des scripts lents

avec

[xml]
    <value name="request_slowlog_timeout">5s</value>
    <value name="slowlog">logs/slow.log</value>

donnera

[log]
 Sep 21 16:22:19.399162 pid 29715 (pool default)
 script_filename = /local/www/stable/www/catalogue.php 
 [0x00007fff23618120] mysql_query() /srv/stable/common/Database/class.MySQLRequest.php:20 
 [0x00007fff23618560] getResult() /srv/stable/common/Database/class.Facade.php:106 
 [0x00007fff23618aa0] query() /srv/stable/common/mysite.com/ORM/class.UsersMapper.php:99 

Journalisation de Stdout & stderr

fastcgi_finish_request()

une fonction spéciale pour clôturer la connexion avec le client, mais continuer un traitement php à découvrir en détail ici

Autres points

  • PHP-FPM est compatible avec ZendOptimizer

à lire aussi

Notes

[1] Qui, le temps de rédiger et publier cet article, a déjà été retravaillée. C'est la magie wikipedia

mercredi 28 juillet 2010

mer
28
juil '10

Utiliser Zend_Log

Allez on va essayer d'utiliser Zend_log convenablement.

L'idée c'est de découper les moments de décisions.

  1. J'écris mon code je décide de journaliser un message ou des infos
  2. Je gère mes journaux, je décide où va tel ou tel message.
  3. Je gère plusieurs staging, je change le comportement des mes dispatching
  4. Je change le format de stockage de mon journal, je décide comment disposer des informations reçues
  5. Je décide où je lis/récupère mes messages.

Julien débroussaille Zend_log dans sa Présentation du Zend Framework et une liste de tuto permet de compléter

J'écris mon code je décide de journaliser un message ou des infos

Pendant que je code ma réflexion doit se limiter à

  1. quel message envoyer
  2. quelles infos complémentaire envoyer
  3. quelle gravité/sévérité/catégoriser de message j'envoie.
<?php 
$log->info('Hello log');
?>

ajoutons une info

<?php 
$log->info('Hello log je suis à la ligne ' . __LINE__);
?>

Bon là on a envoyé le message

Je gère mes journaux, je décide où vont les messages.

Ca se passe plutôt dans le script. On prépare un objet ($log). qui sera utilisé par la suite dans le code mais on va commencer à lui dire que faire de ces messages qui remontent.

<?php 
$log = new Zend_Log();
?>

Première chose (évidente) assigner les writers (les scribes).

<?php 
$redacteur = new Zend_Log_Writer_Stream('/repository/des/ficher.log');
$log ->addWriter($redacteur);
?>

là c'est dans un un fichier mais "stream" permet aussi un accès plus large,

<?php 
$redacteur = new Zend_Log_Writer_Stream('php://output');
?>

Et on a pas que "stream", ca peut-être aussi

  • dans une base de donnée -> Zend_Log_Writer_Db,
  • dans firebug -> Zend_Log_Writer_Firebug,
  • dans un email -> Zend_Log_Writer_Mail,
  • dans un mock -> Zend_Log_Writer_Mock
  • dans syslog -> Zend_Log_Writer_Syslog
  • dans le néant ... (si le temps du développement ou de tests intensifs, vous ne voulez pas polluer vos logs, redirigez les un temps dans null -> Zend_Log_Writer_Null

//php <?php

$redacteur = new Zend_Log_Writer_Null;

?> ///

et si ca ne me plait pas je peux faire mon scribe en partant de Zend_Log_Writer_Abstract

je décide où va tel ou tel message.

Si c'est pour mettre la même chose partout ce n'est pas spécialement intéressant.

On va donc filtrer les messages à envoyer à chaque scribe. (rédacteur dans la doc)

Pour ca on a 4 outils

  • Zend_Log_Filter_Interface
  • Zend_Log_Filter_Message
  • Zend_Log_Filter_Priority
  • Zend_Log_Filter_Suppress

Je change le format de stockage de mon journal, je décide comment disposer des informations reçues

La façon dont on écrit chaque message est un format "par défaut" mais il peut être redéfini

  • Zend_Log_Formatter_Firebug
  • Zend_Log_Formatter_Interface
  • Zend_Log_Formatter_Simple
  • Zend_Log_Formatter_Xml

En utilisant cela vos pourrez

samedi 24 juillet 2010

sam
24
juil '10

Batch : Attention à la mémoire vive et au reste ...

Olivier Hoareau nous rappelle de faire attention à la mémoire vive dans les batch.

Je viens juste en remettre un couche par rapport à des petits bugs identifiés récemment dans différentes relecture de vieux code.

boucle environementée

Il ne faut pas voir un batch comme une application, mais comme un environnement à reseter à chaque itérations.

C'est à dire que la consommation de vos ressources doivent être le même en fin de chaque loop. Et il ne faut qu'un loop.

Classiquement on a lecture - traitement - écriture.

Il faut éviter le réflexe de "tout lire" -> boucler sur ce qu'on a lu -> "tout écrire"

Il faut envisager le processus "lecture - traitement - écriture." au niveau de la ligne.

Un exemple, avec un fichier CSV à transformer en tableau HTML.

Premier réflexe, on découpe traitement et affichage.

<?php
 $arrayContenuDuCsv = readCsvFile(); 
 // contient une boucle qui "lit" toutes les lignes
 
$arrayResultat = traitementDesDonnees($arrayContenuDuCsv);
 // contient une boucle effectue les traitements sur chaque ligne
 
 $stringHtml = arrayToHtmlTable($arrayResultat); 
 // contient une boucle effectue les traitements sur chaque ligne
 
 // traitement fini, j'affiche
 echo $stringHtml;

le problème c'est que

<?php
 $arrayContenuDuCsv = readCsvFile(); 
 // contient une boucle qui "lit" toutes les lignes
 
 // ici $arrayContenuDuCsv est de taille non maitrisée, dépendant de la taille du fichier
 
 $arrayResultat = traitementDesDonnees($arrayContenuDuCsv);
 // contient une boucle effectue les traitements sur chaque ligne
 
 // ici $arrayResultat est de taille non maitrisée, dépendant de la taille du fichier
 // pire, comme on a pas encore fait de "unset" de $arrayContenuDuCsv on a le csv en double en mémoire!!!!
 
 $stringHtml = arrayToHtmlTable($arrayResultat); 
 // contient une boucle qui éffectue les traitements sur chaque ligne
 
 
 //ici $stringHtml est de taille non maitrisée, dépendant de la taille du fichier
 // pire, comme on a pas encore fait de "unset" de $arrayResultat on a le csv en double, 
 // et si on a à faire a un très mauvais codeur, il n'a même pas fait de unset($arrayContenuDuCsv)
 // et on a le fichier en triple
 
 // traitement fini, j'affiche
 echo $stringHtml;

Il faut donc voir l'application au niveau du traitement de la ligne

<?php
 $arrayContenuCsv = readCsvRow(); // <- contient une boucle qui "lit" UNE ligne
 
 //ici $arrayContenuCsv est de taille maitrisée, 1 ligne
 
 $arrayResultatLigne = traitementDesDonnees($arrayContenuCsv);
 // contient un traitement identique pour chaque ligne
 
 //ici $arrayResultat est de taille maitrisée, 1 ligne
 
 $stringHtml = arrayToHtmlRowTable($arrayResultat);  //ici $stringHtml est de taille maitrisée, 1 ligne
 // traitement fini de ligne, j'affiche
 echo $stringHtml;

Bien entendu il faut mettre tout ceci dans une boucle, ajouter le header et le footer de ma table, mais ca reste du traitement unique.

Initialiser ses variables.

Voici un autre cas de mauvaise écriture que j'ai rencontré.

[php]
<?php
$arrayData = array();
$arrListedeListes = getListeDeListe();
foreach ($arrListedeListes as $arrListe )
{
     foreach ($arrListe as $ligne)
     {
           $arrayData[]=getResultatDuTraitementDeLaLigne($ligne);
     }
     $result= ecritureDesDatas($arrayData);
}

Le développeur a vu qu'en faisant cela au deuxième passage le traitement des données incluait le nouvelles mais aussi celle de la passe d'avant.

Solution appliquée par le développeur

[php]
<?php
$arrayData = array();
$arrListedeListes = getListeDeListe();
foreach ($arrListedeListes as $arrListe )
{
     $i=0; // <- il a réinitialisé son compteur
     foreach ($arrListe as $ligne)
     {
           $arrayData[$i]=getResultatDuTraitementDeLaLigne($ligne);
           $i++;
     }
     $result= ecritureDesDatas($arrayData);
}

Très mauvaise idée parce qu'en fait ce n'est qu'une version aussi erronée que la précédente mais en masquant un peu le problème.

En effet, en écrasant sans effacer la liste précédente, il se fait que dés qu'une liste était plus courte que la précédente, les lignes en surplus était reconsidérées à nouveau.

[php]
<?php
$arrListedeListes = getListeDeListe();
foreach ($arrListedeListes as $arrListe )
{
     $arrayData = array();

     foreach ($arrListe as $ligne)
     {
           $arrayData[$i]=getResultatDuTraitementDeLaLigne($ligne);
           
     }
     $result= ecritureDesDatas($arrayData);
}

Autres outils

Avec Zend_Framework il existe un outil qui permet de gérer le traitement gourmands en entrée et surtout en sortie c'est Zend_Memory.

Il va permettre de gérer des grosses entités de données en plaçant hors de la mémoire vive ce qu'on n'utilise pas.

Il place l'inutilisé dans un des backends Zend_Cache.

Pensez aussi à lire l'article d'Olivier Hoareau : attention à la mémoire vive.

mercredi 14 juillet 2010

mer
14
juil '10

Contrer les CSRF avec Zend_Form

Je n'avais pas repéré cet élément qui me semble bien pratique. l'élément hash Il permet de contrer les CSRF.

class Mon_Form_que_je_protege extends Zend_Form {
  public function init() {
    $this->setMethod('post');
    $this->addElement( 'submit'
                     , 'submit'
                     , array( 'ignore'   => true
                     , 'label'    => 'Submit'
                     ,)
                     );
    $form->addElement( 'hash'
                       , 'evite_csrf_foo'
                       , array( 'salt' => 'unique')
                       );
 
}

On demande à Zend_Form de créer une clé unique à la publication du formulaire et d'ensuite s'assurer que la clé à bien été fournie dans la soumission.

Je pourrais en raconter plus... sauf que quelqu'un l'a déjà fait

à lire aussi : doc API

lundi 12 juillet 2010

lun
12
juil '10

Une date pour PHP TestFest 2010 sur la métropole lilloise ?

Ce post est presque copié-collé de - mageekblog : Une date pour PHP TestFest 2010 sur la métropole lilloise ?

Frédéric Hardy souhaite organiser un évènement dans le courant d'août sur la métropole lilloise dans le cadre de la "TestFest" 2010.

Pour l'instant, le lieu ainsi que la forme sont indéfinis, puisque tout dépendra du nombre de personnes susceptibles de participer.

Il faut aller s'inscrire sur doodle

mardi 23 février 2010

mar
23
fév '10

PHPBenelux meeting ce vendredi 19h30 à Leuven

Au Café Sport, juste en face de la gare (comme pour les mysql ug meeting et aperophp qui se sont fait à Leuven)

Macq Électronique paye une tournée.

Schedule:

  • 19:30 - 20:00: welcome
  • 20:00 - 20:50: Zend Framework JQuery by Dennis De Cock
  • 20:50 - 21:00: break
  • 21:00 - 21:50: libre. Quelque chose à présenter ? -> info@phpbenelux.eu.
  • 21:50 - 22:00: Raffle and free podium
  • 22:00 - ... : Drinks and networking

samedi 13 février 2010

sam
13
fév '10

avant - après : array_rand()

Petite optimisation d'un vieux bout de code qui trainait

Avant

[php]
   if (isset($arrItem)) {
      $items_selected_nbr = sizeof($arrItem);

    if ($items_selected_nbr>2) {

      srand((double)microtime() * 1000000);
      $itemList[0] = rand(0,($items_selected_nbr) - 1);

      do {
        srand((double)microtime() * 1000000);
        $rand = rand(0,($items_selected_nbr) - 1);
      } while (in_array($rand, $itemList));
      $itemList[1] = $rand;

      do {
        srand((double)microtime() * 1000000);
        $rand = rand(0,($items_selected_nbr) - 1);
      } while (in_array($rand, $itemList));
      $itemList[2] = $rand;


      $itemList[0] = $arrItem[$itemList[0]];
      $itemList[1] = $arrItem[$itemList[1]];
      $itemList[2] = $arrItem[$itemList[2]];
?>

Après

[php]
<?php
$itemList = array_intersect_key($arrItem, array_flip(array_rand($arrItem, min(3,count($arrItem)))));
?>

Le source pour tester

En fait l'ancien code retourne toujours 3 éléments qui se suivent. et rien du tout si le tableau initial est plus petit que 3

jeudi 4 février 2010

jeu
04
fév '10

Forum PHP Benelux 2010

Le Forum PHP Benelux 2010 a eu lieu ce WE

Photos

Voici quelques photos.

Feedbacks




Slides glanés

jeudi 28 janvier 2010

jeu
28
jan '10

Chaque chose en son temps avec Zend_Queue

Zend_Queue a été proposé par Justin Plock et ajouté à Zend_framework.

En voici la documentation

Voici son API

Dans cet exemple pour l'envoi de mail vous trouverez le script appelé, le cron appelant et la classe qui mes ses emails en queue.

Il peut utiliser MemcacheQ, Simple Queue Service over Memcache.

Moi j'ai commencé mes essais avec Zend_Queue, vous pouvez récupérer cela par SVN. Et suivre mon repository où je rassemble les exemples de la doc et des tutos, ainsi que mes propres essais.

Quelques lectures Stacks and Queues, Files sur Wikipedia, priority Queue, point de vue théorique : mise en bouche en français créusée en anglais, dans la SPL

lundi 25 janvier 2010

lun
25
jan '10

PHP Version Sérieuse.

Colombo 2.0 une délicieuse parodie, qui devrait tous vous mener à lire le livre blanc sur l'industrialisation des développements php.

Utilisez vous un IDE ? Un système de versionning ? Comment déployez-vous ? Comment testez vous ? Les developpeurs sont-ils des dactylo ? L'erreur est-elle acceptable ? Qui fait de la veille ? Quels outils de contrôle automatisé avez vous intégré dans vos process ? Avez vous aussi créé votre propre framework parce que les autres ne font pas ce dont vous avez besoin ? Avez vous profilé avant d'optimiser ? Votre documentation est à jour et reconstruite toutes les nuits ?

Au forum php, Anna Filina nous montrait comment Motiver ses développeurs

Lire la suite...

samedi 16 janvier 2010

sam
16
jan '10

PHP Mess Detector 0.2 released.

Ca commence avec

$ pear channel-discover pear.pdepend.org 
$ pear channel-discover pear.phpmd.org 
$ pear install --alldeps phpmd/PHP_PMD-alpha

Puis une lecture du post de Manuel Pichler

PHPMessDetector est une application frontend, customisable et pratique pour Php_Depend. Un outil d'analyse de code qui permet de cartographier les dépendances entre les différents packages de classes composant une application. présenté ici

mercredi 13 janvier 2010

mer
13
jan '10

De nouveaux channels pour pear

Un channel pear, c'est un repository de packages.

Contrairement à Zend Framework, Pear c'est plus qu'une librairie de classes.

Pear c'est aussi un mécanisme d'installation similaire à ce qu'on utilise pour les RPM.

Envie de faire le vôtre ?

J'expliquais cela il y a 4ans

Mais allez directement à la source :

mardi 12 janvier 2010

mar
12
jan '10

Zend_Locale_Format::convertNumerals return NULL

En voulant essayer l'exemple 31.40 de la doc de ZendFramwork Je me confrontais à un petit problème

Zend_Locale_Format::convertNumerals retourne NULL

En fait ca vient du fait que mon php.ini défini iconv.internal_encoding à ISO-8859-1 et pas UTF-8

  • Solution n°1 : Zend_Framework 1.10 (réparation / test)
  • Solution n°2 : changer iconv.internal_encoding avec un ini_set ou dans la config php/

jeudi 31 décembre 2009

jeu
31
dec '09

Saviez vous qu'il y a un 0 janvier

0 janvier

Alleï. Bonne année !!

Non non je ne vais pas m'en arrêter à ca.

Voici d'autres petites astuces ou choses à savoir...

1 jour = 24 heures x 60 minutes x 60 secondes ...soit 86400 secondes..

toujours ?

non : occasionnellement en juin et/ou en décembre on ajoute une seconde additionnelle et on a 86401 secondes donc l'heure 23:59:60 existe ces 2 jours là. C'est comme pour le 29 février tous les 4 ans. C'est pour corriger un décalage.

A propos de ces 29 Février. C'est vraiment tous les 4 ans ? enfin presque

Il n'y a pas de 29 février les années divisible par 100 qui ne sont pas divisible par 400.

Notez que ce n'est pas encore parfait car cela engendre encore une erreur de 3 jours tous les 10 000 ans.

Nos amis Suédois et russes ont même eut des 30 Février. Mais ca n'a pas eu beaucoup de succès (et en plus ce n'était pas en même temps).

Ce post m'a été inspiré par l'article : Unix Epoch and PHP's calendar system de Derick et du livre sur les Dates dans PHP (par Derick Rethans) que j'ai gagné au phpBelgium Meeting de Gent.

En php on utilise ISO 8601, toujours intéressant à lire.

On y trouve un entre autre un lien vers l'explication des numérotation de semaines qui est à l'origine de problèmes encontrés avec php ou mysql

vendredi 25 décembre 2009

ven
25
dec '09

Zend_Form

Starter kit pour Zend_Form

Lire la suite...

Tags