From 11adeacc98415b97c3b8f6c38685bbcbda314d12 Mon Sep 17 00:00:00 2001 From: WanWizard Date: Mon, 28 Jan 2013 18:36:10 +0100 Subject: [PATCH 1/9] Merged develop into master --- src/FuelPHP/Upload/File.php | 150 +++++++++++++++++++++++-------- src/FuelPHP/Upload/FileError.php | 13 ++- src/FuelPHP/Upload/Upload.php | 119 ++++++++++++++++++------ 3 files changed, 216 insertions(+), 66 deletions(-) diff --git a/src/FuelPHP/Upload/File.php b/src/FuelPHP/Upload/File.php index db2f43a..cc6dbcf 100644 --- a/src/FuelPHP/Upload/File.php +++ b/src/FuelPHP/Upload/File.php @@ -15,7 +15,7 @@ /** * Files is a container for a single uploaded file */ -class File +class File implements \ArrayAccess, \Iterator, \Countable { /** * Our custom error code constants @@ -31,13 +31,18 @@ class File const UPLOAD_ERR_MOVE_FAILED = 109; const UPLOAD_ERR_DUPLICATE_FILE = 110; const UPLOAD_ERR_MKDIR_FAILED = 111; - const UPLOAD_ERR_FTP_FAILED = 112; + const UPLOAD_ERR_EXTERNAL_MOVE_FAILED = 112; /** * @var array Container for uploaded file objects */ protected $container = array(); + /** + * @var int index pointer for Iterator + */ + protected $index = 0; + /** * @var array Container for validation errors */ @@ -71,9 +76,6 @@ class File 'file_chmod' => 0666, 'auto_rename' => true, 'overwrite' => false, - // save-to-ftp settings - 'ftp_mode' => 'auto', - 'ftp_permissions' => null ); /** @@ -92,25 +94,31 @@ class File protected $callbacks = array(); /** - * @var mixed FuelPHP FTP instance, for saving files to an FTP server + * @var mixed Callback to perform error string translations */ - protected $ftpInstance = null; + protected $langCallback = null; + + /** + * @var mixed Callback to a custom file move operation + */ + protected $moveCallback = null; /** * Constructor * * @param array $file Array with unified information about the file uploaded */ - public function __construct(array $file, &$callbacks = array(), &$ftpInstance = null) + public function __construct(array $file, &$callbacks = array(), $langCallback = null, $moveCallback = null) { // store the file data for this file $this->container = $file; - // the callbacks reference + // the file callbacks reference $this->callbacks =& $callbacks; - // and the callbacks reference - $this->ftpInstance =& $ftpInstance; + // and the system callbacks + $this->langCallback = $langCallback; + $this->moveCallback = $moveCallback; } /** @@ -218,7 +226,7 @@ public function validate() // does this upload exceed the maximum size? if ( ! empty($this->config['max_size']) and is_numeric($this->config['max_size']) and $this->container['size'] > $this->config['max_size']) { - $this->errors[] = new FileError(static::UPLOAD_ERR_MAX_SIZE); + $this->addError(static::UPLOAD_ERR_MAX_SIZE); } // add mimetype information @@ -232,7 +240,7 @@ public function validate() catch (\ErrorException $e) { $this->container['mimetype'] = false; - $this->errors[] = new FileError(UPLOAD_ERR_NO_FILE); + $this->addError(UPLOAD_ERR_NO_FILE); } // always use the more specific of the mime types available @@ -253,40 +261,43 @@ public function validate() // check the file extension black- and whitelists if (in_array(strtolower($this->container['extension']), (array) $this->config['ext_blacklist'])) { - $this->errors[] = new FileError(static::UPLOAD_ERR_EXT_BLACKLISTED); + $this->addError(static::UPLOAD_ERR_EXT_BLACKLISTED); } elseif ( ! empty($this->config['ext_whitelist']) and ! in_array(strtolower($this->container['extension']), (array) $this->config['ext_whitelist'])) { - $this->errors[] = new FileError(static::UPLOAD_ERR_EXT_NOT_WHITELISTED); + $this->addError(static::UPLOAD_ERR_EXT_NOT_WHITELISTED); } // check the file type black- and whitelists if (in_array($mimeinfo[1], (array) $this->config['type_blacklist'])) { - $this->errors[] = new FileError(static::UPLOAD_ERR_TYPE_BLACKLISTED); + $this->addError(static::UPLOAD_ERR_TYPE_BLACKLISTED); } if ( ! empty($this->config['type_whitelist']) and ! in_array($mimeinfo[1], (array) $this->config['type_whitelist'])) { - $this->errors[] = new FileError(static::UPLOAD_ERR_TYPE_NOT_WHITELISTED); + $this->addError(static::UPLOAD_ERR_TYPE_NOT_WHITELISTED); } // check the file mimetype black- and whitelists if (in_array($this->container['mimetype'], (array) $this->config['mime_blacklist'])) { - $this->errors[] = new FileError(static::UPLOAD_ERR_MIME_BLACKLISTED); + $this->addError(static::UPLOAD_ERR_MIME_BLACKLISTED); } elseif ( ! empty($this->config['mime_whitelist']) and ! in_array($this->container['mimetype'], (array) $this->config['mime_whitelist'])) { - $this->errors[] = new FileError(static::UPLOAD_ERR_MIME_NOT_WHITELISTED); + $this->addError(static::UPLOAD_ERR_MIME_NOT_WHITELISTED); } + // update the status of this validation + $this->isValid = empty($this->errors); + // validation finished, call the post-validation callback $this->runCallbacks('after_validation'); } else { // upload was already a failure, store the corresponding error - $this->errors[] = new FileError($this->container['error']); + $this->addError($this->container['error']); // and mark this validation a failure $this->isValid = false; @@ -310,7 +321,7 @@ public function save() if ($this->isValid) { // make sure we have a valid path - if (empty($this->config['path'])) + if (empty($this->container['path'])) { $this->container['path'] = rtrim($this->config['path'], DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } @@ -370,7 +381,7 @@ public function save() } // if we're saving the file locally - if ( ! $this->ftpInstance) + if ( ! $this->moveCallback) { // check if the file already exists if (file_exists($this->container['path'].implode('', $filename))) @@ -388,7 +399,7 @@ public function save() { if ( ! (bool) $this->config['overwrite']) { - $this->errors[] = new FileError(static::UPLOAD_ERR_DUPLICATE_FILE); + $this->addError(static::UPLOAD_ERR_DUPLICATE_FILE); } } } @@ -400,7 +411,7 @@ public function save() // does the filename exceed the maximum length? if ( ! empty($this->config['max_length']) and strlen($this->container['filename']) > $this->config['max_length']) { - $this->errors[] = new FileError(static::UPLOAD_ERR_MAX_FILENAME_LENGTH); + $this->addError(static::UPLOAD_ERR_MAX_FILENAME_LENGTH); } // update the status of this validation @@ -419,7 +430,7 @@ public function save() if ( ! is_dir($this->container['path'])) { - $this->errors[] = new FileError(static::UPLOAD_ERR_MKDIR_FAILED); + $this->addError(static::UPLOAD_ERR_MKDIR_FAILED); } } @@ -431,27 +442,19 @@ public function save() if ($this->isValid) { // check if file should be moved to an ftp server - if ($this->ftpInstance) + if ($this->moveCallback) { - throw new \Exception('Moving a file to an FTP server isn\'t supported yet!'); - - $uploaded = $this->ftpInstance->upload( - $this->container['tmp_name'], - $this->container['path'].$this->container['filename'], - $this->config['ftp_mode'], - $this->config['ftp_permissions'] - ); - - if ( ! $uploaded) + $moved = call_user_func($this->container['tmp_name'], $this->container['path'].$this->container['filename']); + if ( ! $moved) { - $this->errors[] = new FileError(static::UPLOAD_ERR_FTP_FAILED); + $this->addError(static::UPLOAD_ERR_EXTERNAL_MOVE_FAILED); } } else { if( ! @move_uploaded_file($this->container['tmp_name'], $this->container['path'].$this->container['filename'])) { - $this->errors[] = new FileError(static::UPLOAD_ERR_MOVE_FAILED); + $this->addError(static::UPLOAD_ERR_MOVE_FAILED); } else { @@ -520,4 +523,75 @@ protected function normalize() $this->container['filename'] = preg_replace("#[/_|+ -]+#u", $this->config['normalize_separator'], $this->container['filename']); $this->container['filename'] = trim($this->container['filename'], $this->config['normalize_separator']); } + + /** + * Add a new error object to the list + * + * @param array $entry uploaded file structure + */ + protected function addError($error) + { + $this->errors[] = new FileError($error, $this->langCallback); + } + + //------------------------------------------------------------------------------------------------------------------ + + /** + * Countable methods + */ + public function count() + { + return count($this->container); + } + + /** + * ArrayAccess methods + */ + public function offsetExists($offset) + { + return isset($this->container[$offset]); + } + + public function offsetGet($offset) + { + return $this->container[$offset]; + } + + public function offsetSet($offset, $value) + { + $this->container[$offset] = $value; + } + + public function offsetUnset($offset) + { + throw new \OutOfBoundsException('You can not unset a data element of an Upload File instance'); + } + + /** + * Iterator methods + */ + function rewind() + { + return reset($this->container); + } + + function current() + { + return current($this->container); + } + + function key() + { + return key($this->container); + } + + function next() + { + return next($this->container); + } + + function valid() + { + return key($this->container) !== null; + } } diff --git a/src/FuelPHP/Upload/FileError.php b/src/FuelPHP/Upload/FileError.php index e540515..fb1e564 100644 --- a/src/FuelPHP/Upload/FileError.php +++ b/src/FuelPHP/Upload/FileError.php @@ -58,10 +58,19 @@ class FileError * * @param int $error Number of the error message */ - public function __construct($error) + public function __construct($error, $langCallback = null) { $this->error = $error; - $this->message = isset($this->messages[$error]) ? $this->messages[$error] : 'Unknown error message number: '.$error; + + if (is_callable($langCallback)) + { + $this->message = call_user_func($langCallback, $error); + } + + if (empty($this->message)) + { + $this->message = isset($this->messages[$error]) ? $this->messages[$error] : 'Unknown error message number: '.$error; + } } /** diff --git a/src/FuelPHP/Upload/Upload.php b/src/FuelPHP/Upload/Upload.php index 1ac1ee5..025b462 100644 --- a/src/FuelPHP/Upload/Upload.php +++ b/src/FuelPHP/Upload/Upload.php @@ -33,7 +33,8 @@ class Upload implements \ArrayAccess, \Iterator, \Countable protected $defaults = array( // global settings 'auto_process' => false, - 'use_ftp' => false, + 'langCallback' => null, + 'moveCallback' => null, // validation settings 'max_size' => 0, 'max_length' => 0, @@ -58,9 +59,6 @@ class Upload implements \ArrayAccess, \Iterator, \Countable 'file_chmod' => 0666, 'auto_rename' => true, 'overwrite' => false, - // save-to-ftp settings - 'ftp_mode' => 'auto', - 'ftp_permissions' => null ); /** @@ -73,11 +71,6 @@ class Upload implements \ArrayAccess, \Iterator, \Countable 'after_save' => array(), ); - /** - * @var mixed FuelPHP FTP instance, for saving files to an FTP server - */ - protected $ftpInstance = null; - /** * Constructor * @@ -103,39 +96,109 @@ public function __construct(array $config = null) // process the data in the $_FILES array $this->processFiles(); - // load all objects with a default config - foreach ($this->container as $file) + // if auto-process was active, run validation on all file objects + if ($this->defaults['auto_process']) { - $file->setConfig($this->defaults); + // and validate it + $this->validate(); } - - // if auto-process was active, run validation on all file objects - $this->defaults['auto_process'] and $this->validate(); } /** * Run save on all loaded file objects * + * @param int|string|array $selection Optional array index, element name or array with filter values + * * @return void */ - public function save() + public function save($selection = null) { - // loop through all files - foreach ($this->container as $file) + // prepare the selection + if (func_num_args()) + { + if (is_array($selection)) + { + $filter = array(); + + foreach ($this->container as $file) + { + $match = true; + foreach($selection as $item => $value) + { + if ($value != $file->{$item}) + { + $match = false; + break; + } + } + + $match and $filter[] = $file; + } + + $selection = $filter; + } + else + { + $selection = (array) $this[$index]; + } + } + else + { + $selection = $this->container; + } + + // loop through all selected files + foreach ($selection as $file) { $file->save(); } } /** - * Run validation on all loaded file objects + * Run validation on all selected file objects + * + * @param int|string|array $selection Optional array index, element name or array with filter values * * @return void */ - public function validate() + public function validate($selection = null) { - // loop through all files - foreach ($this->container as $file) + // prepare the selection + if (func_num_args()) + { + if (is_array($selection)) + { + $filter = array(); + + foreach ($this->container as $file) + { + $match = true; + foreach($selection as $item => $value) + { + if ($value != $file->{$item}) + { + $match = false; + break; + } + } + + $match and $filter[] = $file; + } + + $selection = $filter; + } + else + { + $selection = (array) $this[$index]; + } + } + else + { + $selection = $this->container; + } + + // loop through all selected files + foreach ($selection as $file) { $file->validate(); } @@ -172,7 +235,7 @@ public function isValid() public function getValidFiles($index = null) { // prepare the selection - $selection = func_num_args() ? (array) $this[$index] : $this->container; + $selection = (func_num_args() and ! is_null($index)) ? (array) $this[$index] : $this->container; // storage for the results $results = array(); @@ -198,7 +261,7 @@ public function getValidFiles($index = null) public function getInvalidFiles($index = null) { // prepare the selection - $selection = func_num_args() ? (array) $this[$index] : $this->container; + $selection = (func_num_args() and ! is_null($index)) ? (array) $this[$index] : $this->container; // storage for the results $results = array(); @@ -325,7 +388,11 @@ protected function unifyFile($name, $file) */ protected function addFile(array $entry) { - $this->container[] = new File($entry, $this->callbacks, $this->ftpInstance); + // add the new file object to the container + $this->container[] = new File($entry, $this->callbacks, $this->defaults['langCallback'], $this->defaults['moveCallback']); + + // and load it with a default config + end($this->container)->setConfig($this->defaults); } //------------------------------------------------------------------------------------------------------------------ @@ -335,7 +402,7 @@ protected function addFile(array $entry) */ public function count() { - return count($container); + return count($this->container); } /** From 75e510c680703333e9c6515d79e87dbf3efcb358 Mon Sep 17 00:00:00 2001 From: Luke Armstrong Date: Wed, 30 Jan 2013 12:50:37 +0000 Subject: [PATCH 2/9] fix call_user_func() when ->moveCallback is true --- src/FuelPHP/Upload/File.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/FuelPHP/Upload/File.php b/src/FuelPHP/Upload/File.php index cc6dbcf..4cf88d5 100644 --- a/src/FuelPHP/Upload/File.php +++ b/src/FuelPHP/Upload/File.php @@ -444,7 +444,8 @@ public function save() // check if file should be moved to an ftp server if ($this->moveCallback) { - $moved = call_user_func($this->container['tmp_name'], $this->container['path'].$this->container['filename']); + $moved = call_user_func($this->moveCallback, $this->container['tmp_name'], $this->container['path'].$this->container['filename']); + if ( ! $moved) { $this->addError(static::UPLOAD_ERR_EXTERNAL_MOVE_FAILED); From 7c8158a71d690013f57e796ee8a287cb8b6b5c4a Mon Sep 17 00:00:00 2001 From: WanWizard Date: Wed, 30 Jan 2013 16:11:39 +0100 Subject: [PATCH 3/9] new config push system; removed separate callback treatment --- src/FuelPHP/Upload/File.php | 26 ++++++---------------- src/FuelPHP/Upload/Upload.php | 42 ++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/FuelPHP/Upload/File.php b/src/FuelPHP/Upload/File.php index 4cf88d5..8d97ea3 100644 --- a/src/FuelPHP/Upload/File.php +++ b/src/FuelPHP/Upload/File.php @@ -52,6 +52,8 @@ class File implements \ArrayAccess, \Iterator, \Countable * @var array Configuration values */ protected $config = array( + 'langCallback' => null, + 'moveCallback' => null, // validation settings 'max_size' => 0, 'max_length' => 0, @@ -93,32 +95,18 @@ class File implements \ArrayAccess, \Iterator, \Countable */ protected $callbacks = array(); - /** - * @var mixed Callback to perform error string translations - */ - protected $langCallback = null; - - /** - * @var mixed Callback to a custom file move operation - */ - protected $moveCallback = null; - /** * Constructor * * @param array $file Array with unified information about the file uploaded */ - public function __construct(array $file, &$callbacks = array(), $langCallback = null, $moveCallback = null) + public function __construct(array $file, &$callbacks = array()) { // store the file data for this file $this->container = $file; // the file callbacks reference $this->callbacks =& $callbacks; - - // and the system callbacks - $this->langCallback = $langCallback; - $this->moveCallback = $moveCallback; } /** @@ -381,7 +369,7 @@ public function save() } // if we're saving the file locally - if ( ! $this->moveCallback) + if ( ! $this->config['moveCallback']) { // check if the file already exists if (file_exists($this->container['path'].implode('', $filename))) @@ -442,9 +430,9 @@ public function save() if ($this->isValid) { // check if file should be moved to an ftp server - if ($this->moveCallback) + if ($this->config['moveCallback']) { - $moved = call_user_func($this->moveCallback, $this->container['tmp_name'], $this->container['path'].$this->container['filename']); + $moved = call_user_func($this->config['moveCallback'], $this->container['tmp_name'], $this->container['path'].$this->container['filename']); if ( ! $moved) { @@ -532,7 +520,7 @@ protected function normalize() */ protected function addError($error) { - $this->errors[] = new FileError($error, $this->langCallback); + $this->errors[] = new FileError($error, $this->config['langCallback']); } //------------------------------------------------------------------------------------------------------------------ diff --git a/src/FuelPHP/Upload/Upload.php b/src/FuelPHP/Upload/Upload.php index 025b462..c9b7333 100644 --- a/src/FuelPHP/Upload/Upload.php +++ b/src/FuelPHP/Upload/Upload.php @@ -225,6 +225,19 @@ public function isValid() return empty($this->container) ? false : true; } + /** + * Return the list of uploaded files + * + * @param int|string $index Optional array index or element name + * + * @return array + */ + public function getAllFiles($index = null) + { + // return the selection + return (func_num_args() and ! is_null($index)) ? (array) $this[$index] : $this->container; + } + /** * Return the list of uploaded files that valid * @@ -307,6 +320,33 @@ public static function register($event, $callback) } } + /** + * Set the configuration for this file + * + * @param $name string|array name of the configuration item to set, or an array of configuration items + * @param $value mixed if $name is an item name, this holds the configuration values for that item + * + * @return void + */ + public function setConfig($item, $value = null) + { + // unify the parameters + is_array($item) or $item = array($item => $value); + + // update the configuration + foreach ($item as $name => $value) + { + // is this a valid config item? then update the defaults + array_key_exists($name, $this->defaults) and $this->defaults[$name] = $value; + } + + // and push it to all file objects in the containers + foreach ($this->container as $file) + { + $file->setConfig($item); + } + } + /** * Process the data in the $_FILES array, unify it, and create File objects for them */ @@ -389,7 +429,7 @@ protected function unifyFile($name, $file) protected function addFile(array $entry) { // add the new file object to the container - $this->container[] = new File($entry, $this->callbacks, $this->defaults['langCallback'], $this->defaults['moveCallback']); + $this->container[] = new File($entry, $this->callbacks); // and load it with a default config end($this->container)->setConfig($this->defaults); From fb47c75cc2168e19267b28353462363fc7b6243e Mon Sep 17 00:00:00 2001 From: WanWizard Date: Tue, 5 Feb 2013 22:43:10 +0100 Subject: [PATCH 4/9] deal with relative paths --- src/FuelPHP/Upload/File.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FuelPHP/Upload/File.php b/src/FuelPHP/Upload/File.php index 8d97ea3..b124e02 100644 --- a/src/FuelPHP/Upload/File.php +++ b/src/FuelPHP/Upload/File.php @@ -322,6 +322,7 @@ public function save() throw new \DomainException('Can\'t save the uploaded file. Destination path specified does not exist.'); } } + $this->container['path'] = realpath($this->container['path']).DIRECTORY_SEPARATOR; // was a new name for the file given? if ( ! array_key_exists('filename', $this->container)) From feeadce810da0ee667973dd099ef06f8fde4721a Mon Sep 17 00:00:00 2001 From: WanWizard Date: Tue, 12 Feb 2013 22:21:13 +0100 Subject: [PATCH 5/9] can't cast the result of ArrayAccess to an array --- src/FuelPHP/Upload/Upload.php | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/FuelPHP/Upload/Upload.php b/src/FuelPHP/Upload/Upload.php index c9b7333..72e18bc 100644 --- a/src/FuelPHP/Upload/Upload.php +++ b/src/FuelPHP/Upload/Upload.php @@ -139,7 +139,7 @@ public function save($selection = null) } else { - $selection = (array) $this[$index]; + $selection = array($this[$index]); } } else @@ -189,7 +189,7 @@ public function validate($selection = null) } else { - $selection = (array) $this[$index]; + $selection = array($this[$index]); } } else @@ -235,7 +235,12 @@ public function isValid() public function getAllFiles($index = null) { // return the selection - return (func_num_args() and ! is_null($index)) ? (array) $this[$index] : $this->container; + $selection = (func_num_args() and ! is_null($index)) ? $this[$index] : $this->container; + + // make sure selection is an array + is_array($selection) or $selection = array($selection); + + return $selection; } /** @@ -248,7 +253,10 @@ public function getAllFiles($index = null) public function getValidFiles($index = null) { // prepare the selection - $selection = (func_num_args() and ! is_null($index)) ? (array) $this[$index] : $this->container; + $selection = (func_num_args() and ! is_null($index)) ? $this[$index] : $this->container; + + // make sure selection is an array + is_array($selection) or $selection = array($selection); // storage for the results $results = array(); @@ -274,7 +282,10 @@ public function getValidFiles($index = null) public function getInvalidFiles($index = null) { // prepare the selection - $selection = (func_num_args() and ! is_null($index)) ? (array) $this[$index] : $this->container; + $selection = (func_num_args() and ! is_null($index)) ? $this[$index] : $this->container; + + // make sure selection is an array + is_array($selection) or $selection = array($selection); // storage for the results $results = array(); From fdba921e861a2d8824269301beb8f45d003ae915 Mon Sep 17 00:00:00 2001 From: WanWizard Date: Wed, 6 Mar 2013 21:48:23 +0100 Subject: [PATCH 6/9] fixed incorrect use of 'filename' --- src/FuelPHP/Upload/File.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FuelPHP/Upload/File.php b/src/FuelPHP/Upload/File.php index b124e02..7c8067c 100644 --- a/src/FuelPHP/Upload/File.php +++ b/src/FuelPHP/Upload/File.php @@ -204,11 +204,11 @@ public function validate() $this->container['extension'] = ltrim(strrchr(ltrim($this->container['name'], '.'), '.'),'.'); if (empty($this->container['extension'])) { - $this->container['filename'] = $this->container['name']; + $this->container['basename'] = $this->container['name']; } else { - $this->container['filename'] = substr($this->container['name'], 0, strlen($this->container['name'])-(strlen($this->container['extension'])+1)); + $this->container['basename'] = substr($this->container['name'], 0, strlen($this->container['name'])-(strlen($this->container['extension'])+1)); } // does this upload exceed the maximum size? @@ -336,7 +336,7 @@ public function save() // do we need to normalize the filename? else { - $this->container['filename'] = $this->container['name']; + $this->container['filename'] = $this->container['basename']; (bool) $this->config['normalize'] and $this->normalize(); } } From 4e2460b6a1002f79b314ff04a818d7b16a9f9fb7 Mon Sep 17 00:00:00 2001 From: Alexander Zhuravlev Date: Wed, 13 Mar 2013 16:42:47 +1100 Subject: [PATCH 7/9] Fixed some typos and small improvments of phpdocs --- src/FuelPHP/Upload/File.php | 19 +++++++++++++++---- src/FuelPHP/Upload/FileError.php | 5 ++++- src/FuelPHP/Upload/Upload.php | 7 +++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/FuelPHP/Upload/File.php b/src/FuelPHP/Upload/File.php index 7c8067c..d747694 100644 --- a/src/FuelPHP/Upload/File.php +++ b/src/FuelPHP/Upload/File.php @@ -98,7 +98,8 @@ class File implements \ArrayAccess, \Iterator, \Countable /** * Constructor * - * @param array $file Array with unified information about the file uploaded + * @param array $file Array with unified information about the file uploaded + * @param array|null $callbacks */ public function __construct(array $file, &$callbacks = array()) { @@ -167,8 +168,8 @@ public function getErrors() /** * Set the configuration for this file * - * @param $name string|array name of the configuration item to set, or an array of configuration items - * @param $value mixed if $name is an item name, this holds the configuration values for that item + * @param string|array $item name of the configuration item to set, or an array of configuration items + * @param mixed $value if $name is an item name, this holds the configuration values for that item * * @return void */ @@ -301,6 +302,8 @@ public function validate() /** * Save the uploaded file * + * @throws \DomainException Destination path specified does not exist + * * @return bool */ public function save() @@ -466,6 +469,10 @@ public function save() /** * Run callbacks of he defined type + * + * @param callable $type Valid callable callback + * + * @return void */ protected function runCallbacks($type) { @@ -499,6 +506,8 @@ protected function runCallbacks($type) /** * Convert a filename into a normalized name. only outputs 7 bit ASCII characters. + * + * @return void */ protected function normalize() { @@ -517,7 +526,9 @@ protected function normalize() /** * Add a new error object to the list * - * @param array $entry uploaded file structure + * @param array $error uploaded file structure + * + * @return void */ protected function addError($error) { diff --git a/src/FuelPHP/Upload/FileError.php b/src/FuelPHP/Upload/FileError.php index fb1e564..b33990f 100644 --- a/src/FuelPHP/Upload/FileError.php +++ b/src/FuelPHP/Upload/FileError.php @@ -56,7 +56,10 @@ class FileError /** * Constructor * - * @param int $error Number of the error message + * @param int $error Number of the error message + * @param callable|null $langCallback + * + * @return \FuelPHP\Upload\FileError */ public function __construct($error, $langCallback = null) { diff --git a/src/FuelPHP/Upload/Upload.php b/src/FuelPHP/Upload/Upload.php index 72e18bc..89d80ec 100644 --- a/src/FuelPHP/Upload/Upload.php +++ b/src/FuelPHP/Upload/Upload.php @@ -75,6 +75,8 @@ class Upload implements \ArrayAccess, \Iterator, \Countable * Constructor * * @param array|null $config Optional array of configuration items + * + * @throws NoFilesException No uploaded files were found (did specify "enctype"?) */ public function __construct(array $config = null) { @@ -307,6 +309,7 @@ public function getInvalidFiles($index = null) * @param string $event The type of the event * @param mixed $callback Any valid callback, must accept a File object * + * @throws \InvalidArgumentException Not valid event or not callable second parameter * @return void */ public static function register($event, $callback) @@ -334,8 +337,8 @@ public static function register($event, $callback) /** * Set the configuration for this file * - * @param $name string|array name of the configuration item to set, or an array of configuration items - * @param $value mixed if $name is an item name, this holds the configuration values for that item + * @param string|array $item name of the configuration item to set, or an array of configuration items + * @param mixed $value if $name is an item name, this holds the configuration values for that item * * @return void */ From 08347078aaefdbb95df4fb2b0ddc748de5c8bf1f Mon Sep 17 00:00:00 2001 From: WanWizard Date: Thu, 2 May 2013 16:27:26 +0200 Subject: [PATCH 8/9] merged branch 'develop' into master --- src/FuelPHP/Upload/File.php | 21 ++++++++-- src/FuelPHP/Upload/FileError.php | 6 ++- src/FuelPHP/Upload/Upload.php | 71 ++++++++++++++++++-------------- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/src/FuelPHP/Upload/File.php b/src/FuelPHP/Upload/File.php index d747694..8312c55 100644 --- a/src/FuelPHP/Upload/File.php +++ b/src/FuelPHP/Upload/File.php @@ -132,7 +132,7 @@ public function __get($name) public function __set($name, $value) { $name = strtolower($name); - isset($this->container[$name]) and $this->container[$name] = $value; + array_key_exists($name, $this->container) and $this->container[$name] = $value; } /** @@ -158,7 +158,7 @@ public function isValid() /** * Return the error objects collected for this file upload * - * @return array + * @return FileError[] */ public function getErrors() { @@ -328,7 +328,7 @@ public function save() $this->container['path'] = realpath($this->container['path']).DIRECTORY_SEPARATOR; // was a new name for the file given? - if ( ! array_key_exists('filename', $this->container)) + if ( ! is_string($this->container['filename']) or $this->container['filename'] === '') { // do we need to generate a random filename? if ( (bool) $this->config['randomize']) @@ -378,6 +378,7 @@ public function save() // check if the file already exists if (file_exists($this->container['path'].implode('', $filename))) { + // generate a unique filename if needed if ( (bool) $this->config['auto_rename']) { $counter = 0; @@ -386,9 +387,13 @@ public function save() $filename[3] = '_'.++$counter; } while (file_exists($this->container['path'].implode('', $filename))); + + // claim this generated filename before someone else does + touch($this->container['path'].implode('', $filename)); } else { + // if we can't overwrite, we've got to bail out now if ( ! (bool) $this->config['overwrite']) { $this->addError(static::UPLOAD_ERR_DUPLICATE_FILE); @@ -455,6 +460,14 @@ public function save() } } } + else + { + // remove the temporary file we've created, make sure it exists first though! + if (file_exists($this->container['path'].$this->container['filename'])) + { + unlink($this->container['path'].$this->container['filename']); + } + } // validation starts, call the post-save callback if ($this->isValid) @@ -526,7 +539,7 @@ protected function normalize() /** * Add a new error object to the list * - * @param array $error uploaded file structure + * @param int $error uploaded file number * * @return void */ diff --git a/src/FuelPHP/Upload/FileError.php b/src/FuelPHP/Upload/FileError.php index b33990f..c3a4792 100644 --- a/src/FuelPHP/Upload/FileError.php +++ b/src/FuelPHP/Upload/FileError.php @@ -59,7 +59,7 @@ class FileError * @param int $error Number of the error message * @param callable|null $langCallback * - * @return \FuelPHP\Upload\FileError + * @return FileError */ public function __construct($error, $langCallback = null) { @@ -89,7 +89,7 @@ public function getError() /** * Return the error message * - * @return int The error message set + * @return string The error message set */ public function getMessage() { @@ -98,6 +98,8 @@ public function getMessage() /** * __toString magic method, will output the stored error message + * + * @return string */ public function __toString() { diff --git a/src/FuelPHP/Upload/Upload.php b/src/FuelPHP/Upload/Upload.php index 89d80ec..a56bd33 100644 --- a/src/FuelPHP/Upload/Upload.php +++ b/src/FuelPHP/Upload/Upload.php @@ -95,12 +95,12 @@ public function __construct(array $config = null) throw new NoFilesException('No uploaded files were found. Did you specify "enctype" in your <form> tag?'); } - // process the data in the $_FILES array - $this->processFiles(); - // if auto-process was active, run validation on all file objects if ($this->defaults['auto_process']) { + // process all data in the $_FILES array + $this->processFiles(); + // and validate it $this->validate(); } @@ -141,7 +141,7 @@ public function save($selection = null) } else { - $selection = array($this[$index]); + $selection = array($this[$selection]); } } else @@ -191,7 +191,7 @@ public function validate($selection = null) } else { - $selection = array($this[$index]); + $selection = array($this[$selection]); } } else @@ -232,7 +232,7 @@ public function isValid() * * @param int|string $index Optional array index or element name * - * @return array + * @return File[] */ public function getAllFiles($index = null) { @@ -250,7 +250,7 @@ public function getAllFiles($index = null) * * @param int|string $index Optional array index or element name * - * @return array + * @return File[] */ public function getValidFiles($index = null) { @@ -279,7 +279,7 @@ public function getValidFiles($index = null) * * @param int|string $index Optional array index or element name * - * @return array + * @return File[] */ public function getInvalidFiles($index = null) { @@ -307,31 +307,27 @@ public function getInvalidFiles($index = null) * Registers a Callback for a given event * * @param string $event The type of the event - * @param mixed $callback Any valid callback, must accept a File object + * @param mixed $callback Any valid callback, must accept a File object * * @throws \InvalidArgumentException Not valid event or not callable second parameter * @return void */ - public static function register($event, $callback) + public function register($event, $callback) { // check if this is a valid event type - if (array_key_exists($event, $this->callbacks)) + if ( ! isset($this->callbacks[$event])) { - // check if the callback is acually callable - if (is_callable($callback)) - { - // store it - $this->callbacks[$event][] = $callback; - } - else - { - throw new \InvalidArgumentException('Callback passed is not callable'); - } + throw new \InvalidArgumentException($event.' is not a valid event'); } - else + + // check if the callback is acually callable + if ( ! is_callable($callback)) { - throw new \InvalidArgumentException($event.' is not a valid event'); + throw new \InvalidArgumentException('Callback passed is not callable'); } + + // store it + $this->callbacks[$event][] = $callback; } /** @@ -363,8 +359,12 @@ public function setConfig($item, $value = null) /** * Process the data in the $_FILES array, unify it, and create File objects for them + * + * @param mixed $selection Array of fieldnames to process, or null for all uploaded files + * + * @return void */ - protected function processFiles() + public function processFiles(array $selection = null) { // normalize the multidimensional fields in the $_FILES array foreach($_FILES as $name => $file) @@ -373,15 +373,22 @@ protected function processFiles() if (is_array($file['name'])) { $data = $this->unifyFile($name, $file); + foreach ($data as $entry) { - $this->addFile($entry); + if ($selection === null or in_array($entry['element'], $selection)) + { + $this->addFile($entry); + } } } else { // normal form element, just create a File object for this uploaded file - $this->addFile(array_merge(array('element' => $name), $file)); + if ($selection === null or in_array($name, $selection)) + { + $this->addFile(array_merge(array('element' => $name, 'filename' => null), $file)); + } } } } @@ -410,6 +417,7 @@ protected function unifyFile($name, $file) $data, $this->unifyFile($name.'.'.$key, array( + 'filename' => null, 'name' => $file['name'][$key], 'type' => $file['type'][$key], 'tmp_name' => $file['tmp_name'][$key], @@ -422,6 +430,7 @@ protected function unifyFile($name, $file) else { $data[] = array( + 'filename' => null, 'element' => $name.'.'.$key, 'name' => $file['name'][$key], 'type' => $file['type'][$key], @@ -514,27 +523,27 @@ public function offsetUnset($offset) /** * Iterator methods */ - function rewind() + public function rewind() { $this->index = 0; } - function current() + public function current() { return $this->container[$this->index]; } - function key() + public function key() { return $this->index; } - function next() + public function next() { ++$this->index; } - function valid() + public function valid() { return isset($this->container[$this->index]); } From 202264c09cef19d4d6bb338883b640b0dc70030b Mon Sep 17 00:00:00 2001 From: stevewest Date: Tue, 17 Jun 2014 15:46:58 +0100 Subject: [PATCH 9/9] Passes the File object to the move file closure --- src/FuelPHP/Upload/File.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FuelPHP/Upload/File.php b/src/FuelPHP/Upload/File.php index 8312c55..77cae78 100644 --- a/src/FuelPHP/Upload/File.php +++ b/src/FuelPHP/Upload/File.php @@ -441,7 +441,7 @@ public function save() // check if file should be moved to an ftp server if ($this->config['moveCallback']) { - $moved = call_user_func($this->config['moveCallback'], $this->container['tmp_name'], $this->container['path'].$this->container['filename']); + $moved = call_user_func($this->config['moveCallback'], $this->container['tmp_name'], $this->container['path'].$this->container['filename'], $this); if ( ! $moved) {