Affichage des articles dont le libellé est algorithme. Afficher tous les articles
Affichage des articles dont le libellé est algorithme. Afficher tous les articles
2/15/2009

Algorithme tri de couleur (+ demonstration javascript)

 

Il y a 3 semaines, j’expliquais sur ce blog comment créer un algorithme qui était capable de définir automatiquement la couleur d’un texte par rapport à son arrière plan. Aujourd’hui, je vous propose de trier un set (ou une palette) de couleur.

 

Pour vous faciliter nous faciliter la tâche voici quelques restrictions :

  1. Notre set (ou palette) sera composé de 5 couleurs
  2. Les couleurs devront être triées de la plus claire à la plus foncée (l’inverse est tout aussi possible)

 

En fidèle lecteur de ce blog vous vous souvenez sans doute de cet article où j’expliquais comment réaliser une fonction de tri simple. Grâce à ces deux précédents articles nous sommes capable de réaliser de réaliser une fonction de tri de couleur.

 

La théorie

Pour savoir si une couleur est plus clair ou plus foncée qu’une autre, il suffit de se référer à la luminance de leurs codes HSL. Au lieu de trier des nombres du plus petit au plus grand il faut donc trier les couleurs par leurs composantes HSL de la plus grande (100% : blanc) à la plus petite (0% : noir).

 

L’algorithme

Ce qui nous donne cet algorithme :

tabCouleur = ["0B8C8F", "FCF8BC", "CACF43","2B2825","D6156C"]

//Convertir de HEX en HSL
convertirTableauCouleurHEXversHSL(tabCouleur);

//Le tableau est maintenant de la forme :
//tabCouleur = [[,,], [,,], [,,], [,,], [,,]]

//Luminance de la première couleur : tabCouleur[0][2]

Faire
    Si(tabCouleur[0][2] < tabCouleur[1][2])
        tabCouleur.intervertir(0,1);
    SinonSi(tabCouleur[1][2] < tabCouleur[2][2])
        tabCouleur.intervertir(2,3);
    SinonSi(tabCouleur[2][2] < tabCouleur[3][2])
        tabCouleur.intervertir(2,3);
    SinonSi(tabCouleur[3][2] < tabCouleur[4][2])
        tabCouleur.intervertir(3,4);
TantQue(!(    tabCouleur[0][2] >= tabCouleur[1][2]
        &&     tabCouleur[1][2] >= tabCouleur[2][2]
        &&     tabCouleur[2][2] >= tabCouleur[3][2]
        &&     tabCouleur[3][2] >= tabCouleur[4][2]))

//Convertir de HSL -> HEX
convertirTableauCouleurHSLversHEX(tabCouleur);

L’équivalent Javascript n’est pas très différent. Les fonctions convertirTableauCouleurHEXversHSL et convertirTableauCouleurHSLversHEX vont en fait transformer le code HEXA en RGB puis en HSL et inversement.

 

Pour ce qui est de la méthode intervertir. Elle ne fait rien d’autre qu’une inversion (swap) entre 2 éléments (spécifiés par leurs index) d’un même tableau. Le code Javascript est donc :

var tmp=tabCouleur[x];
tabCouleur[x]=tabCouleur[y];
tabCouleur[y]=tmp;

 

Démonstration en javascript

J’ai réalisé une démonstration en javascript de cet algorithme sur le sous domaine projets. Le script importe dynamiquement (via l’API de ColourLovers) des palettes de couleurs il vous suffit alors de cliquer sur une palette pour la trier.

 

A chaque chargement de l’API, une seconde palette est générée et contient toutes les couleurs des autres palettes le temps de tri est légèrement plus long mais le résultat est là.

 

Pour accéder à la démo de tri des couleurs en javascript c’est par ici.

 

Remarque : Certaines palettes ont déjà leurs couleurs de triées de la plus foncées à la plus clair.

1/25/2009

Choix automatique de la couleur d'un texte en fonction de sa couleur d'arrière plan

Ou en terme plus technique, comment créer un algorithme qui retourne un foregroundColor adéquate en fonction d'un backgroundColor variable.

Dans le cadre de mon stage @ Zlio Nantes, j'ai eu besoin de créer un algorithme qui, à partir de n'importe quelle couleur d'arrières plans, serait capable de définir si la couleur du texte (blanc ou noir) afin que ce dernier soit toujours visible.

Postulat : Pour la démonstration, nous prendrons un vert foncé comme couleur d'arrière plan

#155147 = rgb(21, 81, 71); //RGB (Red, Blue, Green) ou RVB (Rouge, Vert, Bleu)

 

Méthode rapide

La première idée qui pourrait vous venir à l'esprit serait d' additionner les composantes RVB :

21+81+71 = 173

Or, au maximum il est possible d'obtenir une somme de

255+255+255 = 765

Donc il suffirait donc de regarder si la somme des composantes et supérieur ou inférieur à 382,5 (765/2) pour savoir s'il faut mettre le texte en blanc (donc plus clair) ou en noir (plus foncé). Ce qui pourrait donner cet algorithme :

var couleurRGB = [21,81,71];

Si couleurRGB[0]+couleurRGB[1]+couleurRGB[2] > 382 Alors
     //#FFFFFF
Sinon
     //#000000
FinSi

En réalité cet approche est fausse. D'ailleurs en utilisant la couleur de l'exemple, l'algorithme nous propose d'utiliser du noir. Voici le résultat :

En testant on constate que le texte n'est clairement pas visible et que le blanc aurait été un meilleur choix.

 

En baissant la valeur seuil à 170 notre algorithme retourne une couleur correcte (blanc) pour notre exemple, mais qu'en est-il pour ces autres couleurs ? rgb(4, 1, 31), rgb(9, 23, 9), rgb(29, 50, 3), rgb(27, 15, 27). La somme de leurs composantes ne dépasse pas 170 et pourtant la proposition est fausse, notre algorithme propose du noir.

Pour corriger cela nous pourrions baisser la valeur seuil. Lors de mes tests j'ai réussi à obtenir de très bon résultat avec une valeur seuil à 86 mais il reste encore une infinité de cas où notre algorithme propose une couleur erronée.

A ce stade, 2 possibilités. Soit nous complexifions notre algorithme en étudiant chacune des composants les une après les autres et en réalisant un savant mélange de test,... Soit nous passons à la méthode fiable.

 

Méthode fiable

La méthode fiable consiste à convertir le format de gestion de couleur de RGB vers HSL (Hue, Saturation, Lightness) soit TSL (Teinte, Saturation, Lumière) en français. C'est la composante lumière qui nous intéresse :

La lumière est la luminosité (depuis 0 % qui correspond au noir jusqu'à 100 %, luminosité maximale permise par le support, le blanc dans le cas des écrans).

Une fois la conversion effectuée ils nous suffira de définir si la composante "L" est supérieur ou inférieur à 50% et d'en déduire la couleur à appliquer en premier plan. Notre algorithme devient donc :

var couleurRGB = [21,81,71];
var couleurHSL = RGBtoHSL(couleurRGB);

Si couleurHSL[2] > 0.5 Alors //0.5 = 50% 
     //#000000
Sinon
     //#FFFFFF
FinSi 

Et voila ! Cette méthode est légèrement plus lente en calcul processeur car elle nécessite une conversion supplémentaire mais elle est 100% fiable.

[MAJ] La démo est disponible en ligne ici, elle intègre le code javascript fonctionnel des deux algorithmes ainsi qu'un script de test pour comparer automatiquement leurs valeurs de retour.

12/12/2008

Création d’un keygen (générateur de clés) à partir d’un algorithme

Il y a quelques jours, j’ai travaillé sur la sécurité d’une application web. Cette dernière demandait à l’utilisateur de payer une licence afin de faire disparaitre le texte “version demo”. Je montrerai le travail de recherche et d’analyse du code PHP et Javascript la semaine prochaine, pour le moment intéressons nous à la création d’un keygen (générateur de clé) à partir d’un algorithme donné. Je précise une fois de plus que cet article a pour but de faire “découvrir” une petite partie de la “sécurité informatique” et non d’inciter au piratage.

 

Rappel sur les keygens :

Un générateur de clés, aussi appelé keygenerator ou tout simplement keygen, est un logiciel générant des numéros de série afin d'installer/déverrouiller/lancer une application.

Un générateur de clés a deux moyens pour trouver une clé-cd valide : la méthode brute force et la méthode qui consiste à reconstituer l'algorithme utilisé par la société éditrice du logiciel.

Source Wikipedia

J’en profite aussi pour préciser les expressions algorithmiques utilisées dans cet article :

  • POS(X) : retourne le caractère à la position X, en partant de 0, d’une string quelconque.
  • X MOD Y : retourne X modulo Y
  • LEN(STR) : retourne la longueur d’une string

Les postulats sur lesquels nous nous baserons :

  • On se basera sur la string DK suivante (si quelqu’un connait le nom technique je suis intéressé) : 123456789ABCDEFGHJKLMNPQRSTUVWXYZ
  • La clé (licence key) que doit entrer l’utilisateur est de 11 caractères ou plus.
  • Nous comptons, pour les positions de caractère par exemple, à partir de 0.

Une fois la clé de licence spécifiée, le programme va effectuer les traitements suivants afin de définir la validité d’une clé :

  • Création d’une seconde clé (clé temporaire/intermédiaire à partir de la clé de licence entrée par l’utilisateur) sous la forme : [11][0][8][12]
    • [11] est la caractère en 11ème position de la licence originale
    • Si la licence originale est ZK5JC9EO6IEGP alors la clé intermédiaire sera GZ6P
  • On vérifie à partir de cette clé intermédiaire que :
    • Le modulo de la position du second caractère sur DK est différent de 1. On trouvera alors [0] c’est à dire le caractère en 0ème position de notre clé de licence finale.
      • Par exemple pour 12 :
      • 12 MOD 5 = 2 //12 est valide (modulo différent de 1) on cherche donc le caractère correspondant
        POS(12) = C //C est donc un caractère possible en position 1 pour notre clé intermédiaire et en position 0 pour notre clé finale
        [0] = C
    • On prends aléatoirement les positions des 0ème et 2ème caractères sur DK
    • La position du 3ème caractère doit être égale à (j'ai décomposé le code pour une lecture plus aisée) :
      • X = POS([11]) + POS([8]) //on additionne les positions sur DK de 0ème et 3ème caractère
        X *= 9
        X = X Mod (Len(DK) - 1) //on repositionne X sur DK
        [12] = POS(X) //le 3ème caractère de notre clé intermédiaire est donc à la position X sur DK

L’idée est donc de générer aléatoirement des licences qui correspondent à cet algorithme. Voici un code VB6 permettant de résoudre cette problématique :

Randomize '(re)initialisation du moteur de nombre aléatoire
Dim dK as String
dK = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim sr(12) As String 'clé de licence finale que nous allons générer

'#########################################
' Traitement sur la clé intermédiaire
'#########################################

Dim tmp0, tmp1, tmp2, tmp3 As Integer

'Recherche du 2ème caractère
tmp = 1
Do While ((tmp Mod 5) = 1)
tmp = rand(1, Len(dK))
Loop
sr(1) = Mid(dK, tmp, 1)

'On créé le 0ème & 2ème caractère
tmp0 = rand(0, Len(dK) - 1)
tmp2 = rand(0, Len(dK) - 1)

sr(0) = Mid(dK, tmp0 + 1, 1)
sr(2) = Mid(dK, tmp2 + 1, 1)

'Le 3ème caractère doit être égal à
tmp3 = tmp0 + tmp2
tmp3 = tmp3 * 9
tmp3 = tmp3 Mod (Len(dK) - 1)
sr(3) = Mid(dK, tmp3 + 1, 1)

'#########################################
' On en déduit ensuite la clé finale
'#########################################

'Ordre : [11][0][8][12]
sr(11) = sr(0)
sr(0) = sr(1)
sr(8) = sr(2)
sr(12) = sr(3)

sr(1) = Mid(dK, rand(1, Len(dK)), 1)
sr(2) = Mid(dK, rand(1, Len(dK)), 1)
sr(3) = Mid(dK, rand(1, Len(dK)), 1)
sr(4) = Mid(dK, rand(1, Len(dK)), 1)
sr(5) = Mid(dK, rand(1, Len(dK)), 1)
sr(6) = Mid(dK, rand(1, Len(dK)), 1)
sr(7) = Mid(dK, rand(1, Len(dK)), 1)
sr(9) = Mid(dK, rand(1, Len(dK)), 1)
sr(10) = Mid(dK, rand(1, Len(dK)), 1)
'La clé finale = Join(sr, "")

J’utilise des variables intermédiaires et de nombreux appelles à la fonction rand. Ce code est très facilement optimisable mais j’ai préféré le décomposer afin de faire ressortir l’algorithme de base et pour que cet article soit accessible au plus grand nombre.

Si vous avez aimé cet article ou si vous avez des demandes particulières, n’hésitez pas à le faire savoir en commentaire. N’oubliez pas de vous inscrire au flux rss du blog :).

10/01/2008

Algorithme et code C d’une fonction de tri croissante

Dans le cadre d’un cours de C à l’EPSI Nantes, il nous a été demandé de créer une fonction qui permettra de trier de façon croissante (ou décroissante, c’est simplement l’algorithme inverse) une série de 5 nombres entrée par l’utilisateur. Il est à noter que la fonction ne pourra pas utiliser de tableau, ni de pointeur, ni les fonctions de tris disponibles en C.

Je vais donc vous proposer dans cet article un des algorithmes possible pour répondre à cette problématique.

procedure tri
   E: entier : x1,x2,x3,x4,x5;
debut
   Si x1 > x2 Alors
      tri(x2,x1,x3,x4,x5)
   SinonSi x2 > x3
      tri(x1,x3,x2,x4,x5)
   SinonSi (x3 > x4)
      tri(x1,x2,x4,x3,x5)
   SinonSi (x4 > x5)
      tri(x1,x2,x3,x5,x4)
   FinSinonSi
   //Test si x1 > x2 et x2 > x3 ...
   //Afficher les nombres dans le bon ordre

Et le code C :

void tri(float x1, float x2, float x3, float x4, float x5){

   if(x1 > x2)
      tri(x2,x1,x3,x4,x5);
   else if(x2 > x3)
      tri(x1,x3,x2,x4,x5);
   else if(x3 > x4)
      tri(x1,x2,x4,x3,x5);
   else if(x4 > x5)
      tri(x1,x2,x3,x5,x4);
   //Test si x1 > x2 et x2 > x3 ...
   //Afficher les nombres dans le bon ordre

Il est alors facilement imaginable d’améliorer l’algorithme : avec un nombre x d’entier ou de réel au lieu de 5, d’utiliser un tableau et des pointeurs.

7/06/2008

Rétro-ingénierie (reverse-engineering) : Possible algorithme de Tinyurl, minurl et autre Tinyurl-like

Je suis actuellement en train de développer une application Adobe Air comme certains le savent, et j'ai besoin (ou plutôt envie) de créer moi aussi mon propre "raccourcisseur" d'url.

Apparemment la plupart des services du genre se base sur une base de données, l'objectif pour être concurrentiel est donc d'effectuer le moins de requête possible afin que le service soit le plus rapide. Après avoir soumis à la suite plusieurs urls différentes à minurl.fr, j'ai obtenu cette suite d'url :

  • http://minurl.fr/12
  • http://minurl.fr/13
  • http://minurl.fr/14
  • http://minurl.fr/15
  • http://minurl.fr/16
  • http://minurl.fr/17

Que peut-on en conclure ?

  1. A chaque nouvelle url qui n'existe pas dans la base de données
    1. On créé un identifiant, supérieur au dernier identifiant, que l'ont lie à l'url (ou plutôt un équivalent compressé de l'url).
      1. Donc dans la table de notre base de données on à pour le moment les champs suivant :
        1. id varchar(10) (primary) : identifiant pour l'url qui sera afficher
        2. url varchar(40) (index) : champs pour l'url compressée
          1. Il est préférable que le contenu de ce champs soit compressé si l'on ne veut pas une énorme base de données mais cela n'est pas obligatoire !
          2. Dans cette exemple d'algorithme nous ne nous soucierons pas de la compression de l'url.
  2. Si le script reçoit un identifiant
    1. Chercher dans la base de données si l'id existe
      1. Il existe : on retourne l'url (il faudra la décompresser si on l'a compressée)
        1. On redirige vers cette url.
      2. Il n'existe pas : on informe l'utilisateur.
  3. Si le script ne reçoit pas d'identifiant
    1. On propose le formulaire d'ajout

 

Maintenant, on répète l'expérience avec Tinyurl, on à donc cette suite d'url :

  • http://tinyurl.com/6l74df
  • http://tinyurl.com/6d8r75
  • http://tinyurl.com/5o5c7d
  • http://tinyurl.com/5tfegj
  • http://tinyurl.com/63kjqo
  • http://tinyurl.com/6ys8ym

Que peut-on en conclure ?

  1. Il semble que Tinyurl utilise un système de création d'ID aléatoire, ce qui empêche toute prédiction sur le prochain ID à venir.
  2. Chaque nouvelle ID créé est de la forme 5XXXXX ou 6XXXXX (d'après mes tests). Il est donc possible que les ID de la forme 4XXXXX, 3XXXXX, 2XXXXX est déjà été tous utilisé.
    1. Il est donc fort probable que l'algorithme de Tinyurl, répartisse les ID fraichement créé sur deux plages qui n'ont pas encore été complètement remplie (dans notre cas 5XXXXX et 6XXXXX). Nous pouvons émettre cette hypothèse vu que les plages [4XXXXX, 3XXXXX] et [2XXXXX, 1XXXXX] on déjà été rempli.
      1. Exemple, si l'on entre http://google.com l'ID de TinyUrl est http://tinyurl.com/1c2 : notre théorie est donc sans doute valide car cette adresse à été entrée dans les débuts de Tinyurl (par une personne qui souhaitait tester le service) et qu'au lancement l'algorithme devait travailler sur une plage [2XXXXX, 1XXXXX].
  3. L'algorithme semble donc bien plus complexe que celui élaboré plus haut.

 

Nous avons donc une base d'algorithme pour créer notre service, bien sur, il est extrêmement conseillé de l'améliorer mais il reste néanmoins fonctionnel et c'est ce que l'on souhaite d'un algorithme n'est-ce pas ?

6/26/2008

La rétro-ingénierie (reverse-engineering) appliquée à un mini-projet

Avant de commencer cet article, je souhaite préciser plusieurs choses :

  1. Je suis autodidacte, je n'ai aucune formation scolaire sur le sujet, il est donc possible que je n'emploie pas les bons termes, ne sortez pas le fouet pour autant.
  2. Je montrerai dans ce poste qu'un bref aperçu de mes méthodes de R-E (Reverse-engineering), mon but n'est pas de former, mais simplement d'expliquer la démarche.
  3. J'utilise la rétro-ingénierie à des fins de formation personnel et en aucun cas pour de la contrefaçon ou autre forme de piraterie.


Base d'une réflexion de rétro-ingénierie

Pour commencer, nous allons résumer rapidement le projet : Nous devons créer un équivalent à TwitterCounter mais pour Plurk (que nous appellerons PlurkCounter).

La page d'un utilisateur sur TC (TwitterCounter) est de la forme :

TwitterCounter- How popular are you- (open beta)_1214486815920

Maintenant l'idée consiste à chercher l'ensemble des informations dont on va avoir besoin pour réaliser un service similaire. On a donc besoin :

  • De connaitre le nombre de followers actuellement.
    • Pour l'afficher dans le badge/logo.
    • Pour l'afficher dans le graphique dans la colonne de droite.
  • On a besoin de connaitre le nombre de followers au jour X (dans le passé).
    • Pour afficher l'évolution du nombre de followers dans le graphique.
      • On aura donc besoin de stocker un tableau permettant une relation entre les jours et le nombre de followers pour ces jours-là.

Et c'est déjà fini ! Il ne reste plus qu'à retranscrire cela par un algorithme puis par du code, en allant du plus simple au plus complexe. L'objectif et de voir ce que vous pouvez recréer, puis, une fois vos acquis évalués, essayez de voir comment faire pour chercher les informations qui vous manquent.

 

Quelques pistes d'algorithme :

  1. Cherchez comment retrouver le nombre de followers actuels d'un utilisateur (Plurk ou Twitter ou même autre).
  2. Créez un système de cache qui permettra de ne pas aller rechercher l'information si elle n'est pas périmée :
    1. Si (un fichier cache existe pour cet utilisateur et qu'il date de plus de 24h) OU Si(le fichier cache de cette utilisateur n'existe pas)
      1. Chercher le nombre de followers de cet utilisateur et créer le fichier cache.
    2. Sinon
      1. Ouvrir le fichier cache et récupérer/afficher le nombre de followers.
  3. Ensuite pour la journalisation, et permettre le suivi du nombre de followers en fonction du temps, ajoutez un test à votre algorithme :
    1. Si (le fichier cache pour cet utilisateur existe) ET (le fichier cache date de plus de 24h)
      1. On enregistre dans une base de données/fichier le nombre de followers pour la date du fichier cache.
  4. Il ne vous reste plus qu'à afficher les données sous la forme que vous souhaitez.

 

Autre exemple : Reproduire le graphique de TC

Intéressons nous maintenant à l'affichage des données sous la forme de graphique, comme le montre TC :

TwitterCounter- How popular are you- (open beta)_1214487161004

Émettons que vous réussissiez à créer d'une façon ou d'une autre une base de données (ou un tableau) qui contient le nombre de followers en fonction de la date.

La question qu'il reste à vous poser est comment reproduire ce type de graphique ?

  1. Vous avez forcément le nombre de followers d'aujourd'hui pour cet utilisateur, donc la colonne de droite sera toujours remplie.
  2. Ensuite recherchez si hier, pour cet utilisateur, vous aviez le nombre de ses followers :
    1. si oui : vous affichez l'information.
    2. si non : vous informer l'utilisateur que vous n'avez pas de données pour ce jour-là.
  3. Vous pouvez effectuer une boucle jusqu'à J-X (pour TC la boucle va jusqu'à 7 jours en arrière, pour PlurkCounter la boucle va jusqu'à 8 jours en arrière) de la même façon.

 

Voila j'espère que cette petite initiation vous à plu, n'hésitez pas à tester PlurkCounter si vous êtes un utilisateur de Plurk.

4/20/2008

Lire récursivement un répertoire en php

Si vous n'avez jamais réussi à parcourir un répertoire ainsi que tout ses sous répertoire en php, ce message est pour vous !

Mais tout d'abord, un petit rappel, qu'est-ce qu'une fonction récursive ?
Une fonction récursive est une fonction qui peut s'appeler elle-même au cours de son exécution
(Wikipedia)
L'algorithme est donc court :

Fonction parcourir(rep)
E :
chaine : rep /* le répertoire à lire */
S :
chaine : liste_fichier /* liste des fichiers dans ce répertoire */
Var :
chaine : f /* fichier actuel */

Debut

TantQue(f = lire_repertoire(rep)))
Si est_repertoire(f)
Alors
liste_fichier += parcourir(rep + f)
FinSi

Si est_fichier(f)
Alors
liste_fichier += f
FinSi
FinTantQue

retourne liste_fichier
Fin


En bref, notre fonction lit le contenu d'un répertoire et retourne sous forme de chaine la liste des nom de fichier qui compose le répertoire en cours (à savoir "rep"). A chaque sous répertoire découvert, on ré-appelle la fonction "parcourir" avec l'adresse actuelle du répertoire ainsi que le nom du sous répertoire, ce qui nous retournera une liste de fichier composant ce répertoire.

Ainsi on va alors obtenir un enchainement d'appelle de fonction "parcourir" chaque fonction retournant une chaine "liste_fichier" à son appelant qui lui même retournera à son appellant etc... Jusqu'à ce que la première fonction appelante, qui aura récupérée tout les "liste_fichier" retourne elle même cette valeur.

Voici donc un exemple de code, qui permet de parcourir tous les sous répertoires d'un dossier, et de calculer le nombre de ligne de code de chaque fichier php, htm/html, css et javascript qu'il contient.
<style>
quote {padding:5px;padding-left:20px;display:block;}
</style>
<?php
function compte_ligne_code($f)
{
    return count(file($f));
}

function read_dir($dir,$dir_max)
{
    $array = array(2);
    if(!strrchr($dir, '_NO_'))//dossier vide
    {
    $me = 0;
    $hdl = @opendir($dir);
    while($f = @readdir($hdl))
    {
        if(is_dir($dir.'/'.$f) && $f !== '..' && $f !== '.')
        {
            if($dir_max > 0)
            {
            $dir_max--;
            $array[0] .= '<quote style="background:#'.rand(2,9).'f'.rand(2,9).'f'.rand(2,9).'f">[DIR] <h3>'.$dir.'/'.$f.'</h3><br />';
                $narray = read_dir($dir.'/'.$f,$dir_max);
                $array[0] .= $narray[0];//code html
                $array[1] += $narray[1];//nombre de ligne
            $array[0] .= '</quote>
';
            }
        }
        else if((substr($f, -4, 4) == '.php'
        ||    substr($f, -3, 3) == '.js'
        ||    substr($f, -4, 4) == '.css'
        ||    substr($f, -4, 4) == '.htm'
        ||    substr($f, -5, 5) == '.html'
        )  && substr($f, 0, 4) !== '_NO_')//fichier .php ou .js
        {
            $l = count(file($dir.'/'.$f));
            $array[1] += $l;
            $array[0] .= '<quote style="background:#'.rand(2,9).'f'.rand(2,9).'0'.rand(2,9).'f">'.$l.' ligne(s) dans <strong style="float:right">'.$dir.'/'.$f.'</strong>';
            $array[0] .= '</quote>
';
        }
        else
        {
        $array[0] .= '['.$dir.'/'.$f.'] ';
        }
    }
    }
    else
    {
        $array[0] .= '<quote style="background:#000000;color:#ffffff">Passe le dossier dossier : '.$dir.'</quote>';
    }
    return $array;
}

$arr = read_dir('.',100);
echo '<h1>'.$arr[1].' lignes de code !</h1>'.$arr[0];


Si vous souhaitez que des dossiers ou des fichiers ne soient pas pris en compte ajoutez "_NO_" devant, par exemple "images" devient "_NO_images" et ainsi de suite.
»
 
 
Made with on a hot august night from an airplane the 19th of March 2017.