Photo Upload Script (revisited)

Hi all. Okay, so I had a chance to finally finish my “Upload a Photo” script.

Hopefully I was able to take advantage of most suggestions that were made.

Because allowing Users to upload Files onto my VPS is a BIG SECURITY RISK, I would appreciate it if you guys could review my code, and see if you see any glaring problems. (I have tested it extensively and feel it is secure, but who knows?!)


<?php //Build Date: 2012-02-22

	// Initialize Session.
	session_start();

	// Access Constants
	require_once('../config/config.inc.php');

	// Initialize Variables.
	$_SESSION['resultsTitle'] = 'Upload Results';
	$memberID = (isset($_SESSION['memberID']) ? $_SESSION['memberID'] : '');


	// **********************
	// Check if Logged In.	*
	// **********************

	// User must be logged-in to Upload Images.
	if (empty($_SESSION['loggedIn']) || $_SESSION['loggedIn']===FALSE){
		// Not Logged In.
		$_SESSION['resultsCode'] = 'UPLOAD_USER_NOT_LOGGED_IN_2114';

		// Redirect to Outcome Page.
		header("Location: " . BASE_URL . "members/results.php");

		// End script.
		exit();
	}


	// *************************************************************
	// HANDLE FORM.																								 *
	// *************************************************************
	if ($_SERVER['REQUEST_METHOD']=='POST'){
		// Form was Submitted (Post).

		// Initialize Variables.
		$errors = array();

		// Trim all Form data.
		$trimmed = array_map('trim', $_POST);

		// Connect to the database.
		require_once(WEB_ROOT . 'private/mysqli_connect.php');


		// ******************
		// Check for File.	*
		// ******************
		if (empty($_FILES['userPhoto']['tmp_name'])){
			// No File.
			$errors['upload'] = 'Choose a File.';
		}else{
			// File exists.
			$tempFile = $_FILES['userPhoto']['tmp_name'];
//			$origFilename = $_FILES['userPhoto']['name'];		//??????????????
		}//End of CHECK FOR FILE


		// ************************
		// Check Upload-Method.		*
		// ************************
		if (empty($errors)){
			if (!is_uploaded_file($tempFile)){
				// Invalid Upload Method.
				$_SESSION['resultsCode'] = 'UPLOAD_INVALID_METHOD_2115';

				// Redirect to Outcome Page.
				header("Location: " . BASE_URL . "members/results.php");

				// End script.
				exit();
			}else{
				// Valid Upload Method.
				// Continue Processing Upload...
			}
		}//End of CHECK UPLOAD-METHOD


		// ********************
		// Check File-Size.		*
		// ********************
		if (empty($errors)){
			// Check File-Size in Bytes.
			if (filesize($tempFile)<4000){
				// File too small.
				$errors['upload'] = 'File-size must be greater than 4 Kilobytes.';
			}elseif (filesize($tempFile)>100000){
				// File too big.
				$errors['upload'] = 'File-size must be less than 100 Kilobytes.';
			}else{
				// File-Size Okay.
				// Continue Processing Upload...
			}
		}//End of CHECK FILE-SIZE


		// ********************
		// Check File-Type.		*
		// ********************
		if (empty($errors)){
			if ($imageDetails = getimagesize($tempFile)){
				// Image-Array Exists.
				// File is Image.
				$imageType = $imageDetails['mime'];

				// ************************
				// Determine Image-Type.	*
				// ************************
				if ($imageType !== 'image/gif' &&
						$imageType !== 'image/jpeg' &&
						$imageType !== 'image/png'){
					// Invalid Image-Type.
					$errors['upload'] = 'Image-Type must be either GIF, JPG, or PNG.';
				}else{
					// Valid Image-Type.
					// Continue Processing Upload...
				}//End of DETERMINE IMAGE-TYPE
			}else{
				// No Image-Array.
				// File is Not Image.
				$errors['upload'] = 'Only Images can be uploaded (i.e. GIF, JPG, or PNG).';
			}//End of GETIMAGESIZE
		}//End of CHECK FILE-TYPE


		// ************************************************
		// Manipulate Image with GD.											*
		// ************************************************

		// **********************
		// Convert Image File.	*
		// **********************
		if (empty($errors)){

			// **************
			// Load Image.	*
			// **************
//$tempFile=999;
//You could run a file_exists() or is_readable() first.
//HAD TO ADD AMPERSANDS TO AVOID ERRORS.  HOW TO FIX???
			// Assign "Image Identifier" representing the image based on given filename.
			switch ($imageType){
				case 'image/gif':
					$origImage=@imagecreatefromgif($tempFile);
//					$origImage=imagecreatefromgif($tempFile);
					break;

				case 'image/jpeg':
					$origImage=@imagecreatefromjpeg($tempFile);
					break;

				case 'image/png':
					$origImage=@imagecreatefrompng($tempFile);
					break;

				default:
					$origImage=FALSE;
			}

			if ($origImage === FALSE){
				// Load Image Failed.
				$_SESSION['resultsCode'] = 'UPLOAD_LOAD_IMAGE_FAILED_2116';

				// Redirect to Outcome Page.
				header("Location: " . BASE_URL . "members/results.php");

				// End script.
				exit();
			}//End of LOAD IMAGE


			// ****************************
			// Calculate New Dimensions.	*
			// ****************************

			// Capture Dimensions on Original Image.
			$origWidth = imageSX($origImage);
			$origHeight = imageSY($origImage);

			if ($origWidth > $origHeight){
				$newWidth = 100;
				$multiplier = $newWidth/$origWidth;
				$newHeight = $origHeight * $multiplier;
			}

			if ($origWidth < $origHeight){
				$newHeight = 100;
				$multiplier = $newHeight/$origHeight;
				$newWidth = $origWidth * $multiplier;
			}

			if ($origWidth == $origHeight){
				$newWidth = 100;
				$newHeight = 100;
			}//End of CALCULATE NEW DIMENSIONS


			// ******************************
			// Create New TrueColor Image.	*
			// ******************************

//HAD TO ADD AMPERSAND TO AVOID ERRORS.  HOW TO FIX???
			// Return "Image Identifier" representing a black image of the specified size.
			$newImage = @imagecreatetruecolor($newWidth, $newHeight);

			if ($newImage === FALSE){
				// Process Failed.
				$_SESSION['resultsCode'] = 'UPLOAD_TRUE_COLOR_FAILED_2117';

				// Redirect to Outcome Page.
				header("Location: " . BASE_URL . "members/results.php");

				// End script.
				exit();
			}//End of CREATE TRUECOLOR IMAGE


			// ************************
			// Copy & Resize Image.		*
			// ************************

//HAD TO ADD AMPERSAND TO AVOID ERRORS.  HOW TO FIX???
			// Copy & Resize part of an image with resampling
			$resizedImage = @imagecopyresampled($newImage, $origImage, 0, 0, 0, 0, $newWidth, $newHeight, $origWidth, $origHeight);

			if ($resizedImage === FALSE){
				// Resize Failed.
				$_SESSION['resultsCode'] = 'UPLOAD_IMAGE_RESIZE_FAILED_2118';

				// Redirect to Outcome Page.
				header("Location: " . BASE_URL . "members/results.php");

				// End script.
				exit();
			}//End of RESIZE IMAGE


			// ********************
			// Hash New Image.		*
			// ********************
			$newFilename = sha1_file($tempFile);

			if (!$newFilename){
				// Hashing Failed.
				$_SESSION['resultsCode'] = 'UPLOAD_HASH_IMAGE_FAILED_2119';

				// Redirect to Outcome Page.
				header("Location: " . BASE_URL . "members/results.php");

				// End script.
				exit();
			}


			// ********************
			// Assign Form Data.	*
			// ********************
			$photoLabel = $trimmed['photoLabel'];


			// ************************
			// Create New Filename.		*
			// ************************
			$newFilePath = WEB_ROOT . 'uploads/' . $newFilename;

/*
			// ************************
			// Check New File Exist.	*
			// ************************
			$path_parts = pathinfo($newFilePath);
			echo $path_parts['filename'];
//			if (file_exists(WEB_ROOT . 'uploads/' . $path_parts['filename'])){
			if (file_exists(WEB_ROOT . 'uploads/' . 'f21190299a795e9cf3439f7f62c223f79e023ab7.jpg')){
				echo 'TRUE';
				exit();
			}
*/

			// ********************
			// Create New Image.	*
			// ********************

//HAD TO ADD AMPERSANDS TO AVOID ERRORS.  HOW TO FIX???
			// New File to have same File-Type as Original File.
			switch ($imageType){
				case 'image/gif':
					$newThumbnail = @imagegif($newImage, $newFilePath . '.gif');
					break;

				case 'image/jpeg':
					$newThumbnail = @imagejpeg($newImage, $newFilePath . '.jpg');
					break;

				case 'image/png':
					$newThumbnail = @imagepng($newImage, $newFilePath . '.png');
					break;

				default:
					$newThumbnail = FALSE;
			}

			if ($newThumbnail === FALSE){
				// Create Thumbnail Failed.
				$_SESSION['resultsCode'] = 'UPLOAD_CREATE_THUMBNAIL_FAILED_2120';

				// Redirect to Outcome Page.
				header("Location: " . BASE_URL . "members/results.php");

				// End script.
				exit();
			}else{
				// Create Thumbnail Succeeded.

				// ************************
				// Update Member Record.	*
				// ************************

				// Build query.
				$q1 = "UPDATE member
								SET photo_name=?,
										photo_label=?,
										updated_on=NOW()
								WHERE id=?
								LIMIT 1";

				// Prepare statement.
				$stmt1 = mysqli_prepare($dbc, $q1);

				// Bind variables to query.
				mysqli_stmt_bind_param($stmt1, 'sss', $newFilename, $photoLabel, $memberID);

				// Execute query.
				mysqli_stmt_execute($stmt1);

				// Verify Update.
				if (mysqli_stmt_affected_rows($stmt1)!==1){
					// Update Failed.
					$_SESSION['resultsCode'] = 'UPLOAD_UPDATE_RECORD_FAILED_2121';
				}else{
					// Update Succeeded.
					$_SESSION['resultsCode'] = 'UPLOAD_THUMBNAIL_RECORD_CREATED_2122';
				}//End of UPDATE MEMBER RECORD

				// Close prepared statement.
				mysqli_stmt_close($stmt1);

				// Close the connection.
				mysqli_close($dbc);

				// Redirect to Display Outcome.
				header("Location: " . BASE_URL . "members/results.php");

				// End script.
				exit();
			}//End of CREATE NEW IMAGE

		}//End of CONVERT IMAGE FILE

	}else{
		// Form was not Submitted (Get).
		// Drop through to display Form.
	}//End of HANDLE FORM
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
	<!-- ################## DEBBIE ##################### -->
	<!-- HTML Metadata -->
	<title>Upload a Photo</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<meta name="description" content="" />
	<meta name="keywords" content="" />

	<!-- Page Stylesheets -->
	<link type="text/css" rel="stylesheet" href="/css/_main.css" />
	<link type="text/css" rel="stylesheet" href="/css/_layout.css" />
	<link type="text/css" rel="stylesheet" href="/css/top_menu.css" />
	<link type="text/css" rel="stylesheet" href="/css/components.css" />
</head>

<body>
  <div id="pageWrapper" class="clearfix">
    <div id="pageInner">
			<!-- BODY HEADER -->
			<?php	require_once(WEB_ROOT . 'components/body_header.inc.php');	?>


			<!-- MIDDLE COLUMN -->
			<div id="pageMidCol_1">

				<!-- UPLOAD PHOTO FORM -->
				<form id="uploadPhoto" enctype="multipart/form-data"
							action="<?php echo $_SERVER['SCRIPT_NAME']; ?>" method="post">
					<fieldset>
						<legend>Upload a Photo</legend>

						<!-- User Photo -->
						<label for="userPhoto">Filename:</label>
						<input id="userPhoto" name="userPhoto" type="file" />
						<?php
							if (!empty($errors['upload'])){
								echo '<span class="error">' . $errors['upload'] . '</span>';
							}
						?>

						<!-- Photo Label -->
						<label for="photoLabel">Photo Label:</label>
						<input id="photoLabel" name="photoLabel" type="text" maxlength="20"
								value="<?php if(isset($photoLabel)){echo htmlspecialchars($photoLabel, ENT_QUOTES);} ?>" /><!-- Sticky Field -->
						<?php
							if (!empty($errors['photoLabel'])){
								echo '<span class="error">' . $errors['photoLabel'] . '</span>';
							}
						?>
						<br />
						
						<!-- Submit Form -->
						<input type="submit" name="uploadPhoto" class="button" value="Upload Photo"/>

						<!-- Message -->
						<?php
							if (!empty($messages['upload'])){
								echo '<span class="error">' . $messages['upload'] . '</span>';
							}
						?>
					</fieldset>
				</form>
			</div><!-- End of #MIDDLE -->

		</div><!-- End of #INNER -->
	</div><!-- End of #WRAPPER -->


	<!-- BODY FOOTER -->
	<?php	require_once(WEB_ROOT . 'components/body_footer.inc.php');	?>
</body>
</html>

Thanks,

Debbie

Hi Debbie,

Looking pretty good. However you should sanitize all input… this includes sessions. One way to do this is to create a $clean array, run your session variables through a cleaning function, and then store the clean variable in the $clean array like:


$clean = array()
$clean['resultsTitle'] = clean($_SESSION['resultsTitle']);

if($clean['resultsTitle']){
  $title = '';
  $title = $clean['resultsTitle']; // You know this data is clean

function clean($dirty_data){
 //methods of cleaning your data;
 return $clean_data
}

If your session gets hacked then people can tamper with the session data.

Hope this doesn’t throw a wrench into the works?

Regards,
Steve

Well sessions are pretty safe unless you put raw user supplied data into it. Sessions themselves are not accessible to the outside world. The only think a user could do to mess with sessions is to tamper with the session cookie that contains the ID.