HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

Workaround for directory-browsing

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
browsingdirectoryworkaroundfor

Problem

I'm in the process of cross-training myself from CFML to PHP as part of a learning exercise. I'm learning from the docs and online tutorials and googling.

As an initial exercise, I've knocked together the following PHP facsimile of some CFML code I have. I have a blog article explaining the requirement for the code. This is basically a work-around for the fact that the inbuilt PHP web server does not do directory browsing.

I'm just posting the PHP here in case anyone can make observations about how I might improve it. I'm more after PHP-specific info than coding structure "advice", but any observations one might make will be taken on board.

[Parent Directory]";

        echo "";
        opendir($dirCurrent);
        while ($entry = readdir()) {
            if (in_array($entry, [".", ".."])){    // skip these two
                continue;
            }
            $linkText = $entry;
            $wholePathToFile = $dirCurrent . DIRECTORY_SEPARATOR . $entry;
            if (is_dir($wholePathToFile)){
                // we just want to link back to this file, passing the dir
                $linkUrl = $_SERVER["SCRIPT_NAME"] . "?dir=" . $wholePathToFile;
                $linkText .= "/"; // just to make it more clear it's a dir
            }else{
                // we want a link to the actual file
                $linkUrl = $urlPath . "/" . $entry;
            }
            echo "$linkText";
        }
        closedir();
        echo "";
    }else{
        header("HTTP/1.0 404 Not Found");
    }    
?>

Solution

Took this from your blog post:


What I need to do is this:



  • take a directory on the URL, which by default will be the current directory;



  • list the files / directories;



  • for each entry, convert the filesystem path to a URL, using the current HTTP host and port;



  • also provide a "parent directory" link too, for browsing upstream.




Knowing these requirements, your code is way too complicated. That's quite normal for a beginner with PHP, so it's no problem. PHP offers built-in solutions that from time to time make experienced PHP programmers think: "Why didn't I find that before?" -- So what you missed, is glob(), and maybe some other neat functions.

// Directory to create listing for, defaulting to the current one
$dirCurrent = '';
if (!empty($_GET['dir'])) {
    // Remove leading and trailing slashes
    $dirCurrent = trim($_GET['dir'], '/.');
}
if (!empty($dirCurrent)) {
    $dirCurrent .= '/';
}
$dirBase = realpath($_SERVER["DOCUMENT_ROOT"]);

// Since we make $dirCurrent relative, a basedir check is not needed
if (is_dir($dirBase . '/' . $dirCurrent)) {
    // Provide a link to go up a level
    if (!empty($dirCurrent)) {
        $parentDir = dirname($dirCurrent);
        $parentLinkUrl = $_SERVER["SCRIPT_NAME"] . "?dir=" . $parentDir;
        echo "[Parent Directory]";
    }
    echo "";
    foreach (glob("$dirBase/$dirCurrent*") as $entry) {
        // Hidden files (those starting with a dot) are not returned by glob
        $linkText = basename($entry);
        if (is_dir($entry)) {
            // We just want to link back to this file, passing the dir
            $linkUrl = $_SERVER["SCRIPT_NAME"] . "?dir=" . urlencode($dirCurrent . basename($entry));
            $linkText .= "/"; // Just to make it more clear it's a dir
        } else {
            // we want a link to the actual file
            $linkUrl = $dirCurrent . basename($entry);
        }
        echo "$linkText";
    }
    echo "";
} else {
    header("HTTP/1.0 404 Not Found");
}

Code Snippets

// Directory to create listing for, defaulting to the current one
$dirCurrent = '';
if (!empty($_GET['dir'])) {
    // Remove leading and trailing slashes
    $dirCurrent = trim($_GET['dir'], '/.');
}
if (!empty($dirCurrent)) {
    $dirCurrent .= '/';
}
$dirBase = realpath($_SERVER["DOCUMENT_ROOT"]);

// Since we make $dirCurrent relative, a basedir check is not needed
if (is_dir($dirBase . '/' . $dirCurrent)) {
    // Provide a link to go up a level
    if (!empty($dirCurrent)) {
        $parentDir = dirname($dirCurrent);
        $parentLinkUrl = $_SERVER["SCRIPT_NAME"] . "?dir=" . $parentDir;
        echo "<a href=\"$parentLinkUrl\">[Parent Directory]</a><br>";
    }
    echo "<ul>";
    foreach (glob("$dirBase/$dirCurrent*") as $entry) {
        // Hidden files (those starting with a dot) are not returned by glob
        $linkText = basename($entry);
        if (is_dir($entry)) {
            // We just want to link back to this file, passing the dir
            $linkUrl = $_SERVER["SCRIPT_NAME"] . "?dir=" . urlencode($dirCurrent . basename($entry));
            $linkText .= "/"; // Just to make it more clear it's a dir
        } else {
            // we want a link to the actual file
            $linkUrl = $dirCurrent . basename($entry);
        }
        echo "<li><a href=\"$linkUrl\">$linkText</a></li>";
    }
    echo "</ul>";
} else {
    header("HTTP/1.0 404 Not Found");
}

Context

StackExchange Code Review Q#25800, answer score: 3

Revisions (0)

No revisions yet.