Link to home
Start Free TrialLog in
Avatar of jsvb1977
jsvb1977

asked on

How to properly catch file upload errors in php

so i have a form which is designed to upload jpg images to the server. This form action runs 'uploader.php' which does the following:

1. renames the file
2. creates a thumbnail
3. writes form data to a mysql table

i would like to properly account for and catch errors in the beginning of the script. I am storing error descriptions in another table called uploaderrors. my thinking is to catch the errors [as you will see i am attempting to do in the code] and redirect the user to another page called 'cmserrors.php' where i read the errors from the table and display the results to the end user.

all this is fine and good, but since there is no native control to catch an error if the uploaded image is not a jpg i am attempting to integrate this into the error catching as well.

Furthermore, i think that since the max upload setting in php.ini trumps the ability for me to catch the file type and read it into a variable, this also causes a problem.

anyway, check out the code posted below and let me know if there is a way to properly catch all possible errors that may occur. I am referencing this list found here and it is what i have built my error table and error checking on.

http://php.net/manual/en/features.file-upload.errors.php

Thank you in advance for any assistance.
Jason


<?php
require_once('auth.php');
include('../includes/conn_mysql.inc.php');
$conn = dbConnect('query');
// capture the variables, type casting to int
$siteid = (int) mysql_real_escape_string($_GET['pageid']);
$articleid = (int) mysql_real_escape_string($_GET['articleid']);

$sql = "SELECT pageid, pagename, url FROM pages ORDER BY pagename";
$result = mysql_query($sql) or die(mysql_error());
$sql3 = "SELECT pageid, pagename, url FROM pages WHERE pageid='".$siteid."' LIMIT 1";

$uploadedfile = $_FILES["uploadedfile"]["name"] ; 
$filetype = $_FILES["uploadedfile"]["type"] ; 
$filesize = $_FILES["uploadedfile"]["size"] ; 
$tempdir = $_FILES["uploadedfile"]["tmp_name"] ; 
$errorcode = $_FILES["uploadedfile"]["error"] ;
/*
if ($filetype != "image/jpeg"){
	$errorcode = "9";
	}
if ($filesize > "100000000"){
	$errorcode = "10";
	}
*/

if ($errorcode != "0" and $filetype == "images/jpeg")
{
	//echo "The file does not exist"; // Display an error and redirect
	//echo "<br />";
	header("Location: cmserror.php?pageid=0&errorcode=".$errorcode);
    exit;
	else if ($filetype != "images/jpeg")
	{
	header("Location: cmserror.php?pageid=0&errorcode=9");
    exit;		
	}
}
else {

//// MOVE FILE TO UPLOADS DIRECTORY ////

 //This function separates the extension from the rest of the file name and returns it 

 function findexts ($filename) 
 { 
 $filename = strtolower($filename) ; 
 $exts = preg_split("[\\.]", $filename) ; 
 $n = count($exts)-1; 
 $exts = $exts[$n]; 
 return $exts; 
 } 
 
 //This applies the function to our file  
 $ext = findexts ($_FILES['uploadedfile']['name']) ; 
 
 //This line assigns a random number to a variable. You could also use a timestamp here if you prefer. 
 $ran = time();

 //This takes the random number (or timestamp) you generated and adds a . on the end, so it is ready of the file extension to be appended.
 $ran2 = $ran.".";

 //This assigns the subdirectory you want to save into... make sure it exists!
 $target = "uploads/";

//This combines the random file name and the extension
 $newname = $ran2.$ext;

//This combines the directory, the random file name, and the extension
 $target = $target . $ran2.$ext; 

if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target)) 
 {
 echo "The file has been uploaded as ".$newname;
 } 
 else
 {
 echo "Sorry, there was a problem uploading your file.";
 }

 //CREATE THUMBNAILS //

 $new_width = 100; // Fix the width of the thumb nail images
 //$n_height=100; // Fix the height of the thumb nail imaage

 $tsrc = "uploads/thumbs/".$newname; // Path where thumb nail image will be stored

 $img = imagecreatefromjpeg("uploads/".$newname);
 $width = imagesx($img); // Original picture width is stored
 $height = imagesy($img); // Original picture height is stored
 $new_height = floor( $height * ( $new_width / $width ) );
 $newimage=imagecreatetruecolor($new_width,$new_height);
 imagecopyresized($newimage,$img,0,0,0,0,$new_width,$new_height,$width,$height);
 imagejpeg($newimage,$tsrc);
 chmod("$tsrc",0777);

 if (array_key_exists('insert', $_POST)) {
  //include('../includes/conn_mysql.inc.php');
  include('../includes/corefuncs.php');
  $img = basename( $_FILES['uploadedfile']['name']);
  // remove backslashes
  nukeMagicQuotes();
  // prepare an array of expected items
  $expected = array('article_id', 'title', 'uploadedfile');
  // create database connection
  //$conn = dbConnect('admin');
  // make $_POST data safe for insertion into database
  foreach ($_POST as $key => $value) {
    if (in_array($key, $expected)) {
      ${$key} = mysql_real_escape_string($value);
      }
    }
  // prepare the SQL query
  $sql = "INSERT INTO galleryimgs (articleid, title, img, createdate)
          VALUES('$articleid', '$title', '$newname', NOW())";
  // process the query
  $result = mysql_query($sql) or die(mysql_error());
  // if successful, redirect to list of existing records
  
  if ($result) {
    header("Location: cmsgallery.php?articleid=$articleid&pageid=$siteid");
    exit;
    }
	
  }

}

?>

Open in new window

Avatar of amrish80
amrish80
Flag of India image

what kind of result u want tell me so that i can help
Avatar of jsvb1977
jsvb1977

ASKER

I think what i am trying to accomplish is this:

if the uploaded file is not a jpg, then set the error code to be 9.

if ($filetype != "image/jpeg"){
        $errorcode = "9";
        }

I was able to do this but commented it out because what would happen is this:

if the uploaded file exceeded 2 MB [set in the php.ini] then the file type was never assigned. because of this, then i was not able to catch the "file size" error.

Make sense?
Jason
ASKER CERTIFIED SOLUTION
Avatar of amrish80
amrish80
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
hello jsvb1977, In my tests, the -
$_FILES["uploadedfile"]["type"] ;
did NOT necessarily contain the correct file type, only a status of the file extention, if you uploaded a TEXT file with an incorrect file extention of .jpg, this would give the file type as an image/jpeg, but it might vary from browser to browser?

for me I ALWAYS use the php GD getimagesize( ) to check the file type.
here is some code I used in an image upload, it is not from your code, but it may give you some ideas on error checking

ask questions if you need more info
$aDo = 0;
$fmime = '+';
$stat = (empty($_POST['status1'])) ? '+' : $_POST['status1']; // status1 if just a validation check that I used
if (($stat != '+') && (strlen($stat)==7) &&($_POST['MAX_FILE_SIZE'] == '65536')) $aDo = 1;
if ($aDo == 1) {$stat = '+'; $fsize =$_FILES['upfile']['size'];
	if ($_FILES['upfile']['tmp_name'] == '') $aDo = 5; elseif
	($fsize < 16) $aDo = 3; elseif
	($fsize <= 65536) {
	// ALWAYS make sure the upload is a valid IMAGE file
	$imageinfo = getimagesize($_FILES['upfile']['tmp_name']);
	if ($imageinfo['mime'] == 'image/gif') {$stat = '.gif'; $fmime = $imageinfo['mime']; $temImg = imagecreatefromgif($_FILES['upfile']['tmp_name']);}
	elseif ($imageinfo['mime'] == 'image/jpeg') {$stat = '.jpg'; $fmime = $imageinfo['mime']; $temImg = imagecreatefromjpeg($_FILES['upfile']['tmp_name']);}
	elseif ($imageinfo['mime'] == 'image/png') {$stat = '.png'; $fmime = $imageinfo['mime']; $temImg = imagecreatefrompng($_FILES['upfile']['tmp_name']);}
	else $aDo = 2;} else $aDo = 5;
if (($aDo == 1) && ($stat != '+')) {

Open in new window

Slick812,

interesting. i will take a closer look at this. I am not sure about how getimagesize relates to an image type? can you take a moment to explain this to me?

i guess another fail safe, although not fool proof, would be to look at the file extension instead of $_FILES["uploadedfile"]["type"] ; since i am grabbing the extension and setting it as a variable. in this way, i will be able keep a "pseudo-eye" on the file extension [since you suspect that the file-type could vary from browser to browser]. just a thought - not a solution.

Thanks for the reply!
Jason
amrish80,

sorry brother, not sure i follow? can you help me understand what the code is doing? should i and where would i integrate your solution into my app?

I am especially interested in the array [although i would likely limit it to jpg and png for my client.

thanks for the reply!
amrish,

with some slight modifications i was able to make your solution fit in my app. thanks!

Jason
$allowedExtensions = array("jpg","jpeg");
foreach ($_FILES as $file)
{
      if ($file['tmp_name'] > '')
      {
          if (!in_array(end(explode(".", strtolower($file['name']))),$allowedExtensions))
         {
                 //echo "This is not a JPG";
				 $errorcode=9;
          }      
      }
}


if ($errorcode != "0")
{
	//echo "The file does not exist"; // Display an error and redirect
	//echo "<br />";
	header("Location: cmserror.php?pageid=0&errorcode=".$errorcode);
    exit;
}
else {
//the rest of the code as shown in original post
}

Open in new window

Thanks again -- see my final post at the end of this thread for the code mods i made to make your solution fit into my app.

Jason
OK you asked about " how getimagesize relates to an image type" and you use -"since i am grabbing the extension"
My Opinion - I have use a image file upload several many times, and for me I found that general users, know almost nothing about computer image files, and will think that they change a GIF image to a JPEG image, just by changing the file extension, and will upload the gif image with a .jpg extention, and the file Upload as $_FILES["uploadedfile"]["type"] will say it is an image/jpeg even though it is really a GIF image. A few will also change the file extention for a microsoft Word .DOC file that has the image they want in it, to .jpg and think that converts it to an image.
Despite the name the GD getimagesize( ) will read the file header for the file type and the image size in pixels (width and height) and also can tell if it is an INVALID image. Invalid images with a .jpg file extension are not that uncommon in some places.
I have found that people will try and upload some unusual  crap, and with the 8 and 10 megapixel cameras out now, they will try and upload GIGANTIC 10 megapixel images, without having a clue what size it is or how to make it smaller.
slick812,

i concur about end users not understanding our world 100%. I would like to incorporate GD getimagesize() as you have described.

As i am a noob [no excuse with google at my fingertips] could you illustrate an example of how i could easily integrate getimagesize as you have described into my own code posting?

I have a felling that you are helpful without the need to aquire "points" in this forum -- but if you can provide an example that i can follow i will most certainly request that the EE admins revisit this thread and allow me to distribute points accordingly.

Thanks for your feedback and suggestions! I am always looking to improve the code!

Jason
I may can find the time for that, BUT here is the main lines

// first get the info from $_FILES['upfile']['tmp_name'], which is an actual temporary file
$imageinfo = getimagesize($_FILES['upfile']['tmp_name']);
// then test for your type
if ($imageinfo['mime'] == 'image/jpeg') {}
//which will be false if not a jpg or is invalid image

I have more points than I could use, so re-kicking this question, will just use up the valuable time for the moderators, so no need, be sure to thank the moderators whenever you get the chance!
I did not adhere to your code very much, sorry, but I do not have much time now, I did try and keep some of your procedure through the steps of your code, my code is below - Warning, this is Untested, and there may be syntax errors, but I copied much of it, and it seems mostly correct.
It is all PHP code, I did not add the <?php
define("MAX_THUMB", 108);//set this to the thumbnail DIMENTION max

	//this function will create a thumbnail
function doThumb($imInfo, &$imgT){
if (!is_array($imInfo)) return false;
$height = MAX_THUMB;
$width = MAX_THUMB;
if ($imInfo[0] < $imInfo[1]) {
$width = (int) ((MAX_THUMB / ($imInfo[1] / $imInfo[0]))+ 1);}
elseif ($imInfo[0] > $imInfo[1]) {
$height = (int) ((MAX_THUMB / ($imInfo[0] / $imInfo[1]))+ 1);}
if ($height < 2) $height = 2;
if ($width < 2) $width = 2;
$outImg = ImageCreateTrueColor($width, $height);
if (!ImageCopyResampled($outImg, $imgT, 0, 0, 0, 0, $width, $height, $imInfo[0], $imInfo[1])) return false;
return $outImg;
}

$filesize = $_FILES["uploadedfile"]["size"]; 
$tempFile = $_FILES["uploadedfile"]["tmp_name"]; 
$errorcode = $_FILES["uploadedfile"]["error"];

if ($errorcode != "0")// I have Included this, because you did, 
	//but am not sure about if It indicates errors at this point
	{
	header("Location: cmserror.php?pageid=0&errorcode=".$errorcode);
        exit;               
	}
	
if (($filesize < 32) || ($filesize <= 1500000))// about 1.5 meg seems enough for most jpgs?
	{
	header("Location: cmserror.php?pageid=0&fsize=".$filesize);
    exit;               
	}
	
$imageinfo = getimagesize($tempFile);
if ($imageinfo['mime'] != 'image/jpeg')
	{
	header("Location: cmserror.php?pageid=0&errorcode=8888");// whatever code suits you
        exit;               
	}
//after you check the file type, there is no need to do the file extention chop	
$newname = time().'.jpg';
$target = 'uploads/'.$newname;

$img = imagecreatefromjpeg($tempFile);
if ($img === FALSE)
	{
	header("Location: cmserror.php?pageid=0&errorcode=121212");// whatever code suits you
        exit;               
	}
// you do not need a smaller image if the image is small
if ($imageinfo[0] > MAX_THUMB || $imageinfo[1] > MAX_THUMB) 
		$smImg = doThumb($imageinfo, $img); 
		else
		{$smImg = $img;}
	if($smImg != false)
	{
	$tsrc = 'uploads/thumbs/'.$newname;
	imagejpeg($smImg,$tsrc,76);
	ImageDestroy($smImg);
	chmod($tsrc,0777);
	} else echo 'some ERROR for false';
@ImageDestroy($img);
	
if (move_uploaded_file($_FILES['upfile']['tmp_name'], $target)) 
	{echo "The file has been uploaded as ".$newname;}
	else
	{echo 'Sorry, there was a problem uploading your file.'
	$stat = $_FILES['upfile']['error'];}// this is where the $_FILES error works

// I end here where the image file and thumb file are on disk

Open in new window