Programming PHPProgramming PHPSearch this book

12.3. File Uploads

File uploads combine the two dangers we've seen so far: user-modifiable data and the filesystem. While PHP 4 itself is secure in how it handles uploaded files, there are several potential traps for unwary programmers.

12.3.1. Distrust Browser-Supplied Filenames

Be careful using the filename sent by the browser. If possible, do not use this as the name of the file on your filesystem. It's easy to make the browser send a file identified as /etc/passwd or /home/rasmus/.forward. You can use the browser-supplied name for all user interaction, but generate a unique name yourself to actually call the file. For example:

$browser_name = $_FILES['image']['name'];
$temp_name = $_FILES['image']['tmp_name'];
echo "Thanks for sending me $browser_name.";

$counter++; // persistent variable
$my_name = "image_$counter";
if (is_uploaded_file($temp_name)) {
  move_uploaded_file($temp_name, "/web/images/$my_name");
} else {
  die("There was a problem processing the file.");
}

12.3.2. Beware of Filling Your Filesystem

Another trap is the size of uploaded files. Although you can tell the browser the maximum size of file to upload, this is only a recommendation and it cannot ensure that your script won't be handed a file of a larger size. The danger is that an attacker will try a denial of service attack by sending you several large files in one request and filling up the filesystem in which PHP stores the decoded files.

Set the post_max_size configuration option in php.ini to the maximum size (in bytes) that you want:

post_max_size = 1024768        ; one megabyte

The default 10 MB is probably larger than most sites require.

12.3.3. Surviving register_globals

The default variables_order processes GET and POST parameters before cookies. This makes it possible for the user to send a cookie that overwrites the global variable you think contains information on your uploaded file. To avoid being tricked like this, check the given file was actually an uploaded file using the is_uploaded_file( ) function.

In this example, the name of the file input element is "uploaded":

if (is_uploaded_file($_FILES['uploaded_file']['tmp_name'])) {
  if ($fp = fopen($_FILES['uploaded_file']['tmp_name'], 'r')) {
    $text = fread($fp, filesize($_FILES['uploaded_file']['tmp_name']));
    fclose($fp);

    // do something with the file's contents
  }
}

PHP provides a move_uploaded_file( ) function that moves the file only if it was an uploaded file. This is preferable to moving the file directly with a system-level function or PHP's copy( ) function. For example, this function call cannot be fooled by cookies:

move_uploaded_file($_REQUEST['file'], "/new/name.txt");


Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.