PHP help with dir and file listing

Soldato
Joined
20 Oct 2002
Posts
19,036
Location
London
Following on my from my other thread, with my limited PHP skills I've managed to make this little script to list the files in a directory (called $username), when the user enters that name in a little form. Nice and simple, as follows:

PHP:
	$dir_handle = @opendir($username) or die("The username '$username' does not exist. Please try again.");
	echo "Hello $username, the following files are available for you to download.<br/>Please right-click and 'Save as..'<br/>";
	
	// running the while loop to list files
	while ($file = readdir($dir_handle)) 
	{
	if($file!="." && $file!="..")
	echo "<a href='$username/$file'>$file</a><br/>";
	}
	
	// closing the directory
	closedir($dir_handle);
	}
What I'd really like to do is to print the file size next to the name? I've been reading about []bfilesize($file)[/b] but I'm just not getting it. Can anyone help? :)
 
Does the following not work?

PHP:
	$dir_handle = @opendir($username) or die("The username '$username' does not exist. Please try again.");
	echo "Hello $username, the following files are available for you to download.<br/>Please right-click and 'Save as..'<br/>";
	
	// running the while loop to list files
	while ($file = readdir($dir_handle)) {
	    if($file!="." && $file!="..") {
	        echo "<a href='$username/$file'>$file</a>";
                echo " - " . number_format(filesize($file))/1024, 0);
                echo "kb<br />";
            }
	}
	
	// closing the directory
	closedir($dir_handle);
	}
 
Last edited:
Hmn afraid not. I get this error:

Warning: filesize() [function.filesize]: stat failed for sunrise over mountain4.jpg in /var/www/vhosts...
 
Ah, genius. Thanks very much.

I can't look at this now (as I'm at work..) but I'm getting random 4kb 'files' listed for some reason. I have two test directories and they show the following output. You can see the correct files (jpegs plus one zip), but they both have these 4kb files too :confused:

Please right-click and 'Save as..'
sunrise over mountain4.jpg - 31kb
sunrise over mountain2.jpg - 36kb
- 4kb
- 4kb
sunrise over mountain3.jpg - 40kb
grabs.zip - 4,751kb
sunrise over mountain1.jpg - 36kb
and
Please right-click and 'Save as..'
DSC00192.jpg - 69kb
DSC00187.jpg - 89kb
- 4kb
DSC00182.jpg - 64kb
- 4kb
DSC00176.jpg - 95kb
DSC00185.jpg - 88kb
I cant see any hidden files on the server or anything :confused:
 
I'd guess those are the links to parent and current directory.

Check you haven't inadvertantly moved the code for printing filesize outside of the IF block that checks for "." and ".."
 
Last edited:
EDIT: Yup I did, woops. Thanks.

I've now come across the problem that if the username/folder does not exist, then obviously it kills the script. Which means my HTML footers and the bottom of the page don't get printed. I've figured out that much, but I've no idea how to solve it :p Something to do with using a return as opposed to stopping the script with die()...? Argh I wish I knew php! :confused:

PHP:
	// uses the opendir function
	$dir_handle = @opendir('../clientfolders/' . $username) or die("I'm sorry $username, there are no files for you to download at this time. <br/><br/>If you believe there should be files for you, please ensure you are typing your username correctly.");
	echo "Hello $username, the following files are available for you to download.<br/><br/>Please right-click and 'Save as..'<br/>";
	
	// running the while loop to list files
	while ($file = readdir($dir_handle)) 
	{
	if($file!="." && $file!="..")
	{
	echo "<a href='../clientfolders/$username/$file'>$file</a>";
	echo " - " . number_format((filesize("../clientfolders/$username/$file"))/1024, 0);
	echo "kb<br />";
	}
	}
	
	// closing the directory
	closedir($dir_handle);
	}
	?>
 
Last edited:
Here's a slightly neater version:

PHP:
<?php
// base directory including trailing /
$basedir = "../clientfolders/";
// uses the opendir function
if ( !$dir_handle = @opendir($basedir . $username) ) {
    echo "I'm sorry $username, there are no files for you to download at this time.
        <br/><br/>If you believe there should be files for you, please ensure you are typing your username correctly.";
} else {
    echo "Hello $username, the following files are available for you to download.<br/><br/>Please right-click and 'Save as..'<br/>";

    // running the while loop to list files
    while ($file = readdir($dir_handle)) {
        if($file!="." && $file!="..") { 
            echo "<a href='" . $basedir . $username . "/" . $file . "'>$file</a>";
            echo " - " . number_format((filesize($basedir.$username."/".$file))/1024, 0);
            echo "kb<br />";
        }
    }

    // closing the directory
    closedir($dir_handle);
}
?>

Just a quick note: if you aren't already, make sure you sanitize the user's input for their username.

Otherwise they can quite easily put their username as "../../../etc/" or similar!
 
Last edited:
Otherwise they can quite easily put their username as "../../../etc/" or similar!

That's not really a security flaw in this instance, though, since he's only linking to the files client-side; he's not having the server open them or anything. They'll only be able to doctor the URL to point to something that they could just type in manually and which wouldn't do any harm.
 
Sorry to drag up an old thread but I just wanted to say thanks GeForce for the solution. Works a treat. However I've just realised that if the user enters spaces only, it navigates to the ../clientfolders/ folder and then lists the directories that are in there. A rather big flaw as that obviously shows them what they could type in to obtain other file lists. Hmn.

This is my mishmash of cleaning functions, maybe I need to do something to prevent them submitting with just whitespace, rather than just cleaning it out of their input? :confused:

PHP:
	//these functions are used for input cleaning
	function stripLineBreaks($string) {
		return preg_replace('#(%0A|%0D|\\n+|\\r+)#i', '', $string);
	}

	function stripHeaders($string) {
		return preg_replace('#(content-type:|to:|cc:|bcc:)#i', '', $string);
	}
	
	// check if the username is *empty* (if user has JS off)
	$fieldsSet = empty($_POST['username']);

	// check if the user has submitted the form
	if (isset($_POST['username'])) {

	// makes var $username from posted form & does first pass cleaning
	$username = stripLineBreaks($_POST['username']);
	$username = stripHeaders(trim($username));
	
	//removes spaces
	$username = str_replace(' ', '', $username);
	
	// makes only alphanumerical chars allowed
	$username = preg_replace('/[^a-z0-9]/i', '', $username);
	
	// make all lowercase
	$username = strtolower($username);
 
Hmn here's my attempt at fixing that.. does this look ok? Seems to work alright..

PHP:
	// check if the username is *empty* or if they've just entered spaces (if user has JS off)
	$fieldsSet = empty($username);

...

	// uses the opendir function
	if ( !$dir_handle = @opendir($basedir . $username) ) 
	{
	echo "I'm sorry $username, there are no files for you to download at this time.<br/><br/>If you believe there should be files for you, please ensure you are typing your username correctly.";
	} 
	else 	{ 
		// if user has submitted empty form
		if($fieldsSet) {
		echo "Please enter your username. Spaces are not allowed.";
		} 
		else {
	echo "Hello $username, the following files are available for you to download.<br/><br/>Please right-click and 'Save As...'<br/><ul>";
 
Last edited:
Back
Top Bottom