I am in the process of writing an image upload script. I am adding lots of things e.g. store outside webroot and access through php script etc. One thing I have read to check is that a file is uploaded instead of an image. E.g. stop myimage.php.jpeg
I have written the following code to check it is an image file. Is this the best way to check this file has an image name?
$imagename= $_FILES['myimage']['name'];
//check there is only one fullstop in the imagename
if (substr_count($imagename,".")===1){
$imagesuffix = substr($imagename, strpos($imagename, ".") + 1);
//if image type is not a particular type of image
if($imagesuffix != "jpg"|| $imagesuffix != "png"||$imagesuffix != "jpeg"||$imagesuffix != "gif"){
echo"image filename is valid";
}
else{
echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
}
}
else{
echo"this filename is invalid";
}
If your concern is to only allow uploads of files that are images, then you'll have to look at the file contents.
<?php
$image = 'image_file_to_test.png';
if (($imageInfo = getimagesize($image, $jpegInfo)) === FALSE)
die('Not an image.');
// OR
if (($imageType = exif_imagetype($image)) === FALSE)
die('Not an image');
If so desired, you can inspect either $imageInfo (docs) or $imageType (docs) to determine the image format. Please note that exif_imagetype() is the faster of the two, but it won't tell you as much as getimagesize().
Related
I have a PHP script that, if a user-uploaded image file isn't a .png image, it will use Imagemagick to convert it to .png before saving it to a server. However it can only use the .tmp file from the HTML form, so it has to convert the CONTENTS while keeping the .tmp (and its filename) intact. This is my code so far:
if (exif_imagetype($tmpName) != IMAGETYPE_PNG) {
$uploadOk = 0; // don't upload later
$im = new Imagick("$tmpName");
$im->setImageFormat( "png" );
file_put_contents($tmpName, '');
file_put_contents(file_get_contents($im), $tmpName);
if (exif_imagetype($tmpName) != IMAGETYPE_PNG) { //check again
// try again or throw error somehow?
} else {
$uploadOk = 1;
}
} else {
$uploadOk = 1;
}
How do I properly use Imagick to convert the contents of my temp file into a png version of the original (non png) image?
EDIT: It could also be that the script should work fine, and the problem is something entirely different. Not sure at this point.
if you are to use, IMAGICK library, then you can use something like this:
...need to explain how you get the .tmp file, which I guess by using a form on your site... so...
.. get the post file
// This equals to 'some/server/path/temp/filename.tmp'
$original_image = $_FILE['tmp_name'];
// Lets work on the Imagick...
$img = new Imagick($original_image);
$img->setImageBackgroundColor('white');// red, black..etc
$img = $img->flattenImages(); // Use this instead.
$img->setImageFormat('png');
$new_image_name = 'nice_image_name.png';
$img->writeImage($new_image_name);
See if that works for you...
I've read the Secure PHP Upload Scripts thread but I'm having difficulty getting this known good script to accept changes. I want this script to only allow .jpeg, .png, and .gif files. Could someone advise me on how to modify this script to do so?
<?php
$result=0;
if (trim($_POST["action"]) == "Upload File") { //**** User Clicked the Upload File Button
//*********** Execute the Following Code to Upload File *************
$imagename = basename($_FILES['image_file']['name']); // grab name of file
$result = #move_uploaded_file($_FILES['image_file']['tmp_name'], $imagename); // upload it
if ($result==1) echo("Successfully uploaded: <b>".$imagename."</b>"); // did it work?
} // end if
?>
<?php
if ($result==1) echo("<img src='".$imagename."'>"); // display the uploaded file
?>
$filename = $_FILES['image_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if($ext !== 'jpg' && $ext !== 'png' && $ext !== 'gif') {echo 'error';}
is a very bad idea for validation.
echo '<pre>';
$filename = 'image.php\0.jpg';
$extension = pathinfo($filename, PATHINFO_EXTENSION);
var_dump($ext);
The var_dump displays jpg
And the php function move_uploaded_file is vulnerable with null bytes \0.
After the move_uploaded_file the server will create a image.php file..
If you want to stop the upload before it reaches your server, you can filter it with javascript. See this SO answer for more information: stackoverflow.com/questions/71944/… – Kevin Apr 26 at 22:13
Never never never never neverever put trust in client side validation...
Coding a safe upload is hard. Very hard.
You can't trust file extensions or mime type because clients can change this.
If you only want an upload for gif, jpeg or png you could take these steps. With png you can have trouble because of the encoding that can bypass some of these.
Read the temp file by file_get_contents().
Run strip_tags() on it.
Create new images with the GD library
Serve the image by read() - Don't use include() or require()
Disable php engine on that directory
For the sake of brevity, i'm not doing any error checking.. but you can evaluate the extension of a file like this:
$filename = $_FILES['image_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if($ext !== 'jpg' && $ext !== 'png' && $ext !== 'gif') {echo 'error';}
Hey i have a system were in uploading a file. I have a script I've found online and it seems to work well.
Here is the PHP code:
if((!empty($_FILES["uploaded_file"])) && ($_FILES['uploaded_file']['error'] == 0))
{
//Check if the file is JPEG image and it's size is less than 350Kb
$filename = basename($_FILES['uploaded_file']['name']);
$ext = substr($filename, strrpos($filename, '.') + 1);
if (($ext == "jpg") && ($_FILES["uploaded_file"]["type"] == "image/jpeg") && ($_FILES["uploaded_file"]["size"] < 350000))
{
//Determine the path to which we want to save this file
$newname = dirname(__FILE__).'upload/'.$filename;
//Check if the file with the same name is already exists on the server
if (!file_exists($newname))
{
//Attempt to move the uploaded file to it's new place
if ((move_uploaded_file($_FILES['uploaded_file']['tmp_name'],$newname)))
{
echo "It's done! The file has been saved as: ".$newname;
}
else
{
echo "Error: A problem occurred during file upload!";
}
}
else
{
echo "Error: File ".$_FILES["uploaded_file"]["name"]." already exists";
}
}
else
{
echo "Error: Only .jpg images under 350Kb are accepted for upload";
}
}
else
{
echo "Error: No file uploaded";
}
No this works fine if i want to upload a jpg file. But i want to be able to put the file into another directory. because at the moment the upload page is for admin users, they are on a subdomain called admin.mysite.com but the location i want the file to go to is in the members section which is mysite.com/members/video/
Now there are a few bits of code that im not 100% with like "dirname(FILE)" what does this do? I guessed it would get the current locations, but i've changed the whole line where so it looks like this:
$newname = '../mysite.com/members/video/'.$filename;
and
$newname = 'http://www.mysite.com/members/video/'.$filename;
But nothing. Anyone know how i can change this code so i can copy the file to a new directory?
Thanks for the help.
Change $newname to whatever location you want!
//Determine the path to which we want to save this file
$newname = dirname(__FILE__).'upload/'.$filename;
dirname(_ FILE _) returns the current directory of the file, in this case, file_upload.php
So, in this script, the $newname will save the uploaded file to /upload/name_of_new_file_uploaded.ext.
You should try to use realpath() instead dirname. Like this:
$newname = realpath("../../members/video/") . $filename;
depending on you file structure, add/remove the dots.
PS: Remember to change folder permissions, so the php can write on a folder.
For security, you should
Put the file in a location that is not accessible by the general web. /home/uploadedfiles/
Change the name of the file. Store the name of that file in a database and don't let the end users see that actual name.
I'm making a page where the user upload a file. I want an if statement to create an $error variable if the file type is anything other jpg, gif, and pdf.
Here's my code:
$file_type = $_FILES['foreign_character_upload']['type']; //returns the mimetype
if(/*$file_type is anything other than jpg, gif, or pdf*/) {
$error_message = 'Only jpg, gif, and pdf files are allowed.';
$error = 'yes';
}
I'm having difficulty structuring the if statement. How would I say that?
Put the allowed types in an array and use in_array().
$file_type = $_FILES['foreign_character_upload']['type']; //returns the mimetype
$allowed = array("image/jpeg", "image/gif", "application/pdf");
if(!in_array($file_type, $allowed)) {
$error_message = 'Only jpg, gif, and pdf files are allowed.';
$error = 'yes';
}
edit
I just realized that you want to allow PDF files as well. In that case check out PHP's Fileinfo class and functions. But as far as security goes, you still shouldn't rely on $_FILES[]['type'] :)
I'll leave the rest here in case it helps someone else who finds this question
For checking the mime type of the image, $_FILES[]['type'] could be unsafe. This data is sent by the browser and could be easily spoofed.
You should use the getimagesize() function if you only want to allow images to be uploaded (despite its maybe misleading name). This function won't just give you the size but all the data you will probably need about the image.
I used the following script in an image handling class:
private function load_image_data($image_file) {
// Firstly, to disambiguate a loading error with a nonexistant file error,
// check to see if the file actually exists.
if( ! file_exists($image_file) ) {
throw new Nonexistent_Image_Exception("The file '{$image_file}' does not exist");
}
// We're going to check the return value of getimagesize, so we don't
// need any pesky warnings or notices popping up, since we're going to
// stop execution of this function if something goes wrong.
$image_data = #getimagesize($image_file);
if( $image_data === false ) {
throw new Load_Image_Exception("Could not get image data from '{$image_file}'");
}
$this->size = new Dimensions($image_data[0], $image_data[1]);
$this->mime = $image_data['mime'];
}
Notice that getimagesize() returns an associative array containing a 'mime' index. The data here is reliable.
In another function I checked the mime type of the image and converted it to PNG with the appropriate GD function:
private function load_image($image_file) {
// Suppress warning messages because we're going to throw an
// exception if it didn't work instead.
switch( $this->mime ) {
case 'image/jpeg':
case 'image/pjpeg':
$this->image = #imagecreatefromjpeg($image_file);
break;
case 'image/gif':
$this->image = #imagecreatefromgif($image_file);
break;
case 'image/png':
$this->image = #imagecreatefrompng($image_file);
break;
default:
throw new Invalid_Image_Exception("The image was of an invalid type");
}
if( $this->image === false ) {
throw new Load_Image_Exception("Loading of image '{$image_file}' failed");
}
}
You probably won't need to do all of this, but you can see what mime types appear for the filetypes you have specified. Notice that a jpeg could have two different mime types.
Hope this helps.
See also Zend Framework's Zend_File_Transfer_Adapter_Http and
Zend_Form_Element_File. You can add multiple different validators like minimum image resolution, MIME type, minimum file size, allowed file extensions, etc.
Use this simple code...
<?
$path = $_FILES['file']['name']; // file means your input type file name
$ext = pathinfo($path, PATHINFO_EXTENSION);
if ($ext=="jpg" OR $ext=="jpeg" OR $ext=="gif" OR $ext=="png") {
// your code here like...
echo "Upload successful";
}else{
// your invalid code here like...
echo "Invalid image format. Only upload JPG or JPEG or GIF or PNG";
}
?>
You can also try this in the frontend to filter or allow file types you want to accept.
<input type="file" name="file" accept="image/jpeg, image/gif, image/png" />
Please can someone help? I have the following code which uploads a file to my server and renames it to whoever the logged in user is. For example the user 'coca-cola-lover' uploads a jpeg - the script would also rename the jpeg 'coca-cola-lover.jpg'.
My problem is that I need it to limit the upload to just jpegs - and also limit the file size to 2mb.
Please help - I was trying to find a solution all night.
Thanks in advance
// Your file name you are uploading
$file_name = $HTTP_POST_FILES['ufile']['name'];
$username = $row_Recordset1['username'];
$ext = end(explode('.', $file_name));
$renamed_file_name = $username;
$new_file_name=$renamed_file_name.'.'.$ext;
//set where you want to store files
//in this example we keep file in folder upload
//$new_file_name = new upload file name
//for example upload file name cartoon.gif . $path will be upload/cartoon.gif
$path= "../sites/images/users/".$new_file_name;
if($ufile !=none)
{
if(copy($HTTP_POST_FILES['ufile']['tmp_name'], $path))
{
echo "Successful<BR/>";
//$new_file_name = new file name
//$HTTP_POST_FILES['ufile']['size'] = file size
//$HTTP_POST_FILES['ufile']['type'] = type of file
echo "File Name :".$new_file_name."<BR/>";
echo "File Size :".$HTTP_POST_FILES['ufile']['size']."<BR/>";
echo "File Type :".$HTTP_POST_FILES['ufile']['type']."<BR/>";
}
else
{
echo "Error";
}
}
getimagesize tells you what format the file is in
as per bgy's comment, you should also force the file extension to be what you want:
$new_file_name=$renamed_file_name.'.'.$ext; // wrong, uses data from the client
$new_file_name=$renamed_file_name.'.jpg'; // ok, just what we want
never trust and never use filenames provided by the client.
I would recommend exif_imagetype:
<?php
if (exif_imagetype('image.gif') != IMAGETYPE_GIF) {
die(The picture is not a gif');
}
For details see here: http://php.net/manual/en/function.exif-imagetype.php
You can use any of the four to detect a mimetype of the file:
finfo_open (by default enabled as of 5.3)
getimagesize (requires enabled GD)
exif_imagetype (requires enabled Exif)
mime_content_type (deprecated as of 5.3)
You can also limit the MimeType from the FileUpload element, but since this is client-side code, it can easily be removed by malicious users (and it's also buggy across browsers):
<input type="file" name="picture" id="picture" accept="image/jpeg"/>
For further information on how to handle file uploads with PHP (including limiting file size), check the manual.
There is also a lot of very similar questions on Stack Overflow already, one being:
Check picture file type and size before file upload in php
You restrict the size via the normal mechanisms, but you'll need to use the fileinfo functions to determine the filetype after uploading.
A few advices for the current code
Use $_FILES instead of $HTTP_POST_FILES.
If you need to get file extensions use $extension = pathinfo($filename, PATHINFO_EXTENSION);.
Use is_uploaded_file and move_uploaded_file.
Don't relay on $_FILES['file']['type'] - it can be modified by user.
Indent your code.
If you want to limit file upload to the following requirements:
Filesize: max 2mb.
File type: image/jpeg
Do something like that:
$tmpName = $_FILES['file']['tmp_name'];
if (file_is_uploaded($tmpName) {
$filesize = fielsize($tmpName);
$mimeType = exif_imagetype('image.gif');
if ($filesize <= 2 * 1024 * 1024 && $mimeType == IMAGETYPE_JPEG) {
$filename = $USERNAME . '.jpg';
if (move_uploaded_file($tmpName, $filename) == false) {
// sth goes wrong
}
} else {
die('Invalid.');
}
}