phpreaddiropendir

Folders Tree in php


I want to list the contents of a folder in php.

But i would like to display only the folder and not the files.

In addition, i would like to display a maximum of one sub-folder!

Could you help me please !

My code :

<?php
function mkmap($dir){
    echo "<ul>";   
    $folder = opendir ($dir);

    while ($file = readdir ($folder)) {   
        if ($file != "." && $file != "..") {           
            $pathfile = $dir.'/'.$file;           
            echo "<li><a href=$pathfile>$file</a></li>";           
            if(filetype($pathfile) == 'dir'){               
                mkmap($pathfile);               
            }           
        }       
    }
    closedir ($folder);    
    echo "</ul>";   
}
?>

<?php mkmap('.'); ?>

Solution

  • Pass the maximum recursion level to the function. This way you can decide how many levels deep you want to go, at runtime.

    Also, it would be a good idea (I think) to have the "I want the dirs or maybe not" decision done externally and passed as a parameter. This way one function can do both.

    And finally it's rarely a good idea having a function output HTML. It's best to return it as a string, so that you're more free to move code around. Ideally, you want to have all your logic separated from your presentation View (and more than that; google 'MVC').

    Even better would be to pass a HTML template to the mkmap function and have it use that to create the HTML snippet. This way, if in one place you want a <ul> and in another a <ul id="another-tree" class="fancy">, you needn't use two versions of the same function; but that's probably overkill (you might do it easily with str_replace, or XML functions, though, if you ever need it).

    function mkmap($dir, $depth = 1, $only_dirs = True){
        $response = '<ul>';
        $folder = opendir ($dir);
    
        while ($file = readdir ($folder)) {
            if ($file != '.' && $file != '..') {           
                $pathfile = $dir.'/'.$file;
                if ($only_dirs && !is_dir($pathfile))
                    continue;
                $response .= "<li><a href=\"$pathfile\">$file</a></li>";
                if (is_dir($pathfile) && ($depth !== 0))
                    $response .= mkmap($file, $depth - 1, $only_dirs);
            }
        }
        closedir ($folder);
        $response .= '</ul>';
        return $response;
    }
    
    
    // Reach depth 5
    echo mkmap('Main Dir', 5, True);
    
    // The explicit check for depth to be different from zero means
    // that if you start with a depth of -1, it will behave as "infinite depth",
    // which might be desirable in some use cases.
    

    Templating

    There's many way of templating the function, but maybe the simplest is this (for more elaborate customization, XML is mandatory - managing HTML with string functions has nasty space-time continuum implications):

    function mkmap($dir, $depth = 1, $only_dirs = True,
        $template = False) {
        if (False === $template) {
            $template = array('<ul>','<li><a href="{path}">{file}</a></li>','</ul>');
        }
        $response = '';
        $folder = opendir ($dir);
    
        while ($file = readdir ($folder)) {
            if ($file != '.' && $file != '..') {           
                $pathfile = $dir.'/'.$file;
                if ($only_dirs && !is_dir($pathfile))
                    continue;
                $response .= str_replace(array('{path}','{file}'), array($pathfile, $file), $template[1]);
                if (is_dir($pathfile) && ($depth !== 0))
                    $response .= mkmap($file, $depth - 1, $only_dirs, $template);
            }
        }
        closedir ($folder);
        return $template[0] . $response . $template[2];
    }
    

    The function works like before, but you can pass a further argument to customize it:

    echo mkmap('Main Dir', 5, True, array(
        '<ul class="filetree">',
        '<li><a href="{path}"><img src="file.png" /><tt>{file}</tt></a></li>',
        '</ul>'));