Mark’s Site

Pensieve for coding and golf :-)

File Uploads

By admin • Apr 28th, 2008 • Category: 3.2. Useful Classes

This is a useful class I picked up somewhere, and possibly modified in the years since, that handles the work of file uploads. I’ve found it very useful, so hopefully you will to.

Firstly I’ll show you code to use this class. Create your form, taking careful note to include the enctype tag in the form, and MAX_FILE_SIZE field. In this case, the file field is called user_file. I also use a form1_submit field so I can easily catch this form submission.

<form name=”form1″ action=”" method=”post” enctype=”multipart/form-data” >
<input name=”form1_submit” id=”form1_submit” type=”hidden” value=”1″ />
<input type=”hidden” name=”MAX_FILE_SIZE” value=”1024000″ >
<input name=”user_file” id=”user_file” type=”file” class=”input” >
</form>

If the above form was included in our php file, we would catch form requests and process the upload as follows:

<?php
//message variable to tell us what has happened through this upload
$msg = '';
//catch form submission
if($_POST['form1_submit'] == '1') {
	//now upload the actual file
	$file_error = false;
	$upload_class = new Upload_Files;
	if($_FILES['user_file']['size'] > 0){
		$upload_class->temp_file_name = trim($_FILES['user_file']['tmp_name']);
		//prepare filename
		//I md5 the filename, so filenames can not be easily guessed by hackers should they somehow get past my folder security (have all your folders set to 755!)
		$fn1 = $_FILES['user_file']['name']; //Eg: filename = project1.doc
		//grab the file's extension (as i am md5ing the filename, I'll need the extension again)
		$extension = strtolower(strrchr($fn1,".")); //Eg: .doc
		//md5 the filename, adding back on the extension
		$fn1 = md5($fn1.time()).$extension;
		//set our class info
		$upload_class->file_name = $fn1; //Eg: filename will now be something like e343uwer0809809werwer.doc
		$upload_class->upload_dir = SITE_UPLOADS_DIR; //this is a constant of my site
		$upload_class->upload_log_dir = SITE_UPLOADS_DIR; //this is a constant of my site
		$upload_class->max_file_size = MAX_FILE_SIZE; //this is a constant of my site
		$upload_class->ext_array = $SITE_FILE_UPLOAD_EXTENSIONS; //this is a constant of my site
		//validation
		$valid_ext = $upload_class->validate_extension(); //class takes care of extension checking
		$valid_size = $upload_class->validate_size(); //class takes care of size checking
		$file_size = $upload_class->get_file_size(); //class tells me how big the uploaded file is
		$file_exists = $upload_class->existing_file(); //class tells me if this file already exists in my uploads folder
		//in rare case of same name, do this
		$max_rename = 0;
		while ($file_exists == true && $max_rename < 10) { //most times this will run is 10, so no chance of infinite
			$fn1 = md5($fn1.time()).$extension;
			$upload_class->file_name = $fn1;
			$file_exists = $upload_class->existing_file();
			$max_rename++;
		}
		//if still same name, remove existing
		if($file_exists == true) {
			unlink($directory_location.SITE_UPLOADS_DIR.$upload_class->file_name);
		}
		//start validation
		//I use PHP ftp commands to change my uplodas folder permissions to 777 while I upload the file, then set them back again to 755 when file has finished uploading (this allows my files to be publicly available (which i need) and stops me from leaving uploads folder open to hackers)
		//Check the necessary functions exist for what I'll be doing
		if (function_exists('ftp_connect') && function_exists('ftp_login') && function_exists('ftp_site') && function_exists('ftp_close')) {
			//open full write permissions for php file upload
			changemode(777, SITE_UPLOADS_DIR);
			//check validation status and upload file
			if ((int)$id == 0){
				$msg .= 'No document id found';
				$file_error = true;
			} elseif (!$valid_ext){
				$msg .= 'The file extension is invalid, please try again!';
				$file_error = true;
			} elseif (!$valid_size){
				$msg .= 'The file size is invalid, please try again!';
				$file_error = true;
			} else {
				$upload_file = $upload_class->upload_file_with_validation();
				if (!$upload_file){
					$msg .= 'Your file could not be uploaded!';
					$file_error = true;
				} else {
					$msg .= 'File successfully uploaded!';
					//insert our document
					//this is another class I have to track uploaded files, you can ignore
					$params = array(
						'id' => $id,
						'filename' => $upload_class->file_name,
						'filepath' => SITE_UPLOADS_DIR,
						'filesize' => $file_size,
						'filetype' => ''
					);
					$document_object = new Document();
					$document_object->db_update($params);
				}
			}
			//close off full write permissions for php file upload
			changemode(755, SITE_UPLOADS_DIR);
		} else {
			$msg .= 'To upload files, I require PHPs ftp_connect, ftp_login, ftp_site and ftp_close functions. One or more of these is not available.';
		}
	} else {
		$msg .= 'File was found to contain no data.';
	}
	//success or error ...what has happened?
	if($file_error == true){
		//report error
		echo $msg
	} else {
		//success
		echo $msg
	}
}
... HTML form would be shown down here somewhere probably
?>

So this is the class that the above PHP uses to process my file uploads. This does all the mundane work for me :-)

<?php
class Upload_Files
{
	//private variables
	var $temp_file_name;
	var $file_name;
	var $upload_dir;
	var $upload_log_dir;
	var $max_file_size;
	var $banned_array;
	var $ext_array;

	/**
	* Validate Extension
	* validate extensions passed to object
	*/
	function validate_extension() {
		//SECTION #1
		$file_name = trim($this->file_name);
		$extension = strtolower(strrchr($file_name,"."));
		$ext_array = $this->ext_array;
		$ext_count = count($ext_array);
		$valid_extension = '';

		if (!$file_name) {
			return false;
		} else {
			if (!$ext_array) {
				return true;
			} else {
				foreach ($ext_array as $value) {
					$first_char = substr($value,0,1);
						if ($first_char <> ".") {
							$extensions[] = ".".strtolower($value);
						} else {
							$extensions[] = strtolower($value);
						}
				}
				foreach ($extensions as $value) {
					if ($value == $extension) {
						$valid_extension = "TRUE";
					}
				}
				if ($valid_extension) {
					return true;
				} else {
					return false;
				}
			}
		}
	}

	/**
	* Validate Size
	* validate size based on parameter passed to object
	*/
	function validate_size() {
		$temp_file_name = trim($this->temp_file_name);
		$max_file_size = trim($this->max_file_size);

		if ($temp_file_name) {
			$size = filesize($temp_file_name);
				if ($size > $max_file_size) {
					return false;
				} else {
					return true;
				}
		} else {
			return false;
		}
	}

	/**
	* Existing File
	* checks if the file already exists in server location
	*/
	function existing_file() {
		$file_name = trim($this->file_name);
		$upload_dir = $this->get_upload_directory();
		if ($upload_dir == "ERROR") {
			return true;
		} else {
			$file = $upload_dir . $file_name;
			if (file_exists($file)) {
				return true;
			} else {
				return false;
			}
		}
	}

	/**
	* Get File Size
	* gets the size of the file and returns it with appropriate extension ...Meg, Gig, etc
	*/
	function get_file_size() {
		//SECTION #1
		$temp_file_name = trim($this->temp_file_name);
		$kb = 1024;
		$mb = 1024 * $kb;
		$gb = 1024 * $mb;
		$tb = 1024 * $gb;
		$file_size = '';

		if ($temp_file_name) {
			$size = filesize($temp_file_name);
			if ($size < $kb) {
				$file_size = "$size Bytes";
			} elseif ($size < $mb) {
				$final = round($size/$kb,2);
				$file_size = "$final KB";
			} elseif ($size < $gb) {
				$final = round($size/$mb,2);
				$file_size = "$final MB";
			} elseif($size < $tb) {
				$final = round($size/$gb,2);
				$file_size = "$final GB";
			} else 	{
				$final = round($size/$tb,2);
				$file_size = "$final TB";
			}
		} else {
			$file_size = "ERROR: NO FILE PASSED TO get_file_size()";
		}
		return $file_size;
	}

	/**
	* Get Max File Size
	* gets max file size based on parameter passed to object
	*/
	function get_max_size() {
		$max_file_size = trim($this->max_file_size);
		$kb = 1024;
		$mb = 1024 * $kb;
		$gb = 1024 * $mb;
		$tb = 1024 * $gb;
		$max_file_size = '';

		if ($max_file_size) {
			if ($max_file_size < $kb) {
				$max_file_size = "max_file_size Bytes";
			} elseif ($max_file_size < $mb) {
				$final = round($max_file_size/$kb,2);
				$max_file_size = "$final KB";
			} elseif ($max_file_size < $gb) {
				$final = round($max_file_size/$mb,2);
				$max_file_size = "$final MB";
			} elseif($max_file_size < $tb) {
				$final = round($max_file_size/$gb,2);
					$max_file_size = "$final GB";
			} else {
				$final = round($max_file_size/$tb,2);
				$max_file_size = "$final TB";
			}
		} else {
			$max_file_size = "ERROR: NO SIZE PARAMETER PASSED TO  get_max_size()";
		}
		return $max_file_size;
	}

	/**
	* Validate User
	* allows you to create a banned IP list so certain users can't upload ..stops trouble makers
	*/
	function validate_user() {
		//SECTION #1
		$banned_array = $this->banned_array;
		$ip = trim($_SERVER['REMOTE_ADDR']);
		$cpu = gethostbyaddr($ip);
		$count = count($banned_array);

		if ($count < 1) {
			return true;
		} else {
			foreach($banned_array as $key => $value) {
				if ($value == $ip ."-". $cpu) {
					return false;
				} else {
					return true;
				}
			}
		}
	}

	/**
	* Upload Directory
	* gets the set upload directory path
	*/
	function get_upload_directory() {
		$upload_dir = trim($this->upload_dir);

		if ($upload_dir) {
			$ud_len = strlen($upload_dir);
			$last_slash = substr($upload_dir,$ud_len-1,1);
			if ($last_slash <> "/") {
				$upload_dir = $upload_dir."/";
			} else {
				$upload_dir = $upload_dir;
			}
			$handle = @opendir($upload_dir);
			if ($handle) {
				$upload_dir = $upload_dir;
				closedir($handle);
			} else {
				$upload_dir = "ERROR";
			}
		} else {
			$upload_dir = "ERROR";
		}
		return $upload_dir;
	}

	/**
	* Log Directory
	* gets the log directory ...where we store logs about uploads to track what has been happening
	*/
	function get_upload_log_directory() {
		$upload_log_dir = trim($this->upload_log_dir);
		if ($upload_log_dir) {
			$ud_len = strlen($upload_log_dir);
			$last_slash = substr($upload_log_dir,$ud_len-1,1);
			if ($last_slash <> "/") {
				$upload_log_dir = $upload_log_dir."/";
			} else {
				$upload_log_dir = $upload_log_dir;
			}
			$handle = @opendir($upload_log_dir);
			if ($handle) {
				$upload_log_dir = $upload_log_dir;
				closedir($handle);
			} else {
				$upload_log_dir = "ERROR";
			}
		} else {
			$upload_log_dir = "ERROR";
		}
		return $upload_log_dir;
	}

	/**
	* Upload with NO validation
	* uploads a file with NO validation
	*/
	function upload_file_no_validation() {
		//SECTION #1
		$temp_file_name = trim($this->temp_file_name);
		$file_name = trim(strtolower($this->file_name));
		$upload_dir = $this->get_upload_directory();
		$upload_log_dir = $this->get_upload_log_directory();
		$file_size = $this->get_file_size();
		$ip = trim($_SERVER['REMOTE_ADDR']);
		$cpu = gethostbyaddr($ip);
		$m = date("m");
		$d = date("d");
		$y = date("Y");
		$date = date("m/d/Y");
		$time = date("h:i:s A");

		if (($upload_dir == "ERROR") OR ($upload_log_dir == "ERROR")) {
			return false;
		} else {
			if (is_uploaded_file($temp_file_name)) {
				if (move_uploaded_file($temp_file_name,$upload_dir . $file_name)) {
					$log = $upload_log_dir.$y."_".$m."_".$d.".txt";
					$fp = fopen($log,"a+");
					fwrite($fp,"$ip-$cpu | $file_name | $file_size | $date | $time");
					fclose($fp);
					return true;
				} else {
					return false;
				}
			} else {
				return false;
			}
		}
	}

	/**
	* Upload with validation
	* upload file with said validation
	*/
	function upload_file_with_validation() {
		//SECTION #1
		$temp_file_name = trim($this->temp_file_name);
		$file_name = trim(strtolower($this->file_name));
		$upload_dir = $this->get_upload_directory();
		$upload_log_dir = $this->get_upload_log_directory();
		$file_size = $this->get_file_size();
		$ip = trim($_SERVER['REMOTE_ADDR']);
		$cpu = gethostbyaddr($ip);
		$m = date("m");
		$d = date("d");
		$y = date("Y");
		$date = date("m/d/Y");
		$time = date("h:i:s A");
		$existing_file = $this->existing_file();    //<-Add On
		$valid_user = $this->validate_user();        //<-Add On
		$valid_size = $this->validate_size();        //<-Add On
		$valid_ext = $this->validate_extension();    //<-Add On

		if (($upload_dir == "ERROR") OR ($upload_log_dir == "ERROR")) {
			return false;
		} elseif ((((!$valid_user) OR (!$valid_size) OR (!$valid_ext) OR ($existing_file)))) {
			return false;
		} else {
			if (is_uploaded_file($temp_file_name)) {
				if (move_uploaded_file($temp_file_name,$upload_dir . $file_name)) {
					$log = $upload_log_dir.$y."_".$m."_".$d.".txt";
					$fp = fopen($log,"a+");
					fwrite($fp,"$ip-$cpu | $file_name | $file_size | $date | $time");
					fclose($fp);
					return true;
				} else {
					return false;
				}
			} else {
				return false;
			}
		}
	}
} //end class
?>

You may have noticed a function I used to change folder permissions on server …here it is:

<?php
function changemode($mod, $path)
{
   //call the required site constants
   global $FTP_HOST,$FTP_USERNAME,$FTP_PASSWORD,$FTP_ROOTDIR;
   // set up basic connection
   $conn_id = ftp_connect($FTP_HOST);

   // login with username and password
   $login_result = ftp_login($conn_id, $FTP_USERNAME, $FTP_PASSWORD);

   // try to chmod $path directory
   if (ftp_site($conn_id, 'CHMOD '.$mod.' '.$FTP_ROOTDIR.$path) !== false) {
       $success=TRUE;
   }
   else {
       $success=FALSE;
   }

   // close the connection
   ftp_close($conn_id);
	return $success;
}
?>

admin is
Email this author | All posts by admin

Leave a Reply