From 9d935c3e4e89a03ba8e3ab9b1567f6557de14cf5 Mon Sep 17 00:00:00 2001 From: webtechnick Date: Sat, 17 Apr 2010 04:00:56 +0000 Subject: [PATCH] Added new fileName manipulation callbacks and settings. --- config/file_upload_settings.php | 68 ++++++++++++++++++++++++++++++-- models/behaviors/file_upload.php | 21 ++++++++-- readme.txt | 14 +++++-- vendors/uploader.php | 62 +++++++++++++++++++++++++---- 4 files changed, 146 insertions(+), 19 deletions(-) diff --git a/config/file_upload_settings.php b/config/file_upload_settings.php index 1910a49..f6ca702 100644 --- a/config/file_upload_settings.php +++ b/config/file_upload_settings.php @@ -26,7 +26,10 @@ class FileUploadSettings { */ var $defaults = array( /** - * Component Setting Only. + * Component and Behavior Setting. + * + * If using the behavior, and a fileNameFunction setting is detected + * the fileModel setup here will be used by default. * * fileModel is the name of the model used if we want to * keep records of uploads in a database. @@ -67,6 +70,8 @@ class FileUploadSettings { 'allowedTypes' => array('image/jpeg','image/gif','image/png','image/pjpeg','image/x-png'), /** + * Component and Behavior Setting. + * * Max file size in bytes * @var mixed false ignore maxFileSize (php.ini limit). int bytes of max file size */ @@ -76,6 +81,7 @@ class FileUploadSettings { * Component and Behavior Setting. * * fields are the fields relating to the database columns + * @var array of fields related to database columns. */ 'fields' => array('name'=>'name','type'=>'type','size'=>'size'), @@ -86,6 +92,9 @@ class FileUploadSettings { * along with just the Uploaded data. By default this is turned off. * Turning this feature on will require you to have your model associations * set correctly in your Upload model. + * @var boolean + * - if true: a saveAll() will be executed. + * - if false: a save() will be executed (default) */ 'massSave' => false, @@ -93,13 +102,64 @@ class FileUploadSettings { * Component Setting Only. * * automatic determines if the process of all files will be called automatically upon detection. - * if true: files are processed as soon as they come in - * if false: when a file is ready hasFile is set to true * it is then up to the calling application to call processAllFiles() * whenever it wants. this allows params to be changed per uploaded file * (save every file in a different folder for instance) + * @var boolean + * - if true: files are processed as soon as they come in (default) + * - if false: when a file is ready hasFile is set to true + */ + 'automatic' => true, + + /** + * Behavior Setting Only. + * + * required determines and checks if a file was sent to the server. + * @var boolean + * - if true: a file is required to be uploaded to save relative records + * - if false: related records will saved even if there is no uploaded file (default) + */ + 'required' => false, + + /** + * Component and Behavior Setting. + * + * unique will decide if uploaded files can overwrite other files of the same name + * if true: uploaded files will never overwrite other files of the same name (default) + * if false: uploaded files can overwrite files of the same name. + */ + 'unique' => true, + + /** + * Behavior Setting Only. + * + * Define a model or function callback for the filename. + * You can define this function within your attaching model + * or as a stand-alone function somewhere in your app. + * + * The function will take in the current fileName to be saved to the + * database and allow the user to return the desired fileName defined + * by the function + * + * Note: be sure to return the fileName or the file will not be saved + * + * Model callback example: + * 'fileNameFunction' => 'sanitizeFileName' + * + * Example defined in your model: + * function sanitizeFileName($fileName){ + * //Logic for sanitizing your filename + * return 'prefix_' . $fileName; + * } + * + * You can also set a standard PHP string parsing like sha1, or md5 for your filenames. + * + * Example of using basic PHP string parsing function: + * 'fileNameFunction' => 'sha1' + * 'fileNameFunction' => 'md5' + * 'fileNameFunction' => 'crc32' */ - 'automatic' => true + 'fileNameFunction' => false ); } diff --git a/models/behaviors/file_upload.php b/models/behaviors/file_upload.php index aa81acc..7bf97a5 100644 --- a/models/behaviors/file_upload.php +++ b/models/behaviors/file_upload.php @@ -3,16 +3,25 @@ * Behavior for file uploads * * Example Usage: - * var $actsAs = array( + * + * @example + * var $actsAs = array('FileUpload.FileUpload'); + * + * @example + * var $actsAs = array( * 'FileUpload.FileUpload' => array( * 'uploadDir' => 'files', * 'fields' => array('name' => 'file_name', 'type' => 'file_type', 'size' => 'file_size'), * 'allowedTypes' => array('application/pdf'), - * 'requilred' => false, + * 'required' => false, + * 'unique' => false //filenames will overwrite existing files of the same name. (default true) + * 'fileNameFunction' => 'sha1' //execute the Sha1 function on a filename before saving it (default false) * ) * ) * - * @version: 4.3.0 + * + * @note: Please review the plugins/file_upload/config/file_upload_settings.php file for details on each setting. + * @version: since 4.4.0 * @author: Nick Baker * @link: http://www.webtechnick.com */ @@ -25,6 +34,9 @@ class FileUploadBehavior extends ModelBehavior { */ var $Uploader = null; + /** + * Setup the behavior + */ function setUp(&$Model, $options = array()){ $FileUploadSettings = new FileUploadSettings; if(!is_array($options)){ @@ -34,6 +46,7 @@ function setUp(&$Model, $options = array()){ $uploader_settings = $this->options; $uploader_settings['uploadDir'] = WWW_ROOT . $uploader_settings['uploadDir']; + $uploader_settings['fileModel'] = $Model->alias; $this->Uploader = new Uploader($uploader_settings); } @@ -95,7 +108,7 @@ function beforeDelete(&$Model, $cascade){ $data = $Model->read(); $this->Uploader->removeFile($data[$Model->alias][$this->options['fields']['name']]); - return true; + return $Model->beforeDelete($cascade); } } diff --git a/readme.txt b/readme.txt index 9c68e21..b026a8b 100644 --- a/readme.txt +++ b/readme.txt @@ -15,6 +15,7 @@ BLOG ARTICLE: http://www.webtechnick.com/blogs/view/221/CakePHP_File_Upload_Plugin CHANGELOG: + 4.4.0: Added new fileName maniupluation callbacks and settings. 4.3.0: Added a new 'maxFileSize' validation key. 4.2.0: Added a new 'required' key in Behavior settings that would produce a validation error if a file wasn't uploaded. 4.1.2: Fixed a regression, passing in custom settings to the helper now changes those settings. @@ -50,7 +51,7 @@ model will move the file to its specified area (webroot/files). All the file up automatically, including multiple file uploads and associations. -===================== BEHAVIOR CONFIGURATION ========================== +===================== BEHAVIOR CONFIGURATION (RECOMMENDED) ========================== Simply attach the FileUpload.FileUpload behavior to the model of your choice. array('name' => 'file_name', 'type' => 'file_type', 'size' => 'file_size'), 'allowedTypes' => array('application/pdf'), 'required' => false, //default is false, if true a validation error would occur if a file wsan't uploaded. - 'maxFileSize' => '10000' //bytes OR false to turn off maxFileSize (default false) + 'maxFileSize' => '10000', //bytes OR false to turn off maxFileSize (default false) + 'unique' => false //filenames will overwrite existing files of the same name. (default true) + 'fileNameFunction' => 'sha1' //execute the Sha1 function on a filename before saving it (default false) ) ); } ?> +NOTE: Please review the FileUpload/config/file_upload_settings.php for details on each setting. + Now with your upload model set, you'll be able to upload files and save to your database even through associations in other models. Example: @@ -93,8 +98,11 @@ Assuming an Application->hasMany->Uploads you could do the following: The Behavior method is by far the easiet and most flexible way to get up and rolling with file uploads. -===================== COMPONENT CONFIGURATION ========================== +===================== COMPONENT CONFIGURATION (NOT RECOMMENDED) ========================== The second options is to use the Component + Helper method. + +NOTE: This not the recommended way. I do not recommend using the comopnent unless you do *not* require a model. + Including with this plugin is another method that requires a component. The advantage of using a component is a model is not required for file uploading. If you do not need a database, and you simply want to upload data to your server quickly and easily simply skip to the WITHOUT MODEL CONFIGURATION diff --git a/vendors/uploader.php b/vendors/uploader.php index da1b402..06a8836 100644 --- a/vendors/uploader.php +++ b/vendors/uploader.php @@ -3,7 +3,7 @@ * Uploader class handles a single file to be uploaded to the file system * * @author: Nick Baker - * @verion: 4.3.0 + * @version: since 4.4.0 * @link: http://www.webtechnick.com */ class Uploader { @@ -59,6 +59,56 @@ function __construct($options = array()){ $this->options = array_merge($this->options, $options); } + /** + * Preform requested callbacks on the filename. + * + * @var string chosen filename + * @return string of resulting filename + * @access private + */ + function __handleFileNameCallback($fileName){ + if($this->options['fileNameFunction']){ + if($this->options['fileModel']){ + $Model = ClassRegistry::init($this->options['fileModel']); + if(method_exists($Model, $this->options['fileNameFunction'])){ + $fileName = $Model->{$this->options['fileNameFunction']}($fileName); + } + elseif(function_exists($this->options['fileNameFunction'])){ + $fileName = call_user_func($this->options['fileNameFunction'], $fileName); + } + } + else { + if(function_exists($this->options['fileNameFunction'])){ + $fileName = call_user_func($this->options['fileNameFunction'], $fileName); + } + } + + if(!$fileName){ + $this->_error('No filename resulting after parsing. Function: ' . $this->options['fileNameFunction']); + } + } + return $fileName; + } + + /** + * Preform requested target patch checks depending on the unique setting + * + * @var string chosen filename target_path + * @return string of resulting target_path + * @access private + */ + function __handleUnique($target_path){ + if($this->options['unique']){ + $temp_path = substr($target_path, 0, strlen($target_path) - strlen($this->_ext())); //temp path without the ext + $i=1; + while(file_exists($target_path)){ + $target_path = $temp_path . "-" . $i . $this->_ext(); + $i++; + } + } + return $target_path; + } + /** * processFile will take a file, or use the current file given to it * and attempt to save the file to the file system. @@ -78,13 +128,9 @@ function processFile($file = null){ //make sure the file doesn't already exist, if it does, add an itteration to it $up_dir = $this->options['uploadDir']; - $target_path = $up_dir . DS . $this->file['name']; - $temp_path = substr($target_path, 0, strlen($target_path) - strlen($this->_ext())); //temp path without the ext - $i=1; - while(file_exists($target_path)){ - $target_path = $temp_path . "-" . $i . $this->_ext(); - $i++; - } + $fileName = $this->__handleFileNameCallback($this->file['name']); + $target_path = $up_dir . DS . $fileName; + $target_path = $this->__handleUnique($target_path); //now move the file. if(move_uploaded_file($this->file['tmp_name'], $target_path)){