Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
FORUM PHP FAQ PHP COURS PHP SOURCES PHP LIVRES PHP SCRIPTS PHP OUTILS PHP COMPARATIFS PHP TV Zend Framework
 

Explorateur de fichiers en PHP

Dernière mise à jour : 29 mars 2003

Par Hugo ETIEVANT



Présentation

Cet article a pour but de présenter les diverses fonctions sur les dossiers ainsi que la méthode à suivre pour la gestion des fichiers et répertoires d'une arborescence à travers un cas d'école : un explorateur de fichiers en PHP.

[ haut ]

Liste des fichiers d'un répertoire

Notre premier objectif est d'obtenir la liste des fichiers d'un répertoire.

La classe dir

La classe dir contient les propriétés et méthodes permettant de parcourir un dossier pour en lister les fichiers.

PropriétéDescription
handleValeur du pointeur vers le dossier
pathChemin du dossier ouvert (chaîne de caractères)

MéthodeDescription
dir($str)Constructeur de la classe, ouvre le dossier défini par le chemin $str (chaîne de caractères) et retourne une instance de la classe dir.
read()Lecture d'une entrée du dossier ouvert
close()Fermeture du dossier

Exemple :

<?php
$d 
dir(".");
echo 
"Pointeur: ".$d->handle."<br>\n";
echo 
"Chemin: ".$d->path."<br>\n";
while(
$entry = $d->read()) {
    echo 
$entry."<br>\n";
}
$d->close();
?>      
Pointeur: Resource id #1
Chemin: .
.
..
index.php3
show.php3
test.php3
images
common
tester | télécharger | voir le code source

Cet exemple ouvre le dossier courant . en instanciant la classe dir dans l'objet $d dont on affiche le pointeur (Resource id #1) et le chemin (.). Puis, on liste les fichiers avec la méthode read() qui retourne une chaîne de caractères contenant le nom de l'entrée ou bien false s'il n'y a plus d'entrée. A chaque appel à cette fonction, un pointeur interne à l'objet $d se déplace d'un cran dans le dossier afin d'en parcourir itérativement toutes les entrées. Une entrée peut être un fichier ou bien un autre dossier. Ne pas oublier que tout dossier même vide contient deux autres dossiers : le dossier courant . qui renvoie au dossier actuellement ouvert, et le dossier parent .. qui permet de remonter d'un cran dans l'arborescence du système de fichiers.

[ haut ]

Fonctions standards sur les dossiers

On peut se passer de la pseudo-classe dir et n'utiliser que les fonctions standards et même utiliser en plus de la classe dir les fonctions standards qui n'ont pas de méthodes équivalentes dans la classe.

FonctionDescription
getcwd()Retourne le nom (chaîne de caractères) du dossier en cours
chdir($str)Change de dossier courant pour aller en $str, retourne true en cas de succès ou false si échec
opendir($str)Ouvre le dossier défini par le chemin $str et retourne un pointeur vers ce dossier si succès, ou bien false si échec
closedir($d)Ferme le dossier identifié par le pointeur $d
readdir($d)Lit une entrée du dossier défini par le pointeur $d : retourne une chaîne de caractères contenant le nom de cette entrée
rewinddir($d)Remet à zéro le pointeur interne de parcours du dossier identifié par le pointeur $d

Exemple :

<?php
if ($dir opendir(".")) {
  echo 
"Pointeur: ".$dir."<br>\n"
  echo 
"Chemin: ".getcwd()."<br>\n"
  while(
$file readdir($dir)) {
    echo 
"$file<br>\n";
  }
  
closedir($dir);
}
?>
Pointeur: Resource id #1
Chemin: d:\internet\cyberzoide\php4\file
.
..
index.php3
show.php3
test.php3
test2.php3
images
common
tester | télécharger | voir le code source

Ici le résultat est le même qu'avec l'exemple de la classe dir : on ouvre le dossier avec opendir(), on en affiche le pointeur $dir et le chemin avec getcwd(), puis on en liste les entrées avec readdir() qu'on referme enfin avec closedir().

[ haut ]

Liste récursive

Lister les fichiers du seul répertoire courant n'est pas très intéressant, on peut vouloir déployer l'arboscence complète d'un dossier en listant aussi les fichiers de ses sous-répertoires et ainsi de suite. Pour cela nous allons créer une fonction list_dir($name) qui liste toutes les entrées du répertoire dont on passe le nom en argument. Pour chaque entrée du répertoire, on teste si elle est un dossier ou pas avec la fonction is_dir(). Si c'est le cas, on la liste aussi, en prenant garde à exclure les dossiers courant et parent.

Exemple :

<?php
function list_dir($name) {
  if (
$dir opendir($name)) {
    while(
$file readdir($dir)) {
      echo 
"$file<br>\n";
      if(
is_dir($file) && !in_array($file, array(".",".."))) {
        
list_dir($file);
      }
    }
    
closedir($dir);
  }
}
list_dir(".");
?>
.
..
index.php3
show.php3
test.php3
test2.php3
test3.php3
common
.
..
bookmark.lib.php
build_dump.lib.php
common.lib.php
defines.lib.php
images
.
..
equa1.gif
equa2.gif
fizeau.gif
index.htm
schema.gif
schema.jpg
arborescence du répertoire
tester | télécharger | voir le code source

Dans l'exemple vous avez à gauche le code source, au milieu le résultat et à droite l'arborescence complète réelle du dossier. Le script placé dans le dossier file parcours l'arborescence du dossier courant et de ses fils. Il est important de tester le nom du dossier afin de ne pas parcourir le dossier courant . car cela provoquerait une boucle infinie. De plus, on interdit la remontée dans les dossiers parents .. pour préserver la confidentialité des autres dossiers du site web.

On voit que l'affichage actuel est élémentaire et l'arborescence ne saute pas yeux. On va y remédier par l'affichage de retraits à gauche. Et on en profite pour rajouter un argument $level à la fonction list_dir($name, $level). Ce nouvel argument signale la profondeur du dossier en cours dans l'arborescence.

Exemple :

<?php
function list_dir($name$level=0) {
  if (
$dir opendir($name)) {
    while(
$file readdir($dir)) {
      for(
$i=1$i<=(4*$level); $i++) {
          echo 
"&nbsp;";
      }
      echo 
"$file<br>\n";
      if(
is_dir($file) && !in_array($file, array(".",".."))) {
        
list_dir($file,$level+1);
      }
    }
    
closedir($dir);
  }
}
list_dir(".");
?>
.
..
index.php3
show.php3
test.php3
test2.php3
test3.php3
images
    .
    ..
    equa1.gif
    equa2.gif
    fizeau.gif
    index.htm
    schema.gif
    schema.jpg
common
    .
    ..
    bookmark.lib.php
    build_dump.lib.php
    common.lib.php
    defines.lib.php
arbo.gif
test4.php3
tester | télécharger | voir le code source

Dans ce nouvel exemple, on rajoute un retrait à gauche dont la longueur est proportionnel à la profondeur.

[ haut ]

Fonctions standards sur les fichiers

Nous allons maintenant aborder un exemple concrêt d'application de gestion d'une arborescence en programmant en PHP un explorateur de fichiers du même type que l'Explorateur Windows de Microsoft.

Avant de rentrer dans le vif du sujet, voyons quelques fonctions sur les fichiers que l'on pourra utiliser par la suite :

FonctionDescription
copy($source, $dest) Copie le fichier $source vers $dest et retourne true si succès ou false si echec
rename($source, $dest) Renomme le fichier $source en $dest et retourne true si succès ou false si echec
unlink($file) Supprime le fichier $file et retourne true si succès ou false si echec
mkdir($dir, $mode) Créée le dossier $dir avec les droits unix $mode (exprimés en octal) et retourne true si succès ou false si echec
rmdir($dir) Supprime le dossier $dir et retourne true si succès ou false si echec
fileatime($file) Retourne la date à laquelle le fichier $file a été accédé pour la dernière fois ou false si échec
filectime($file) Retourne l'heure à laquelle le fichier $file a été accédé pour la dernière fois ou false si échec
filemtime($file) Retourne la date de dernière modification du fichier $file ou false si échec
fileperms($file) Retourne les permissions associées au fichier $file ou false si échec
filesize($file) Retourne la taille du fichier $file (en octets) ou false si échec
filetype($file) Retourne le type du fichier $file (fifo, char, dir, block, link, file, unknown) ou false si échec
is_dir($file) Retourne true si $file est un répertoire ou false sinon
is_executable($file) Retourne true si $file est exécutable ou false sinon
is_file($file) Retourne true si $file est un fichier ou false sinon
is_link($file) Retourne true si $file est un lien symbolique ou false sinon
is_readable($file) Retourne true si $file est accessible en lecture ou false sinon
is_writable($file) Retourne true si $file est accessible en écriture ou false sinon
touch($file) Change la date de dernière modification du fichier $file en maintenant

[ haut ]

Navigation

Notre explorateur doit comporter la liste des répertoires à gauche et la liste des fichiers de ce répertoire à droite. La variable $BASE défini la racine de l'explorateur, et pour des raisons de sécurité comme de confidentialité, le visiteur ne doit pas pouvoir remonter plus loin.

La fonction list_dir($base, $cur, $level) a été modifiée de manière à ce que tous les dossiers ne soient pas automatiquement déployés. Seule la branche vers celui en cours de listage doit être déployée. L'argument $base est le chemin complet (relatif au script) du dossier dont on doit afficher les sous-dossiers. Les noms des entrées sont exprimés en fonction de la racine $BASE. On contrôle que chaque entrée du dossier soit un dossier autre que . et .. et on affiche une marge à gauche en fonction de la profondeur. L'argument $cur est le dossier courant ouvert par le visiteur. Si une entrée du dossier est égale à $cur alors inutile de placer un lien pour permettre au visiteur de l'ouvrir car il est déjà ouvert, on va plutôt le mettre en évidence en l'écrivant en gras. Pour développer la branche depuis la racine $BASE jusqu'au dossier en cours $cur, on ne rappelera récursivement la fonction que si le nom de l'entrée (+ "/") est compris dans celui du dossier en cours (+ "/").

La fonction list_file($dir) permet de lister toutes les entrées (fichiers et dossiers) du dossier en cours.

Exemple :

<html>
<body>

<?php
$BASE 
"../..";
function 
list_dir($base$cur$level=0) {
  global 
$PHP_SELF$BASE;
  if (
$dir opendir($base)) {
    while(
$entry readdir($dir)) {
      
/* chemin relatif à la racine */
      
$file $base."/".$entry;
      if(
is_dir($file) && !in_array($entry, array(".",".."))) {
        
/* marge gauche */
        
for($i=1$i<=(4*$level); $i++) {
            echo 
"&nbsp;";
        }
        
/* l'entrée est-elle le dossier courant */
        
if($file == $cur) {
          echo 
"<b>$entry</b><br />\n";
        } else {
          echo 
"<a href=\"$PHP_SELF?dir=".rawurlencode($file)."\">$entry</a><br />\n";
        }
        
/* l'entrée est-elle dans la branche dont le dossier courant est la feuille */
        
if(ereg($file."/",$cur."/")) {
            
list_dir($file$cur$level+1);
        }
      }
    }
    
closedir($dir);
  }
}
function 
list_file($cur) {
  if (
$dir opendir($cur)) {
    while(
$file readdir($dir)) {
      echo 
"$file<br />\n";
    }
    
closedir($dir);
  }
}
?>

<table border="1" cellspacing="0" cellpadding="10" bordercolor="gray">
<tr valign="top"><td>

<!-- liste des répertoires
et des sous-répertoires -->
<?php 
/* lien sur la racine */
if(!$dir) {
  echo 
"/<br />";
} else {
  echo 
"<a href=\"$PHP_SELF\">/</a><br />";
}
list_dir($BASErawurldecode($dir), 1); 
?>

</td><td>

<!-- liste des fichiers -->
<?php
/* répertoire initial à lister */
if(!$dir) {
  
$dir $BASE;

list_file(rawurldecode($dir)); 
?>

</td></tr>
</table>

</body>
</html>
/
    images
    surfu
    pourquoi
    opinions
    info
    html
    fizeau
    triptique
    unix
    phpMyAdmin
    php4
    phpMyAdmin-2.2.5
        CVS
        images
            CVS
        lang
        libraries
        scripts
    avatars
    latex
.
..
CVS
arrow_ltr.gif
arrow_rtl.gif
asc_order.gif
bkg.gif
browse.gif
desc_order.gif
fulltext.png
item_ltr.gif
item_rtl.gif
minus.gif
partialtext.png
plus.gif
spacer.gif
tester | télécharger | voir le code source

[ haut ]

Graphismes

On a donc la trame de l'explorateur. La prochaine étape est purement graphique, il s'agit d'habiller l'application pour qu'elle ressemble d'avantage au vrai Explorateur Windows. Pour cela on va reprendre les icônes Windows suivantes : , et .

Exemple :


/* listage des dossiers */
if($file==$cur){
  echo
"<img src=\"dir-open.gif\"/>&nbsp;$entry<br/>\n";
}else{
  echo
"<img src=\"dir-close.gif\"/>&nbsp; <a href=\"$PHP_SELF?dir=".rawurlencode($file)."\">$entry</a><br/>\n";
}


/* listage des entrées du dossier courant */
if(
is_dir($cur."/".$file)){
  echo
"<img src=\"dir-close.gif\"/>&nbsp;$file<br/>\n";
}else{
  echo
"<img src=\"file-none.gif\"/>&nbsp;$file<br/>\n";
}


/* lien sur la racine */
if(!$dir){
  echo
"<img src=\"dir-open.gif\" />&nbsp;/<br />";
}else{
  echo
"<img src=\"dir-close.gif\"/>&nbsp;<a href=\"$PHP_SELF\">/</a><br/>";
}
 /
     images
     surfu
     proquo
     pourquoi
     opinions
     info
     html
     fizeau
     triptique
     unix
         images
         scripts
     phpMyAdmin
     php4
     phpMyAdmin-2.2.5
     avatars
     latex
 .
 ..
 mtools.php3
 unix.cpt
 scripts.php3
 texte.php3
 images
 compress.php3
 unix.css
 index.php3
 files.php3
 smtp.php3
 droits.php3
 sys.php3
 ftp.php3
 shell.php3
 menu.php3
 scripts
tester | télécharger | voir le code source

[ haut ]

Tri des fichiers

Jusqu'à maintenant l'ordre des entrées dans les dossiers était assez obscure, ni sur le nom, ni sur le type... Quel critère d'ordre le serveur ou PHP utilise-t-il ? Il semblerait que se soit la date de création. Il serait très intéressant de pouvoir trier les fichiers sur le nom, la date, la taille, etc.

Tri sur le nom

Comme la fonction readdir() ne permet pas d'imposer un critère de tri, il faut d'abord extraire tous les noms de fichier et les stocker temporairement dans un tableau et trier ce tableau avant d'afficher les listes de dossiers et de fichiers.

Dans la fonction list_dir(), on créer un simple tableau qui contient les entrées $entry lues par readdir(). Ainsi le while() se contente de remplir le tableau $tab des entrées qui sont des répertoires autres que . et ... Puis, on tri le tableau avec sort(). Et enfin, on reprend les traitements que l'on faisait dans le while() pour les appliquer à chacune des entrées du tableau.

Dans la fonction list_file(), on créer deux tableaux : un pour les dossiers et un autre pour les fichiers. Ainsi le while() se contente de remplir le tableau $tab_dir des entrées qui sont des répertoires, et le tableau $tab_file des entrées qui n'en sont pas. Puis, on tri les tableaux Et enfin, on affiche le contenu des deux tableaux, l'un après l'autres car on doit afficher les dossiers avant les fichiers.

Exemple :


<?php
/* racine */
$BASE "../..";
/* liste des dossiers */
function list_dir($base$cur$level=0) {
  global 
$PHP_SELF$BASE;
  if (
$dir opendir($base)) {
    
$tab = array();
    while(
$entry readdir($dir)) {
      if(
is_dir($base."/".$entry) && !in_array($entry, array(".",".."))) {
        
$tab[] = $entry;
      }
    }
    
sort($tab);
    foreach(
$tab as $entry) {
      
/* chemin relatif à la racine */
      
$file $base."/".$entry;
     
/* marge gauche */
      
for($i=1$i<=(4*$level); $i++) {
        echo 
"&nbsp;";
      }
      
/* l'entrée est-elle le dossier courant */
      
if($file == $cur) {
        echo 
"<img src=\"dir-open.gif\" />&nbsp;$entry<br />\n";
      } else {
        echo 
"<img src=\"dir-close.gif\" />&nbsp; <a href=\"$PHP_SELF?dir=".rawurlencode($file)."\">$entry</a><br />\n";
      }
      
/* l'entrée est-elle dans la branche dont le dossier courant est la feuille */
      
if(ereg($file."/",$cur."/")) {
        
list_dir($file$cur$level+1);
      }
    }
    
closedir($dir);
  }
}
/* liste des fichiers */
function list_file($cur) {
  if (
$dir opendir($cur)) {
    
/* tableaux */
    
$tab_dir = array();
    
$tab_file = array();
    
/* extraction */
    
while($file readdir($dir)) {
      if(
is_dir($cur."/".$file)) {
          
$tab_dir[] = $file;
      } else {
          
$tab_file[] = $file;
      }
    }
    
/* tri */
    
sort($tab_dir);
    
sort($tab_file);
    
/* affichage */
    
foreach($tab_dir as $elem) {
      echo 
"<img src=\"dir-close.gif\" />&nbsp;".$elem."<br />\n";
    }
    foreach(
$tab_file as $elem) {
      echo 
"<img src=\"file-none.gif\" />&nbsp;".$elem."<br />\n";
    }
    
closedir($dir);
  }
}
?>
 /
     avatars
     fizeau
     html
     images
     info
     latex
     opinions
     php4
     phpMyAdmin
     phpMyAdmin-2.2.5
     pourquoi
     surfu
     triptique
     unix
         images
         scripts
 .
 ..
 images
 scripts
 compress.php3
 droits.php3
 files.php3
 ftp.php3
 index.php3
 menu.php3
 mtools.php3
 scripts.php3
 shell.php3
 smtp.php3
 sys.php3
 texte.php3
 unix.cpt
 unix.css
tester | télécharger | voir le code source

[ haut ]

Autres tris

Tout comme le permet le véritable Explorateur Windows, nous allons permettre au visiteur de trier les listes de fichiers selon différents critères :

  • le nom
  • la date et heure de dernière modification extraite par filemtime()
  • la taille extraite par filesize()
  • le type (au sens Unix : fifo, char, dir, block, link, file, unknown) extrait par filetype()
  • l'extention (synonyme du type au sens Windows) extraite par un traitement du nom
  • la date de dernier accès extraite par fileatime()
  • les droits d'accès extraits par fileperms()
et selon les ordres :
  • croissant
  • décroissant

Ainsi le tableau associatif contenant toutes les infos sur une entrée d'un dossier est généré par la fonction décrite ci-dessous. Cette fonction addScheme() est utilisé tant par list_dir() pour le listage des dossiers que par list_file() pour le listage des fichiers.

/* infos à extraire */
function addScheme($entry,$base,$type) {
  
$tab['name'] = $entry;
  
$tab['type'] = filetype($base."/".$entry);
  
$tab['date'] = filemtime($base."/".$entry);
  
$tab['size'] = filesize($base."/".$entry);
  
$tab['perms'] = fileperms($base."/".$entry);
  
$tab['access'] = fileatime($base."/".$entry);
  
$t explode("."$entry);
  
$tab['ext'] = $t[count($t)-1];
  return 
$tab;
}

Dans list_dir() seule l'information sur le nom de l'entrée sera exploitée, et seul un tri sur le nom sera effectué car la liste de gauche sur les dossiers de la racine doit être triée alphabétiquement en toute circonstance.

/* liste des dossiers */
function list_dir($base$cur$level=0) {
  global 
$PHP_SELF$BASE$order$asc;
  if (
$dir opendir($base)) {
    
$tab = array();
    while(
$entry readdir($dir)) {
      if(
is_dir($base."/".$entry) && !in_array($entry, array(".",".."))) {
        
$tab[] = addScheme($entry$base'dir');
      }
    }
    
/* tri */
    
usort($tab,"cmp_name");
    foreach(
$tab as $elem) {
      
$entry $elem['name'];
      ...
    }
    
closedir($dir);
  }
}

La fonction de tri usort() fait appel à la fonction de compaison sur le nom cmp_name().

function cmp_name($a,$b) {
    global 
$asc;
    if (
$a['name'] == $b['name']) return 0;
    if(
$asc == 'a') {
        return (
$a['name'] < $b['name']) ? -1;
    } else {
        return (
$a['name'] > $b['name']) ? -1;
    }
}

Toutes les autres fonctions de comparaison, reposent sur le même modèle sauf qu'en cas d'égalité, elle font appel à la fonction de comparaison sur le nom.


function 
cmp_size($a,$b) {
    global 
$asc;
    if (
$a['size'] == $b['size']) return cmp_name($a,$b);
    if(
$asc == 'a') {
        return (
$a['size'] < $b['size']) ? -1;
    } else {
        return (
$a['size'] > $b['size']) ? -1;
    }
}

Dans list_file(), on effectue un affichage détaillé de chaque entrée du dossier courant : nom, taille, date de dernière modification, type, extention, permissions et date de dernier accès. En cliquant sur un titre de colonne, le visiteur pourra forcer le tri sur cette colonne. Et en cliquant de nouveau sur la même colonne, le tri sera inverse (d'où la nécessité de garder en mémoire le précédent critère de tri).

Un titre de colonne a la forme suivante : on teste s'il est critère de tri, si c'est le cas, on test la valeur d'ordre (ascendant ou descendant) pour afficher le symbole /\ ou \/. Un titre de colonne porte un lien hypertexte avec les paramètres suivants : $dir (dossier en cours, que l'on prend soin d'encoder avec rawurlencode()), $order (critère de tri, qui peut être l'un de la liste : 'name', 'size', 'date', 'access', 'type', 'ext', 'perms'), $asc (ordre de tri : 'a' croissant ou 'b' décroissant) et $order0 (qui est la précédente valeur de $order).

<th>".(($order=='name')?(($asc=='a')?'/\\ ':'\\/ '):'')."<a href=\"$PHP_SELF?dir=". rawurlencode($cur) ."&order=name&asc=$asc&order0=$order\">Nom</a></th><td>&nbsp;</td>

On liste d'abord les sous-dossiers du dossier en cours $cur, puis les autres entrées de ce dossier (que l'on considère comme des fichiers, bien qu'il puisse il avoir aussi des liens symboliques, des flux...). On affichera les dates et heures au format francophone grâce à date() (car l'information extraite par les fonctions standards est le timestamp Unix), on formatera la taille avec formatSize() afin que sa lecture soit aisée, on affichera le type de l'entrée que l'on converti en français grâce à assocType(), on affiche aussi l'extention que l'on peut judicieusement remplacé par le nom de l'application associée avec assocExt().

/* liste des fichiers */
function list_file($cur) {
  global 
$PHP_SELF$order$asc$order0;
  if (
$dir opendir($cur)) {
    
/* tableaux */
    
$tab_dir = array();
    
$tab_file = array();
    
/* extraction */
    
while($file readdir($dir)) {
      if(
is_dir($cur."/".$file)) {
        if(!
in_array($file, array(".",".."))) {
          
$tab_dir[] = addScheme($file$cur'dir');
        }
      } else {
          
$tab_file[] = addScheme($file$cur'file');
      }
    }
    
/* tri */
    
usort($tab_dir,"cmp_".$order);
    
usort($tab_file,"cmp_".$order);
    
/* affichage */
    
echo "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">";
    echo 
"<tr style=\"font-size:8pt;font-family:arial;\">
    <th>"
.(($order=='name')?(($asc=='a')?'/\\ ':'\\/ '):'')."<a href=\"$PHP_SELF?dir=".rawurlencode($cur). "&order=name&asc=$asc&order0=$order\">Nom</a></th><td>&nbsp;</td>
    <th>"
.(($order=='size')?(($asc=='a')?'/\\ ':'\\/ '):'')."<a href=\"$PHP_SELF?dir=".rawurlencode($cur). "&order=size&asc=$asc&order0=$order\">Taille</a></th><td>&nbsp;</td>
    <th>"
.(($order=='date')?(($asc=='a')?'/\\ ':'\\/ '):'')."<a href=\"$PHP_SELF?dir=".rawurlencode($cur). "&order=date&asc=$asc&order0=$order\">Dernière modification</a></th><td>&nbsp;</td>
    <th>"
.(($order=='type')?(($asc=='a')?'/\\ ':'\\/ '):'')."<a href=\"$PHP_SELF?dir=".rawurlencode($cur). "&order=type&asc=$asc&order0=$order\">Type</a></th><td>&nbsp;</td>
    <th>"
.(($order=='ext')?(($asc=='a')?'/\\ ':'\\/ '):'')."<a href=\"$PHP_SELF?dir=".rawurlencode($cur). "&order=ext&asc=$asc&order0=$order\">Extention</a></th><td>&nbsp;</td>
    <th>"
.(($order=='perms')?(($asc=='a')?'/\\ ':'\\/ '):'')."<a href=\"$PHP_SELF?dir=".rawurlencode($cur). "&order=perms&asc=$asc&order0=$order\">Permissions</a></th><td>&nbsp;</td>
    <th>"
.(($order=='access')?(($asc=='a')?'/\\ ':'\\/ '):'')."<a href=\"$PHP_SELF?dir=".rawurlencode($cur). "&order=access&asc=$asc&order0=$order\">Dernier accès</a></th></tr>";
    foreach(
$tab_dir as $elem) {
      echo 
"<tr><td><img src=\"dir-close.gif\" />&nbsp;". $elem['name']."</td><td>&nbsp;</td>
      <td>&nbsp;</td><td>&nbsp;</td>
      <td>"
.date("d/m/Y H:i:s"$elem['date'])."</td><td>&nbsp;</td>
      <td>"
.assocType($elem['type'])."</td><td>&nbsp;</td>
      <td>&nbsp;</td><td>&nbsp;</td>
      <td>"
.$elem['perms']."</td><td>&nbsp;</td>
      <td>"
.date("d/m/Y"$elem['access'])."</td></tr>\n";
    }
    foreach(
$tab_file as $elem) {
      echo 
"<tr><td><img src=\"file-none.gif\" />&nbsp;".$elem['name']."</td><td>&nbsp;</td>
      <td align=\"right\">"
.formatSize($elem['size'])."</td><td>&nbsp;</td>
      <td>"
.date("d/m/Y H:i:s"$elem['date'])."</td><td>&nbsp;</td>
      <td>"
.assocType($elem['type'])."</td><td>&nbsp;</td>
      <td>"
.assocExt($elem['ext'])."</td><td>&nbsp;</td>
      <td>"
.$elem['perms']."</td><td>&nbsp;</td>
      <td>"
.date("d/m/Y"$elem['access'])."</td></tr>\n";
    }
    echo 
"</table>";
    
closedir($dir);
  }
}

La fonction formatSize() a pour but de former la taille du fichier de manière la rendre la plus simple et la plus compréhensible possible. Pour cela va afficher l'unité la plus adaptée : l'octet, le kilo octet, le giga octet ou le téra octet. Et on ne va conserver que les deux premières décimales.

/* formatage de la taille */
function formatSize($s) {
  
/* unités */
  
$u = array('octets','Ko','Mo','Go','To');
  
/* compteur de passages dans la boucle */
  
$i 0;
  
/* nombre à afficher */
  
$m 0;
  
/* division par 1024 */
  
while($s >= 1) {
    
$m $s;
    
$s /= 1024;
    
$i++;
  }
  if(!
$i$i=1;
  
$d explode(".",$m);
  
/* s'il y a des décimales */
  
if($d[0] != $m) {
    
$m number_format($m2","" ");
  }
  return 
$m." ".$u[$i-1];
}

La fonction assocType() permet de donner une description francophone du type d'entité via un tableau de correspondance.

/* formatage du type */
function assocType($type) {
  
/* tableau de conversion */
  
$t = array(
    
'fifo' => "file",
    
'char' => "fichier spécial en mode caractère",
    
'dir' => "dossier",
    
'block' => "fichier spécial en mode bloc",
    
'link' => "lien symbolique",
    
'file' => "fichier",
    
'unknown' => "inconnu"
  
);
  return 
$t[$type];
}

La fonction assocExt() permet de donner une description francophone à l'extention d'un fichier, généralement le nom de l'application associée. Actuellement un tableau associatif, il pourra avantageusement être remplacé par un fichier csv ou une table d'une base de données. Une couleur différente pourra même être associée à chaque des extentions afin de mieux distinguer les fichiers entre eux.

/* description de l'extention */
function assocExt($ext) {
  
$e = array(
    
'' => "inconnu",
    
'doc' => "Microsoft Word",
    
'xls' => "Microsoft Excel",
    
'ppt' => "Microsoft Power Point",
    
'pdf' => "Adobe Acrobat",
    
'zip' => "Archive WinZip",
    
'txt' => "Document texte",
    
'gif' => "Image GIF",
    
'jpg' => "Image JPEG",
    
'png' => "Image PNG",
    
'php' => "Script PHP",
    
'php3' => "Script PHP",
    
'htm' => "Page web",
    
'html' => "Page web",
    
'css' => "Feuille de style",
    
'js' => "JavaScript"
  
);
  if(
in_array($extarray_keys($e))) {
    return 
$e[$ext];
  } else {
    return 
$e[''];
  }
}

Exemple :

<html>
<head>
<style type="text/css">
* {font-size: 10pt;}
</style>
</head>
<body>

<?php

/* racine */
$BASE "../..";

/* infos à extraire */
function addScheme($entry,$base,$type) {
  
$tab['name'] = $entry;
  
$tab['type'] = filetype($base."/".$entry);
  
$tab['date'] = filemtime($base."/".$entry);
  
$tab['size'] = filesize($base."/".$entry);
  
$tab['perms'] = fileperms($base."/".$entry);
  
$tab['access'] = fileatime($base."/".$entry);
  
$t explode("."$entry);
  
$tab['ext'] = $t[count($t)-1];
  return 
$tab;
}

/* liste des dossiers */
function list_dir($base$cur$level=0) {
  global 
$PHP_SELF$BASE$order$asc;
  if (
$dir opendir($base)) {
    
$tab = array();
    while(
$entry readdir($dir)) {
      if(
is_dir($base."/".$entry) && !in_array($entry, array(".",".."))) {
        
$tab[] = addScheme($entry$base'dir');
      }
    }
    
/* tri */
    
usort($tab,"cmp_name");
    foreach(
$tab as $elem) {
      
$entry $elem['name'];
      
/* chemin relatif à la racine */
      
$file $base."/".$entry;
     
/* marge gauche */
      
for($i=1$i<=(4*$level); $i++) {
        echo 
"&nbsp;";
      }
      
/* l'entrée est-elle le dossier courant */
      
if($file == $cur) {
        echo 
"<img src=\"dir-open.gif\" />&nbsp;$entry<br />\n";
      } else {
        echo 
"<img src=\"dir-close.gif\" />&nbsp;<a href=\"$PHP_SELF?dir=". rawurlencode($file) ."&order=$order&asc=$asc\">$entry</a><br />\n";
      }
      
/* l'entrée est-elle dans la branche dont le dossier courant est la feuille */
      
if(ereg($file."/",$cur."/")) {
        
list_dir($file$cur$level+1);
      }
    }
    
closedir($dir);
  }
}

/* liste des fichiers */
function list_file($cur) {
  global 
$PHP_SELF$order