Wouldn't it be nice if you could upload files from a local machine to the server using the directory navigator you just created? PHP offers an easy way to put this sort of functionality into your applications. You can let users upload files with their browsers using an <input> form tag of the type file. The <form> tag's enctype attribute, which is usually omitted when creating a normal form, also needs to be set to multipart/form-data.
Here's a sample upload form:
<form method="POST" enctype="multipart/form-data"
action="<?php echo "$_SERVER[PHP_SELF]?action=upload_file&dir=$dir"; ?>">
Local Filename <input type="file" name="userfile">
<input type="submit" name="submit" value="Upload">
</form>
The action attribute of the form should point to a PHP script that will handle the uploaded file. You don't have to provide the second text input tag unless you want to let users choose a different filename with which the uploaded file will be stored on the server.
Once a file is uploaded, the following variable values become available for use via the superglobal $_FILES array:
| Variable | Description |
|---|---|
| $_FILES[userfile] | The array in $_FILES that contains the other array values |
| $_FILES[userfile][name] | The original path and the filename of the uploaded file |
| $_FILES[userfile][size] | The size of the uploaded file in bytes |
| $_FILE[userfile][type] | The type of the file (if the browser provides the information) |
Suppose a user has just uploaded a 20,000-byte ZIP file, C:\docs\projects.zip, using this form. These variables now contain the following:
- $_FILES[userfile][tmp_name]: The path to the file in the temporary directory (as set in php.ini) plus the temporary filename in the format "php-###" format (where "###" is a number which is automatically generated by PHP), for example, "/tmp/php-512".
- $_FILES[userfile][name]: "C:\docs\projects.zip"
- $_FILES[userfile][size]:20000
- $_FILES[userfile][type]: "application/x-zip-compressed"
You can set these values to normal variables if you like, as shown here:
//get the userfile particulars
$userfile_name = $_FILES['userfile']['name'];
$userfile_tmp_name = $_FILES['userfile']['tmp_name'];
$userfile_size = $_FILES['userfile']['size'];
$userfile_type = $_FILES['userfile']['type'];
if(isset($_ENV['WINDIR'])) {
$userfile = str_replace("\\\\","\\", $_FILES['userfile']['name']);
}
The uploaded file is saved in the temporary directory set in php.ini and destroyed at the end of the request, so you need to copy it to somewhere else. For security reasons, it's recommended that you use the move_uploaded_file() function instead of the copy() function:
$archive_dir = "/Inetpub/wwwroot/beginning_php5/ch07/docs";
$filename = basename($userfile_name);
if(!@move_uploaded_file($userfile, "$archive_dir/$filename"))
echo "Error: $filename cannot be copied.";
else echo "Successfully uploaded $filename.";
You may want to set a limit on the size of an uploaded file and check whether the uploaded file is larger than the limit by using the $userfile_size variable:
$archive_dir = "./docs";
$max_filesize = 200000;
$filename = basename($userfile_name);
if($userfile_size > $max_filesize)
echo "Error: $filename is too big. " .
number_format($max_filesize) . " bytes is the limit.";
else if(!copy($userfile, "$archive_dir/$filename"))
echo "Error: $filename cannot be copied.";
else echo "Successfully uploaded $filename.";
Another way to limit the size of the uploaded file is to use a hidden field in the upload form:
<input type="hidden" name="max_file_size" value="200000">
...
if($userfile_size > $max_file_size)
echo "Error: $filename is too big. " .
number_format($max_file_size) . " bytes is the limit.";
Setting the limit within the script is a much more secure method because anyone can edit the Web page containing the upload form and increase the limit all he wants.
Try it Out: File Uploading
Here's a complete example of how to implement the file-uploading feature:
<?php //file_upload.php function upload__form() { ?> <table border="1" align="center"> <tr><td> <form method="POST" enctype= "multipart/form-data" action="<? echo $_SERVER['PHP_SELF'] ?>"> Upload file! <input type="file" name="userfile"> <input type="submit" name="action" value="upload"> </form> </td></tr> </table> <? } function upload_file() { //set the archive directory $archive_dir = "/Inetpub/wwwroot/beginning_php5/ch07/docs"; //get the userfile particulars $userfile_name =$_FILES['userfile']['name']; $userfile_tmp_name = $_FILES['userfile']['size']; $userfile_size = $_FILES['userfile']['size']; $userfile_type = $_FILES['userfile']['type']; if(isset($_ENV['WINDIR'])) { $userfile = str_replace("\\\\", "\\", $FILES['userfile']['name']); } $filename = basename($userfile_name); if($userfile_size <= 0) die ("$filename is empty."); if (!@move_uploaded_file($userfile_tmp_name, "$archive_dir/$filename")) die("Can't copy $userfile_name to $filename."); if(isset($_ENV['WINDIR']) && !@unlink($userfile)) die("Can't delete the file $userfile_name."); echo "$filename has been successfully uploaded.<BR>"; echo "Filesize: " . number_format($userfile_size) . "<BR>"; echo "Filetype" $userfile_type<BR>"; } ?> <html> <head><titile>File Upload</tile></head> <body> <?php if($_POST[action] == 'upload') { upload_file(); } else { upload_form(); } ?> </body> </html>
How it Works
When a user uploads a file from his local machine, the script first retrieves the $_FILES values and then tests the platform on which it is run. If it's the Windows platform, all occurrences of double forward slashes need to be reduced to single slashes:
//set the archive directory $archive_dir = "/Inetpub/wwwroot/beginning_php5/ch07/docs"; //get the userfile particulars $userfile_name = $_FILES[userfile][name]; $userfile_tmp_name = $_FILES[userfile][tmp_name]; $userfile_size = $_FILES[userfile][size]; $userfile_type = $_FILES[userfile][type]; if(isset($_ENV[WINDIR])) $userfile = str_replace("\\\\", "\\$",$_FILES[userfile][name]));
If the size of the file is less then 0, the user submitted the form without designating a file to be uploaded:
if($userfile_size <= 0) die ("$filename is empty.");
If everything looks fine, the script copies the uploaded file to an archive directory and tests to see whether it's running on Windows. If not, it's okay to use unlink() to delete the temporary file. Then echo back to the user that the file has been uploaded, as well as the file's size and type.
