wrs223 Posted June 19, 2015 Share Posted June 19, 2015 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 Quote Link to comment https://forums.phpfreaks.com/topic/296923-renaming-file-upload/ Share on other sites More sharing options...
fastsol Posted June 19, 2015 Share Posted June 19, 2015 That is extremely scary if that is your upload script. You don't have any security checks of any kind. Someone could upload literally anything they wanted! Quote Link to comment https://forums.phpfreaks.com/topic/296923-renaming-file-upload/#findComment-1514379 Share on other sites More sharing options...
wrs223 Posted June 19, 2015 Author Share Posted June 19, 2015 Thanks for that?! I have protected the upload folder with .htaccess and can only accept photo files.. We are just beginners seeking some much needed help so if you can advise how we can rename files during uploading I would appreciate it. Quote Link to comment https://forums.phpfreaks.com/topic/296923-renaming-file-upload/#findComment-1514393 Share on other sites More sharing options...
fastsol Posted June 19, 2015 Share Posted June 19, 2015 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. Quote Link to comment https://forums.phpfreaks.com/topic/296923-renaming-file-upload/#findComment-1514399 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.