L'affichage du contenu d'un dossier ne peut pas se limiter au premier niveau de l'arborescence, car un dossier peut contenir des sous-dossiers, qui peuvent à leur tout contenir des dossiers, qui peuvent à leur tour... etc.

Nous allons voir comment utiliser la récursivité pour passer en revue tous les niveaux de l'arborescence, et comment mettre en forme les résultats.

Pour les exemples, nous utiliserons l'aborescence de dossiers ci-contre.

Cet aborescence se trouve dans le dossier test du tutoriel. Vous pouvez voir son contenu avec le bouton dans la barre de menu du tutoriel.

Si vous ne voyez pas cet aborescence, ou si vous voulez la ré-initialiser utilisez ce script.

### Lecture récursive

Pour afficher le contenu complet de l'arborescence, il faut construire une fonction récursive de lecture de dossier : chaque fois que dans un dossier nous sommes en présence d'un dossier, la fonction listerDossier() appelle la fonction listerDossier pour effectuer le traitement.

Nous commencerons par placer le code de lecture d'un dossier dans une fonction qui accepte comme argument le nom du dossier à lire.

Exemple : lecture récursive
<?php ob_start(); require('bib_fonctions.php'); htmlDebut('Lecture récursive'); $nomDossier = 'test_repert'; htmlInfo("Contenu du dossier $nomDossier"); listerDossier($nomDossier); htmlFin(); //===================================================== /** * Affiche le contenu d'un dossier * @param string $nomDossier Nom du dossier à lister */ function listerDossier($nomDossier) { $dossier = @opendir($nomDossier); if (! $dossier) { return FALSE; } while (($elem = readdir($dossier)) !== FALSE) { if ($elem == '.' || $elem == '..') { continue; } echo '<li>', $elem; } closeDir($dossier); } ?>

Nous devons ensuite définir avec la fonction is_dir() si l'élément lu est un fichier ou un dossier. Si c'est un dossier, la fonction de lecture s'appelle elle-même (récursivité) pour afficher le contenu du dossier.

Le nom passé à is_dir() doit être composé par la concaténation du chemin du dossier en cours avec le nom de l'élément à tester :
$complet = "$nomDossier/$elem";

Exemple : lecture récursive
<?php ob_start(); require('bib_fonctions.php'); htmlDebut('Lecture récursive'); $nomDossier = 'test_repert'; htmlInfo("Contenu du dossier $nomDossier"); listerDossier($nomDossier); htmlFin(); //===================================================== /** * Affiche le contenu d'un dossier * @param string $nomDossier Nom du dossier à lister */ function listerDossier($nomDossier) { $dossier = @opendir($nomDossier); if (! $dossier) { return FALSE; } while (($elem = readdir($dossier)) !== FALSE) { if ($elem == '.' || $elem == '..') { continue; } echo '<br>', $elem; $complet = "$nomDossier/$elem"; if (@is_dir($complet)) { listerDossier($complet); } } closeDir($dossier); } ?>

La récursivité fonctionne bien : nous obtenons la liste de tous les élements contenus dans l'arborescence. Mais cette liste n'est pas lisible car elle ne représente pas les niveaux de profondeur. Nous allons voir une façon de mettre en forme ces résultats.

### Mise en forme

La mise en évidence des différents niveaux de l'arborescence est surtout un travail avec HTML et CSS. La méthode donnée ici n'est pas la seule méthode possible, mais elle est sans doute la plus simple et la plus évolutive.

La mise en place des résultats est effectuée par l'intermédiaire de listes HTML, soit les tags <ul> et <li> : le contenu d'un dossier est une liste d'éléments :

    echo '<ul>';

    while (($elem = readdir($dossier)) !== FALSE) {
    	if ($elem == '.' || $elem == '..') {
    		continue;
    	}
    	echo '<li>', $elem;

    	$complet = "$nomDossier/$elem";
    	if (@is_dir($complet)) {
    		listerDossier($complet);
    	}
    }

    echo '</ul>';

Exemple : lecture récursive - mise en forme
<?php ob_start(); require('bib_fonctions.php'); htmlDebut('Lecture récursive mise en forme'); $nomDossier = 'test_repert'; htmlInfo("Contenu du dossier $nomDossier"); listerDossier($nomDossier); htmlFin(); //===================================================== /** * Affiche le contenu d'un dossier * @param string $nomDossier Nom du dossier à lister */ function listerDossier($nomDossier) { $dossier = @opendir($nomDossier); if (! $dossier) { return FALSE; } echo '<ul>'; while (($elem = readdir($dossier)) !== FALSE) { if ($elem == '.' || $elem == '..') { continue; } echo '<li>', $elem; $complet = "$nomDossier/$elem"; if (@is_dir($complet)) { listerDossier($complet); } } echo '</ul>'; closeDir($dossier); } ?>

Il faut maintenant utiliser des propriétés CSS pour mettre en forme les listes comme nous le voulons (et pas comme le navigateur le fait).

On pourra utiliser le code CSS suivant (dossier.css) :

    ul,
    li {
    	margin: 0;
    	padding: 0;
    	}

    li {
    	background: url('document.png') no-repeat;
    	padding-left: 20px;
    	list-style: none;
    	}

    .dossier {
    	background-image: url('dossier.png');
    	}

Exemple : lecture récursive - mise en forme
<?php ob_start(); require('bib_fonctions.php'); htmlDebut('Lecture récursive mise en forme', 'dossier.css'); $nomDossier = 'test_repert'; htmlInfo("Contenu du dossier $nomDossier"); listerDossier($nomDossier); htmlFin(); //===================================================== /** * Affiche le contenu d'un dossier * @param string $nomDossier Nom du dossier à lister */ function listerDossier($nomDossier) { $dossier = @opendir($nomDossier); if (! $dossier) { return FALSE; } echo '<ul>'; while (($elem = readdir($dossier)) !== FALSE) { if ($elem == '.' || $elem == '..') { continue; } $complet = "$nomDossier/$elem"; if (@is_dir($complet)) { echo '<li class="dossier">', $elem; listerDossier($complet); } else { echo '<li>', $elem; } } echo '</ul>'; closeDir($dossier); } ?>

### Tri du contenu

Comme vous l'avez remarqué, le contenu des dossiers n'apparaît pas dans l'ordre habituel de présentation des arborescence, à savoir les dossiers placés avant les fichiers. Pour réaliser un affichage de cette sorte, il faut d'abord passer en revue tous les éléments d'un niveau avant d'en faire l'affichage. On réalisera également un tri naturel sur les éléments contenus car sinon ils risquent d'être présentés dans n'importe quel ordre.

Nous avons vu que la fonction natsort() réalise le tri de tableau par ordre naturel. Nous allons donc stocker les éléments d'un dossier dans 2 tableaux : un pour les sous-dossiers, un pour les fichiers. Une fois ces dossiers remplis ils seront triés puis affichés (en commençant par le tableau des sous-dossiers).

Exemple : tri d'un dossier
<?php ob_start(); require('bib_fonctions.php'); htmlDebut('Tri d\'un dossier', 'dossier.css'); $nomDossier = 'test_repert'; htmlInfo("Contenu du dossier $nomDossier"); listerDossier($nomDossier); htmlFin(); //===================================================== /** * Affiche le contenu d'un dossier * @param string $nomDossier Nom du dossier à lister */ function listerDossier($nomDossier) { $dossier = @opendir($nomDossier); if (! $dossier) { return FALSE; } $sousDos = $fichiers = array(); echo '<ul>'; // Lecture du contenu du dossier while (($elem = readdir($dossier)) !== FALSE) { if ($elem == '.' || $elem == '..') { continue; } if (@is_dir("$nomDossier/$elem")) { $sousDos[] = $elem; } else { $fichiers[] = $elem; } } // Tri du tableau sous-dossiers, // affichage et récursivité natsort($sousDos); foreach ($sousDos as $elem) { echo '<li class="dossier">', $elem; listerDossier("$nomDossier/$elem"); } // Tri du tableau fichiers et affichage natsort($fichiers); foreach ($fichiers as $elem) { echo '<li>', $elem; } echo '</ul>'; closeDir($dossier); } ?>