diff --git a/CHANGELOG b/CHANGELOG index ddceb9ec9..e01e85031 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ Version 1.0 to be released - Added CTabView (Qiang) - Added CActiveRecord::safeAttributes (Qiang) - Added CHtml::activeFileField (Qiang) +- Added CUploadedFile (Qiang) +- Added CFileValidator (Qiang) Version 1.0rc November 10, 2008 ------------------------------- diff --git a/framework/YiiBase.php b/framework/YiiBase.php index fda2a22df..fc6baf366 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -464,6 +464,7 @@ class YiiBase 'CCaptchaValidator' => '/validators/CCaptchaValidator.php', 'CCompareValidator' => '/validators/CCompareValidator.php', 'CEmailValidator' => '/validators/CEmailValidator.php', + 'CFileValidator' => '/validators/CFileValidator.php', 'CFilterValidator' => '/validators/CFilterValidator.php', 'CInlineValidator' => '/validators/CInlineValidator.php', 'CNumberValidator' => '/validators/CNumberValidator.php', @@ -490,6 +491,7 @@ class YiiBase 'CPagination' => '/web/CPagination.php', 'CTheme' => '/web/CTheme.php', 'CThemeManager' => '/web/CThemeManager.php', + 'CUploadedFile' => '/web/CUploadedFile.php', 'CUrlManager' => '/web/CUrlManager.php', 'CWebApplication' => '/web/CWebApplication.php', 'CWebService' => '/web/CWebService.php', diff --git a/framework/validators/CFileValidator.php b/framework/validators/CFileValidator.php new file mode 100644 index 000000000..646712d1b --- /dev/null +++ b/framework/validators/CFileValidator.php @@ -0,0 +1,48 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CFileValidator verifies if the attribute is receiving a valid uploaded file. + * + * + * @author Qiang Xue + * @version $Id$ + * @package system.validators + * @since 1.0 + */ +class CFileValidator extends CValidator +{ + /** + * @var boolean whether the attribute value can be null or empty. Defaults to true, + * meaning that if the attribute is empty, it is considered valid. + */ + public $allowEmpty=true; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel the object being validated + * @param string the attribute being validated + */ + protected function validateAttribute($object,$attribute) + { + $value=$object->$attribute; + if($this->allowEmpty && ($value===null || $value==='')) + return; + + $file=CUploadedFile::getInstance(get_class($object).'['.$attribute.']'); + + if(!$valid) + { + $message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be {type}.',array('{type}'=>$this->type)); + $this->addError($object,$attribute,$message); + } + } +} diff --git a/framework/web/CHttpRequest.php b/framework/web/CHttpRequest.php index de1611756..418d6def7 100644 --- a/framework/web/CHttpRequest.php +++ b/framework/web/CHttpRequest.php @@ -71,6 +71,15 @@ class CHttpRequest extends CApplicationComponent if(isset($_COOKIE)) $_COOKIE=$this->stripSlashes($_COOKIE); } + // copy uploaded file names to $_POST array so that they can be assigned to models more easily + if(isset($_FILES) && is_array($_FILES)) + { + foreach($_FILES as $name=>$info) + { + if(is_array($info) && isset($info['name'])) + $_POST[$name]=$info['name']; + } + } } /** diff --git a/framework/web/CUploadedFile.php b/framework/web/CUploadedFile.php new file mode 100644 index 000000000..39c826d51 --- /dev/null +++ b/framework/web/CUploadedFile.php @@ -0,0 +1,156 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CUploadedFile represents the information for an uploaded file. + * + * Call {@link getInstance} to retrieve the instance of an uploaded file, + * and then use {@link saveAs} to save it on the server. + * You may also query other information about the file, including {@link name}, + * {@link tempName}, {@link type}, {@link size} and {@link error} + * + * @author Qiang Xue + * @version $Id$ + * @package system.web + * @since 1.0 + */ +class CUploadedFile extends CComponent +{ + private $_name; + private $_tempName; + private $_type; + private $_size; + private $_error; + + /** + * Returns an instance of the specified uploaded file. + * @param string the name of the file input field. + * @return CUploadedFile the instance of the uploaded file. + * Null is returned if no file is uploaded for the specified name. + */ + public static function getInstance($name) + { + static $files; + if($files===null) + { + if(isset($_FILES) && is_array($_FILES)) + { + foreach($_FILES as $key=>$info) + { + if(is_array($info['name'])) + { + $subKeys=array_keys($info['name']); + foreach($subKeys as $subKey) + $files[$key.'['.$subKey.']']=new CUploadedFile($info['name'][$subKey],$info['tmp_name'][$subKey],$info['type'][$subKey],$info['size'][$subKey],$info['error'][$subKey]); + } + else + $files[$key]=new CUploadedFile($info['name'],$info['tmp_name'],$info['type'],$info['size'],$info['error']); + } + } + else + $files=array(); + } + return isset($files[$name]) ? $files[$name] : null; + } + + /** + * Constructor. + * Use {@link getInstance} to get an instance of an uploaded file. + * @param string the original name of the file being uploaded + * @param string the path of the uploaded file on the server. + * @param string the MIME-type of the uploaded file (such as "image/gif"). + * @param integer the actual size of the uploaded file in bytes + * @param integer the error code + */ + protected function __construct($name,$tempName,$type,$size,$error) + { + $this->_name=$name; + $this->_tempName=$tempName; + $this->_type=$type; + $this->_size=$size; + $this->_error=$error; + } + + /** + * Saves the uploaded file. + * @param string the file path used to save the uploaded file + * @param boolean whether to delete the temporary file after saving. + * If true, you will not be able to save the uploaded file again in the current request. + * @return boolean true whether the file is saved successfully + */ + public function saveAs($file,$deleteTempFile=true) + { + if($this->_error===UPLOAD_ERR_OK) + { + if($deleteTempFile) + return move_uploaded_file($this->_tempName,$file); + else if(is_uploaded_file($this->_tempName)) + return file_put_contents($file,file_get_contents($this->_tempName))!==false; + else + return false; + } + else + return false; + } + + /** + * @return string the original name of the file being uploaded + */ + public function getName() + { + return $this->_name; + } + + /** + * @return string the path of the uploaded file on the server. + * Note, this is a temporary file which will be automatically deleted by PHP + * after the current request is processed. + */ + public function getTempName() + { + return $this->_tempName; + } + + /** + * @return string the MIME-type of the uploaded file (such as "image/gif"). + * Since this mime type is not checked on the server side, do not take its value for granted. + */ + public function getType() + { + return $this->_type; + } + + /** + * @return integer the actual size of the uploaded file in bytes + */ + public function getSize() + { + return $this->_size; + } + + /** + * Returns an error code describing the status of this file uploading. + * @return integer the error code + * @see http://www.php.net/manual/en/features.file-upload.errors.php + */ + public function getError() + { + return $this->_error; + } + + /** + * @return boolean whether there is an error with the uploaded file. + * Check {@link error} for detailed error code information. + */ + public function getHasError() + { + return $this->_error!=UPLOAD_ERR_OK; + } +} \ No newline at end of file diff --git a/framework/yiilite.php b/framework/yiilite.php index 23142b60b..1df775404 100644 --- a/framework/yiilite.php +++ b/framework/yiilite.php @@ -268,6 +268,7 @@ class YiiBase 'CCaptchaValidator' => '/validators/CCaptchaValidator.php', 'CCompareValidator' => '/validators/CCompareValidator.php', 'CEmailValidator' => '/validators/CEmailValidator.php', + 'CFileValidator' => '/validators/CFileValidator.php', 'CFilterValidator' => '/validators/CFilterValidator.php', 'CInlineValidator' => '/validators/CInlineValidator.php', 'CNumberValidator' => '/validators/CNumberValidator.php', @@ -294,6 +295,7 @@ class YiiBase 'CPagination' => '/web/CPagination.php', 'CTheme' => '/web/CTheme.php', 'CThemeManager' => '/web/CThemeManager.php', + 'CUploadedFile' => '/web/CUploadedFile.php', 'CUrlManager' => '/web/CUrlManager.php', 'CWebApplication' => '/web/CWebApplication.php', 'CWebService' => '/web/CWebService.php', @@ -1790,6 +1792,15 @@ class CHttpRequest extends CApplicationComponent if(isset($_COOKIE)) $_COOKIE=$this->stripSlashes($_COOKIE); } + // copy uploaded file names to $_POST array so that they can be assigned to models more easily + if(isset($_FILES) && is_array($_FILES)) + { + foreach($_FILES as $name=>$info) + { + if(is_array($info) && isset($info['name'])) + $_POST[$name]=$info['name']; + } + } } public function stripSlashes(&$data) {