XHTML.net

Technology talks by Loïc d’Anterroches

News, articles, PHP, scripts, XHTML/CSS, …

  1. Home
  2. PHP: Hypertext Preprocessor
  3. Pluf - Framework en PHP5

Habitudes pour la montée en charge des applications web PHP

The 2010-06-07 at 18:51 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.


ou pourquoi je hais les présentations faites pour des experts qui ensuite collent leurs slides sur le réseau. J’ai déjà critiqué pour cela un des membres actifs de Symfony et je vais vous faire une lecture critique des slides de Habits of Highly Scalable Web Applications.

Notez que probablement, dans le podcast de 1h, des explications plus détaillées sont distillées mais personne ne va l’écouter et tout le monde va regarder le pdf.

Le problème de base est que vous ne trouverez pas le moindre vrai point d’interrogation dans ces slides alors que la base pour la montée en charge c’est de se poser les bonnes questions et d’avoir les mesures pour prendre ensuite les bonnes décisions.

En gros, il présente du déjà dit et donne comme chemin pour la montée en charge de l’application web :

  1. on commence tout simple avec un serveur
  2. puis on découpe serveur web + base de données
  3. puis on ajoute des machines sur chaque niveau en mettant des esclaves pour la base de données
  4. puis on met en cache (c’est traité en dernier dans les slides, mais bon, on sait qu’il faut faire cela avant les esclaves)

Comme les questions sont rhétoriques sans fondamentaux, les réponses sont directes sans nuance et analyse :

  • slides 13/14 l’option de mettre un slave en face de chaque serveur est rejetée sans faire remarquer que si le load balancer sur le web serveur hash par ip, on peut faire travailler chaque slave pour un groupe d’utilisateur donné et donc avoir une meilleure mise en cache des données au niveau de l’OS et donc éviter des accès disques inutiles tout en gardant la flexibilité de passer de l’un à l’autre en cas de besoin si on a une erreur.
  • l’étape 4 du partitioning arrive après les slaves. Pourquoi ? Google partitionne avant de faire du slave car l’index ne tient pas sur un serveur. Cheméo c’est pareil, je dois faire du partitionnement avant d’avoir des slaves car sinon je finis par faire de l’accès disque.
  • slide 31 pour les bonnes pratiques de mise en cache, write through cache arrive en premier. Il oublie que cela dépend des besoins, on peut avoir une cache qui dit, je n’ai rien et donne rien (perte "partielle" de l’information) et on laisse en tâche de fond un write back qui va mettre à jour.

En gros, une liste de recettes mais pas le pourquoi. Le truc pour faire grandir votre site est simple, tout simple, tellement que cela ne permet pas d’écrire un livre et vendre des heures de consultant par milliers. Il est connu depuis des dizaines d’années dans l’industrie, c’est connu dans le grand public sous le nom de la méthode de Toyota et cela s’appelle la gestion intégrale de la productivité ou total productivity management (TPM).

TPM, c’est simple :

  1. on mesure tout ce qui se passe ;
  2. on cherche les goulots d’étranglement ;
  3. on supprime les goulots en utilisant les bons moyens ;
  4. on recommence ad vitam eternam.

Entre la productivité d’une raffinerie pour mieux convertir le pétrole en essence et diminuer les besoins d’aller faire de l’ultra deep offshore et la productivité de votre site web (la capacité à répondre aux requêtes dans les temps impartis) il n’y a pas de différence de méthodologie.

Mais cela veut dire que la première étape pour un site qui monte en charge c’est de tout écrire et garder des logs de performance pour savoir exactement quels sont les points problématiques. C’est ensuite que l’analyse des tendances est possible et qu’il est alors possible d’agir avant que le problème ne survienne et que si le problème survient, on peut faire quelque chose en connaissance de cause.

La prochaine fois que vous lisez un document avec des recettes, posez-vous la question du pourquoi avant d’appliquer une recette et vérifier d’où vient votre problème avec vos logs. Toutes les recettes dans cette présentation sont bonnes, mais il manque le contexte, voilà pourquoi je hais le powerpoint sur le réseau.

Quel framework PHP/Python/Ruby choisir si vous devez apprendre un nouveau aujourd'hui ?

The 2010-04-27 at 09:33 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Supposez que vous codez avec Symfony et que vous le trouvez lourd et n’avez pas la patience d’attendre la version 2 qui devrait améliorer cela ou que vous codez avec Pluf et que si vous le trouvez super rapide vous voulez découvrir autre chose et vous êtes séduit par les sirènes de Django ou Ruby on Rails. En gros, vous voulez changer et vous ne savez pas très bien quel framework choisir pour votre changement. Si vous avez la chance de pouvoir prendre le temps d’apprendre comme vous voulez, voici mon avis, issu de 15 ans de développement de sites internet :

  • Symfony : Poubelle.
  • Pluf : Poubelle.
  • RoR : Poubelle.
  • Django : Poubelle.
  • Votre framework inspiré de Django/RoR/etc… : Poubelle.

Une autre question ? Poubelle.

Si vous devez apprendre quelque chose aujourd’hui pour demain, n’investissez pas votre temps dans des frameworks conçus sur des concepts vieux de 10 ans. Investissez votre temps dans des concepts nettement plus prometteurs.

Les problèmes des frameworks actuels

Le premier problème est l’ORM. Vous allez traîner avec plus ou moins de succès une correspondance entre votre base de données SQL et votre code orienté objet. Par exemple pour la homepage de The Onion, codé avec Django, ils ont besoin de 800 ms pour générer le SQL et 400 ms pour faire les requêtes et cela ne prend même pas en compte le coût pour convertir le résultat de la requête en objets Python.

Que vous utilisiez un framework ou un autre, vous aurez ce problème dans la majorité des cas.

Le second problème vient du langage et de la manière d’écrire votre code car il est toujours implicitement séquentiel : Faire A, puis B, sinon C, puis D, etc… Je prenais l’exemple suivant avec l’excellent piouPiouM (Si vous cherchez un excellent développeur web sur la région lyonnaise, il est bientôt dispo) :

Avec Indefero vous listez le contenu d’un répertoire de votre dépôt Subversion, le répertoire contient 5 fichiers à 5 révisions différentes. Combien vous faut-il d’appels systèmes à Subversion pour les lister avec le message de commit de chaque révision ? 6 appels. 1 pour la liste, 5 pour les 5 révisions. Supposez qu’il faille 15 ms par appel pour récupérer l’information, cela donne un temps de 80 ms pour récupérer l’information. Pourtant, vous pouvez faire cela en 40 ms.

Vous récupérez la liste, puis vous lancez en parallèle les 5 appels pour récupérer les messages de commit. Comme faites vous cela en PHP/Ruby/Python ? Vous ne le faites pas, car les bibliothèques sont codées pour bloquer sur les appels systèmes et le langage lui-même est conçu pour ne pas vous permettre de faire cela. (Ok, vous avez Twisted, mais ce n’est presque plus du Python…).

Votre langage et votre framework sont lourds via l’ORM et par définition non performants de part leur structure.

Le premier sauveur, node.js

node.js est un projet qui repart d’une feuille blanche et est conçu pour ne jamais bloquer. Vous programmez avec des callbacks et toutes vos actions peuvent être lancées simultanément. Surtout, toutes les bibliothèques sont conçues pour ne pas bloquer. Vous pouvez donc exécuter en parallèle des séries d’actions pour récupérer les informations qui vont être utilisées pour construire votre page. Vous laissez le soin à votre OS de gérer la pile des accès disques pour avoir une exécution dans le meilleur sens…

Le second sauveur, JSON

Si vous n’avez pas besoin des fonctionnalités ACID de votre RDBMS, utilisez autre chose (même un simple stockage dans des fichiers textes) mais stockez au format JSON. Vous pourrez stocker aussi cela dans MongoDB. JSON, c’est simplement des listes, dictionnaires, en gros, un stockage simple des structures de données que vous avez normalement dans votre programme, pas de lourdeur dans la conversion entre votre stockage et votre code.

Au final, node.js, JSON et MongoDB

Si je devais démarrer un projet avec un peu de temps devant moi je prendrais :

  • Node.js pour le faire tourner.
  • MongoDB pour stocker les données.
  • JsonTemplate pour formatter les données.
  • Un système à la Pluf pour router les requêtes.

Cela donne un système haute performance, non bloquant, sans la lourdeur d’un ORM et nettement plus "future proof" que le gros des troupes du moment.

Bien entendu, je continuerais d’utiliser Indefero pour héberger mon code (non, ceci n’est pas une publicité).

Funnel analysis avec Pluf, PHP et MongoDB

The 2010-04-10 at 16:09 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Si vous n’avez pas lu l’article sur les tests A/B avec Pluf, c’est le moment de le lire avant de revenir ici.

Quand on cherche à vendre ou à faire faire une action par une personne sur un site, cela correspond souvent à de multiples étapes successives. Il est alors intéressant de suivre les pertes le long des étapes, c’est l’analyse de l’entonnoir ou funnel analysis. Le but est de savoir quelle étape doit être améliorée. Pluf permet de faire cette analyse en une ligne de code par étape. Le résultat est le suivant :

Funnel analysis with Pluf

Vous pouvez voir pour le funnel les pertes à chaque étape et le résultat final de 11,30%, vous pouvez aussi voir pour les propriétés de vos visiteurs (vous les configurez comme vous voulez) la conversion par étape et au final. Ici je filtre sur la propriété "month_price" et je peux constater que si elle vaut 1 j’ai un taux au total de 9.9% et si elle vaut 0 j’ai un taux de 12.18%. Et oui, "month_price" est en fait un test A/B. Je peux suivre l’impact de mon test A/B tout au long de mon funnel !

Et dans le code ?

Fidèle à l’esprit et la forme de Pluf, le code PHP est simple et élégant, totalement inspiré de MixPanel.

Pour noter une étape dans le funnel :

Pluf_AB::trackFunnel('forge_creation', 1, 'Plans', $request);

C’est l’étape 1, nommée Plans du funnel forge_creation.

Pour ajouter des propriétés de vos visiteurs à suivre :

 Pluf_AB::register($request, array('month_price' => $month_price));

Et là, $month_price peut être la valeur d’un test A/B, le pays du visiteur, etc. Vous pouvez en ajouter autant que vous voulez et vous pouvez les ajouter à tout moment dans vos vues.

Oui, c’est tout, rien d’autre, nada, une ligne et boum cela fonctionne.

Tests A/B avec PHP, Pluf et MongoDB en 4 lignes de code

The 2010-04-08 at 19:55 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Si vous voulez optimiser votre site pour augmenter votre taux de conversion, rendre votre site plus agréable pour vos visiteurs, une solution simple et efficace est de réaliser des tests dits "A/B". Un test "A/B" ou "split test" est tout simple:

Vous donnez à 50% de vos visiteurs la version A de votre site et aux autres la version B. Vous regardez ensuite quelle version marche le mieux.

A/B testing avec Pluf en PHP

Vous aimez jouer au poker ou aux dés ? Oui ? C’est très bien, car cela veut dire que vous avez une petite idée des statistiques. Un test A/B peut être très facilement analysé avec une série de tests statistiques standards, le test Z, pour savoir si c’est la chance qui vous annonce que la version A est meilleure que la B ou si c’est vraiment le cas. Cela vous permet aussi de savoir si vos dés sont pipés :).

À partir de ce test, on peut calculer la certitude avec laquelle on sait que la version A est meilleure que la B. Une certitude de 50% veut dire qu’on a aucune idée, c’est 50/50. Pour être vraiment certain, il faut avoir une certitude de 95% (ce n’est de la chance qu’une fois sur 20). Sur la capture d’écran, vous avez une certitude de 93%, c’est très bien, mais il vaut mieux attendre au moins une exposition à 100 ou 150 personnes par alternative pour considérer le test comme terminé.

Maintenant, si vous n’aimez pas les stats, mais que vous avez compris que cela va vous permettre d’améliorer massivement votre application en testant différentes pages, vous avez raisons. Si vous codez en PHP et que vous connaissez le framework Pluf, vous avez de la chance, le système de tests A/B est inclut en standard.

La première chose à faire est de lancer MongoDB pour stocker les résultats des tests et d’avoir Memcached ou APC comme cache Pluf histoire que les performances soient optimales.

Ensuite, vous mettez dans le code de votre vue:

$download_style = Pluf_AB::test('download_style', $request,
              array('normal', 'bold', 'italic', 'bolditalic'));

Cela veut dire que vous faites le test ‘download_style’ et que vous avez 4 alternatives. J’utilise la valeur de $download_style dans mon gabarit pour afficher le bon style.

Dans ce cas test, j’ai fait une vue qui fait la redirection vers la page de download du logiciel et dans cette vue je mets simplement avant la redirection :

Pluf_AB::convert('download_style', $request);

Cela veut dire que j’ai eu une conversion pour cette utilisateur. L’utilisateur est suivi par des cookies et le système est correctement résistant aux robots.

2 lignes de code pour un test A/B avec Pluf !

Maintenant pour voir les stats comme dans la capture d’écran, il vous suffit d’ajouter à la définition de vos urls, la vue suivante :

array('regex' => '#^/urlquevousvoulez/$#',
      'base' => $base,
      'model' => 'Pluf_AB_Views',
      'method' => 'dashboard',
      'name' => 'pluf_ab_dashboard'
      ),

C’est simple, efficace et comme d’habitude haute performance…

Utiliser assert pour faire du log à haute performance en PHP

The 2009-10-31 at 09:30 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Imaginez que vous vouliez tracer des informations dans l’exécution de votre application web, en gros, logger des informations, vous trouverez très facilement des class PHP vous permettant d’ajouter cela dans votre code :

// mon code qui fait quelque chose
$logger->log('Mon information');
Mon_Logger::debug($variable);
// la suite du code etc...

Dans le premier cas vous loggez via une méthode d’un objet, dans le suivant via une méthode statique, cela pourrait aussi être via un code du genre Factory::get('logger')->log('message').

Cette approche a malheureusement 2 problèmes :

  1. une perte de performance du code en production quand on ne veut pas logger ;
  2. le manque de contexte au niveau du log, il faut souvent alors ajouter des informations dans le message pour savoir d’où vient le message.

La perte de performance peut être partiellement levée par l’utilisation de l’injection de dépendances et charger ainsi un objet de log stupide, qui ne fera rien à son appel. Mais on garde alors un triple coût au niveau des performances :

  1. coût de l’injection de dépendance pour charger le bon logger ;
  2. coût de la génération du message pour ensuite ne rien en faire ;
  3. coût de l’appel à une méthode statique PHP utilisateur, qui ne fait rien.

Dans Pluf, je n’ai pas proposé de méthode particulière et je laisse les gens utiliser le système de leur choix car je n’avais pas trouvé de méthode qui limite vraiment la perte de performance en production, jusqu’à hier.

PHP dispose des assertions, les assertions permettent d’évaluer un morceau de code et d’agir si le résultat est false. Je vous laisse lire la documentation, c’est rapide.

Les côtés très intéressants des assertions sont :

  1. on peut les activer et les désactiver dynamiquement ;
  2. si on passe une chaîne en entrée elle est évaluée comme du code dans le contexte local ;
  3. on peut récupérer le nom du fichier et la ligne où l’exception a été exécutée via un callback.

Conclusion, vous pouvez mettre votre code à logger dans votre chaîne pour votre exception et si votre logger retourne false votre callback va se faire appeler. Si dans votre logger vous ne faites que stocker temporairement votre message, vous pouvez dans le callback reconstituer l’ensemble des informations et vraiment stocker dans votre fichier de log ou ailleurs.

Voici un bout de code pour illustrer :

<?php
function log_assert($file, $line, $code)
{
    $GLOBALS['log'][] = array(
        microtime(true),
        $file, $line, $code,
        isset($GLOBALS['last_assert_res']) ? $GLOBALS['last_assert_res'] : ''
                              );
    $GLOBALS['last_assert_res'] = null;
}

function logger($text)
{
    $GLOBALS['last_assert_res'] = $text;
    // false va forcer l'appel à log_assert
    return false; 
}

// Active les assert en les rendant silencieuses
assert_options(ASSERT_ACTIVE, 1); 
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_QUIET_EVAL, 1);
assert_options(ASSERT_CALLBACK, 'log_assert');

$assert = array(1, 0);
$n = 10000;
foreach ($assert as $active) {
    $GLOBALS['log'] = array();
    assert_options(ASSERT_ACTIVE, $active); 
    $start = microtime(true);
    for ($i=0;$i<$n;$i++) {
        assert('logger($i.' is an integer')');
    }
    $time = microtime(true) - $start;
    print "Assert active: $active\n";
    print "Elapsed time: $time\n";
    print "Per call: ".($time/$n)."\n";
    print "Log size: ".count($GLOBALS['log'])."\n\n";
    if (count($GLOBALS['log'])) {
        var_dump($GLOBALS['log'][0]);
        print "\n\n";
    }
}

Cela vous donnera un résultat du genre :

$ php test.php 
Assert active: 1
Elapsed time: 0.403494119644
Per call: 4.03494119644E-5
Log size: 10000

array(5) {
  [0]=>
  float(1256912192.17)
  [1]=>
  string(36) "/home/loa/Projects/pluf/tmp/test.php"
  [2]=>
  int(32)
  [3]=>
  string(27) "logger($i.' is an integer')"
  [4]=>
  string(15) "0 is an integer"
}


Assert active: 0
Elapsed time: 0.03799700737
Per call: 3.799700737E-6
Log size: 0

En gros, votre logger est 10x plus rapide en production si il ne logge rien. Le assert('code') coûte autant que le coût d’un appel de la plus simple des fonctions PHP comme is_numeric ou autre, totalement négligeable en mode production. Si on compare avec l’appel à une méthode statique utilisateur qui ne fait rien, le code qui logge ne coûte que 30% de plus ! La fonction assert est donc très optimisée et on peut en profiter.

Et comme vous avez un framework bien fait, vous pouvez toujours faire la chose suivante :

  1. en fonction de la requête (cookie, url, etc) activer ou non le log ;
  2. accumuler les logs pendant la requête ;
  3. stocker le log dans memcache ou APC en fin de requête ;
  4. flusher les informations sur le disque ou dans votre base de données toutes les x requêtes/minutes.

Notez que c’est la seule manière d’avoir le contexte du message au meilleur coût (pas d’introspection). Un inconvénient quand même, votre message est l’évaluation d’une chaîne de caractères, donc cela se lit moins bien dans le code. J’ai quand même trouvé une méthode pour logger dans Pluf, chouette.

Le rappel de l’existence de assert m’a été fait par François dans les commentaires ici, merci !

Mise à jour: Ceci est une utilisation détournée de la fonction assert, cela peut poser des problèmes si vous combinez cette approche avec du code utilisant assert pour réellement faire des tests. Ce qui me rassure c’est que dans l’intégralité du code PHP que j’utilise, incluant de nombreuses bibliothèques issues de PEAR, je n’ai pas trouvé une seule utilisation de assert.

Combiner type hinting et interfaces en PHP pour sécuriser son code

The 2009-10-27 at 09:42 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Si vous faites du type hinting, c’est qu’à priori vous faites très attention à la structure de vos projets PHP. Si vous avez un code du type :

function maFonction(MaClass $objet) {
    // corps de la fonction
    $objet->faitTruc();
    echo $objet->bidule;
}

vous n’acceptez que des objets de type MaClass en entrée. Supposons que maintenant, une personne veuille utiliser votre fonction avec un objet de la class AutreClass en sachant très bien que son objet fourni les méthodes et propriétés nécessaires à maFonction. Il ne peut pas car AutreClass n’est pas MaClass.

Une approche élégante si vous voulez donner de la flexibilité à vos utilisateurs finaux est de dire : "J’accepte tous les objets qui implémentent la bonne interface.".

 function maFonction(IMaClass $objet) {
    // corps de la fonction
    $objet->faitTruc();
    echo $objet->bidule;
}

Maintenant, il suffit que AutreClass implémente l’interface IMaClass pour satisfaire maFonction. Cela donne de la flexibilité tout en forçant un peu de contrôle car PHP au niveau du langage va forcer le respect de ce contrat entre maFonction et le paramètre. Si vous avez une utilisation parcimonieuse des interfaces dans vos logiques métier (histoire d’éviter d’avoir ensuite des class qui implémentent 5 interfaces ou plus), cela vous donne une certaine assurance, surtout si votre code est ensuite utilisé par d’autres entités dans votre société. Vous êtes certain que la personne a été obligée d’implémenter l’interface avant d’utiliser votre fonction.

Une autre approche est de demander de manière implicite l’interface sans jamais le déclarer réellement dans le code. C’est à dire que la fonction va accepter n’importe quoi :

function maFonction($objet) {
    // corps de la fonction
    $objet->faitTruc();
    echo $objet->bidule;
}

C’est alors au moment de l’exécution dans la fonction que PHP va retourner une erreur si l’interface implicite n’est pas respectée. Ceci peut être très mauvais dans certains cas. Si on suppose que maFonction fait une série d’opérations sur des fichiers et que l’objet fournit les chemins nécessaires :

function maFonction($objet) {
    grosse_copie($objet->source(), $objet->destination());
    nettoyage($objet->sourceExcludeBackup());
    echo $objet->bidule;
}

On va supposer que grosse_copie fait une grosse copie de fichiers de la source vers la destination et que nettoyage va ensuite nettoyer la source mais garder le backup. Dans ce cas là, si l’objet ne fournit pas la méthode sourceExcludeBackup, PHP va s’arrêter après la grosse copie et laisser votre système dans un mauvais état. En ayant utiliser le type hinting, PHP n’aurait même pas commencé l’exécution de maFonction, le système aurait été protégé.

Le type hinting et les interfaces ont un impact au niveau des performances et complexifie le code, donc ces outils doivent être utilisés avec soin, particulièrement dans le cœur d’exécution de votre programme mais ces outils apportent une sécurité indéniable dans certains cas particuliers, surtout dans la logique métier, là où le non respect d’une interface explicite ou implicite peut faire des dégâts.

Un endroit où je n’utiliserais pas le type hinting et les interfaces est par exemple la boucle de dispatch dans une application web. De toute façon si vos objets de requête et de réponses n’implémentent pas les bonnes méthodes, vous allez vite vous en rendre compte et les dégâts seront une requête plantée. L’erreur ne prendra pas longtemps pour être trouvée et corrigée, et dans tous les autres cas vous payerez le prix au niveau des performances, ce qui serait dommage.

Bien utilisée, la combinaison type hinting et interfaces peut donc se montrer être un outil très puissant de contrôle de la qualité.

Pluf, le framework PHP le plus rapide du monde (troll)

The 2009-10-23 at 09:01 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Si vous ne connaissez pas Pluf, le framework PHP le plus rapide du monde, je vous invite à lire une petit brève ici et un benchmark de framework PHP là, vous pouvez aussi lire comment je tire à vue sur certains développements ici avec un benchmark de template PHP là.

Pluf, le framework PHP le plus rapide du monde, c’est aussi un joli troll dans les chaumières des développeurs PHP, il semble que cela commence même à troller dans les SSII sur le sujet. Aïe, pour un programmeur, voir son code être le sujet d’un troll, cela peut paraître ennuyeux, mais dans mon cas, cela me fait très plaisir. Je ne suis pas sado, loin de là, mais essayer de faire passer une idée qui va à l’encontre des pratiques du moment est toujours difficile.

Donc à toutes les personnes qui se moquent, je vous dis merci, et je vous dis surtout continuez ! Continuez de troller sur la rapidité du framework X par rapport au Y.

Maintenant pourquoi je tape sur les bibliothèques et frameworks PHP qui ne font que prendre du poids avec le temps ?

InDefero est une application web dite de forge logicielle. Vous pouvez au choix la télécharger (licence GPL) ou profiter d’un hébergement pour vous contre quelques Euros. L’hébergement InDefero c’est 1500 forges dont 1300 d’actives. Quand vous gérez cela, vous gérez un système qui au niveau performance doit supporter 50 à 100 fois plus de charge qu’une installation unique (la charge se répartie dans la journée avec les fuseaux horaires, donc ce n’est pas un facteur 1000).

Un facteur de 50 à 100, cela veut dire que très rapidement, si vous utilisez des bibliothèques qui font trop, votre composant web va s’essouffler, en gros votre serveur web ne va plus ternir la charge tout seul. Il faut être réaliste, dans la majorité des applications web, la logique métier est principalement de la requête sur la base de données. Donc on peut faire un calcul simple, de derrière d’une enveloppe et décomposer une requête web en 2 parties, logique métier et framework :

  • logique métier: 50ms par requête ;
  • logique framework: 50ms par requête.

On obtient donc une réponse en 100ms pour une requête, performance tout à fait honorable, on va l’appeler le cas optimisé.

Maintenant, je tape dès que je vais des facteurs 3 à 5 sur les performances des bibliothèques. Comme la logique métier est incompressible on obtient :

  • logique métier: 50 ms par requête (ne change pas) ;
  • logique framework: environ 150 ms par requête (facteur 3).

Total 200 ms, un facteur 2.

Cela veut dire quoi ? Cela veut dire que votre ensemble DB + serveur web va avoir besoin de 2 fois plus de cycles CPU pour servir la même charge. Cela veut dire que votre coût pour faire croître votre site va être multiplié par 2.

En fait c’est pas très juste, le premier goulot dans une architecture share nothing est toujours la base de données. Donc dès que le système ne tient plus, on déporte la base sur son serveur propre. Maintenant, on refait le calcul mais on prend en compte la distinction serveur de BD et serveur Web.

Version optimisée par requête :

  • logique métier: 50ms par requête (serveur BD) ;
  • logique framework: 50ms par requête (serveur Web).

Version lourde :

  • logique métier: 50 ms par requête (ne change pas, serveur BD) ;
  • logique framework: environ 150 ms par requête (facteur 3, serveur Web).

Maintenant, si on suppose que dans le cas optimisé un serveur web peut saturer un serveur de BD, on obtient pour assurer la même charge :

  • Version optimisée : 1 serveur web et 1 serveur de base de données.
  • Version lourde : 3 serveurs web et 1 serveur de base de données.

Facteur 2 au total, mais un facteur 3 sur le front end. Je vous laisse penser à tous les problèmes de répartition de la charge et de synchronisation du code que cela implique ainsi que les coûts associés. Bien entendu c’est du calcul de dos d’enveloppe donc à prendre comme un ordre de grandeur surtout l’approximation logique métier équivalente aux requêtes vers la base de données.

Pourquoi un différence si importante ? Car à tous les échelons, le choix à été fait de prendre la solution qui fait plus au cas où qui n’arrive dans 99% des cas jamais mais qui coûte 3 fois plus de cycles. L’agilité c’est introduire dans un système la complexité strictement nécessaire et suffisante en choisissant les bons outils et en refactorisant en continu. C’est très dur (j’ai vraiment du mal) mais cela vaut la peine !

Note pour les trolls : je pars en WE et ne vais avoir le temps de répondre que lundi.

La philosophie d'Erlang appliquée à PHP : Don't worry about errors, just let it fail

The 2009-10-12 at 11:08 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Si vous ne connaissez pas Erlang prenez le temps de vous documenter un peu sur le sujet et revenez.

Une chose que j’aime beaucoup avec Erlang et la philosophie suivante :

"let some other process fix the error".

C’est une philosophie non conventionnelle dans le domaine de la programmation de systèmes complexes et pourtant elle fonctionne très très bien. Elle fonctionne très bien non pas parce que les programmeurs Erlang sont meilleurs que les autres, mais de part la nature du langage et de la VM associées et par l’utilisation abondante du principe :

Check at the interfaces and trust inside.

Grosso modo, faites votre travail de vérification en entrée mais ensuite faites confiance une fois les données dedans.

La rapidité de Pluf provient en très grande partie de l’application de ces choix, pas de type hiting, pas d’interfaces, le minimun de vérifications en interne et surtout un error_handler qui va très joliment retourner toutes les erreurs aux administrateurs avec une copie de la pile.

Pourquoi pas de type hinting et pas d’interfaces ?

Je réponds par une question : Pourquoi forcer le type et l’interface au niveau du code quand cela coûte des cycles d’exécution et que de toute façon vous faites des tests unitaires de vos programmes ? Quel bénéfice cela apporte-t’il vraiment ? Quel problème peut apporter le duck typing ?

La performance de PHP vient de sa simplicité, la résilience d’Erlang vient de la simplicité de son modèle de process… La performance vient du dépouillement pour aller à l’essentiel.

Saint Exupéry écrivait "Il semble que la perfection soit atteinte non quand il n’y a plus rien à ajouter, mais quand il n’y a plus rien à retrancher." et ce qui aurait très bien pu être la réponse d’Einstein : "Everything should be made as simple as possible, but not simpler."

Note : Je ne suis pas un programmeur de formation, mon travail qui me fait vivre est d’optimiser ça, j’ai donc une déformation professionnelle pour la simplicité et la performance et je prends donc des raccourcis dans le formalisme de la programmation. Chacun voit midi à sa porte, c’est bien connu.

Pluf Template 3x plus rapide et 2x moins gourmand que Twig

The 2009-10-12 at 06:58 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

La sortie de Twig annoncée par Fabien Potencier m’avait fait hurler. Twig est un système de gabarits pour PHP comme il en existe des centaines. En fait, au bout d’un certain temps, tout développeur s’est essayé à la création d’un système de gabarits/templates pour bien délimiter la logique métier de la présentation.

J’ai hurlé car Twig est une très grosse bibliothèque (presque 100 fichiers) et que cela m’a fait tout de suite penser à mes tests de performances de Pluf.

Je n’avais jamais fait la moindre optimisation du système de gabarits de Pluf et ma version n’est qu’une version simplifiée et étendue de jTpl, le système du framework Jelix, une bonne occasion de faire des tests.

J’ai d’abord mis en place des tests dont voici l’archive complète. Les premiers runs ne montraient pas de différence significative entre Twig et Pluf_Template. Frustration, comment Twig, pouvait être grosso modo aussi rapide que Pluf_Template ?

Un petit tour dans les entrailles de Twig via xdebug et je découvre que :

  1. effectivement Twig est très lourd ;
  2. mais que l’auteur est futé, le test est taillé sur mesure pour favoriser Twig.

Twig compile les gabarits en une ou plusieurs classes PHP, donc un rendu n’est qu’un appel à une fonction d’une classe. Pas besoin de faire un include comme pour Pluf. Twig génère des classes lourdes en réinventant PHP, d’où le besoin de ne faire que 3 itérations affichages dans ces tests car sinon les performances se dégradent trop. Un rendu ne devient dans ce test qu’un echo et 3 appels de fonctions.

J’ai donc repris cette idée d’une classe par gabarit et fais quelques petites optimisations par endroits, voici les résultats pour le gabarit Twig suivant :

base.html :

{% autoescape on %}<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    {% block head %}
      <link rel="stylesheet" href="main.css" />
    {% endblock %}
  </head>
  <body>
    {% block content %}{% endblock %}
  </body>
</html>
{% endautoescape %}

content.html :

{% extends "tbase.html" %}
{% block content %}
{% for item in items %} item {% endfor %}
{% endblock %}

Vraiment très simple, en fait un peu trop simple mais cela correspond aux tests faits par Fabien, donc cela permettra de faire une comparaison.

Les tests ont été faits sur 3 et 50 éléments dans items avec respectivement 10000 et 1000 rendus. Pour chaque test, 10 runs et les 9 meilleurs ont été conservés. Tous les temps sont sans le coût de la compilation.

Performances
SystèmeTestRendus/sComparaison
Twig3/1000013767 -
Pluf3/10000351512.55 fois plus rapide
Twig50/10001325 -
Pluf50/100043003.24 fois plus rapide

Twig est nettement plus lent, rien à commenter.

Mémoire
SystèmeTestPic mémoire avec compilation (ko)Pic mémoire sans (ko) Comparaison
Twig3 itérations/1 renbu996 342 -
Pluf3 itérations/1 rendu4902631.3 à 2 fois moins gourmand
Twig50/10001330 691 -
Pluf50/10004952652.6 fois moins gourmand

Les chiffres parlent d’eux-même, mais surtout, ce que je trouve très étonnant, c’est l’augmentation de l’utilisation mémoire de manière aussi importante de Twig en fonction du nombre de rendus. Des objets qui perdent de la mémoire ? Ce n’est pas très propre et je n’arrive pas à m’expliquer ces différences. Le temps de compilation est accessoire, Pluf_Template ne peut que être plus rapide mais on peut très bien précompiler tous les gabarits.

Maintenant, pourquoi battre Pluf_Template sera très dur pour quiconque ?

  • Compilation : Laurent Jouanneau a eu la meilleure idée qui soit, Pluf_Template utilise directement le tokenizer de PHP, c’est le code C le mieux optimisé de PHP.
  • Exécution : Le code PHP résultant est du code avec le minimum de constructions et d’appels à des fonctions. Le seul gros travail est l’autoescaping. Chose qui ne peut pas être évité dans la majorité des cas.
Conclusion

Vive le logiciel libre et la simplicité. La simplicité de Pluf_Template m’a permis d’améliorer ses performances en moins de 30 minutes grâce à ce que j’avais appris via le code de Twig. Gardez vos frameworks légers pour que la mascotte de PHP ne devienne pas un objet de moqueries…

Twig et template de Pluf, effet marketing d'un système de templates pour PHP

The 2009-10-12 at 10:08 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Mise à jour : Un test "rigoureux" est disponible maintenant.

Fabien Potencier vient d’annnoncer Twig un système de gabarits pour PHP. En dehors du fait que le texte d’annonce commence par quelque chose qui ressemble à du copier/coller de la documentation du framework PHP Pluf, ce qui m’honore, le projet annonce des fonctionnalités exclusives qui en fait ne le sont pas.

Cela fait plus de 2 ans que Pluf propose l’auto échappement des variables dans les gabarits et cela même avant Django. Regardez le système de gabarit de Jelix dont est issu celui de Pluf, tout est dedans (sauf peut-être l’héritage mais il est dans celui de Pluf). Vous constaterez d’ailleurs que Fabien se garde bien de mentionner ces systèmes dans son article… manifestement il connaît bien les effets marketing des omissions bien choisies comme nos amis de Microsoft, Apple, etc…

Et c’est stupide, carTwig apporte une valeur ajoutée certaine, le mode "bac à sable" qui permet l’exécution dans un contexte restreint. C’est là la réelle valeur ajoutée de ce système de gabarit car tout le reste existe déjà, alors pourquoi ne pas mettre l’accent dessus ?

Mise à jour: Twig c’est une bibliothèque de presque 100 fichiers et 160ko, le système de templates de Pluf c’est 10 fichiers dans 70ko en comptant les tags optionnels et les exemples. J’ai un nouveau slogan pour Sensio, "Nos produits sont conçus pour vendre du service associés et des clusters pour votre application web!". Les DSI doivent se frotter les mains, cela leur fait plus de chiffre à gérer. Mais bon, je préfère l’agilité et la légèreté, chacun son truc.

Mise à jour le 10 octobre: Twig est très rapide, mais après un petit coup de xdebug (les 15 premières minutes que je passe pour optimiser le code du système de Pluf) je passe de 5% plus lent à 5% plus rapide que Twig.

Mise à jour 10 minutes après: Le benchmark de Fabien n’est pas correct on va dire. Twig est 4 fois plus lent que Pluf_Template pour 1000 rendu d’une itération sur 1000 éléments ! En gros, c’est un benchmark calculé pour le cas idéal de Twig. Par contre il y a une bonne idée dans Twig que je vais inclure dans Pluf_Template. Au lieu de faire un include à chaque rendu, le code PHP est en fait une classe avec une méthode de rendu. Donc pas besoin de 1000 include. En pratique, dans une application web, cela ne change pas grand chose, car généralement on ne fait le rendu que de 2 ou 3 templates au maximum par requête. Je vais creuser cela même si Pluf_Template est déjà plus rapide et sera toujours plus rapide que Twig. Pourquoi ? Car il fait nettement moins pour aboutir à la même chose. La meilleure façon d’aller vite est de reste simple et ne rien faire d’inutile.

Mise à jour finale ? En implémentant l’idée de la class par template, Pluf_Template est 3 à 4 fois plus rapide que Twig dans tous les scénarii. Je mets en ligne le code demain soir, car là c’est du code rapide entre les petits fours d’un mariage.

Surflexibilité d'un framework agile (PHP, Python, Ruby ou autre)

The 2009-07-04 at 13:29 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Un très bon article qui illustre bien pourquoi je hurle quand je vois des frameworks introduire toujours plus de flexibilité pour des raisons très souvent d’idéal d’implémentation technique au détriment des performances et de la facilité de compréhension du code : Premature Flexibilization Is The Root of Whatever Evil Is Left.

Je n’ajoute de la flexibilité dans Pluf que si j’ai réellement besoin et si je fais cela, je m’assure de suivre la règle du projet WebKit : "The way to make a program faster is to never let it get slower".

Auto admin avec Pluf, tout simplement

The 2009-05-14 at 13:28 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Je suis en train de passer le site de Céondo sous Pluf. Le but est de pouvoir facilement ajouter un carnet et de rendre ce site plus dynamique au niveau de son contenu. J’ai décidé que toute son administration passera via l’auto admin de Pluf. Voici donc une capture d’écran de l’ajout d’une ressource.

Ajout d'un objet avec l'auto admin de Pluf

Pour avoir vos modèles dans l’auto-admin, vous devez simplement créer un fichier papp.php dans le répertoire de votre application avec par exemple le contenu suivant :

<?php
return array('path' => 'ceo',
             'name' => 'Ceondo',
             'models' => array('page' => 
                               array('model' => 'CEO_Page',
                                     'list_display' => 
                                     array('title', 
                                           'path',
                                           'category', 
                                     ),
                                     )
                               )
             );

Cela veut dire que l’application Ceondo va avoir le modèle CEO_Page et que pour l’affichage dans la liste je veux les trois champs title, path et category. Vraiment tout simple… car le formulaire va directement être créé à partir de la définition du modèle.

Auto admin avec Pluf - Redux

The 2009-05-13 at 12:36 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Juste une petite note pour vous annoncer que l’auto-admin de Pluf arrive enfin… Le style est encore à revoir, il reste encore beaucoup de choses à faire au niveau de la gestion des permissions et du suivi des changements, mais la base est là. Je pousse le code dans le dépôt cette semaine. Cela ne sera pas encore parfait, mais cela sera une bonne base qui intéressera je pense déjà beaucoup de monde.

Auto admin à la Django avec Pluf

Mise à jour : Le code est disponible.

Yummy, version 3.1.1 d'APC

The 2009-02-19 at 13:10 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

APC, Alternative PHP Cache, introduit avec la version 3.1.1 les fonctions apc_inc, apc_dec et apc_cas.

Voici comme les utiliser dans vos scripts :

<?php
apc_add('count', 0); // Cela fait la création uniquement si 'count' n'éxiste pas
$i = apc_inc('count', 7); // incrémente de 5 la valeur de count.
$i = apc_dec('count', 3); // décrémente de 3 la valeur de count.
apc_cas('count', 4, 10); // si 'count' == 4, alors mettre 10 dans count
echo $i; 
?>

Ces opérations sont dites comme atomiques, cela vous permet donc de faire un compteur efficace car vous gardez en mémoire le compteur et non avec un accès disque nécessitant un système de verrou pour les accès en lecture/écriture. Vous pouvez ainsi régulièrement faire la copie du nouveau compteur sur le disque ou votre base de données et utiliser dans la majorité des cas le compteur d’APC.

Besoin d'aide pour essayer de faire passer Pluf sur reddit

The 2009-01-29 at 10:53 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Aujourd’hui j’ai besoin de vous chers lecteurs. Si vous avez un compte sur reddit, je vous invite à plusser le lien vers Pluf. Cela va vous prendre 30 secondes et ça serait bien sympa ! Merci.

Symfony, patterns et autres joyeusetés, petite mise au point

The 2008-12-16 at 08:42 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Mon dernier billet sur les injections de dépendances et l’inversion de contrôle a été pris par certains comme une attaque à l’encontre de Symfony. Ce n’était pas voulu et voici la raison de ce billet.

Mon travail, celui qui me fait gagner ma vie, est dans le domaine des procédés industriels, en fait, dans la thermodynamique. Je fais des calculs d’équilibre de phases entre différents composants à différentes conditions, etc. Je travaille avec une multitude de langages (C, C++, Fortran, Delphi, Python) sur du code qui peut dater du début des années 70 jusqu’à du code frais de quelques minutes. Cela veut aussi dire que je travaille avec du code créé par de nombreuses personnes avec des compétences très variées et dans ce cas là on souffre du syndrome du débutant que voici :

Le débutant motivé :

  1. lit beaucoup d’articles de partout ;
  2. découvre chaque jour de nouvelles techniques ;
  3. découvre chaque jour qu’il peut appliquer la super technique X pour résoudre le problème Y ;
  4. finit par appliquer 17 techniques différentes dans un module pour résoudre le problème Z.

Remplacez technique par motif (pattern) et vous comprendrez le désastre.

En mettant en ligne, sans contexte, cette présentation, Fabien Potencier participe à cela, et c’est bien cela qui m’irrite profondément. D’ailleurs, si vous relisez mon billet, je le dis bien, il n’y a que les exemples que je trouve mal encadrés. Proposer de l’introspection sur un appel effectué dans le rendu de toutes les pages d’une application web est pour moi comme proposer un 33T pour transporter votre grand mère pour lui permettre d’acheter son pain.

Maintenant oui, cette présentation n’est que le support d’une présentation faite dans une conférence, mais le problème, c’est quand le recyclant sur le web, cette présentation se trouve avec une seconde vie, c’est de cela que je parle et de rien d’autres. J’ai fait des dizaines de présentations du fond du Japon jusqu’à la Californie, pas besoin de venir m’expliquer la différence entre le support et la prestation, merci.

Je ne fais donc pas du Symfony bashing, je recommande toujours à toute personne qui se pose la question "Quel framework choisir ?" d’utiliser 3 ou 4 et de faire une petite application avec, puis de rester avec celui qui convient. D’ailleurs, si vous voulez tester Symfony, c’est le bon moment, ils font un joli tutoriel.

Injection de dépendances et inversion de contrôle, cela fait peur à voir

The 2008-12-12 at 22:27 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Via Laurent, je suis tombé ce soir sur une présentation de Fabien Potencier sur le découplage du code et effectivement, la présentation est une jolie présentation. Les 22 premières slides sont de bonne facture, avec un rappel des fondamentaux d’un design de qualité dans tout type d’application (web, desktop, serveur, etc.). Slides 23 à 38, vous avez ensuite une illustration assez claire de ce que cela veut dire. Si vous êtes un utilisateur de Pluf, vous connaissez cela depuis le début, votre fichier de configuration est là pour vous permettre de changer comme bon vous semble certains éléments de votre application.

Les slides 41 et 42 vous donne la conclusion importante, si votre code est bien conçu, vous pouvez facilement passer utiliser une implémentation ou une autre. Par exemple avec Pluf, vous utilisez PostgreSQL, MySQL ou SQLite pour la base de données, vous utilisez memcached ou un stockage dans des fichiers pour la mise en cache, le tout en changeant une ligne dans votre fichier de configuration. Très bien.

Mais attention, slide 48, il y a un "retour à la case départ" et le retour, c’est pas un atterrissage en douceur du marché de l’immobilier tant attendu, c’est le bon crash d’un A320 en pilotage automatique. Brutalement, l’idée qui était bonne de faire un découplage, devient tellement bonne, qu’il faut l’appliquer à tous les objets en tout lieu et toute condition, pour tout le monde, Ubi Et Orbi.

Et là, c’est parti, on définit un conteneur, on arrive même à utiliser les classe de réflexion et on finit même par ne plus utiliser PHP mais directement utiliser une configuration en XML, c’est certain, dans une démo pour un grand compte, cela doit faire joli. Mais chez moi, tous les signaux d’alerte passent au rouge, cela clignote de partout, cela fait peur à voir…

Sinon, ensuite la présentation redevient correcte (pour moi) avec l’explication du principe des signaux. Ce sont les signaux qui permettent à InDefero de faire la synchro de dépôts Subversion/Mercurial automatiquement pour vous. Les signaux c’est bien !

Conclusion, vous lisez jusqu’à la 47, puis vous passez directement à la 78. Maintenant vous savez aussi pourquoi Pluf est 5 fois plus performant que Symfony, le secret est d’ajouter un niveau de complexité uniquement si le besoin est là.

Par exemple, vous pouvez changer facilement de type de base de données ou de système de mise en cache, vous avez de nombreux paramètres de configuration pour vous permettre de plier le framework dans votre sens, mais ce n’est pas parce qu’une recette fonctionne pour un type d’objet qu’il faut l’appliquer partout.

Une petite analogie qui peut illustrer mes propos, quand vous faites un gâteau au chocolat, pour qu’il soit bien moelleux est fondant, vous montez des blancs en neige ou selon la recette vous battez vos œufs entiers jusqu’à ce que le mélange blanchisse. La conclusion symofniesque serait donc, vous voulez du fondant moelleux, il faut des œufs battus. Donc, dans ma soupe à la tomate, je vais mettre des œufs battus. Oups, erreur, application d’une recette à tous les problèmes sans distinction du contexte et du besoin réel, la soupe à la tomate, elle est onctueuse par l’ajout de crème et si vous faites vraiment bien les choses, par le mixage puis lyophilisation de vos tomates (congélation, évaporation) avant utilisation.

Si à chaque niveau de votre framework PHP, vous ajoutez un niveau d’abstraction pour vous permettre de changer les fonctionnalités, oui vous aurez un framework souple mais oui aussi vous devrez utiliser une ferme de serveurs comme Yahoo pour gérer vos bookmarks.

Une autre manière de voir les choses, si vous voulez partir de manière souple en vacances, vous pouvez partir avec un 33 tonnes et dès que les conditions météo changent, vous avez l’équipement exactement adapté aux conditions extérieures. Vous pouvez faire aussi ce que j’ai fait avec ma femme, partir 20 jours au Japon, sans valise, tout en bagage à main, quand il s’est mis à pleuvoir, pas besoin de faire tourner le 33T, juste de sauter au dessus de la flaque d’eau et d’aller sous un porche.

Quand je vois ce type de présentation, je reconnais la compétence certaine de programmeur et d’architecte logiciel de Fabien Potencier, mais ma formation n’est pas une formation d’ingénieur en logiciel, mais une formation en procédés industriels et la première qualité d’un procédé, après bien entendu la satisfaction des specs, c’est la simplicité. Quand vous avez une merde sur un FPSO, vous êtes content de garder la simplicité avec vous. Je conçois Pluf ainsi, InDefero aussi.

C’est très facile de rajouter des niveaux d’abstraction et de mise en cache etc…, c’est nettement plus dur de rester simple et efficace et de toujours restructurer votre code pour le rester. J’ai choisi le difficile chemin de la simplicité, chez moi le code n’est pas de la poésie en prose de Proust, mais plutôt de la musique de Miles Davis "Why play so many notes instead of just choosing the most beautiful?".

Protection de votre site contre les attaques extérieures avec Pluf

The 2008-12-05 at 23:05 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Pluf offre depuis le début une protection active contre les attaques liées au cross site scripting ou XSS en faisant un échappement automatique de toutes les informations affichées dans les gabarits par défaut. Si vous voulez spécifiquement afficher une chaîne HTML venant d’une variable dans un gabarit, il faut la marquer comme sûre:

{$htmlpropre|safe} ou {$venantdunutilisateur}

Ici l‘html propre sera bien affiché mais la variable venant d’un utilisateur sera échappée. Avec cette méthode, vous savez ce que vous faites.

Il restait un point important que n’était pas pris en compte. Supposez que sur votre site, vous avez un formulaire pour supprimer un article. Vous cliquez sur le bouton, cela fait une requête POST sur le serveur pour supprimer l’article. On va dire que le formulaire est tout simple :

<form method="post" action="/admin/article/32/delete">
<input type="submit" />
</form>

Si vous êtes authentifié sur votre site, le formulaire va fonctionner, sinon, il va demander de vous authentifier. Maintenant, vous pensez que votre site est sécurisé avec le login. En fait, non, il n’est pas. Supposons que vous visitiez le site mechant.com qui contient une page toute normale avec ceci :

<form name="myform" action="votresite.com/admin/article/32/delete" method="post">
<a href="#" onClick="document.myform.submit();">plus d'informations à propos des pelles à neige</a>
</form>

si vous avez javascript d’activé et que vous loggué sur votre site, cela va supprimer l’article 32 de votre site. Aïe !

Vous avez compris, vous ne pouvez même pas considérer votre formulaire comme sûr, même s’il a été soumis par une personne authentifiée. La seule solution viable est d’ajouter en plus du besoin d’authentification, une variable supplémentaire dans le formulaire, variable unique pour chaque utilisateur et donc très difficile à trouver pour le site mechant.com. Cela veut dire qu’il faut faire cela pour chaque formulaire de vos pages. Oups…

Bonne nouvelle, un petit middleware de Pluf permet de faire cela automatiquement, juste une ligne à rajouter dans votre configuration.

Gestion des formulaires avec Pluf

The 2008-11-20 at 18:47 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Hop, je viens de mettre en ligne la gestion des formulaires avec Pluf. C’est un début de documentation mais cela couvre déjà bien la base avec les widgets et la gestion des validations complexes.

Petite mise à jour de la documentation de Pluf

The 2008-11-11 at 09:22 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Je continue de mettre à jour la documentation de Pluf au fil des jours. Vous avez maintenant le droit à :

Il reste à faire la description du système de formulaires, le système d’authentification et les différents middleware. Une bonne documentation sur comment installer l’application de test sous Windows serait aussi une bonne chose.

J’ai aussi ajouté la base d’un système de cache. L’utilisation est très simple :

$cache = new Pluf_Cache::factory();
if (null === ($foo=$cache->get('ma-clef'))) {
    $foo = operation_complexe();
    $cache->set('ma-clef', $foo);
}
// $foo est maintenant disponible.

Pour définir quel système de mise en cache l’application va utiliser, il suffit de déclarer cela dans le fichier de configuration. Par exemple, j’ai pour InDefero :

$cfg['cache_engine'] = 'Pluf_Cache_File';
$cfg['cache_timeout'] = 300;
$cfg['cache_file_folder'] = $cfg['tmp_folder'].'/cache';

Il faut que je joue un peu plus avec memcached pour implémenter ce système.

Mise à jour: J’ai restructuré la doc et ajouté une documentation sur l’upload de fichiers.

Next Page


Logo of Plume CMS