logologo

"Only variables should be passed by reference"

Geoffray Warnants|12/02/2010|0 commentaires

Dans un environnement de développement normalement configuré pour afficher les erreurs de type E_NOTICE mais aussi E_STRICT, on se retrouve parfois confronté à une curieuse alerte, provoquée par une séquence d'instructions qui semble pourtant anodine.

Par exemple, pour extraire l'extension d'un nom de fichier, j'écris souvent de façon machinale :

$extension = end(explode('.', $filename));

Ce qui provoque une alerte assez déroutante :

Strict Standards: Only variables should be passed by reference

Pour comprendre ce message, il faut d'abord se rappeler que la fonction end() accepte en réalité une référence de tableau, ce qui est tout à fait compréhensible puisqu'elle va le modifier en positionnant le pointeur interne sur son dernier élément.

Ensuite [1], il faut savoir que lorsqu'une fonction retourne une valeur, une variable temporaire est créée. Généralement, on récupère cette variable temporaire en l'assignant à une autre variable déclarée explicitement, mais dans notre cas, elle est directement transmise à la fonction end() qui, bien qu'elle soit effectivement du type Array, la refuse et lance l'alerte.

Ce comportement tout à fait légitime ne date pas d'hier. Il a été introduit en PHP 5.0.5 afin d'éviter des corruptions mémoire. On peut certainement mieux comprendre ce risque en se souvenant de la différence significative entre les pointeurs et les références du C++.

Selon Rasmus Ledorf, fondateur de PHP, il est recommandé d'effectuer l'opération en deux étapes, en transitant par une variable déclarée.

$split = explode('.', $filename);
$extension = end($split);

Il souligne aussi à très juste titre que dans ce cas bien précis qui consiste en une opération fondamentale sur une chaîne de caractère, il est absolument injustifié de passer par un tableau pour résoudre ce problème alors que des fonctions spécifiquement dédiées aux chaînes de caractères suffisent. J'ajouterai même qu'elles seront aussi plus performantes !

$extension = substr(strrchr($filename, '.'), 1);

J'ai cependant découvert que la fonction current() ne provoque pas d'erreur avec une variable temporaire alors que son prototype signale aussi un passage par référence. On peut donc supposer, en sachant que current() ne modifie pas le pointeur interne du tableau, que le message d'erreur généré par PHP n'est pas tout à fait pertinent. Il devrait plutôt mentionner "Only variables should be updated by reference". Rasmus, si tu pouvais confirmer... ;)

Sachant cela, les fanatiques qui voudraient à tout prix s'en tirer avec une seule ligne de code peuvent toujours le faire, au prix d'une opération certainement assez coûteuse :

$extension = current(array_reverse(explode('.', $filename)));

Notes

  1. Je me base ici sur mes lointaines et médiocres connaissances des compilateurs C++ pour me faire une idée de la popote interne de PHP, qui doit probablement fonctionner de façon assez similaire, puisque écrit en C. A vérifier dans le code source... par un expert ;)

Liens utiles

Réagir à cet article | Lire la suite >>>

L'upcasting en PHP

Geoffray Warnants|11/02/2010|0 commentaires

Les problèmes de casting (transtypage) sont souvent considérés comme le propre des langages à typage fort tels que par exemple Java, C++ ou C#. L'upcasting (communément traduit en français par "transtypage vers le haut" ou encore "surclassement") consiste à transformer une classe dérivée en une classe dont elle hérite, lui faisant ainsi volontairement perdre de sa spécificité. C'est cette notion d'ascendance qui lui vaut le nom de casting vers le haut, par opposition au downcasting.

Bien que PHP ne puisse pas réaliser cette transformation nativement, voyons comme faire pour y remédier en imaginant l'exemple suivant :

class Person
{
}
class Child extends Person
{
}

Ainsi, avec une hiérarchie similaire écrite en Java, convertir une instance de Child en un objet de type Person aurait pu se faire tout naturellement.

Child c = new Child();
Person m = c;

Ce n'est malheureusement pas pareil en PHP, puisque comme l'indique la documentation sur le type casting, seule la conversion vers les types natifs est possible. La tentative suivante se solderait donc par une erreur de syntaxe.

$c = new Child();
$m = (Person)$c;

Pour remédier à ce problème, je m'inspire ici du concept de "constructeur de copie" qu'on retrouve en C++ et qui a pour but de réaliser une copie d'un objet via le constructeur de la classe. Bien souvent, la copie consiste tout bêtement en une initialisation dite membre à membre. On peut donc ajouter à la classe mère un constructeur jouant ce rôle :

class Person
{
    /**
     * Constructeur de copie
     */
    public function __construct(Person $c=null)
    {
        if ($c !== null) {
            foreach (get_object_vars($c) as $property => $value) {
                if (!is_object($value)) {
                    $this->$property = $value;
                } else {
                    $this->$property = clone $value;
                }
            }
        }
    }
}

On peut alors simuler l'upcasting :

$c = new Child();
$m = new Person($c);

Un tel besoin peut paraître déroutant, puisque en réalité, une instance de Child est déjà par héritage une instance de Person, à laquelle des spécificités sont apportées. Néanmoins, dans certains cas, il peut s'avérer utile de retirer les atouts d'une instance dérivée pour n'en retrouver que les comportement et propriétés héritées. Par exemple, une méthode qui accepte un objet en paramètre pourrait interdire la réception d'une classe dérivée dont les caractéristiques seraient jugées inopportunes.

class Person
{
    public function haveSex(Person $p)
    {
        if ($p instanceof Child) {
            throw new Exception('Tu devrais pas être au lit toi ?');
        }
        // n'golo golo !
    }
}

Finalement, voici comment conclure par un malheureux inceste programmatique ;)

$serge = new Person();
$charlotte = new Child();
$serge->haveSex(new Person($charlotte));

Réagir à cet article | Lire la suite >>>

Plugin phpMyAdmin : exporter des tables en PHP Array

Geoffray Warnants|10/06/2009|3 commentaires

Par soucis de performance, il m'arrive de temps en temps d'exporter le contenu d'une table MySQL pour en créer un tableau PHP associatif. Disposant ainsi des données en mémoire, ceci me permet, par exemple lors d'une requête de sélection, d'épargner une jointure avec cette table. Bien entendu, ceci n'est réellement intéressant que pour les tables de petite taille (table de devises, de pays, etc...)

Malgré la petite taille de ces tables, la procédure pour générer le code du tableau est généralement fastidieuse à moins de disposer d'un petit script "fait maison" sous la main.

J'ai donc décidé de publier un modeste outil utilisable sous la forme d'un plugin pour phpMyAdmin. Il ajoute la fonctionnalité désirée (cf. checkbox "PHP Array") à la liste des formats disponibles pour l'export des bases de données.

exporter tables MySQL en tableau PHP

Pour l'installation, rien de plus simple. Il suffit de télécharger le plugin ici et d'extraire le fichier PHP dans le répertoire phpMyAdmin/libraries/export/.

Par contre, le script étant toujours en version beta, tout rapport de bug ou suggestion d'amélioration sera vivement apprécié. Merci d'avance !

Réagir à cet article | Lire la suite >>>

La compression de données par RLE en PHP

Geoffray Warnants|28/05/2009|1 commentaire

Intrigué par les algorithmes de compression de données, je me suis penché sur RLE qui est sans conteste l'un des moins complexe à implémenter. Il s'applique aux données qui présentent de longues répétitions d'un même caractère. Le principe consiste à ne conserver qu'un seul caractère de chaque plage auquel on préfixera le nombre réel de répétitions attendues. Par exemple :

AAAABBBBBBCDDDDDEEEEEEEEE (25 octets)
devient
4A6B1C5D9E (10 octets)
Dans ce cas bien choisi le niveau de compression est intéressant, mais loin d'être systématiquement satisfaisant : l'algorithme s'avère en effet très peu approprié aux données qui ne présentent pas de répétitions suffisantes. Ainsi :
ABCDE (5 octets)
devient
1A1B1C1D1E (10 octets)

On voit clairement que RLE ne peut être envisagé que dans des domaines d'application bien précis pour pouvoir en espérer un quelconque bénéfice. Initialement inventé pour compresser les documents scannés en noir et blanc (qui présentent inévitablement de longues plages d'octets "blancs"), on peut l'appliquer au cas typique des images bitmaps formées de grandes zones d'une couleur unie. Ces pixels contigus dont le code couleur est identique se traduiront dans le fichier par une suite consécutive d'octets identiques.

Piet Mondrian Pour illustrer ce principe, j'ai testé la compression du fichier bitmap ci-contre. La compression RLE a permi de réduire le poids du fichier de 67.3 Ko à 9.1 Ko, c'est qui est déjà appréciable.
Ce qui laisse rêveur, c'est d'imaginer l'inventivité mise en oeuvre par le format PNG, pour arriver avec ce même fichier source à un résultat final d'à peine 400 petits octets !

Ma classe PHP

/**
 * "Run-length encoding" algorithm compression class
 *
 * @author  Geoffray Warnants - http://www.geoffray.be/
 * @version 1.0
 */
class RLE
{
    /**
     * Compress a string using RLE
     *
     * @param   string  $str
     * @return  string
     */
    public static function encode($str)
    {
        $encoded = '';
        for ($i=0, $l=strlen($str), $cpt=0; $i<$l; $i++) {
            if ($i+1<$l && $str[$i]==$str[$i+1] && $cpt<255) {
                $cpt++;
            } else {
                $encoded .= chr($cpt).$str[$i];
                $cpt = 0;
            }
        }
        return $encoded;
    }
    
    /**
     * Uncompress a RLE string
     *
     * @param   string  $str
     * @return  string     
     */
    public static function decode($str)
    {
        $decoded = '';
        for ($i=0,$l = strlen($str); $i<$l; $i+=2) {
            if ($i+1<$l && ord($str[$i]) > 0) {
                $decoded .= str_repeat($str[$i+1], 1+ord($str[$i]));
            } else {
                $decoded .= $str[$i+1];
            }
        }
        return $decoded;
    }
}

Réagir à cet article | Lire la suite >>>

PHP 5.2.9 améliore la méthode magique __call()

Geoffray Warnants|02/03/2009|0 commentaires

Avec quelques jours de retard, je viens de tester les améliorations mineures apportées par la toute fraiche release 5.2.9 de PHP, dernière ligne droite avant la très attendue 5.3. Outre les corrections de plusieurs bugs, cette nouvelle version présente une légère amélioration du comportement de la méthode magique __call() vis à vis des méthodes privées et protégées. Ainsi, sous les versions antérieures à 5.2.9, l'exemple suivant se soldait par une toute belle Fatal error: Call to private method Foo::bar() from context ''

<?php
class Foo {
    public function __call($method, $args) {
        if (method_exists($this, $method)) {
            call_user_func_array(array($this, $method), $args);
        }
    }
    private function bar() {
        echo 'Hello';
    }
}

$foo = new Foo();
$foo->bar();
?>

Bonne nouvelle : cet agaçant comportement que tout un chacun a probablement déjà rencontré fait désormais partie du passé.

Réagir à cet article | Lire la suite >>>

Le chiffrement en ROT13

Geoffray Warnants|29/01/2009|1 commentaire

A l'école primaire, il m'arrivait souvent de jouer les agents secrets en mettant mes camarades au défi de déchiffrer des messages codés. Un codage utilisé était par exemple de remplacer chacune des lettres par sa précédente dans l'alphabet, rendant ainsi le texte illisible mais facilement déchiffrable par qui en connaissait l'astuce.

Sans le savoir, je venais de mettre en pratique une méthode de chiffrement ancestrale appelée le Chiffre de César en l'honneur à Jules César, son inventeur, qui l'utilisait probablement en son temps pour transmettre ses mots doux en toute discrétion ;-). Un cas particulier de cet algorithme est le ROT13, qui décale chaque caractère alphabétique de 13 positions. Une clé qui n'a pas été choisie sans raison : Considérant notre alphabet de 26 lettres comme une suite circulaire (on revient au A après le Z), appliquer la translation 2 fois de suite permet de retrouver le texte original.

C'est d'ailleurs pourquoi la fonction PHP str_rot13() ne possède tout logiquement pas d'équivalence pour le décodage.

echo str_rot13(str_rot13('La boucle est bouclée'));
Je trouve cet exemple très pertinent pour illustrer que le fait d'appliquer successivement une même fonction d'encodage contribue parfois à affaiblir la robustesse d'un algorithme !

Réagir à cet article | Lire la suite >>>

Récupérer les en-têtes HTTP en PHP avec la lib cURL

Geoffray Warnants|13/12/2008|2 commentaires

Voulant une fois pour toutes pouvoir gérer correctement les appels à des pages distantes via HTTP, j'ai décidé de me pencher sur la librairie cURL. Une des premières étapes que je souhaitais accomplir était d'extraire les en-têtes HTTP afin d'obtenir une indication sur le déroulement de la requête HTTP demandée. Une première approche permet de réaliser ceci très simplement grâce à l'option de transmission CURLOPT_HEADER :

<?php
$url = curl_init();
curl_setopt($url, CURLOPT_URL, 'http://www.google.com');
curl_setopt($url, CURLOPT_RETURNTRANSFER, true);
curl_setopt($url, CURLOPT_HEADER, true);

$page = curl_exec($url);
curl_close($url);
?>

L'inconvénient majeur de cette méthode est que les en-têtes HTTP et le contenu de la page demandée se retrouvent concaténés dans le résultat de curl_exec(). Effectuer une décomposition manuelle du résultat obtenu pourrait fournir le résultat attendu, mais c'est alors omettre une solution plus propre offerte par la librairie. Elle propose en effet un mécanisme de fonctions "callbacks" appelées lorsqu'un évènement particulier se produit. Dans le cas qui nous intéresse ici, l'option CURLOPT_HEADERFUNCTION permet d'appeler une fonction à chaque en-tête HTTP rencontré. Attention que cette fonction doit absolument retourner le nombre d'octets de l'en-tête reçu en paramètre.

<?php
function read_header($url, $str) {
    echo 'Header : '.$str."\n";
    return strlen($str);
}

$url = curl_init();
curl_setopt($url, CURLOPT_URL, 'http://www.google.com');
curl_setopt($url, CURLOPT_RETURNTRANSFER, true);
curl_setopt($url, CURLOPT_HEADER, true);
curl_setopt($url, CURLOPT_HEADERFUNCTION, 'read_header');

$page = curl_exec($url);
curl_close($url);
?>

Sur base de ce principe, on peut alors se construire rapidement une petit classe, histoire d'encapsuler ces traitements dans un objet :

<?php
/**
 * A sample class to read HTTP headers
 * @author Geoffray Warnants - http://www.geoffray.be
 */
class HTTPReader {
    protected $_url = null;
    protected $_headers = array();
    protected $_body = '';
    
    public function __construct($url) {
        $this->_url = curl_init($url);   
        curl_setopt($this->_url, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->_url, CURLOPT_HEADER, true);
        curl_setopt($this->_url, CURLOPT_HEADERFUNCTION,
            array($this, 'readHeaders')
        );
    }
    public function __destruct() {
        curl_close($this->_url);
    }
    public function getHeaders() {
        $this->_body = curl_exec($this->_url);
        return $this->_headers;
    }
    public function getBody() {
        return $this->_body;
    }
    protected function readHeaders($url, $str) {
        if (strlen($str) > 0) {
            $this->_headers[] = $str;
        }
        return strlen($str);
    }
}
?>

Réagir à cet article | Lire la suite >>>

Comment utiliser un objet PHP sans le déclarer ?

Geoffray Warnants|19/10/2008|3 commentaires

Pour illustrer ce que je voulais pouvoir faire en PHP, je me suis inspiré du langage Java où on rencontre parfois ce genre d'appel :
// en Java
new Application(login, pwd).start();
La particularité est qu'on peut utiliser un objet sans avoir forcément besoin de le déclarer dans une variable. Ceci est souvent utilisé dans le cas où cet objet n'est nécessaire qu'à un unique endroit du programme. Malheureusement, PHP n'autorise pas cette syntaxe, ce qui nous contraint de scinder l'opération et de s'encombrer d'une variable intermédiaire qui nous est inutile.
// en PHP
$app = new Application($login, $pwd);
$app->start();
unset($app);

L'avantage de la première solution, outre le fait apprécié qu'elle offre une écriture plus concise, réside dans la mise en évidence de l'inutilité de l'instance en dehors de cet unique appel, ce qui peut s'avérer d'une grande utilité pour une compréhension rapide du code par un tierce développeur.

Pour pouvoir reproduire cette écriture en PHP, j'ai créé la petite classe suivante (qui aurait très bien pu n'être qu'une simple fonction) :
class ClassLoader {
    public static function load($className, $arg=null) {
        $c = new ReflectionClass($className);
        return ($c->hasMethod('__construct') || $c->hasMethod($className)) ?
            $c->newInstanceArgs(array_splice(func_get_args(), 1)) :
            $c->newInstance();
    }
}
On peut alors écrire :
ClassLoader::load('Application', $login, $pwd)->start();
Le principe devient intéressant, mais la clarté du code en a pris un sacré coup ! Pour simplifier, j'ai pensé à une nouveauté très attendue de PHP 5.3 : la nouvelle méthode magique __callStatic, dont le comportement est identique à la méthode __call bien connue, mais adaptée aux méthodes statiques.
// à partir de PHP 5.3
class ClassLoader {
    public static function __callStatic($method, $args) {
        $c = new ReflectionClass($method);
        return ($c->hasMethod('__construct') || $c->hasMethod($method)) ?
            $c->newInstanceArgs($args) :
            $c->newInstance();
    }
}    
L'écriture gagne ainsi nettement en simplicité :
ClassLoader::Application($login, $pwd)->start();
Il ne reste plus qu'à finaliser la classe pour la rendre compatible PHP 5 et 6, ce qui ne pose pas de problème. Il sera juste laissé au développeur le soin de réaliser les appels adéquats selon la version de PHP utilisée, avec la seule petite restriction qu'en PHP 6, le chargement d'une éventuelle classe nommée "Load" devra inévitablement se faire via l'écriture PHP 5.
class ClassLoader {
    public static function load($className, $arg=null) {
        $c = new ReflectionClass($className);
        return ($class->hasMethod('__construct') || $c->hasMethod($className)) ?
            $c->newInstanceArgs(array_splice(func_get_args(), 1)) :
            $c->newInstance();
    }
    
    public static function __callStatic($className, $args) {
        return call_user_func_array(
            array(self, 'load'), array_merge(array($className),$args)
        );
    }
}

Réagir à cet article | Lire la suite >>>

Formater les noms de répertoires en PHP

Geoffray Warnants|06/10/2008|0 commentaires

Lors de la manipulation de noms de répertoires dans des variables PHP, il m'est souvent arrivé d'être embêté par un slash final parfois manquant, parfois présent. Pour éviter ce désagrément, j'ai pris pour habitude d'adopter la convention qui impose qu'un nom de répertoire doit toujours être terminé par un slash. Ainsi, pour uniformiser mes variables dès leur initialisation, j'opère un rapide formatage désormais devenu un réflexe :
$path = rtrim($path, '/\\').'/';
Pour être pointilleux, on pourrait même pousser le vice jusqu'à utiliser la constante DIRECTORY_SEPARATOR afin de terminer la chaîne par le caractère slash ou backslash adéquat selon le système d'exploitation sur lequel on se trouve :
$path = rtrim($path, '/\\').DIRECTORY_SEPARATOR;
J'avoue me contenter généralement de la première solution, bien plus rapide à écrire et qui se révèle tout aussi portable puisque gérée par les principaux OS (Windows, *nix, Mac OS). Cette constante n'est pas pour autant totalement dénuée d'intérêt puisqu'elle peut par exemple trouver son utilité lorsqu'on souhaite traiter un chemin retourné par le système d'exploitation. Il peut donc s'avérer utile de faire :
$path = str_replace(DIRECTORY_SEPARATOR, '/', rtrim(getcwd(), '/\\')).'/';

Réagir à cet article | Lire la suite >>>

Un effet pervers du transtypage avec in_array

Geoffray Warnants|27/05/2008|0 commentaires

Malgré son apparente simplicité, voici un bel exemple qui montre qu'une bonne connaissance des subtilités du langage PHP s'avère très importante :
in_array(0, array('A','B','C'));   // Retourne TRUE !!
Cette instruction montre que pour PHP, le nombre 0 se trouve bien dans le tableau ne comportant que des chaînes de caractères. Bien que cela puisse paraître surprenant, ce comportement est tout à fait normal. Pour le comprendre, il faut se souvenir de la manière dont PHP réalise les comparaisons entre valeurs de types différents. PHP étant un language faiblement typé, pour pouvoir comparer ce qui est comparable, il doit parfois réaliser implicitement des conversions de type (transtypage, ou casting) sur l'une des 2 opérandes. Ainsi, dans le cas d'une comparaison nombre/chaîne, il est important de savoir que c'est toujours la chaîne qui est implicitement castée en nombre.
// cette condition sera vérifiée
echo (0 == 'A') ? 'TRUE' : 'FALSE';

// car elle est identique à
echo (0 == (int)'A') ? 'TRUE' : 'FALSE';
Et comme on sait que le casting d'une chaîne non numérique en un nombre retournera tout logiquement la valeur 0, voilà notre condition vérifiée !

Bien entendu, une comparaison stricte à l'aide de l'opérateur "triple égal" nous aurait offert le résultat initialement attendu puisqu'il réalise une comparaison aussi bien les valeurs que sur les types.

// cette condition ne sera pas vérifiée
echo (0 === 'A') ? 'TRUE' : 'FALSE';
Il faut aussi savoir que la fonction in_array possède elle même le moyen de réaliser cette comparaison stricte car elle accepte un dernier paramètre optionnel qui permet d'activer ou non cette fonctionnalité. Non activée par défaut, il nous aurait fallu écrire dès le départ :
in_array(0, array('A','B','C'), true);   // Retourne FALSE
Pour conclure, outre le fait que profiter du confort offert par le faible typage de PHP ne se fait pas sans une extrême vigilance, j'ajouterai qu'avant d'accuser le langage d'un nouveau bug, il est peut-être utile d'envisager une éventuelle défaillance du programmeur ;)

Liens utiles

Réagir à cet article | Lire la suite >>>

Sortie du Zend Framework 1.5

Geoffray Warnants|18/03/2008|0 commentaires

Zend Framework 1.5Vivement attendue, la release 1.5 du célèbre framework signé Zend Technologies débarque en version finale. Une sortie toute fraiche dont j'attendais impatiemment l'arrivée avant de me lancer dans l'apprentissage de ce framework, choisi après mûre réflexion parmi les nombreux autres prétendants très convaincants qui se bousculent au portillon. Voilà, maintenant plus d'excuses, va falloir s'y mettre !

Réagir à cet article | Lire la suite >>>

Convertir un tableau PHP en Javascript

Geoffray Warnants|21/01/2008|0 commentaires

Cette petite fonction à l'allure peu digeste permet de transformer un tableau PHP en un tableau Javascript. Rien de bien formidable en soi, mais elle à tout de moins le mérite de gérer correctement les tableaux multidimensionnels (merci la récursivité), les valeurs NULL, booléennes ou non numériques. C'est pas du grand art, mais c'est simple et efficace.
/**
 * @author Geoffray Warnants
 */
public static function writeArray($aInput, $jsVarName, $eol=PHP_EOL) {
    $js = $jsVarName.'=new Array();'.$eol;
    foreach ($aInput as $key => $value) {
        if (!is_numeric($key)) {
            $key = '"'.$key.'"';
        }
        if (is_array($value)) {
            $js .= self::writeArray($value, $jsVarName.'['.$key.']', $eol);
        } else {
            if (is_null($value)) {
                $value='null';
            } elseif (is_bool($value)) {
                $value = ($value) ? 'true' : 'false';
            } elseif (!is_numeric($value)) {
                $value = '"'.$value.'"';
            }
            $js .= $jsVarName.'['.$key.']='.$value.';'.$eol;
        }
    }
    return $js;
}

Réagir à cet article | Lire la suite >>>

Simulateur de fautes de frappe

Geoffray Warnants|13/01/2008|0 commentaires

Travaillant sur un petit système de correction orthographique online, je me suis penché sur la réalisation d'une classe PHP qui permettrait d'obtenir toutes les combinaisons qu'il pourrait résulter d'une faute de frappe lors de l'encodage d'un mot au clavier. L'algorithme se base sur l'adjacence des touches du clavier (azerty et qwerty supportés) pour ne proposer que les fautes de frappe les plus probables dues à la maladresse humaine. Il est par exemple peu fréquent d'encoder un "s" alors qu'on vise un "k", ces deux touches étant complètement opposées.
<?php
$clumsy = new ClumsyTyper();
print_r($clumsy->getMistypedString('sexy''));
?>
Va afficher :
Array (
    [0] => zexy
    [1] => eexy
    [2] => qexy
    [3] => dexy
    [4] => wexy
    [5] => xexy
    [6] => szxy
    [7] => srxy
    [8] => ssxy
    [9] => sdxy
    [10] => sesy
    [11] => sedy
    [12] => sewy
    [13] => secy
    [14] => sext
    [15] => sexu
    [16] => sexg
    [17] => sexh
)
Bien évidemment, certains petits filous auront vite cerné l'utilité de cette classe dans d'autres domaines complètement machiavéliques tels que le typosquatting (ou URL hijacking), la génération massive de mots clés (Massive keyword list), et tout un tas de trucs avec des noms qui font très peur, à essayer avec prudence dans un but purement éducatif, bien entendu !

Réagir à cet article | Lire la suite >>>

<<< Articles plus récents | Articles plus anciens >>>

zend framework

Valid XHTML 1.0 Strict Built with PHP 5 built with Zend Framework 1.7 Built with MooTools Geoffray.be RSS feed