ASPit - Totally ASP JSit - Totally JavaScript
Search PHPit

Use this textbox to search for articles on PHPit. Seperate keywords with a space.

Advertisements

Creating a file manager with PHP

(Page 2 out of 3)

Streaming Files

Once a file has been uploaded, you might want to be able to download it as well. The easiest way to do this is to simply redirect the user to the location of the file, but what if your upload directory is off limits to the general public? To solve this problem, you need to write a script that reads the file, and then sends it to the user.

PLEASE NOTE: Do NOT have your upload directory in a public place, as this leads to huge security problems. Make sure your upload directory cannot be accessed by visitors.

The first thing our streaming script will do is some standard validation, like so:

$path = 'G:\projects\PHPit\content\creating file system php\demos\upload\\';

// Get file
if (!isset($_GET['file'])) { die('Invalid File'); }
$file = $_GET['file'];

// Create file path
$filepath = $path . $file;

// Now check if there isn't any funny business going on
if ($filepath != realpath($filepath)) {
        die('Security error! Please go back and try again.');
}

This code basically makes sure that the passed filename is in the upload directory, and not somewhere else, which is extremely important.

The next step is to try and determine what kind of file it is. We do this by looking at the extension, and then guessing the type. Although this is far from foolproof, it doesn't really matter, as the file will still be downloaded anyway. This does what we want:

// Get file extension
$ext = explode('.', $file);
$extension = $ext[count($ext)-1];

// Try and find appropriate type
switch(strtolower($extension)) {
        case 'txt': $type = 'text/plain'; break;
        case "pdf": $type = 'application/pdf'; break;
        case "exe": $type = 'application/octet-stream'; break;
        case "zip": $type = 'application/zip'; break;
        case "doc": $type = 'application/msword'; break;
        case "xls": $type = 'application/vnd.ms-excel'; break;
        case "ppt": $type = 'application/vnd.ms-powerpoint'; break;
        case "gif": $type = 'image/gif'; break;
        case "png": $type = 'image/png'; break;
        case "jpg": $type = 'image/jpg'; break;
        case "jpeg": $type = 'image/jpg'; break;
        case "html": $type = 'text/html'; break;
        default: $type = 'application/force-download';
}

Now that everything's been checked, the script can start sending the appropriate headers to the browser to let it know that it's about to send a file. The first thing the script has to send is a few generic caching headers:

// General download headers:
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Transfer-Encoding: binary");

These are all very general, and are used to make sure the browser doesn't do anything wrong (like cache the file, or try and display the file instead of downloading it). The next step is to send the file type:

// Filetype header
header("Content-Type: " . $type);

After that the script sends a header with the total length of the file. This is not a necessary header, but it's certainly recommended. If you don't include this header, the browser won't know how big the file is, and won't display a progress bar.

// Filesize header
header("Content-Length: " . filesize($filepath));

Finally, you must also send a header with the name of the file, like so:

// Filename header
header("Content-Disposition: attachment; filename=\"" . $file . "\";" );

Now that all the headers have been sent, all that's left is to send the actual file, by reading the file, and printing the data:

// Send file data
readfile($filepath);

And that's the whole file streaming script in a nutshell.

Editing Files

Our file manager should also let certain files be edited online, using a simple text editor. Obviously only certain types of files can be edited, like text files, HTML files, PHP files, etc, so the first thing our editing script must do is check whether the file can be edited.

To check what type the file is, we use the same technique as in the streaming script. The script will look at the extension, and then determine whether the file is editable or not. It's possible that the file will have a wrong extension (i.e. a text file with an .exe extension), but there's nothing we can do about that.

The following code will determine if the file is editable:

$path = 'G:\projects\PHPit\content\creating file system php\demos\upload\\';

// Get file
if (!isset($_GET['file'])) { die('Invalid File'); }
$file = $_GET['file'];

// Create file path
$filepath = $path . $file;

// Now check if there isn't any funny business going on
if ($filepath != realpath($filepath)) {
        die('Security error! Please go back and try again.');
}

// Get file extension
$ext = explode('.', $file);
$extension = $ext[count($ext)-1];

// Is this file editable or not?
// Check if extension matches an invalid one
$invalid = array('exe', 'doc', 'jpg', 'gif');
if (in_array(strtolower($file['extension']), $invalid)) {
        die('Can\'t edit this file. Not suitable for editing. Please go back.');
}

As you can see the script uses a 'bad extensions' array that contains a list of all extensions that can't be edited and any other extension that doesn't match this list can be edited.

The next step of the script is to determine whether an editing form should be shown, or if the form has already been submitted, like this:

// Form submitted?
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
        // ... update file ...
} else {
        // ... show the edit form ...
}

The edit form is a fairly simple task, and all that needs to be done is reading the file, and displaying the form:

// Get file data
$f = fopen($filepath, 'r');
$data = fread($f, filesize($filepath));
fclose($f);

?>

Edit File: echo htmlentities($file); ?>

"POST">
       
       
        "submit" name="submit" value="Save File" />

Updating the file is also quite an easy task. First the script should check if any new data has been submitted, and after that it should open the file, and write the new data. This does exactly what we want:

// Check if new data has been set
if (!isset($_POST['newfile'])) {
        die('Please enter some new data for this file.');
}

// Write new data
$f = fopen($filepath, 'w');
fwrite($f, $_POST['newfile']);
fclose($f);

And that finishes the editing script. Let's have a look at the final feature: a deleting script.

« Previous: Uploading files
Next: Deleting & Wrap-up »



10 Responses to “Creating a file manager with PHP”

  1. Evert Says:

    This is a really bad tutorial in a few ways:

    * All files are uploaded in a directory accessible by the webserver, I can enter /upload on the live example and run my own php scripts.
    * Magic quotes is probably enabled. So in the files ‘ will be converted to \’ . This is not really usefull for most files

  2. Bocse L Filip Says:

    Now think about a file manager web 2.0. Using set of class like prototype.js … now that would be something wouldn’t it?.

  3. Dennis Pallett Says:

    Evert: you are absolutely right, and I’ve fixed the problem, though this problem only exists in the demo. Normally, you would place the upload directory above the web root anyway.

    As for the magic quotes problem; it’s a very easy fix.

    Bocse: That would be pretty neat, and something to consider writing. Imagine what you could create with prototype.js, ajax, and more.

  4. Piku’s PHP Blog » PHPit articles Says:

    […] The second article is Creating a file manager with PHP. It treats the basics of uploading files and working with files in PHP (opening, editing, deleting files) […]

  5. Matthijs Says:

    Interesting article Dennis. I don’t agree with Evert, it’s not a bad tutorial. But it’s good you added the lines about security. The difficulty with tutorials like these is that you want to focus on one problem. Here, uploading/managing files. If you would add an explanation of every weak point of every script, each tutorial would be at least 20 pages. But nonetheless, a few warnings, even just a few lines is never bad. Looking forward to your next articles.

  6. PHPit - Totally PHP » Creating a SECURE file manager with PHP Says:

    […] var site=”s20phpit” « Previous Creating a file manager with PHP […]

  7. Piku’s PHP Blog » Creating a SECURE file manager with PHP Says:

    […] In a previous article I have posted a link to a PHPIt article: Creating a file manager with PHP. Now, PHPIt created the second tutorial in this series: Creating a SECURE file manager with PHP. It has all the information you need to secure your file manager made using the previous article. […]

  8. Tyler Says:

    This is a great tutorial, however why does it not include the ability to access different folders in a directory? Do I need to change something in the code? Maybe I am just overlooking something. If someone could help me I would greatly apreciate it.

  9. Moses Says:

    This is a great tutorial. You can add some AJAX to show the Progress bar to the user. Keep it up..

  10. Levi Says:

    I have problem in viewing encryted image file to view in IE6 SP1. just the images doesnt render properly while the other type (like pdf) doesnt have any error.

    is it IE setting? IE really sucks at all time.

Leave a Reply

About the author
Dennis Pallett is the main contributor to PHPit. He owns several websites, including ASPit and Chill2Music. He is currently still studying.
Article Index
  1. Uploading files
  2. Streaming & Editing
  3. Deleting & Wrap-up
Bookmark Article
Download Article
PDF
Download this article as a PDF file