advanced php file uploads
TRANSCRIPT
Advanced PHP
File & Image Uploads
Uploads In some dynamic web applications, it is
necessary to allow users to upload files from their local computer to the Web server.
Such an application may allow users to share files with others or simply provide a mechanism for storing files for later use.
PHP File Functions move_uploaded_file(filename, destination)
moves a file to a specified destination on the server.
is_uploaded_file ( string $filename ) Returns TRUE if the file named by filename was
uploaded via HTTP POST. This is useful to help ensure that a malicious user hasn't tried to trick the script into working on files upon which it should not be working--for instance, /etc/passwd.
PHP File Functions cont. copy ( string $source , string $dest [, resource
$context ] ) Makes a copy of the file source to dest .
rename ( string $oldname , string $newname [, resource $context ] ) Renames a file or directory
unlink ( string $filename [, resource $context ] ) Deletes a file
The Form Before we look at the details of the PHP code,
lets focus on the XHTML form controls needed to create the file upload page.
<form enctype="multipart/form-data" action="upload.php" method="post">
Select File: <input type="file" name="uploadFile">
<input name="Submit" type="submit" value="Upload File">
</form>
A form used for file uploads must include the encode type or "enctype" attribute.
The value of the enctype attribute "multipart/form-data" should be included when a form is used to upload files.
The Form cont. Following the <form> is an <input> text box control. This control is used to specify the location and name
of the file that will be uploaded. The control includes a name and type attribute. The type attribute must be set to "file". The name is a user-defined value that will be used by
the server to identify the source file during the upload process.
The file text box also includes a "Browse..." button when viewed in the browser window. When the browse button is clicked, a dialog window appears and allows the user to browse their local computer for the file that will be uploaded.
Generic PHP Upload Script<?php
if ($_POST[‘Submit’] == "Upload File") { move_uploaded_file ($_FILES['uploadFile'] ['tmp_name'],
"uploads/{$_FILES['uploadFile'] ['name']}");echo "File uploaded.";
} ?>
<form enctype="multipart/form-data" action="upload.php" method="post">
Select File: <input type="file" name="uploadFile">
<input name="Submit" type="submit" value="Upload File">
</form>
Whats Happenin? When the "Upload File" button is clicked, the
file specified in the <input type="file" name="UploadFile"/> is automatically posted to a temporary folder on the webserver
When the "Upload File" button is clicked, the file specified in the <input type="file" name="UploadFile"/> is automatically posted to a temporary folder on the webserver..
What’s goin on – move_uploaded_file()? The first parameter of the function -
$_FILES['uploadFile'] ['tmp_name'], becomes a reference to the file as the function prepares to move it to its final destination.
The second parameter - “/uploads/FILES['uploadFile'] ['name']}", is a relative path to the folder were the file will be permanently saved.
The last part of the path includes the code - {$_FILES['uploadFile'] ['name']}. This can be interpreted as the name of the file which was entered into the file text box named "uploadFile".
move_uploaded_file cont. In short, the move_uploaded_file() function
moves the file from a temporary upload folder to the folder ($_FILES['uploadFile'] ['tmp_name']) to the folder (“/uploads”) and the file is saved with the same name as entered by the user ({$_FILES['uploadFile'] ['name']}).
Files can be uploaded to any directory on the web server, however, the destination folder must have "write" access permissions.
Setting Permissions On our local machines,
set up permissions by right clicking on the folder and choosing properties.
Then click the ‘Allow’ button to allow full control of the folder.
On a web server, set the permissions to 777.
Uh-Oh! We have not considered what happens when
a user attempts to upload a file that exceeds size limits, if the upload folder does not have appropriate security permissions, or some unforeseen network issue prevents the entire file from being uploaded.
To improve the file upload code, we must provide routines that check for errors and provide feedback to the user on how to correct these problems.
Adding Error Checkingif ($_POST['Submit'] == "Upload File"){
move_uploaded_file ($_FILES['uploadFile'] ['tmp_name'], "uploads/{$_FILES['uploadFile'] ['name']}");
if($_FILES['uploadFile'] ['error'] > 0) { switch ($_FILES['uploadFile'] ['error']){
case 1: echo 'File exceeded maximum server upload size'; break; case 2: echo 'File exceeded maximum file size'; break; case 3: echo 'File only partially uploaded'; break; case 4: echo 'No file uploaded'; break;
} } else{ echo 'File successfully uploaded'; } }
The Form for Error Checking
Another new feature included in this example is an XHTML hidden text box called "MAX_FILE_SIZE". This is a special hidden tag that can be used with the file tag <input type="file" name="uploadFile"/> to set a maximum file size..but it cannot be relied upon.
Use the php.ini setting as well.
<form enctype="multipart/form-data" action="upload.php" method="post">
Select File: <input type="file" name="uploadFile"> <input type="hidden" name="MAX_FILE_SIZE" value="1000000"/> <input name="Submit" type="submit" value="Upload File">
</form>
What else? We know that we want to allow someone to
upload files – but the question is, what kind of files?
Should we allow to upload .dll, exe, .php files? What if they are uploading code that will execute and destroy our database?
We should limit the uploads to .pdf, .doc, .jpg, .gif, etc.
Finding the file type We can use: $_FILES["uploadFile"]["type"] to
find the name of the file before excepting it: $_FILES is the name to use for any file upload The second part [“uploadFile”] is the name of
the file input field The third, [“type”] is the mime type of the file
uploaded Getting this ‘type’ will allow us to create if
statements that will check to see if it is an allowed file – and it will also allow us to apply different file handling.
Acceptable File Types For our purposes,
we only want to allow the following File Types: jpeg,png word,pdf,avi videos
Use PHP to check the file type:
if($_FILES['uploadFile'] ['error'] > 0) {switch ($_FILES['uploadFile'] ['error']){case 1: echo 'File exceeded maximum server upload
size';break;case 2: echo 'File exceeded maximum file size';break;case 3: echo 'File only partially uploaded';break;case 4: echo 'No file uploaded';break;}
}$aryImages=array(“image/jpeg","image/png");$aryDocs=array("application/msword","application/pdf","video/x-msvideo");if (in_array($_FILES["uploadFile"]["type"],$aryImages)){
//do image stuff}elseif (in_array($_FILES["uploadFile"]["type"],$aryDocs)){
//do doc stuff}
GD To create images with PHP you need to have
the gd image library installed and activated in your PHP.
To see if it is installed, view your phpinfo file. If GD is enabled, you will see the following:
Thumbnails We want to create a thumbnail version of any
image that is uploaded. We assume the thumbnail should be 100 pixels, either
wide or high. We load the original image, and check its dimensions. If the picture is higher than wide, we set the height of the
thumb to 100 pixels. The width of the thumbnail is the original width multiplied
with 100 pixels divided by its height. Thumbnail height = original width * (100 / original height,
preserving the original aspect ratio. If the original picture is wider than high, we do the same
to the height of the thumbnail. If they are the same, we simply create a 100x100 pixels
image.
GD cont. If you know for sure that there is gd on the
machine but PHP does not recognize it, it may still be commented in the php.ini.
Scan your machine for the php.ini and edit it. You will find loads of extensions, simply remove the semicolon in front of the gd dll and restart the server:
PHP GD Functions PHP has a whole lot of functions to help us
with generating graphics with gd. The ones we need to use here are:
imageCreateFromJPEG() to create a copy to work on of a .jpg image.
imageCreateFromPNG() to create a copy to work on of a .png image.
imageSX() to get the width of the original image. imageSY() to get the height of the original image. imageCreateTrueColor() to create a new true color
image object. imageCopyResampled() to resample the image.
Never assume the user won’t make mistakes! Always plan for the worst What will happen if the user uploads a file
with the same name as a file that was already uploaded?
Will it overwrite the original file? What about the filename? What if it has
invalid characters? (%& #, etc.)
Checking the File Name This function is going to
check the filename for invalid characters, spaces, etc. It is also going to check the database to see if any files have been inserted with that name already – if so, we break it apart, insert the unique timestamp into the filename and put it back together again.
function filenameSafe($filename) {$temp = $filename;// Lower case$temp = strtolower($temp);// Replace spaces with a ’_’$temp = str_replace(" ", "_", $temp);// Loop through string$result = "";for ($i=0; $i<strlen($temp); $i++) {
if (preg_match('([0-9]|[a-z]|_|.)', $temp[$i])) {$result = $result.$temp[$i];
}}dbConnect();$SQL="SELECT fileID FROM tblFile WHERE fileName='".
$result."'";$rs=mysql_query($SQL);if (mysql_num_rows($rs)!=0){
$extension=strrchr($result,'.');$result=str_replace($extension,time(),$result);$result=$result.$extension;
}return $result;
}
Calling the function Notice our function takes one parameter only,
the file name – this makes invoking this function pretty easy:
A safe, clean, unique filename is returned
$filenameSafe=filenameSafe($_FILES['uploadFile'] ['name']);
function createThumb($type,$tmpname,$filename,$new_w,$new_h){$thumbFilename="tmb-".$filename;if (is_numeric(strpos($type,"jpeg"))){
$src_img=imagecreatefromjpeg($tmpname);}if (is_numeric(strpos($type,"png"))){
$src_img=imagecreatefrompng($tmpname);}$old_x=imageSX($src_img);$old_y=imageSY($src_img);if ($old_x > $old_y) {
$thumb_w=$new_w;$thumb_h=$old_y*($new_h/$old_x);
}if ($old_x < $old_y) {
$thumb_w=$old_x*($new_w/$old_y);$thumb_h=$new_h;
}if ($old_x == $old_y) {
$thumb_w=$new_w;$thumb_h=$new_h;
}$dst_img=imagecreatetruecolor($thumb_w,$thumb_h);imagecopyresampled($dst_img,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y);if (is_numeric(strpos($type,"jpeg"))){
imagejpeg($dst_img,"../uploads/".$thumbFilename);imagejpeg($src_img,"../uploads/".$filename);
}if (is_numeric(strpos($type,"png"))){
imagepng($dst_img,"../uploads/".$thumbFilename);imagepng($src_img,"../uploads/".$filename);
}imagedestroy($dst_img);imagedestroy($src_img);dbInsert($filename,$thumbFilename,$type);
}
Adding to the database Our function to add to the database is simple:
Calling it is easy too – if it’s an image we have the thumbnail filename renamed with ‘tmb-’ at the beginning –
Otherwise (a document) we send a blank value:
function dbInsert($filename,$thumbFilename,$type){dbConnect();$SQL="INSERT Into tblFile (fileName,thumbFileName,fileType) values('".$filename."','".$thumbFilename."','".
$type."')";echo $SQL;mysql_query($SQL);
}
dbInsert($filename,$thumbFilename,$type);
move_uploaded_file ($_FILES['uploadFile'] ['tmp_name'], "../uploads/".$filenameSafe);dbInsert($filenameSafe,'',$fileType);
Wrapping up It may take some fine tuning – but this will
leave you with a working script to upload images and documents.
Note: GD does NOT work with .gif files because the technology that makes .gif files is copyrighted.
Another great piece of software to manipulate images is ImageMagick.