<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="https://www.nikrou.net/feed/rss2/xslt" ?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Le Journal de Nikrou - PHP</title>
    <link>https://www.nikrou.net/</link>
    <atom:link href="https://www.nikrou.net/feed/category/Php/rss2" rel="self" type="application/rss+xml" />
    <description>Ce journal n'est pas un blog!</description>
    <language>fr</language>
    <pubDate>Sun, 30 Mar 2025 07:06:26 +0200</pubDate>
    <copyright></copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>Dotclear</generator>
          <item>
        <title>Encore une migration...</title>
        <link>https://www.nikrou.net/post/2024/01/09/Encore-une-migration...</link>
        <guid isPermaLink="false">urn:md5:1ed7a5a1d63421ed967b83919a768720</guid>
        <pubDate>Tue, 09 Jan 2024 16:39:00 +0100</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>kimsufi</category>
                  <category>postgresql</category>
                <description> &lt;p&gt;En ce début d'année, après &lt;a class=&quot;ref-post&quot; href=&quot;https://www.nikrou.net/post/2008/10/11/Migration-reussie&quot;&gt;une première migration&lt;/a&gt;, puis &lt;a class=&quot;ref-post&quot; href=&quot;https://www.nikrou.net/post/2010/06/20/Migration-vers-un-nouveau-Kimsufi&quot;&gt;une deuxième&lt;/a&gt; et &lt;a class=&quot;ref-post&quot; href=&quot;https://www.nikrou.net/post/2014/10/18/Et-encore-une-migration-kimsufi&quot;&gt;une troisième&lt;/a&gt;, j'ai de nouveau migré mon serveur dédié sur une nouvelle machine, avec plus d'espace disque, plus de mémoire, plus de performance processeur et pour moins cher. Que demander de plus ?&lt;br /&gt;
&lt;br /&gt;
J'en ai profité pour passer postgreSQL de la version 14 à la version 16. Au passage, la configuration est un peu plus stricte et je suis tombé sur un message un peu abscon :&amp;nbsp;&lt;br /&gt;
&lt;em&gt;user does not have a valid scram secret&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
Le mot de passe de l'utilisateur était trop simple ou plus exactement, l'algorithme pour chiffrer le mot de passe était trop simple. Jusqu'à présent c'était &lt;a href=&quot;https://fr.wikipedia.org/wiki/MD5&quot;&gt;md5&lt;/a&gt;. PostgreSQL conseille très fortement un algorithme&amp;nbsp;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7677&quot;&gt;scram-sha-256&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Pour cela il suffit, par exemple de se connecter au serveur avec la commande psql et pour chaque mot de passe n'utilisant pas le bon algorthme de taper : &amp;nbsp;&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-sql&quot;&gt;postgres=# \password NOM_DU_ROLE&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;puis en réponse de taper le mot de passe et la confirmation.&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Phyxo et PHP 8</title>
        <link>https://www.nikrou.net/post/2021/05/30/Phyxo-et-PHP-8</link>
        <guid isPermaLink="false">urn:md5:2e8843d7c440a35175b8ea72925e5ac2</guid>
        <pubDate>Sun, 30 May 2021 13:58:00 +0200</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                  <category>phpstan</category>
                <description> &lt;p&gt;&lt;a href=&quot;https://www.phyxo.net/&quot;&gt;Phyxo&lt;/a&gt;&amp;nbsp;fonctionne sans aucun soucis avec PHP 8, sorti&amp;nbsp;au mois de novembre 2020. Phyxo nécessite php 7.3 au minimum. D'ailleurs je vais changer ce minimum et passer à php 7.4 à minima car le support actif&amp;nbsp;de php 7.3 s'est arrêté au mois de janvier 2021. La version 7.3 ne reçoit plus que des patchs de sécurité et va arriver en fin de vie à la fin de 2021. On peut voir toutes les &lt;a href=&quot;https://www.php.net/supported-versions.php&quot;&gt;versions supportées&lt;/a&gt; sur le le site officiel.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;La version 8 de PHP apporte de &lt;a href=&quot;https://www.php.net/releases/8.0/en.php&quot;&gt;nombreuses nouveautés&lt;/a&gt;. Une évolution pose un petit problème : &lt;a href=&quot;https://www.php.net/manual/en/functions.arguments.php#functions.arguments.default&quot;&gt;l'ordre des paramètres d'une fonction ou d'une méthode&lt;/a&gt;.&amp;nbsp;&lt;a href=&quot;https://phpstan.org/&quot;&gt;PHPStan&lt;/a&gt;&amp;nbsp;se plaint car le code de Phyxo contient de nombreuses méthodes dont certains paramètres obligatoires suivent des paramètres optionnels. Un exemple valant mieux qu'un long discours voici une méthode qui fait râler PHPStan :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;
public function findRandomImages(array $forbidden_categories = [], int $max): array
{
   // code de la méthode
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ce code fonctionne parfaitement. Mais si on exécute ce code avec PHP 8, on a en retour le message suivant :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-bash&quot;&gt;Deprecated: Required parameter $max&amp;nbsp;follows optional parameter $forbidden_categories&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cet avertissement dénote un problème de logique dans le prototype de la méthode. Si la méthode accepte que le paramètre &lt;strong&gt;$forbidden_categories&lt;/strong&gt; soit non défini alors il doit être après le paramètre obligatoire &lt;strong&gt;$max&lt;/strong&gt;. C'est le sens du message d'avertissement renvoyé.&amp;nbsp;&amp;nbsp;&lt;br /&gt;
 &lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Atoum ou PHPUnit ou les deux ?</title>
        <link>https://www.nikrou.net/post/2021/04/04/Atoum-ou-PHPUnit-ou-les-deux</link>
        <guid isPermaLink="false">urn:md5:88b69f4dadba4d57fc0fb311b2add900</guid>
        <pubDate>Sun, 04 Apr 2021 17:42:00 +0200</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>atoum</category>
                  <category>php</category>
                  <category>phpunit</category>
                  <category>tests</category>
                <description> &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://www.nikrou.net/post/2014/04/15/Phyxo-en-gestation&quot;&gt;Depuis que j'ai commencé le développement de Phyxo&lt;/a&gt;, j'ai utilisé &lt;a href=&quot;https://atoum.org&quot;&gt;Atoum&lt;/a&gt; pour faire des tests unitaires. J'aime l'approche plus &quot;moderne&quot; de la façon d'écrire les tests. Mais depuis quelques temps je commence à écrire des tests fonctionnels de mes contrôleurs et du coup, j'utilise aussi &lt;a href=&quot;https://phpunit.de/&quot;&gt;PHPUnit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;J'ai essayé d'utiliser &lt;a href=&quot;https://github.com/atoum/AtoumBundle&quot;&gt;AtoumBundle&lt;/a&gt; pour tester mes contrôleurs mais le&amp;nbsp;projet a l'air mort ou tout du moins pas très actif : le dernier commit date de presque 3 ans et ne supporte que&amp;nbsp;&lt;strong&gt;symfony/framework-bundle&lt;/strong&gt;&amp;nbsp;en version 2.0 ou 3.0. Du coup j'ai laissé tomber cette possibilité.&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Travailler simultanément sur plusieurs branches d'un même dépôt git</title>
        <link>https://www.nikrou.net/post/2021/04/01/Travailler-simultan%C3%A9ment-sur-plusieurs-branches-d-un-m%C3%AAme-d%C3%A9p%C3%B4t-git</link>
        <guid isPermaLink="false">urn:md5:cf5198346e0d4781411313e68109272e</guid>
        <pubDate>Thu, 01 Apr 2021 17:31:00 +0200</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>composer</category>
                  <category>git</category>
                  <category>php</category>
                  <category>tests</category>
                <description> &lt;p&gt;Dans le cadre du développement de &lt;a href=&quot;https://www.phyxo.net/&quot;&gt;Phyxo&lt;/a&gt;, il m'arrive de devoir travailler sur plusieurs branches en même temps pour de multiples raisons :&amp;nbsp;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;vérifier &quot;visuellement&quot; que n'ai rien cassé entre deux versions&lt;/li&gt;
	&lt;li&gt;vérifier un comportement que je trouve étrange sur la version en cours de développement et m'apercevoir que le comportement était le même sur une branche précédente&lt;/li&gt;
	&lt;li&gt;exécuter les tests fonctionnels (en utilisant &lt;a href=&quot;https://behat.org/&quot;&gt;Behat&lt;/a&gt;) d'une branche sur le code d'une autre branche&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ce ne sont que quelques cas d'usage. Tous ces cas peuvent être gérés simplement en clonant plusieurs fois le &lt;a href=&quot;https://www.nikrou.net/post/2021/04/01/git@github.com:nikrou/phyxo.git&quot;&gt;dépôt de Phyxo&lt;/a&gt;&amp;nbsp;et ça fonctionne parfaitement mais il y a beaucoup mieux : la commande &lt;a href=&quot;https://git-scm.com/docs/git-worktree/fr&quot;&gt;git worktree&lt;/a&gt;. Cette commande&amp;nbsp;permet de gérer plusieurs copie de travail à partir du même dépôt git.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Par exemple si j'ai un clone sur la branche master et que je veux en même temps bosser sur la branche &lt;strong&gt;new-feature&lt;/strong&gt;, il me suffit de taper la commande suivante :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-shell&quot;&gt;$ git worktree add ../phyxo_new-feature new-feature&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;La commande va créer une nouvelle copie de travail du dépôt dans le répertoire &lt;strong&gt;../phyxo_new-release&lt;/strong&gt; en se positionnant sur la branche &lt;strong&gt;new-feature&lt;/strong&gt;. Pour chaque branche c'est comme si on avait un projet différent sur disque. On peut vérifier que notre nouvelle copie de travail a été créée en tapant la commande suivante qui liste toutes les copies de travail :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-shell&quot;&gt;$ git worktree list

/var/projets/git/phyxo&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 8a8bae91f [master]
/var/projets/git/phyxo_new-feature&amp;nbsp; 699393471 [new-feature]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Il y a de nombreux avantages à utiliser &lt;strong&gt;git worktree&lt;/strong&gt;&amp;nbsp;plutôt que de faire un &lt;strong&gt;git clone&lt;/strong&gt;&amp;nbsp;: elle est plus rapide (les données sont déjà là), utilise des liens. C'est une copie light du dépôt d'origine et qui prend bien moins de place sur disque.&lt;/p&gt;

&lt;p&gt;Et pour finir de convaincre, d'autres exemples d'utilisation :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;travailler sur une branche sans impacter le travail en cours sur la branche courante. On peut par exemple utiliser &lt;a href=&quot;https://git-scm.com/docs/git-stash/fr&quot;&gt;git stash&lt;/a&gt;&amp;nbsp;pour mettre de côté des modifications sur la branche courante et corriger un bug sur la version en production. Mais ces deux branches peuvent avoir beaucoup de différences. Mon IDE va devoir reconstruire ces index pour pouvoir me proposer de l'aide. Les dépendances ne sont pas forcément les mêmes, ni dans les mêmes versions. Il va falloir que je n'oublie pas de faire un &lt;strong&gt;composer install&lt;/strong&gt;.&amp;nbsp;&lt;/li&gt;
	&lt;li&gt;vérifier que le projet fonctionne sur une installation &quot;propre&quot; comme si je venais de cloner le dépôt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
 &lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Mettre à jour les traductions d'un module drupal</title>
        <link>https://www.nikrou.net/post/2011/02/10/Mettre-%C3%A0-jour-les-traductions-d-un-module-drupal</link>
        <guid isPermaLink="false">urn:md5:76321fce6cb11b28ce0a1e373c5e7ee5</guid>
        <pubDate>Thu, 10 Feb 2011 13:56:00 +0100</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>drupal</category>
                  <category>php</category>
                <description>&lt;p&gt;Lorsqu'on développe un module drupal, les traductions ajoutées au fur et à mesure ne sont pas prises en compte automatiquement. drupal ne prend en compte les traductions d'un module que lors de l'installation de celui-là. En cours de développement cela peut rapidement devenir pénible (pour rester poli !) de devoir installer/déinstaller le module à chaque mise à jour...&lt;/p&gt; &lt;p&gt;Heureusement il y a une solution pour se faciliter la vie. En fait c'est d'une bêtise insondable : il suffit d'utiliser le &lt;a hreflang=&quot;en&quot; rel=&quot;external&quot; href=&quot;http://api.drupal.org/api/drupal/update.php/6&quot;&gt;mécanisme de mise à jour d'un module&lt;/a&gt;. Pour ce faire, dans le fichier &lt;strong&gt;mon_module.install&lt;/strong&gt;, on déclare une fonction &lt;strong&gt;mon_module_update_N&lt;/strong&gt;, où N est incrémenté à chaque nouvelle mise à jour.&lt;/p&gt;&lt;p&gt;Cette façon de faire est généralement utilisé pour mettre à jour le schéma de la base de données mais on peut aussi l'utiliser pour mettre à jour les traductions de la manière suivante :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;function mon_module_update_N() {
   $ret = array();
   if (module_exists('locale')) {
      locale_system_update(array('mon_module'));
      $ret[] = array('success' =&gt; true, 'query' =&gt; 'New translations were imported.');
   }
   
   return $ret;
}&lt;/code&gt;&lt;/pre&gt;</description>
        
              </item>
          <item>
        <title>Pourquoi faut-il bannir l'arobase de tout code PHP ?</title>
        <link>https://www.nikrou.net/post/2010/06/26/Pourquoi-faut-il-bannir-l-arobase-de-tout-code-PHP</link>
        <guid isPermaLink="false">urn:md5:af6d3635107d8869be52c17a03e39bfb</guid>
        <pubDate>Sat, 26 Jun 2010 15:07:00 +0200</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description>&lt;p&gt;Nombreux sont les développeurs (débutants ou non) qui utilisent l'arobase (@) pour masquer les erreurs. C'est un peu cacher la misère et c'est surtout un énorme problème lorsqu'il s'agît de trouver un bug dans un code où fleurissent les arobases.&lt;/p&gt; &lt;p&gt;L'arobase est un opérateur de contrôle d'erreur. Si on préfixe une &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.php.net/manual/fr/language.expressions.php&quot;&gt;expression&lt;/a&gt; (affectation de variable, include ou require, expression de comparaison,...) par cet opérateur, les messages d'erreurs qui pourraient éventuellement être générés sont ignorés et par conséquent ne sont pas affichés. C'est de là que vient le problème. Les débutants ne maîtrisant pas tous les concepts du langage utilisent l'arobase pour arriver plus vite à leurs fins. On ne peut pas les blâmer mais le remède est pire que le mal !&lt;/p&gt;&lt;p&gt;Le principal problème de cet opérateur est qu'il ne masque pas que le problème que l'on a sur le moment. Il masque toutes les erreurs dont les erreurs critiques qui stoppent le programme. Par exemple, si une variable ou une fonction est mal orthographiée, on ne le saura pas.&lt;/p&gt;&lt;p&gt;Voici un exemple de code à ne pas reproduire qui produirait sans l'arobase un message d'avertissement &quot;Notice Undefined index var ...&quot; :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;$ma_var = @$_GET['var'];&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Si la variable $_GET['var'] n'existe pas, on ne le saura pas et on devra faire le test ultérieurement. Donc autant tester directement :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;if (isset($_GET['var'])) {
   $ma_var = $_GET['var'];
} else {
   $ma_var = '';
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dans l'exemple précédent il y a peu de conséquences. Imaginons que l'on veuille inclure un fichier de configuration que s'il existe. Une mauvaise pratique serait de préfixer l'inclusion par un arobase :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;@include 'conf.inc.php';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;De prime abord on pourrait penser qu'on a atteint le but souhaité. Si le fichier n'existe pas, on n'aura pas d'erreurs ; dans le cas contraire il sera inclus. Pour rendre les choses plus claires imaginons le code suivant :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;$nom = 'Pouce';
$prenom = 'Tom';
@include 'conf.inc.php';
echo &quot;Bonjour $prenom $nom&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Et voici le contenu du fichier conf.inc.php :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;$prenom = 'Nicolas';
$nom = 'Cémoi';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bon l'intérêt de ce code est plus que discutable mais en revanche il va permettre d'expliquer plus clairement mon propos. Si le fichier existe, et que le script courant peut l'inclure alors on aura le super message : &quot;Bonjour Nicolas Cémoi&quot;. Si le fichier n'existe pas on aura le message : &quot;Bonjour Tom Pouce&quot;. Jusque là tout va bien.&lt;/p&gt;&lt;p&gt;Maintenant supposons que le fichier soit bien là mais qu'il y ait une erreur dans le fichier conf.inc.php, par exemple qu'il manque le point virgule à la fin de la première ligne. On n'aura aucun message d'erreur, mais comme l'erreur est critique l'exécution du script s'arrête et on n'a pas de message du tout. L'exécution du script s'arrête à la ligne où on tente de faire l'inclusion du fichier. L'arobase a masqué l'erreur de syntaxe &quot;Parse error: syntax error, unexpected T_VARIABLE ...&quot;. L'exemple est très simple et on ne fait appel qu'à deux fichiers mais si on fait de nombreuses inclusions, et/ou des inclusions en cascade, trouver le problème devient un vrai casse-tête.&lt;/p&gt;&lt;p&gt;Encore une fois, le code pour éviter le problème est d'une simplicité enfantine :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;
if (file_exists('conf.inc.php')) {
   include 'conf.inc.php';
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;L'utilisation de l'arobase est une très mauvaise pratique qui est à bannir. Elle crée plus de problèmes qu'elle n'en résoud.&lt;/p&gt;&lt;p&gt;Il y a tout de même des exceptions à cette pratique : si on teste l'erreur. Par exemple lorsqu'on veut créer une connexion à une base de données pour ne pas afficher d'erreur si un problème survenait, on peut utiliser l'arobase devant la fonction pg_connect() (ou mysql_connect() ou ...). Il faut bien entendu ensuite tester le retour de la fonction qui est soit false soit une ressource de connexion.&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>symfony : hydrater un objet à la main</title>
        <link>https://www.nikrou.net/post/2009/04/17/symfony-hydrater-un-objet-%C3%A0-la-main</link>
        <guid isPermaLink="false">urn:md5:cd5bc912357797f47c637a884f41a4a6</guid>
        <pubDate>Fri, 17 Apr 2009 17:49:00 +0200</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                  <category>symfony</category>
                <description>&lt;p&gt;En utilisant symfony, on ne fait plus réellement de sql du fait de la couche d'abstraction &lt;acronym title=&quot;Object Relational Mapping&quot; lang=&quot;en&quot;&gt;ORM&lt;/acronym&gt; (Propel ou Doctrine). On ne travaille qu'avec des objets. Cela facilite grandement la vie et contribue pour une grande part à la rapidité de développement. Mais cela ne répond pas toujours à tous les besoins...&lt;/p&gt; &lt;p&gt;Imaginons un modèle &lt;em&gt;Script&lt;/em&gt; ayant une propriété &lt;em&gt;category&lt;/em&gt; qui permet de classifier les différents scripts par catégorie. Si je veux récupérer toutes les catégories de scripts, le code que je vais écrire pourrait ressembler à ça :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;
public static function getCategories() {
   $criteria = new Criteria();
   $criteria-&gt;addGroupByColumn(self::CATEGORY);
   
   return self::doSelect($criteria);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;J'aurais pu aussi faire un &quot;select distinct catgeory&quot; mais pour les besoins suivants j'ai préféré faire un &quot;group by&quot;. Je voudrais maintenant pour chaque catégorie de scripts savoir combien de scripts y sont associés pour afficher dans un menu. Toute ressemblance avec &lt;a hreflang=&quot;fr&quot; href=&quot;http://www.phpscripts-fr.net/&quot;&gt;un menu existant&lt;/a&gt; n'est pas purement fortuite; mais c'est une autre histoire !&lt;/p&gt;&lt;p&gt;La requête sql serait toute simple :&lt;br /&gt;&lt;code&gt;select category, count(*) as c from scripts group by category; &lt;/code&gt;&lt;/p&gt;&lt;p&gt;Il n'est pas possible de faire la même chose en tout objet. Il va falloir hydrater les objets résultats &quot;à la main&quot;. On va commencer par ajouter la propriété &lt;em&gt;count&lt;/em&gt; à notre object &lt;em&gt;Script&lt;/em&gt;, ainsi que les méthodes pour renseigner (&lt;em&gt;setCount&lt;/em&gt;) et récupérer (&lt;em&gt;getCount&lt;/em&gt;) cette nouvelle propriété:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;
class Script extends BaseScript
{
  protected $count = 0;

  public function setCount($n) {
    $this-&gt;count = $n;
  }

  public function getCount() {
    return $this-&gt;count;
  }  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Voici maintenant le code pour symfony 1.2.* qui va permettre d'hydrater (c'est-à-dire de transformer chaque ligne de résultat en un objet &lt;em&gt;Script&lt;/em&gt; :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;
  public static function getCategories() {
    $criteria = new Criteria();
    self::addSelectColumns($criteria);
    $criteria-&gt;addGroupByColumn(self::CATEGORY);
    $criteria-&gt;addAsColumn('cnt', 'COUNT(*)');
    
    $stmt = self::doSelectStmt($criteria);    
    $scripts = array();

    while ($row = $stmt-&amp;gt;fetch(PDO::FETCH_NUM)) {
      $script = new Script;
      $col = $script-&amp;gt;hydrate($row);
      $script-&amp;gt;setCount(($row[$col] !== null) ? (int) $row[$col] : null);
      $scripts[] = $script;
    }

    return $scripts;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Le code pour symfony 1.0.* et plus généralement les versions inférieures à 1.2 est légèrement différents car symopfy 1.2 se base désormais sur PDO:&lt;/p&gt;&lt;p&gt;Il va falloir remplacer la ligne :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;$stmt = self::doSelectStmt($criteria);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;par&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;$row = self::doSelectRs($criteria);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Et la ligne :&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;while ($row = $stmt-&gt;fetch(PDO::FETCH_NUM)) {&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;par&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code&gt;while ($row-&gt;next()) {&lt;/code&gt;&lt;/pre&gt;</description>
        
              </item>
          <item>
        <title>Envoyer des mails avec php</title>
        <link>https://www.nikrou.net/post/2007/09/16/130-envoyer-des-mails-avec-php</link>
        <guid isPermaLink="false">urn:md5:20507765f7520609f46f73f32829ddb1</guid>
        <pubDate>Sun, 16 Sep 2007 21:35:53 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description>&lt;p&gt;Quoi de plus simple que d'envoyer des mails avec php avec la fonction &lt;a href=&quot;http://fr.php.net/manual/fr/function.mail.php&quot;&gt;mail&lt;/a&gt; ! Les choses se compliquent légèrement si on n'a pas de serveur de mail ! Et c'est peu de le dire. Evidemment on peut se lancer dans l'installation d'un serveur de mail (sendmail ou postfix par exemple) mais ce n'est pas à la portée de monsieur tout le monde si on ne veut pas servir de relais de spam! Une solution simple: &lt;a href=&quot;http://untroubled.org/nullmailer/&quot; hreflang=&quot;en&quot;&gt;nullmailer&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Hier en voulant tester le module d'envoi de mail de mon application utilisant &lt;a href=&quot;http://www.symfony-project.com/&quot; hreflang=&quot;en&quot;&gt;symfony&lt;/a&gt;, je me suis apperçu que je ne pouvais pas envoyer de mail pour tester ! Ne voulant pas installer un serveur de mail j'ai installé &lt;strong&gt;nullmailer&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Après un &lt;strong&gt;apt-get install nullmailer&lt;/strong&gt;, les trois-quarts du boulot étaient faits. L'installeur pose deux questions:&lt;/p&gt;
&lt;ol&gt;
 &lt;li&gt;Nom de courrier de votre système ?&lt;/li&gt;
 &lt;li&gt;Machines relais ?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A la première question, j'ai répondu &lt;strong&gt;free.fr&lt;/strong&gt; et à la deuxième j'ai répondu &lt;strong&gt;smtp.free.fr smtp&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Le serveur de mail (qui n'en est en fait pas un &lt;sup&gt;[&lt;a href=&quot;https://www.nikrou.net/post/2007/09/16/130-envoyer-des-mails-avec-php#pnote-130-1&quot; id=&quot;rev-pnote-130-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;!) se lance et après ça marche!!! &lt;/p&gt;
&lt;p&gt;Il ne reste plus qu'à modifier la configuration de php pour qu'il utilise nullmailer au lieu de chercher en vain sendmail ! J'ai juste modifier le &lt;em&gt;sendmail_path&lt;/em&gt;: sendmail_path = /usr/bin/nullmailer-inject -fmoi@free.fr&lt;/p&gt;
&lt;p&gt;La modification de la configuration de php ne me plait qu'à moitié et je pense que je vais écrire un wrapper pour ne pas avoir à la modifier.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;h4&gt;Notes&lt;/h4&gt;
  &lt;p&gt;[&lt;a href=&quot;https://www.nikrou.net/post/2007/09/16/130-envoyer-des-mails-avec-php#rev-pnote-130-1&quot; id=&quot;pnote-130-1&quot;&gt;1&lt;/a&gt;] Et oui contrairement à ce qu'on pourrait croire nullmailer n'est pas un serveur de mail. Ce n'est qu'un &lt;acronym title=&quot;Mail Transfer Agent&quot;&gt;MTA&lt;/acronym&gt;. Il ne fait que transférer les messages à un autre MTA ou à un &lt;acronym title=&quot;Mail Delivery Agent&quot;&gt;MDA&lt;/acronym&gt; qui se charge de l'envoyer à destination.&lt;/p&gt;
&lt;/div&gt;</description>
        
              </item>
          <item>
        <title>Mettre fin à une authentification http</title>
        <link>https://www.nikrou.net/post/2006/10/02/115-mettre-fin-a-une-authentification-http</link>
        <guid isPermaLink="false">urn:md5:147650b27e99a888a3fe685b3437bab3</guid>
        <pubDate>Mon, 02 Oct 2006 10:06:00 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>apache</category>
                  <category>php</category>
                <description>&lt;p&gt;Le but du jeu est de mettre fin à une authentificaiton http faite avec le mécanisme des fichiers &lt;em&gt;.htaccess&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Tout le monde connait l'authentification http fournie par &lt;a href=&quot;http://httpd.apache.org/docs/1.3/&quot; hreflang=&quot;en&quot;&gt;apache&lt;/a&gt; que l'on met en place aisément avec un fichier &lt;em&gt;.htaccess&lt;/em&gt;. Vous trouverz tous les détails sur &lt;a href=&quot;http://httpd.apache.org/docs/1.3/howto/auth.html#basic&quot; hreflang=&quot;en&quot;&gt;la doc d'apache&lt;/a&gt;. Ce type de protection a l'avantage d'être standard mais aussi de protéger tout le contenu d'un répertoire, contrairement &lt;a href=&quot;https://www.nikrou.net/post/2006/09/02/112-ouverture-d-une-session-avec-php&quot;&gt;aux sessions php&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mais la question que l'on se pose est comment mettre fin à cette &quot;session&quot; ? Une solution pour le moins bancale est de proposer au visiteur de fermer son navigateur. On oublie tout de suite. Les visiteurs utilisant &lt;a href=&quot;http://www.mozilla.com/firefox/&quot; hreflang=&quot;en&quot;&gt;firefox&lt;/a&gt; et l'extension &lt;a href=&quot;http://chrispederick.com/work/webdeveloper/&quot; hreflang=&quot;en&quot;&gt;web developer&lt;/a&gt; peuvent le faire aussi aisément sans fermer leur navigateur en cliquant sur:&lt;/p&gt;
&lt;pre&gt;&lt;strong&gt;Miscellaneous &amp;gt; Clear Private Data &amp;gt; Clear HTTP Authentification&lt;/strong&gt;. &lt;/pre&gt;
&lt;p&gt;Cette solution n'est pas non plus une solution satisfaisante. Tout le monde n'utilise malheureusement pas encore firefox!&lt;/p&gt;
&lt;p&gt;Il n'y a alors pas de solution comme nombreux le prétendent (ils se reconnaitront et ne resteront peut-être pas dans leur ignorance!), allant jusqu'à me modérer parce que j'avais l'affront de prétendre que c'était possible. C'est dur de reconnaitre que l'on a tort et c'est plus facile de ramener la cavalerie pour essayer d'enfoncer la personne qui met un coup de pied dans la fourmillière.&lt;/p&gt;
&lt;p&gt;Revenons à nos moutons. Imaginons que nous voulions protéger un répertoire &lt;a href=&quot;https://www.nikrou.net/private-data&quot;&gt;de données confidentielles&lt;/a&gt;. En supposant que la configuration d'apache nous y autorise - c'est-à-dire qu'il n'y ait aucun &lt;em&gt;AllowOverride None&lt;/em&gt;, il suffit de placer dans le répertoire un fichier &lt;strong&gt;.htaccess&lt;/strong&gt; contenant:&lt;/p&gt;
&lt;pre&gt;AuthType Basic&lt;br /&gt;AuthName &quot;Private Access By Invitation Only&quot;&lt;br /&gt;AuthUserFile /absolute/path/to/pass.db&lt;br /&gt;Require valid-user&lt;/pre&gt;
&lt;p&gt;Ce type de protection n'est pas conseillé. On ne met pas le fichier de mot de passe dans le répertoire à protéger; c'ets juste pour la démonstration!&lt;/p&gt;
&lt;p&gt;Il faut ensuite créer un fichier de mot de passe avec l'utilitaire &lt;strong&gt;htpasswd&lt;/strong&gt;. J'y ai placé l'identifiant nico avec comme mot de passe nico. On va placer dans ce répertoire un fichier &lt;strong&gt;test.php&lt;/strong&gt; nous donnant le couple identifiant/mot de passe que l'on a entré. Ce couple est accessible à travers le tableau &lt;strong&gt;$_SERVER&lt;/strong&gt; au moyen des clés &lt;em&gt;PHP_AUTH_USER&lt;/em&gt; et &lt;em&gt;PHP_AUTH_PW&lt;/em&gt;. Je vais aussi créer un script &lt;strong&gt;logout.php&lt;/strong&gt; qui va permettre de mettre fin à cette authentification http. Cette déconnexion se fait en envoyant au navigateur un code http &lt;strong&gt;401&lt;/strong&gt; (authentificaiton requise), le même code qu'apache envoie au navigateur à la première tentative d'accès au répertoire. Le code ressemble à ceci:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: rgb(0, 0, 187);&quot;&gt;&amp;lt;?php&amp;nbsp;&lt;br /&gt;header&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 119, 0);&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(221, 0, 0);&quot;&gt;'WWW-Authenticate:&amp;nbsp;Basic&amp;nbsp;realm=&quot;Private&amp;nbsp;Access&amp;nbsp;By&amp;nbsp;Invitation&amp;nbsp;Only&quot;'&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 119, 0);&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 187);&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 119, 0);&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(221, 0, 0);&quot;&gt;'HTTP/1.0&amp;nbsp;401&amp;nbsp;Unauthorized'&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 119, 0);&quot;&gt;);&amp;nbsp;&lt;br /&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(221, 0, 0);&quot;&gt;'Texte&amp;nbsp;affiche&amp;nbsp;en&amp;nbsp;cas&amp;nbsp;d\'annulation'&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 119, 0);&quot;&gt;;&amp;nbsp;&lt;br /&gt;exit();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 187);&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vous pouvez maintenant aller &lt;a href=&quot;https://www.nikrou.net/private-data/test.php&quot;&gt;voir mes données confidentielles&lt;/a&gt; (login: nico mot de passe: nico). &lt;a href=&quot;https://www.nikrou.net/private-data/logout.php&quot;&gt;Déconnectez-vous&lt;/a&gt;, désormais vous ne pouvez plus voir les &lt;a href=&quot;https://www.nikrou.net/private-data/test.php&quot;&gt;données confidentielles&lt;/a&gt;. Vous pouvez cliquer sur annuler si ça vous chante mais vous serez tout de même déconnecter! N'essayer pas directement d'accéder au répertoire car vous auriez un accès non autorisé car par défaut ma configuration n'autorise pas de lister les répertoires (Options -Indexes)&lt;/p&gt;
&lt;p&gt;Notez bien que le &lt;strong&gt;realm&lt;/strong&gt; doit être le même que celui déclaré dans le .htaccess!&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Qu'est-ce qu'un singleton ?</title>
        <link>https://www.nikrou.net/post/2006/05/28/99-qu-est-ce-qu-un-singleton</link>
        <guid isPermaLink="false">urn:md5:1bb9d61b116869742754dd5074cdbfc0</guid>
        <pubDate>Sun, 28 May 2006 14:28:39 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description>&lt;p&gt;Le singleton est un modèle de conception (design pattern pour les grands bretons). En clair c'est une façon éprouvée de résoudre un problème. Avec le sinleton on cherche à n'avoir qu'une seule instance d'un même objet.&lt;/p&gt; &lt;p&gt;L'implémentation de l'objet singleton consiste à créer une instance de l'objet uniquement si elle n'existe pas encore. On stocke l'instance unique dans une propriété statique de l'objet. Cela peut donner quelque chose comme cela:&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Singleton&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;private&amp;nbsp;static&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$instance&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;private&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;static&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getInstance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$instance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$instance&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Singleton&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$instance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;La théorie c'est bien joli mais j'entends déjà les questions fuser: à quoi ça sert et comment on s'en sert ? Pour répondre à la première question, je dirais qu'à chaque fois que l'on a besoin d'un objet qui doit rester unique, on utilise un singleton. Je pense par exemple à une classe de log ou une classe de debbugage.&lt;/p&gt;
&lt;p&gt;Pour la deuxième question, voici la façon de récupérer l'instance unique:&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;$instance1&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Singleton&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getInstance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'&amp;lt;pre&amp;gt;Instance&amp;nbsp;n°1:'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;var_dump&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$instance1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;),&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'&amp;lt;/pre&amp;gt;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$instance2&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;Singleton&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;getInstance&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'&amp;lt;pre&amp;gt;Instance&amp;nbsp;n°2:'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;var_dump&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$instance2&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;),&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'&amp;lt;/pre&amp;gt;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;En exécutant ce code, on obtient:&lt;/p&gt;
&lt;pre&gt;Instance n°1:object(Singleton)#1 (0) {
}

Instance n°2:object(Singleton)#1 (0) {
}
&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;#1&lt;/b&gt; est une référence vers l'instance. Dans les deux cas on a la même, ce qui est le but recherché. Au prochain épisode je vous donne un exemple concret!&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Faut-il utiliser $_REQUEST ?</title>
        <link>https://www.nikrou.net/post/2006/05/26/96-faut-il-utiliser-request</link>
        <guid isPermaLink="false">urn:md5:a9b673aa4733f7fa1894b0a090bebacc</guid>
        <pubDate>Fri, 26 May 2006 11:14:49 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description>&lt;p&gt;Depuis que je suis tout petit, j'utilise &lt;b&gt;$_GET&lt;/b&gt; pour les données provenant de l'url et &lt;b&gt;$_POST&lt;/b&gt; pour celles provenant de mes formulaires (utilisant la méthode &quot;post&quot;!).&lt;/p&gt;

&lt;p&gt;En lisant divers articles, je me demande si je ne prends pas un peu la tête et si je ne devrais pas utiliser &lt;b&gt;$_REQUEST&lt;/b&gt; quelle que soit la provenance des données. Peu importe la provenance, de toute façon il faut filtrer, vérifier, contrôler la cohérence de ces données.&lt;/p&gt; &lt;p&gt;Pour commencer par le commencement, &lt;b&gt;$_REQUEST&lt;/b&gt; est un  tableau associatif constitué du contenu des variables &lt;b&gt;$_GET&lt;/b&gt;, &lt;b&gt;$_POST&lt;/b&gt;, &lt;b&gt;$_COOKIE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Nombreux sont ceux qui se disent au premier abord que cela est vraiment important de pouvoir distinguer la provenance des informations. Si l'utlisateur envoie les données par l'url (méthode &quot;get&quot;) ou via un formulaire utilisant la méthode &quot;post&quot; qu'est-ce qui est le plus important ? La façon de recevoir les données ou les données elles-même ? Pour ma part je pense que la façon de recevoir les données n'a aucune importance. L'important est de bien contrôler ce que l'on reçoit et de ne faire confiance à aucune donnée même celles qui pourraient sembler anodines et non modifiables telle que &lt;b&gt;$_SERVER['PHP_SELF']&lt;/b&gt; &lt;sup&gt;[&lt;a href=&quot;https://www.nikrou.net/post/2006/05/26/96-faut-il-utiliser-request#pnote-96-1&quot; id=&quot;rev-pnote-96-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;. Du coup l'utilisation de &lt;b&gt;$_REQUEST&lt;/b&gt; serait plutôt déconseillée aux débutants qui ont déjà du mal à bien faire la différence entre &lt;b&gt;$_GET&lt;/b&gt; et &lt;b&gt;$_POST&lt;/b&gt;. Ceux-ci se contentent généralement de peu de vérifications sur les données transmises via la méthode &quot;post&quot;; ces données leur semblent sûres. Je ne parle même pas des cookies!&lt;/p&gt;
&lt;p&gt;On pourrait se dire que l'utilisation de &lt;b&gt;$_REQUEST&lt;/b&gt; pourrait être intéressante pour les cas où on laisse le choix aux utilisateurs de transmettre les données en utilisant la méthode &quot;get&quot; ou la méthode &quot;post&quot;. La gestion de la provenance des données serait ainsi transparente.&lt;/p&gt;
&lt;p&gt;Je vois un réel intéret d'utiliser &lt;b&gt;$_REQUEST&lt;/b&gt; pour le cas où je veux continuer une session valide sans dépendre de la configuration du serveur, c'est-à-dire sans se demander de quelle manière transite l'identifiant de session (soit par cookie, soit par l'url soit par un champ caché d'un formulaire) alors au lieu d'utiliser une cascade de &lt;b&gt;if&lt;/b&gt; pour savoir d'où vient l'identifiant je peux utiliser un code tel que:&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;if&amp;nbsp;(isset(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$_REQUEST&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;session_name&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()]))&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;session_start&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;Pour conclure je ne suis pas complétement convaincu d'utiliser ce tableau magique qu'est &lt;b&gt;$_REQUEST&lt;/b&gt; surtout si on se réfère à l'utilisation des méthodes &quot;get&quot; et &quot;post&quot; et sur une architecture &lt;a href=&quot;http://fr.wikipedia.org/wiki/REST&quot;&gt;REST&lt;/a&gt; d'une application web. Les méthodes &quot;get&quot; et &quot;post&quot; sont bien distinctes et donc récupérer les données sans en connaitre la provenance leurs fait perdre un peu de leur sens.&lt;/p&gt;

 &lt;p&gt;[&lt;a href=&quot;https://www.nikrou.net/post/2006/05/26/96-faut-il-utiliser-request#rev-pnote-96-1&quot; id=&quot;pnote-96-1&quot;&gt;1&lt;/a&gt;] Je m'égare; ce sera l'objet d'un prochain billet. Oui j'ai honte de faire du teasing!&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Ne pas réinventer la roue.</title>
        <link>https://www.nikrou.net/post/2006/05/06/94-ne-pas-reinventer-la-roue</link>
        <guid isPermaLink="false">urn:md5:77100c5e996bd99b8d9af2e0e75265b2</guid>
        <pubDate>Sat, 06 May 2006 22:48:00 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description>&lt;p&gt;On répète souvent que lorsqu'on fait un script il ne faut pas réinventer la roue et utiliser au maximum les fonctions natives du langage. Cela a de multiples avantages: c'est optimisé, sans bug,... Mais on n'imagine pas toujours lorsqu'on est débutant à quel point cet adage doit être pris au sérieux!&lt;/p&gt; &lt;p&gt;Prenons un exemple concret pour éclairer le débat. Imaginons deux tables sql liées entre elles par un identifiant numérique:&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;table1: id, champ1, champ2&lt;/li&gt;
 &lt;li&gt;table2: cid, champ3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si on n'utilise mysql comme base de données on va utiliser en général un entier auto-incrémenté comme clé primaire de la première table et on va se servir de cet indentifiant comme clé étrangère dans l'autre table. On fait l'insertion d'un enregistrement dans la première table:&lt;/p&gt;
&lt;pre&gt;insert into table1 (champ1, champ2) values('valeur1', 'valeur2');&lt;/pre&gt;
&lt;p&gt;Jusque là tout va bien. Comment récupérer cet identifiant nouvellement créé ? La première solution qui vient à l'esprit est de récupérer le plus grand identifiant de la table1:&lt;/p&gt;
&lt;pre&gt;select max(id)as max_id from table1;&lt;/pre&gt;
&lt;p&gt;Le résultat obtenu risque de ne pas être le résultat escompté: il se peut qu'une nouvelle insertion intervienne avant que l'on récupère l'identifiant. Si le site n'a que 3 visiteurs par mois le risque que cela arrive est faible mais non négligeable pour un site à fort traffic. Ce n'est pas la bonne méthode: il faut utiliser la fonction &lt;a href=&quot;http://www.php.net/mysql_insert_id&quot; hreflang=&quot;en&quot;&gt;mysql_insert_id()&lt;/a&gt;. Cette fonction récupère l'identifiant auto-incrémenté lié à la dernière insertion, pour la connexion courante.&lt;/p&gt;
&lt;p&gt;Essayons de prouver cela avec les deux scripts suivants en simulant une insertion parasite:&lt;/p&gt;

&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;
// script n°1 basé sur mysql_insert_id():&lt;br&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_connect&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$host&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$password&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_select_db&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'db'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query_max&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;select&amp;nbsp;max(id)&amp;nbsp;as&amp;nbsp;max_id&amp;nbsp;from&amp;nbsp;table1&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Plus&amp;nbsp;grand&amp;nbsp;id&amp;nbsp;de&amp;nbsp;la&amp;nbsp;table:&amp;nbsp;%d&amp;lt;br&amp;gt;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_fetch_assoc&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_query&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query_max&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;insert&amp;nbsp;into&amp;nbsp;table1&amp;nbsp;(champ1,&amp;nbsp;champ2)&amp;nbsp;values('value1',&amp;nbsp;'value2')&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$result&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_query&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'id&amp;nbsp;inséré:&amp;nbsp;%d&amp;lt;br&amp;gt;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_insert_id&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;));&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;br&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br&gt;
// script n°2 basé sur le max:&lt;br&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_connect&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$host&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$password&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_select_db&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'db'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query_max&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;select&amp;nbsp;max(id)&amp;nbsp;as&amp;nbsp;max_id&amp;nbsp;from&amp;nbsp;table1&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Plus&amp;nbsp;grand&amp;nbsp;id&amp;nbsp;de&amp;nbsp;la&amp;nbsp;table:&amp;nbsp;%d&amp;lt;br&amp;gt;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_fetch_assoc&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_query&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query_max&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;insert&amp;nbsp;into&amp;nbsp;table1&amp;nbsp;(champ1,&amp;nbsp;champ2)&amp;nbsp;values('value1',&amp;nbsp;'value2')&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$result&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_query&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'id&amp;nbsp;inséré:&amp;nbsp;%d&amp;lt;br&amp;gt;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_fetch_assoc&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mysql_query&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$query_max&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$mysql_link&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;

&lt;p&gt;Imaginons que le plus grand identifiant de la table1 soit 10. On exécute d'abord le script n°2 puis tout de suite après le script n°1. Le scritp n°2 fait une pause de 10 secondes après l'insertion pour simuler une requête qui s'exécuterait avant la récupération du maximum. L'identifiant inséré par le script n°2 sera donc 11 et celui inséré par le script n°1 sera 12. Mais le résultat obtenu n'est pas bon: le scritp n°2 renvoie 12 et le script n°1 renvoie 12.&lt;/p&gt;

&lt;p&gt;On pourrait faire l'opération inverse pour mettre en défaut la fonction mysql_insert_id() en faisant une pause de 10 seconde avant l'appel de la fonction. On verrait que la fonction renvoie bien le résultat voulu.&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Quel est mon mot de passe ?</title>
        <link>https://www.nikrou.net/post/2006/03/14/84-quel-est-mon-mot-de-passe</link>
        <guid isPermaLink="false">urn:md5:bf0ae13a9531fbbee24f1f6e151a0c18</guid>
        <pubDate>Tue, 14 Mar 2006 15:27:10 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description> &lt;p&gt;Dans une interface d'administration qui se respecte, on doit pouvoir à un moment créer des comptes. Il est souvent agréable de se voir proposer un mot de passe aléatoire. En général, je n'utilise pas un mot de passe complétement alétaoire: je supprime les caractères ambigus tels que 0, 1, i, j, l, m, n, o, u, v,I,O. Le code peut ressembler à ça. La fonction attend en paramètre la longueur du mot de passe à générer. Cette fonction n'a rien d'extraordinaire mais elle ne fait que ce qu'on lui demande mais elle le fait bien!&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;generate_password&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$size&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$listeChar&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'23456789abcdefghkpqrstwxyzABCDEFGHKJLMNPQRSTUVWXYZ'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$max&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;strlen&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$listeChar&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)-&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$key&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;''&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;for&amp;nbsp;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$size&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$i&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;++)&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$key&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;.=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$listeChar&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;mt_rand&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$max&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)];&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$key&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;

&lt;p&gt;Petite mise à jour. J'avais oublié de préciser une chose: pourquoi je supprime certains caractères ? Je supprime les caractères 0, 1, i, j, l, m, n, o, u, v,I,O car ils sont potentiellement ambigus. Le &quot;i&quot; peut être confondu avec le &quot;l&quot;, le &quot;0&quot; avec le &quot;O&quot;. Même dans la phrase précédente on ne sait pas au premier coup d'oeil si j'ai écris &quot;le zéro et la lettre O&quot; ou &quot;la lettre O et  le zéro. L'intérêt est de générer des mots de manière automatique en enlevant les ambiguïtés visuelles.&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Développement piloté par les tests.</title>
        <link>https://www.nikrou.net/post/2006/02/21/80-developpement-pilote-par-les-tests</link>
        <guid isPermaLink="false">urn:md5:85f284d7fe71c40135027b8eb1fc01cb</guid>
        <pubDate>Tue, 21 Feb 2006 17:16:00 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description>&lt;p&gt;Il ne semble pas évident au premier abord de faire des tests du code que l'on écrit. En général, on se borne à vérifier qu'il n'y a pas d'erreurs de syntaxe. On vérifie que les 3 ou 4 pages que l'on vient de modifier fonctionnent toujours de la même façon. Cette manière de fonctionner atteint rapidement ses limites au fur et à mesure que l'application grossie. Comment se rappeler que le code écrit aujourd'hui n'aura pas d'impact sur le code écrit il y a 6 mois ? Sans tests exhaustifs, c'est tout simplement impossible.&lt;/p&gt; &lt;p&gt;Il est hors de question de dérouler les tests &quot;à la main&quot;. On va écrire des tests automatiques ou plus particulièrement des tests de non-régression, c'est-à-dire des tests qui permettent de vérifier que les modifications apportées à l'application n'ont pas apportées de  bugs ou de modifications fonctionnelles. En fait ils permettent de s'assurer que l'application fonctionnera de la même façon.&lt;/p&gt;
&lt;p&gt;En PHP, il y a de nombreuses bibliothèques pour se faciliter la tâche, notament &lt;a href=&quot;http://www.phpunit.de/wiki/Main_Page&quot; hreflang=&quot;en&quot;&gt;PHPUnit&lt;/a&gt; ou &lt;a href=&quot;http://www.lastcraft.com/simple_test.php&quot; hreflang=&quot;en&quot;&gt;Simple Test&lt;/a&gt;. En ayant un peu regardé les deux je me suis décidé à utiliser Simple Test.&lt;/p&gt;
&lt;p&gt;Après avoir lu &lt;a href=&quot;https://www.nikrou.net/post/2006/01/28/75-l-extreme-programming-bientot-chez-vous&quot;&gt;un livre sur l'Extrême Programming&lt;/a&gt;, il me parait plus judicieux d'écrire les tests avant de commencer à coder quoi que ce soit. Ca peut sembler étrange au premier abord mais en utilisant cette pratique de plus en plus souvent cela semble bien plus naturel et surtout plus facile que d'écrire le code et de s'assurer que les tests que l'on va mettre en place couvrent bien tout l'aspect fonctionnel du code.&lt;/p&gt;
&lt;p&gt;Un p'tit exemple valant mieux qu'un long discours, imaginons que l'on veuille écrire une &quot;interface&quot; de connexion à &lt;a href=&quot;https://www.nikrou.net/xp/login1.php&quot;&gt;une zone membre&lt;/a&gt;. On veut que l'utilisateur ayant un couple identifiant/mot de passe correct soit connecté à la zone et que les autres utilisateurs soient rejettés.&lt;/p&gt;
&lt;p&gt;Code préliminaire: // login_test.php&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;require_once(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'../simpletest/web_tester.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;require_once(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'../simpletest/reporter.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TestOfLogging&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;extends&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;WebTestCase&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;testAuth&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;WebTestCase&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$test&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TestOfLogging&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$test&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;HtmlReporter&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;());&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;Et on obtient le joli panneau suivant:&lt;/p&gt;
&lt;h1&gt;TestOfLogging&lt;/h1&gt;
&lt;div style=&quot;padding: 8px; margin-top: 1em; background-color: green; color: white;&quot;&gt;1/1 test cases complete:
&lt;strong&gt;0&lt;/strong&gt; passes, &lt;strong&gt;0&lt;/strong&gt; fails and &lt;strong&gt;0&lt;/strong&gt; exceptions.&lt;/div&gt;
&lt;p&gt;C'est un peu normal puisque l'on a rien testé! Premier test:&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;require_once(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'../simpletest/web_tester.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;require_once(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'../simpletest/reporter.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TestOfLogging&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;extends&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;WebTestCase&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;testAuth&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;WebTestCase&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;testUnknownUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;get&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'http://localhost/xp/login1.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setField&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'login'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;inconnu&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setField&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'password'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'mot-de-passe'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;clickSubmit&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Ok'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;assertWantedPattern&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/utilisateur&amp;nbsp;inconnu/i'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$test&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TestOfLogging&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$test&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;HtmlReporter&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;());&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;On obtient ceci:&lt;/p&gt;
&lt;h1&gt;TestOfLogging&lt;/h1&gt;
&lt;span class=&quot;fail&quot;&gt;Fail&lt;/span&gt;: testUnknownUser -&amp;gt; Pattern [/utilisateur inconnu/i] not detected in [String: &amp;lt;br /&amp;gt;
&amp;lt;b&amp;gt;Warning&amp;lt;/b&amp;gt;:  require_once(./classes/Auth.php) [&amp;lt;a href='function.require-once'&amp;gt;function.require-once&amp;lt;/a&amp;gt;]: failed to open stream: No such file or directory in &amp;lt;b&amp;gt;/home/nicolas/webspace/simp...] at [/home/nicolas/webspace/simpletests/tests/login_test.php line 15]&lt;br /&gt;
&lt;div style=&quot;padding: 8px; margin-top: 1em; background-color: red; color: white;&quot;&gt;1/1 test cases complete:
&lt;strong&gt;0&lt;/strong&gt; passes, &lt;strong&gt;1&lt;/strong&gt; fails and &lt;strong&gt;0&lt;/strong&gt; exceptions.&lt;/div&gt;
&lt;p&gt;C'est normal puisque l'on n'a pas encore écrit de code! Une fois le formulaire soumis on affiche le message &quot;utilisateur inconnu&quot;. C'est ce message que l'on cherche dans le test&lt;/p&gt;
&lt;p&gt;L'idée principal du développement piloté par les tests (écrire les tests puis coder) est d'écrire les tests fonctionnels dans un premier temps puis d'écrire le code minimal qui permette de valider le test. On ne cherche pas à faire le code le plus beau et le plus performant à cette étape. Au test d'après on peut factoriser des bouts de code pour améliorer la qualité générale. On n'aura l'assurance que l'on a rien cassé grâce aux tests. Donc pour passer le test, il suffit d'ajouter dans le script login1.php (qui devient &lt;a href=&quot;https://www.nikrou.net/xp/login2.php&quot;&gt;login2.php&lt;/a&gt;), une ligne avec &quot;Utilisateur inconnu&quot;. C'est loin d'être optimal et c'est même un peu moche comme code. On est confronté à un nouveau problème. La première fois que l'on arrive sur la page, on a le message &quot;Utilisateur inconnu&quot;.&lt;/p&gt;
&lt;p&gt;Lorsqu'on se trouve avec un &quot;bug&quot; ou un comportement non voulu, on commence par écrire le test correspondant et qui échoue nécessairement. Le voici (en tête de la fonction testUnknownUser):&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;assertNoUnWantedPattern&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/utilisateur&amp;nbsp;inconnu/i'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;Il nous faut maintenant écrire le code minimal qui permette de passer ce test. Il suffit d'ajouter le code suivant: (&lt;a href=&quot;https://www.nikrou.net/xp/login3.php&quot;&gt;login3.php&lt;/a&gt;)&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;if&amp;nbsp;(isset(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$_POST&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'sub'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;]))&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'&amp;lt;p&amp;gt;Utilisateur&amp;nbsp;inconnu&amp;lt;/p&amp;gt;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;Et on arrive au résultat attendu:&lt;/p&gt;
&lt;h1&gt;TestOfLogging&lt;/h1&gt;
&lt;div style=&quot;padding: 8px; margin-top: 1em; background-color: green; color: white;&quot;&gt;1/1 test cases complete:
&lt;strong&gt;2&lt;/strong&gt; passes, &lt;strong&gt;0&lt;/strong&gt; fails and &lt;strong&gt;0&lt;/strong&gt; exceptions.&lt;/div&gt;
&lt;p&gt;Attaquons-nous à la partie &quot;utilisateur reconnu&quot;!  On va créer un objet User qui regroupera toutes les propriétés d'un utilisateur et en particulier le fait que son identification est correcte. Les tests dans login.php se résumeront à appeler une méthode vérifiant la validité du couple login/mot de passe pour pouvoir accéder à la zone membre. On va supposer dans un premier temps que l'objet existe et que l'on peut l'utiliser de la manière suivante:&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;require_once(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'./classes/User.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$is_valid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&lt;br /&gt;if&amp;nbsp;(isset(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$_POST&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'sub'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;]))&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$is_valid&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$_POST&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'login'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;],&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$_POST&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'password'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;]);&lt;br /&gt;}&lt;br /&gt;if&amp;nbsp;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$is_valid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Vous&amp;nbsp;êtes&amp;nbsp;connecté&amp;lt;br&amp;gt;'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;}&amp;nbsp;else&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #FF8000&quot;&gt;//&amp;nbsp;affichage&amp;nbsp;du&amp;nbsp;formulaire&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;Ecrivons maintenant les tests vérifiant qu'un utilisateur reconnu (login: Lebon et mot de passe: Secret) peut se connecter:&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;require_once(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'../simpletest/web_tester.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;require_once(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'../simpletest/reporter.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;require_once(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'../classes/User.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&lt;br /&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TestOfLogging&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;extends&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;WebTestCase&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;testAuth&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;WebTestCase&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;testUnknownUser&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;get&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'http://localhost/xp/login.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;assertNoUnWantedPattern&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/utilisateur&amp;nbsp;inconnu/i'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setField&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'login'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;&quot;inconnu&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setField&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'password'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'mot-de-passe'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;clickSubmit&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Ok'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;assertWantedPattern&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/utilisateur&amp;nbsp;inconnu/i'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;testKnownUserCanLogIn&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;get&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'http://localhost/xp/login.php'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setField&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'login'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Lebon'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;setField&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'password'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Secret'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;clickSubmit&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Ok'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;assertWantedPattern&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'/connecté/i'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$test&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;=&amp;nbsp;&amp;nbsp;new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;TestOfLogging&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$test&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(new&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;HtmlReporter&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;());&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;En testant, on obtient ça:&lt;/p&gt;
&lt;code&gt;
Warning: require_once(../classes/User.php) [function.require-once]: failed to open stream: No such file or directory in /var/www/xp/test/login_test.php on line 4&lt;br /&gt;
Fatal error: require_once() [function.require]: Failed opening required '../classes/User.php' (include_path='.:/usr/share/php') in /var/www/xp/test/login_test.php on line 4
&lt;/code&gt;
&lt;p&gt;Après avoir créer la classe User, on obtient:&lt;/p&gt;
&lt;h1&gt;TestOfLogging&lt;/h1&gt;
&lt;span class=&quot;fail&quot;&gt;Fail&lt;/span&gt;: testUnknownUser -&amp;gt; Pattern [/utilisateur inconnu/i] not detected in [String: &amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot; &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&amp;gt;
&amp;lt;html lang=&quot;fr&quot;&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Zone membre&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Zone membre&amp;lt;/h1&amp;gt;
&amp;lt;br /&amp;gt;
&amp;lt;b&amp;gt;Fatal...] at [/var/www/xp/test/login_test.php line 17]&lt;br /&gt;
&lt;span class=&quot;fail&quot;&gt;Fail&lt;/span&gt;: testKnownUserCanLogIn -&amp;gt; Pattern [/connecté/i] not detected in [String: &amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot; &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&amp;gt;
&amp;lt;html lang=&quot;fr&quot;&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Zone membre&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Zone membre&amp;lt;/h1&amp;gt;
&amp;lt;br /&amp;gt;
&amp;lt;b&amp;gt;Fatal...] at [/var/www/xp/test/login_test.php line 25]&lt;br /&gt;
&lt;div style=&quot;padding: 8px; margin-top: 1em; background-color: red; color: white;&quot;&gt;1/1 test cases complete:
&lt;strong&gt;1&lt;/strong&gt; passes, &lt;strong&gt;2&lt;/strong&gt; fails and &lt;strong&gt;0&lt;/strong&gt; exceptions.&lt;/div&gt;
&lt;p&gt;On va donc écrire une classe User minimale permettant de passer le nouveau test. Elle pourrait ressembler à ça:&lt;/p&gt;
&lt;code&gt;&lt;span style=&quot;color: #000000&quot;&gt;
&lt;span style=&quot;color: #0000BB&quot;&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;class&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;User&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;()&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$login&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$password&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;((&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;trim&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$login&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)==&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Lebon'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;trim&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;$password&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;)==&lt;/span&gt;&lt;span style=&quot;color: #DD0000&quot;&gt;'Secret'&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;))&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #007700&quot;&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000BB&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;Et on obtient alors le beau panneau vert suivant:&lt;/p&gt;
&lt;h1&gt;TestOfLogging&lt;/h1&gt;
&lt;div style=&quot;padding: 8px; margin-top: 1em; background-color: green; color: white;&quot;&gt;1/1 test cases complete:
&lt;strong&gt;3&lt;/strong&gt; passes, &lt;strong&gt;0&lt;/strong&gt; fails and &lt;strong&gt;0&lt;/strong&gt; exceptions.&lt;/div&gt;
&lt;p&gt;Tout le code écrit n'est pas forcément optimal mais on l'idée générale du développement dirigé par les tests. On va pouvoir modifier le code sans risquer d'avoir des régressions fonctionnelles ce qui est un des buts principaux de la méthode.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Version finale de la page d'accès à la zone membre: &lt;a href=&quot;https://www.nikrou.net/xp/login.php&quot;&gt;login.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Version finale du script de tests: &lt;a href=&quot;https://www.nikrou.net/xp/tests/login_test.php&quot;&gt;login_test.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Version finale de la classe User: &lt;a href=&quot;https://www.nikrou.net/xp/classes/User.php&quot;&gt;User.php&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
        
              </item>
          <item>
        <title>A la découverte de php5</title>
        <link>https://www.nikrou.net/post/2006/01/15/73-a-la-decouverte-de-php5</link>
        <guid isPermaLink="false">urn:md5:37843b6fcc6e4e1a5c97f9586768eee4</guid>
        <pubDate>Sun, 15 Jan 2006 20:22:24 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description> &lt;p&gt;La version 5 de &lt;acronym title=&quot;PHP: Hypertext Preprocessor&quot; lang=&quot;en&quot;&gt;PHP&lt;/acronym&gt; est sortie depuis plus d'un an, le 13 juillet 2004 exactement. Je ne parlerais pas des nombreux changements tellement c'est énorme. Mais de quoi je vais parler, alors ? De ma déouverte de php5.&lt;/p&gt;
&lt;p&gt;Je me suis mis à  php5 voici quelques mois. L'installation sur HP-UX n'a pas été une mince affaire mais ça fonctionne!&lt;/p&gt;
&lt;p&gt;J'avais pris comme habitude avec php4 de développer sur le serveur de test avec le niveau d'erreur E_ALL (2047). Avec php5, je suis passé à  E_ALL &amp;amp; E_STRICT, soit 4095. La plupart des scripts qui se disent compatibles php5 ne passent pas avec ce niveau d'erreurs. Un exemple flagrant: on ne peut plus déclarer un attribut de classe (une variable) de la manière suivante:&lt;/p&gt;
&lt;pre&gt;
&lt;?php
class Essai {
   var $ma_variable;
// etc
}
?&gt;
&lt;/pre&gt;
&lt;p&gt;Il faut utiliser un des mots-clés de portée, à savoir &lt;em&gt;public&lt;/em&gt;, &lt;em&gt;protected&lt;/em&gt; ou &lt;em&gt;private&lt;/em&gt;.&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Précédence des opérateurs</title>
        <link>https://www.nikrou.net/post/2005/12/21/71-precedence-des-operateurs</link>
        <guid isPermaLink="false">urn:md5:114b0dbbf9720cb854c86a2fb298843c</guid>
        <pubDate>Wed, 21 Dec 2005 11:01:01 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description> &lt;p&gt;Il existe en PHP deux types de &quot;ET&quot; (and et &amp;amp;&amp;amp;) et de &quot;OU&quot; (or et ||). La raison est qu'ils ont des priorités différentes. Le &lt;em&gt;and&lt;/em&gt; et le &lt;em&gt;or&lt;/em&gt; ont une priorité plus faible que l'opérateur &lt;em&gt;=&lt;/em&gt; alors que le &lt;em&gt;&amp;amp;&amp;amp;&lt;/em&gt; et le &lt;em&gt;||&lt;/em&gt; ont une priorité plus élevée que le &lt;em&gt;=&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Par exemple si on a le code suivant:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;?php
$choix1 = &quot;un&quot;;
$choix2 = &quot;deux&quot;;
$choix3 = &quot;trois&quot;;

$val1 = $choix1 || $choix2 || $choix3; 
$val2 = $choix1 or $choix2 or $choix3; 
?&gt;
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;$val1&lt;/em&gt; sera égal à &lt;em&gt;true&lt;/em&gt; et $val2 sera égal à &quot;un&quot;.&lt;/p&gt;
&lt;p&gt;Pour régler le problème, soit on met tout le temps des parenthèses, soit on n'utilise les opérateurs &lt;em&gt;&amp;amp;&amp;amp;&lt;/em&gt; et &lt;em&gt;||&lt;/em&gt;.&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Afficher une arborescence avec menu et sous-menu.</title>
        <link>https://www.nikrou.net/post/2005/07/22/55-afficher-une-arborescence-avec-menu-et-sous-menu</link>
        <guid isPermaLink="false">urn:md5:70fa548e8ee2ccdaa934f829dea18a10</guid>
        <pubDate>Fri, 22 Jul 2005 22:25:36 +0000</pubDate>
        <dc:creator>Nicolas</dc:creator>
                  <category>PHP</category>
                          <category>php</category>
                <description> &lt;p&gt;On est souvent confronté à ce type de problème: afficher sous forme d'arbre (liste ul/li par exemple) un menu ou un forum. On récupère les informations d'une base de données où chaque enregistrement comprend les champs suivants (au minimum): id, label, parent. La requête de sélection est toute simple: &lt;em&gt;select id, nom, parent from table&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Imaginons que l'on est récupéré ces enregistrements là:&lt;/p&gt;
&lt;code class=&quot;php&quot;&gt;
    &lt;span class=&quot;vars&quot;&gt;&amp;lt;?php&lt;br&gt;
	$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu1'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu1.1'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu1.1.1'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu1.1.2'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu1.2'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu2'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu3'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu3.1'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu3.2'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
    &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = array(&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'menu3.3'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class=&quot;vars&quot;&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;
&lt;p&gt;On veut obtenir ça:&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;menu1
      &lt;ul&gt;
         &lt;li&gt;menu1.1
            &lt;ul&gt;
               &lt;li&gt;menu1.1.1&lt;/li&gt;
               &lt;li&gt;menu1.1.2&lt;/li&gt;
            &lt;/ul&gt;
         &lt;/li&gt;
         &lt;li&gt;menu1.2&lt;/li&gt;
      &lt;/ul&gt;
   &lt;li&gt;menu2&lt;/li&gt;
   &lt;li&gt;menu3
      &lt;ul&gt;
         &lt;li&gt;menu3.1&lt;/li&gt;
         &lt;li&gt;menu3.2&lt;/li&gt;
         &lt;li&gt;menu3.3&lt;/li&gt;
      &lt;/ul&gt;
   &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Et le code &lt;acronym lang=&quot;en&quot; title=&quot;PHP Hypertext Processor&quot;&gt;PHP&lt;/acronym&gt; correspondant peut ressembler à çà:&lt;/p&gt;
&lt;code class=&quot;php&quot;&gt;
&lt;span class=&quot;vars&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br&gt;
&lt;span class=&quot;keywords&quot;&gt;function &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;addTree&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;(&amp;amp;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$Tree&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$feuille&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;) {&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;global &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;;&lt;/span&gt;&lt;br&gt;
	&lt;br&gt;
&lt;span class=&quot;vars&quot;&gt;   $Tree&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$feuille&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;]][&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'__LABEL'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$feuille&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;];&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;foreach (&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab &lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$cle &lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt; &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;) {&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;]==&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;) {&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;addTree&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$Tree&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$feuille&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'label'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;]],&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$cle&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
	  &amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
	    }&lt;br&gt;
	      &lt;br&gt;
    &lt;/span&gt;
    &lt;span class=&quot;vars&quot;&gt;$Tree &lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;= array();&lt;br&gt;
	foreach (&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$tab &lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$cle &lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;=&amp;gt; &lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$feuille&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;) {&lt;br&gt;
	&amp;nbsp;&amp;nbsp;if (&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$feuille&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;strings&quot;&gt;'parent'&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;]==&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;) {&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;addTree&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$Tree&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$feuille&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vars&quot;&gt;$cle&lt;/span&gt;&lt;span class=&quot;keywords&quot;&gt;);&lt;br&gt;
	&amp;nbsp;&amp;nbsp;}&lt;br&gt;
	  }&lt;br&gt;
	  &lt;span class=&quot;vars&quot;&gt;
	      ?&amp;gt;
	  &lt;/span&gt;
       &lt;/span&gt;
  &lt;/code&gt;
&lt;p&gt;Cette petite fonction récurssive peut sembler anodine mais elle fait tout le boulot et elle le fait bien.&lt;/p&gt;</description>
        
              </item>
      </channel>
</rss>
