Jump to content

Recommended Posts

Hi All,

 

Would really appreciate some help.. Our website visitors upload photos to our site and I would the files to be renamed to avoid files being over written. 

 

Upload.PHP script is as follows :-

 

<?php

if($_SERVER['REQUEST_METHOD'] == "POST"){
if(move_uploaded_file($_FILES['file']['tmp_name'], "uploads/".$_FILES['file']['name'])){
echo($_POST['index']);
}
exit;
}
?>
 
Please can you advise what I need to change to ensure all files are renamed during / after the upload? We would like the file names to be a number 1 to 99 for example.
 
Thanks in advance!
 
Will
 
Link to comment
https://forums.phpfreaks.com/topic/296923-renaming-file-upload/
Share on other sites

I have a upload class I built that is very easy to use and allows unique naming of files. Plus if even a unique named file some how already exists in the folder, it can append a number notation to the file name. Now granted it's not designed to increment a file name internally, but it does have a class method to set the end file name. The method still uses the extension of the uploaded file, but will set the actual file name to what you tell it.

So in order to do it dynamically, you would maybe have to store all the file names in a database and use the auto-increment number of the row to set the filename of the upload. Or read the folder first and figure out what the highest number filename is in there and +1 it. Honestly that is not a good way to do it cause if more than one upload is happening at the same time, you could easily overwrite a file.

I honestly don't know if a htaccess is going to stop a bad image upload from executing code within it. Some best practices are to place the upload folder outside the root of the website so the uploader person can't access the folder in any way. Then set the folder permissions to 0700 so it can only be accessed by the php script. Then I use a serve-image script to display the image safely. Here is that file.

serve-image.php

$path = KEY_UPL_FOLDER; // Set your own path here
$img_path = $path.$_GET['image'];

$files = glob($path."*.{jpg, jpeg}", GLOB_BRACE); // Change the {jpg, jpeg} to the extensions the glob() should look for files, typically match what the upload extensions you set.

if(in_array($img_path, $files))
{
	header('Content-Type: image/jpeg');
	readfile($img_path);
}

Then call the image in a script like this

// $image being the filename
<?php echo '<img src-"serve-image.php?image='.$image.'">'; ?>

There are full working examples at the top of the script. Make sure to read all the comments. Understand though, this was built to work on php 5.5 or higher. If you have a lower version php, the main things that would need to be edited is the use of [ ] for arrays compared to array() in older versions. I think I removed or edited everything that would make this work on any site. I had certain things in there that were specific to my CMS cause this wasn't really designed to be portable outside the CMS.

I hope this gets you going anyway.

Upload.class.php

<?php

/******* EXAMPLE CODE *******************************
Example useage for multiple file upload:

if(isset($_POST['submit']))
{
	$sep_files = Upload::filesArraySeparation($_FILES['file1']); // REQUIRED
	
	foreach($sep_files as $file_array) // REQUIRED
	{
		$u = new Upload('file1', 'image', $file_array); // 3rd param required and set to array item from foreach loop
		$u->setMaxImageFileSize('1.2mb');
		$u->setImageExts(['jpg', 'png']);
		$u->setSaveFolder('images/t3/init');
		$u->queValidated(TRUE);
		$u->uniqueName(TRUE);
		$u->overwriteFile(FALSE);
		
		if($u->hasUpload(TRUE)) // MUST set hasUpload to TRUE
		{
			$u->validate();
		
			//echo Errors::setOut($u->errors()); // Optional, handle errors how you like
		}
	}
	
	$u->setQuedResults(); // REQUIRED
	$u->quedMove(); // REQUIRED
	diagDiv($u->getQuedFinalResults());
	
	//diagDiv($u->fullDump());
	//print_r($_SESSION['validated_uploads']);
}

<form action="" method="post" enctype="multipart/form-data">
	<input type="file" name="file1[]" multiple="multiple">
	<input type="submit" name="submit" value="Submit">
</form>

********************************************************
Another example with moving the file immediately after validation with multiple files uploaded:

if(isset($_POST['submit']))
{
	$sep_files = Upload::filesArraySeparation($_FILES['file1']); // REQUIRED
	
	foreach($sep_files as $file_array) // REQUIRED
	{
		$u = new Upload('file1', 'image', $file_array); // 3rd param required and set to array item from foreach loop
		$u->setMaxImageFileSize('1.2mb');
		$u->setImageExts(['jpg', 'png']);
		$u->setSaveFolder('images/t3/init');
									
									// Removed $u->queValidated(TRUE); so the class uses normal single item processes.
									
		$u->uniqueName(TRUE);
		$u->overwriteFile(FALSE);
		
		if($u->hasUpload(TRUE)) // MUST set hasUpload to TRUE
		{
			$u->validate();
			$u->move();
		
			echo Errors::setOut($u->errors()); // Optional, handle errors how you like
		}
	}
}

<form action="" method="post" enctype="multipart/form-data">
	<input type="file" name="file1[]" multiple="multiple">
	<input type="submit" name="submit" value="Submit">
</form>


********************************************************
Example usage for single file upload:

if(isset($_POST['submit']))
{
	$u = new Upload('file1', 'image');
	$u->setMaxImageFileSize('1.2mb');
	$u->setImageExts(['jpg', 'png']);
	$u->setSaveFolder('images/t3/init');
	$u->uniqueName(TRUE);
	$u->overwriteFile(FALSE);
	
	if($u->hasUpload())
	{
		$u->validate();
	
		echo Errors::setOut($u->errors()); // Optional, handle errors how you like
	}
	
	$u->move(); // REQUIRED
	
	//diagDiv($u->fullDump());
}

<form action="" method="post" enctype="multipart/form-data">
	<input type="file" name="file1">
	<input type="submit" name="submit" value="Submit">
</form>

*******************************************************/

class Upload
{
	protected $allowed_img_exts;
	protected $allowed_file_exts;
	
	/**********************************************
	Max file sizes can be provided in several formats.
	Examples:
		1000 which would be 1000 bytes.
		180k or 180kb would be 180 kilobytes
		1.2m or 1.2mb would be 1.2 megabytes
		1.2g or 1.2 gb would be 1.2 gigabytes
	Uppercase and lowercase notation supported.
	***********************************************/
	protected $max_img_file_size; // Defined in bytes i.e. 200000, k, kb, m, mb, g, gb
	protected $max_doc_file_size; // Defined in bytes i.e. 200000, k, kb, m, mb, g, gb
	protected $save_folder; // Creates folder with provided/default chmod if folder does not exist. Trailing slash is optional
	protected $thumb_save_folder; // Creates folder with provided/default chmod if folder does not exist. Trailing slash is optional
	protected $save_folder_chmod = 0755;
	protected $thumb_save_folder_chmod = 0755;
	protected $input_name; // Name of the file input field. Arrayed file inputs not supported.
	protected $files; // The array data from the uploaded file.
	public	  $file_name;
	protected $file_base_name;
	protected $file_ext;
	protected $max_img_width; // If not declared any size will be available until file size is exceeded
	protected $max_img_height; // If not declared any size will be available until file size is exceeded
	protected $min_img_width;
	protected $min_img_height;
	protected $restrict_img_size = FALSE; // Set to TRUE if image must be the provided width and height.
	protected $valid = FALSE;
	protected $errors = [];
	protected $create_unique_name = FALSE;
	protected $set_file_name;
	public	  $unique_name;
	protected $upload_file_type; // Values can be image or doc.  Used to determine what kind of things to check against.
	protected $overwrite_file = TRUE; // Set to false to make a new name for uploaded file if another file with the same name already exists. Appends a _ and incrementing number.
	protected $image_size_passed = FALSE;
	protected $image_width;
	protected $image_height;
	protected $image_mime;
	protected $que_validated = FALSE;
	protected $qued_results = [];
	protected $qued_final_results = []; // Values set in quedMove() if move is successful
	protected $bytes; //Number of bytes in a single MB.
	protected $k_bytes; // KB
	protected $ini_max_file_size; // PHP ini max upload file size parameter
	protected $is_uploaded = FALSE;
	protected $final_file_name; // Value is set if move() is successful
	protected $final_full_path; // Value is set if move() is successful
	protected $moved = FALSE; // Will be TRUE if move() is successful
	
	
	// Provide the file input name
	// Type is either image or doc depending on what kind of file you are validating
	public function __construct($input_name, $type, $array = [])
	{
		$this->isUploaded($input_name, $array);
		//$this->files = (is_array($_FILES[$input_name]['name'])) ? filesArraySeparation($_FILES[$input_name]) : $_FILES[$input_name];
		
		$this->input_name = $input_name;
		$this->upload_file_type = $type;
		$this->bytes = $bytes = 1024 * 1024;
		$this->k_bytes = 1024;
		$this->ini_max_file_size = $this->calculateMaxFileSize(ini_get('upload_max_filesize'), 'ini');
		
		// Predefine default parameters here or set them with the class methods.
		$this->allowed_img_exts = [];
		$this->allowed_file_exts = [];
		$this->max_img_file_size = 0;
		$this->max_doc_file_size = 0; 
	}
	
	// Returns the full upload object
	public function fullDump()
	{ return $this; }
	
	// Returns an array of upload errors
	public function errors()
	{ return $this->errors; }
	
	// Generally used for diagnostics
	public function valid()
	{ return $this->valid; }
	
	// Generally used for diagnostics
	public function moved()
	{ return $this->moved; }
	
	// Returns just the final named filename
	public function getFinalName()
	{ return $this->final_file_name; }
	
	// Returns a full file path to the file uploaded
	public function getFinalFullPath()
	{ return $this->final_full_path; }
	
	// Returns an array of final file info for each file uploaded ONLY when uploading multiple files
	public function getQuedFinalResults()
	{ return $this->qued_final_results; }
	
	public function hasUpload($multiple = FALSE)
	{ 
		if($multiple === TRUE)
		{ return !empty($_FILES[$this->input_name]['name'][0]); }
		else
		{ return !empty($_FILES[$this->input_name]['name']); }
	}
	
	private function isUploaded($input_name, $array)
	{
		$files_input_tmp_name = (!empty($array)) ? $array['tmp_name'] : ((isset($_FILES[$input_name]['tmp_name'])) ? $_FILES[$input_name]['tmp_name'] : FALSE);
	
		if(isset($_FILES[$input_name]) && is_uploaded_file($files_input_tmp_name))
		{ 
			$this->is_uploaded = TRUE;
			$this->files = (!empty($array)) ? $array : $_FILES[$input_name];
			$this->file_name = (!empty($array)) ? $array['name'] : $_FILES[$input_name]['name'];
			$this->extension(); 
		}
		else
		{ return FALSE; }
	}
	
	// Breaks apart a submitted files array into separate full arrays.
	// $clear = TRUE will automatically clear the session validated_uploads var upon pageload.
	// This is the typical desired result so the session var doesn't have duplicate files saved to it.
	// Set $clear to FALSE to NOT automatically clear the session que
	public static function filesArraySeparation($array, $clear = TRUE)
	{
		foreach($array as $key => $val)
		{
			foreach($val as $key2 => $val2)
			{
				$sep[$key2][$key] = $val2;
			}
		}
		
		if($clear === TRUE)
		{ self::clearQue(); }
		
		return $sep;
	}

	public static function clearQue()
	{ unset($_SESSION['validated_uploads']); }
	
	/////// Set parameters /////////////////////////////////////
	
	// Allows setting the end file name no matter what was uploaded for a file name.
	public function setFileName($name)
	{ $this->set_file_name = $name; }
	
	// Provide and array of image (not standard file) extensions to allow
	public function setImageExts(array $exts)
	{ $this->allowed_img_exts = $exts; }
	
	// Provide an array of file (not image) extensions to allow
	public function setFileExts(array $exts)
	{ $this->allowed_file_exts = $exts; }
	
	// Defined in bytes i.e. 200000, k, kb, m, mb, g, gb
	// See notes at top
	public function setMaxImageFileSize($size)
	{ $this->max_img_file_size = $this->calculateMaxFileSize($size, 'setMaxImageFileSize'); }
	
	// Defined in bytes i.e. 200000, k, kb, m, mb, g, gb
	// See notes at top
	public function setMaxDocFileSize($size)
	{ $this->max_doc_file_size = $this->calculateMaxFileSize($size, 'setMaxDocFileSize'); }
	
	// Required
	// Path to folder
	// Trailing slashes are optinal, function automatically assigns them.
	public function setSaveFolder($path)
	{ $this->save_folder = rtrim($path, '/').'/'; }
	
	// Path to folder
	// Trailing slashes are optinal, function automatically assigns them.
	public function setThumbSaveFolder($path)
	{ $this->thumb_save_folder = rtrim($path, '/').'/'; }
	
	// CHMOD does not work on Windows system
	public function setFolderChmod($num)
	{ $this->save_folder_chmod = (int)$num; }
	
	// CHMOD does not work on Windows system
	public function setThumbFolderChmod($num)
	{ $this->thumb_save_folder_chmod = (int)$num; }
	
	// Whole integers only
	// Required if restrict_img_size is set to TRUE
	public function maxImageWidth($num)
	{ $this->max_img_width = (int)$num; }
	
	// Whole integers only
	// Required if restrict_img_size is set to TRUE
	public function maxImageHeight($num)
	{ $this->max_img_height = (int)$num; }
	
	// Whole integers only
	public function minImageWidth($num)
	{ $this->min_img_width = (int)$num; }
	
	// Whole integers only
	public function minImageHeight($num)
	{ $this->min_img_height = (int)$num; }
	
	// TRUE or FALSE values, default is FALSE
	public function restrictImageSize($val)
	{ $this->restrict_img_size = $val; }
	
	// TRUE or FALSE values, default is FALSE
	public function uniqueName($val)
	{ $this->create_unique_name = $val; }
	
	// TRUE or FALSE values, default is TRUE
	public function overwriteFile($val)
	{ $this->overwrite_file = $val; }
	
	// TRUE or FALSE values, default is FALSE
	public function queValidated($val)
	{ $this->que_validated = $val; }
	
	// Sets a var to the session array of validate_uploads
	// Only used for multiple file uploads
	public function setQuedResults()
	{ $this->qued_results = (!empty($_SESSION['validated_uploads'])) ? $_SESSION['validated_uploads'] : []; }
		
	/////// END set parameters ////////////////////////////////
	
	
	// Validates the file based on settings
	public function validate()
	{
		if($this->is_uploaded === TRUE)
		{
			if($this->files['error'] > 0)
			{ $this->errors[] = 'There was a problem uploading file "'.htmlentities($this->files['name'], ENT_QUOTES).'".  Error: '.$this->files['error']; }
			else
			{			
				$this->checkExtension();
				$this->checkFileSize();
				
				if($this->upload_file_type == 'image')
				{ 
					$this->checkImageSize();
					
					if($this->image_size_passed === TRUE)
					{ 
						if($this->restrict_img_size === TRUE && (empty($this->max_img_width) || empty($this->max_img_height)))
						{ throw new Exception('Must provide a max image height and max image width when setting restrictImageSize() to TRUE'); }
						
						$this->checkImageSizing();
					} 
				}
						
				$this->valid = (empty($this->errors)) ? TRUE : $this->valid;
				
				if($this->valid === TRUE && $this->que_validated === TRUE)
				{ $_SESSION['validated_uploads'][] = $this->files; }
			}
		}
		return $this;
	} 
	
	// Moves the file to the settings folder
	public function move()
	{
		if($this->que_validated === FALSE)
		{
			if($this->valid === TRUE)
			{
				if(empty($this->save_folder))
				{ throw new Exception('No save folder has been specificed.'); }
				
				$this->checkSaveFolders();
				
				if(!empty($this->set_file_name))
				{
					$name = $this->set_file_name.'.'.$this->file_ext;
				}
				else
				{
					$name = ($this->create_unique_name === TRUE) ? $this->createUniqueName() : $this->file_base_name;
				
					$name = ($this->overwrite_file === FALSE) ? $this->checkFileExists(ROOT.$this->save_folder, $name, $this->file_ext) : $name.'.'.$this->file_ext;
				}
				
				$full_save_path = $this->save_folder.$name;
				
				if(move_uploaded_file($this->files['tmp_name'], $full_save_path) === TRUE)
				{
					$this->moved = TRUE;
					$this->final_file_name = $name;
					$this->final_full_path = $full_save_path;
				}
			}
		}
		else
		{ throw new Exception('Must use quedMove() when queValidated() is set to TRUE'); }
		
		return $this;
	}
	
	public function quedMove()
	{
		if($this->que_validated === TRUE)
		{
			if(!empty($this->qued_results))
			{
				if(empty($this->save_folder))
				{ throw new Exception('No save folder has been specificed.'); }
				
				$this->checkSaveFolders();
				
				foreach($this->qued_results as $qr)
				{
					$this->extension($qr['name']);
					
					$name = ($this->create_unique_name === TRUE) ? $this->createUniqueName() : $this->file_base_name;
					
					$name = ($this->overwrite_file === FALSE) ? $this->checkFileExists(ROOT.$this->save_folder, $name, $this->file_ext) : $name.'.'.$this->file_ext;
					
					$full_save_path = $this->save_folder.$name;
					
					if(move_uploaded_file($qr['tmp_name'], $full_save_path) === TRUE)
					{
						$this->moved = TRUE;
						$this->final_file_name = $name;
						$this->final_full_path = $full_save_path;
						
						$this->qued_final_results[] = [
							'moved' => $this->moved,
							'final_file_name' => $this->final_file_name,
							'final_full_path' => $this->final_full_path,
							'original_name' => $qr['name']
						];
					}
				}
			}
		}
		else
		{ throw new Exception('Must use move() when queValidated() is set/defaulted to FALSE'); }
		
		return $this;
	}
	
	protected function checkFileExists($path, $filename, $e)
	{
		$name = $filename;
		$ext = '.'.$e;
		
	    $newpath = $path.'/'.$filename.$ext;
	    $newname = $filename;
	    $counter = 0;
	    while (file_exists($newpath)) 
	    {
			$newname = $name .'_'. $counter . $ext;
			$newpath = $path.'/'.$newname;
			$counter++;
	    }
		
	    return ($newname == $filename) ? $newname.$ext : $newname;
	}
	
		
	protected function createUniqueName()
	{
		return $this->unique_name = uniqid();
	}
	
	protected function cleanName()
	{
		$this->file_base_name = str_replace(array(" ", "%20"), "_", strtolower($this->file_base_name));
		return $this;
	}
	
	protected function extension($name = FALSE)
	{
		$file_info = (!empty($name)) ? explode(".", $name) : explode(".", $this->files['name']);
		
		$ext = end($file_info);
		$ext = strtolower($ext);
		
		$this->file_base_name = $file_info[0];
		$this->cleanName(); 
		$this->file_ext = $ext;
		
		return $this;
	}
	
	protected function checkExtension()
	{
		$extensions = ($this->upload_file_type == 'image') ? $this->allowed_img_exts : $this->allowed_file_exts;
		
		if(!in_array($this->file_ext, $extensions))
		{ $this->errors[] = 'File extension .'.htmlentities($this->file_ext, ENT_QUOTES).' not allowed for file "'.htmlentities($this->file_name, ENT_QUOTES).'"'; }
		
		return $this;
	}
	
	protected function checkImageSize()
	{
		$size = getimagesize($this->files['tmp_name']);
		
		if($size === FALSE)
		{ $this->errors[] = 'File "'.htmlentities($this->files['name'], ENT_QUOTES).'" is not an actual image file.'; }
		else
		{
			$this->image_width = $size[0]; // Width
			$this->image_height = $size[1]; // Height
			$this->image_mime = $size['mime'];
			$this->image_size_passed = TRUE;
		}
		
		return $this;
	}
	
	protected function checkImageSizing()
	{
		if($this->restrict_img_size === TRUE && ($this->image_width != $this->max_img_width || $this->image_height != $this->max_img_height))
		{ $this->errors[] = "The image must be ".$this->max_img_width." pixels in width and ".$this->max_img_height." pixels in height."; }		
		else
		{
			if(!empty($this->min_img_width) && $this->image_width < $this->min_img_width)
			{ $this->errors[] = "The image must be at least ".$this->min_img_width." pixels in width."; }
			
			if(!empty($this->min_img_height) && $this->image_height < $this->min_img_height)
			{ $this->errors[] = "The image must be at least ".$this->min_img_height." pixels in height."; }
			
			if(!empty($this->max_img_width) && $this->image_width > $this->max_img_width)
			{ $this->errors[] = "The image must not be greater than ".$this->max_img_width." pixels in width."; }
		
			if(!empty($this->max_img_height) && $this->image_height > $this->max_img_height)
			{ $this->errors[] = "The image must not be greater than ".$this->max_img_height." pixels in height."; }
		}
				
		return $this;
	}
	
	protected function checkAgainstIni($size, $function)
	{
		$e = 'Function '.$function.' is trying to set a max file size limit higher than the PHP ini setting.';
		if($function != 'ini' && $size > $this->ini_max_file_size)
		{ throw new Exception($e); }
		
		return $this;
	}
	
	protected function calculateMaxFileSize($size, $function)
	{	
		if(is_numeric($size))
		{ 
			$this->checkAgainstIni($size, $function);				
			return $size; 
		}
		else
		{
			if(stripos($size, 'm'))
			{ 
				$new_size = (float)$size * $this->bytes;
				$this->checkAgainstIni($new_size, $function); 
			}
			elseif(stripos($size, 'k'))
			{ 	
				$new_size = (float)$size * $this->k_bytes;
				$this->checkAgainstIni($new_size, $function); 
			}
			elseif(stripos($size, 'g'))
			{
				echo $new_size = (float)$size * $this->bytes * $this->k_bytes; 
				$this->checkAgainstIni($new_size, $function);
			}
			
			return $new_size;
		}
	}
	
	protected function checkFileSize()
	{	
		$file_size = ($this->upload_file_type == 'image') ? $this->max_img_file_size : $this->max_doc_file_size;
	
		if(round($this->files['size'], 2) > $file_size)
		{ 
			if(($this->files['size']/$this->bytes) < 1)
			{
				$sufix = 'kb';
				$total = number_format(($this->files['size']/$this->bytes * $this->k_bytes), 2);
				$total_allowed = number_format($file_size/$this->bytes * $this->k_bytes, 2);
			}
			else
			{
				$sufix = 'MB';
				$total = number_format(($this->files['size']/$this->bytes), 2);
				$total_allowed = number_format($file_size/$this->bytes, 2);
			}
			htmlentities($this->files['name'], ENT_QUOTES).'" is too big at '.$total.$sufix.'<br>File size limit is '.$total_allowed.$sufix; }
		
		return $this;
	}
	
	protected function checkSaveFolders()
	{
		if(!empty($this->save_folder))
		{
			if(!is_dir($this->save_folder))
			{ mkdir($this->save_folder, $this->save_folder_chmod, TRUE); }
		}
		
		if(!empty($this->thumb_save_folder))
		{
			if(!is_dir($this->thumb_save_folder))
			{ mkdir($this->thumb_save_folder, $this->thumb_save_folder_chmod, TRUE); }
		}
		
		return $this;
	}
	
	
}

?>

Let me know if you need help making it work.  Only thing that is difficult to do on shared hosting is put a upload folder outside the root folder. As long as you set it to 0700 permissions, it should still be fine with the serve-image.php getting the file.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.