PHP Directory Listing Script

kbjradmin

New Member
Messages
512
Reaction score
2
Points
0
i have this script that lists the files in a current directory as well as a directory structure of all the directories under a certain level. the first level of directories works fine, but below that it has problems. the page this is on is at http://cs.clark.edu/~jbrum4030/ctec122/directory.php (try clicking on "labs" to see what i'm talking about) and the php code is below. please help.

PHP:
<?php


// lists all the files is a given directory
function listing()
{
    $relPath = $_REQUEST['path'] ;
    $path = "/home/students/jbrum4030/public_html/ctec122".$relPath;
        
    //using the opendir function
    $dir_handle = @opendir($path) or die("Cannot Open Directory $path");
    
    echo "<p>Directory Listing For:<br />~/public_html/ctec122${relPath}<br /><br />File<span>Size (bytes)</span></p>";
    
    //running the while loop
    while ( $file = readdir($dir_handle) ) 
    {
        if ( $file != '.' && $file != '..' && $file[0] == '.' )
        {
            continue;
        }
        elseif ( $file == '.' )
        {
            echo "<p><a href='?path=${relPath}'>$file</a><span>".filesize($file)."</span></p>\n";
            continue;
        }
        elseif ( $file == '..' )
        {
            $relPath = upLevel($relPath);
            echo "<p><a href='?path=${relPath}'>$file</a><span>".filesize($file)."</span></p>\n";
            continue;
        }
        if ( ! is_dir($file) )
        {
            echo "<p><a href='$file'>$file</a><span>".filesize($file)."</span></p>\n";
        }
        else
        {
            echo "<p><a href='?path=${relPath}/${file}'>$file</a><span>".filesize($file)."</span></p>\n";
        }
    }
    
    echo "<br />";
    
    //closing the directory
    closedir($dir_handle);
}


// moves the current directory up one level (used by listing function)
function upLevel( $path )
{
    $excess = strrchr($path,"/");
    $excessLen = strlen($excess);
    $pathLen = strlen($path);
    $newPath = substr($path,0,($pathLen - $excessLen));
    return $newPath;
}


// checks all directories in the current directory for sub-directories (used by directory listing and itself)
function recurse( $path, $relPath, $level )
{
    // open the directory
    $dir_handle = @opendir($path.$relPath) or die("Could not open $path");
    
    // go through each file checking if they are directories
    while ( $file = readdir($dir_handle) )
    {
        if ( is_dir($file) && $file != '.' && $file != '..' )
        {
            $dirs[] = $file;
        }
    }
    
    // check that directory is not empty
    if ( count($dirs) == 0 )
    {
        return;
    }
    
    echo "<div class=\"level${level}\">\n";
    
    // go through each directory, repeating the search process for each
    foreach ( $dirs as $index => $file )
    {
        $tempRelPath = $relPath.'/'.$file;
        echo "<a href=\"?path=${tempRelPath}\">${file}</a><br />\n";
        recurse($path, $tempRelPath, ($level + 1));
    }
    
    echo "</div>\n";
    
    // closing the directory
    closedir($dir_handle);
}


// lists all directories recursively in the current directory
function directoryListing()
{
    echo "<p>Directory Structure</p>\n";

    // default the array dirs
    $dirs = array();
    
    // level var used to know how many recursion levels has been traversed
    $level = 1;
    
    // the root path to be listed from
    $path = '/home/students/jbrum4030/public_html/ctec122';
    
    echo "<a href=\"?path=\">ctec122</a>\n";
    
    recurse($path, '', $level);
    
    echo "<br />\n";
}
?>
 
Last edited:

garrettroyce

Community Support
Community Support
Messages
5,609
Reaction score
250
Points
63
the problem is the usage of is_dir()

readdir returns the name of a file without the path and is_dir uses the current working directory, not the same path as readdir.

So, when you want to check the file /home/user/public_html/test/dir/ you are really checking /home/user/public_html/dir

Also, when you use paths, use the path relative of the site's home directory, ie /home/username/public_html should be /

Also also, use !== and === not != and == for this. If you have a directory named 0, $file == false evaluates to true and $file === false evaluates to false!
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Note that the error message says (e.g.) "stat failed for lab1" when getting the size of ctec122/labs/lab1. The current directory is ctec122, so filesize("lab1") is looking for lab1 in ctec122. Try filesize($path . '/' . $file).

You've also got a sizable security hole in listing() by not sanitizing $_REQUEST['path'] (try http://cs.clark.edu/~jbrum4030/ctec122/directory.php?path=/../). Use realpath to get the canonical path and test that $path begins with the (safe) base path.

No need for upLevel when you've got dirname

The doc is nicely structured (not too many elements) except for the <br>s in the file listing. An unordered list is more appropriate. Furthermore, you can replace the nested <div>s in the directory listing with <ul>s, allowing you to drop the .level[1-4] classes and easily add icons (if you want) using list-style-image. Once you do that, refactor directoryListing() and recurse() so the link for each directory is printed from only 1 spot.

Edit: You know what? The file information is tabular data. A table might be the best way of structuring the file information, semantically speaking.
 
Last edited:
Top