Вход Регистрация
Файл: framework/validators/CFileValidator.php
Строк: 400
<?php
/**
 * CFileValidator class file.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.yiiframework.com/
 * @copyright 2008-2013 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

/**
 * CFileValidator verifies if an attribute is receiving a valid uploaded file.
 *
 * It uses the model class and attribute name to retrieve the information
 * about the uploaded file. It then checks if a file is uploaded successfully,
 * if the file size is within the limit and if the file type is allowed.
 *
 * This validator will attempt to fetch uploaded data if attribute is not
 * previously set. Please note that this cannot be done if input is tabular:
 * <pre>
 *  foreach($models as $i=>$model)
 *     $model->attribute = CUploadedFile::getInstance($model, "[$i]attribute");
 * </pre>
 * Please note that you must use {@link CUploadedFile::getInstances} for multiple
 * file uploads.
 *
 * When using CFileValidator with an active record, the following code is often used:
 * <pre>
 *  $model->attribute = CUploadedFile::getInstance($model, "attribute");
 *  if($model->save())
 *  {
 *     // single upload
 *     $model->attribute->saveAs($path);
 *     // multiple upload
 *     foreach($model->attribute as $file)
 *        $file->saveAs($path);
 *  }
 * </pre>
 *
 * You can use {@link CFileValidator} to validate the file attribute.
 *
 * In addition to the {@link message} property for setting a custom error message,
 * CFileValidator has a few custom error messages you can set that correspond to different
 * validation scenarios. When the file is too large, you may use the {@link tooLarge} property
 * to define a custom error message. Similarly for {@link tooSmall}, {@link wrongType} and
 * {@link tooMany}. The messages may contain additional placeholders that will be replaced
 * with the actual content. In addition to the "{attribute}" placeholder, recognized by all
 * validators (see {@link CValidator}), CFileValidator allows for the following placeholders
 * to be specified:
 * <ul>
 * <li>{file}: replaced with the name of the file.</li>
 * <li>{limit}: when using {@link tooLarge}, replaced with {@link maxSize};
 * when using {@link tooSmall}, replaced with {@link minSize}; and when using {@link tooMany}
 * replaced with {@link maxFiles}.</li>
 * <li>{extensions}: when using {@link wrongType}, it will be replaced with the allowed extensions.</li>
 * </ul>
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @package system.validators
 * @since 1.0
 */
class CFileValidator extends CValidator
{
    
/**
     * @var boolean whether the attribute requires a file to be uploaded or not.
     * Defaults to false, meaning a file is required to be uploaded.
     * When no file is uploaded, the owner attribute is set to null to prevent
     * setting arbitrary values.
     */
    
public $allowEmpty=false;
    
/**
     * @var mixed a list of file name extensions that are allowed to be uploaded.
     * This can be either an array or a string consisting of file extension names
     * separated by space or comma (e.g. "gif, jpg").
     * Extension names are case-insensitive. Defaults to null, meaning all file name
     * extensions are allowed.
     */
    
public $types;
    
/**
     * @var mixed a list of MIME-types of the file that are allowed to be uploaded.
     * This can be either an array or a string consisting of MIME-types separated
     * by space or comma (e.g. "image/gif, image/jpeg"). MIME-types are
     * case-insensitive. Defaults to null, meaning all MIME-types are allowed.
     * In order to use this property fileinfo PECL extension should be installed.
     * @since 1.1.11
     */
    
public $mimeTypes;
    
/**
     * @var integer the minimum number of bytes required for the uploaded file.
     * Defaults to null, meaning no limit.
     * @see tooSmall
     */
    
public $minSize;
    
/**
     * @var integer the maximum number of bytes required for the uploaded file.
     * Defaults to null, meaning no limit.
     * Note, the size limit is also affected by 'upload_max_filesize' INI setting
     * and the 'MAX_FILE_SIZE' hidden field value.
     * @see tooLarge
     */
    
public $maxSize;
    
/**
     * @var string the error message used when the uploaded file is too large.
     * @see maxSize
     */
    
public $tooLarge;
    
/**
     * @var string the error message used when the uploaded file is too small.
     * @see minSize
     */
    
public $tooSmall;
    
/**
     * @var string the error message used when the uploaded file has an extension name
     * that is not listed among {@link types}.
     */
    
public $wrongType;
    
/**
     * @var string the error message used when the uploaded file has a MIME-type
     * that is not listed among {@link mimeTypes}. In order to use this property
     * fileinfo PECL extension should be installed.
     * @since 1.1.11
     */
    
public $wrongMimeType;
    
/**
     * @var integer the maximum file count the given attribute can hold.
     * It defaults to 1, meaning single file upload. By defining a higher number,
     * multiple uploads become possible.
     */
    
public $maxFiles=1;
    
/**
     * @var string the error message used if the count of multiple uploads exceeds
     * limit.
     */
    
public $tooMany;

    
/**
     * Set the attribute and then validates using {@link validateFile}.
     * If there is any error, the error message is added to the object.
     * @param CModel $object the object being validated
     * @param string $attribute the attribute being validated
     */
    
protected function validateAttribute($object$attribute)
    {
        
$files=$object->$attribute;
        if(
$this->maxFiles 1)
        {
            if(!
is_array($files) || !isset($files[0]) || !$files[0] instanceof CUploadedFile)
                
$files CUploadedFile::getInstances($object$attribute);
            if(array()===
$files)
                return 
$this->emptyAttribute($object$attribute);
            if(
count($files) > $this->maxFiles)
            {
                
$message=$this->tooMany!==null?$this->tooMany Yii::t('yii''{attribute} cannot accept more than {limit} files.');
                
$this->addError($object$attribute$message, array('{attribute}'=>$attribute'{limit}'=>$this->maxFiles));
            }
            else
                foreach(
$files as $file)
                    
$this->validateFile($object$attribute$file);
        }
        else
        {
            if (
is_array($files))
            {
                if (
count($files) > 1)
                {
                    
$message=$this->tooMany!==null?$this->tooMany Yii::t('yii''{attribute} cannot accept more than {limit} files.');
                    
$this->addError($object$attribute$message, array('{attribute}'=>$attribute'{limit}'=>$this->maxFiles));
                    return;
                }
                else
                    
$file = empty($files) ? null reset($files);
            }
            else
                
$file $files;
            if(!
$file instanceof CUploadedFile)
            {
                
$file CUploadedFile::getInstance($object$attribute);
                if(
null===$file)
                    return 
$this->emptyAttribute($object$attribute);
            }
            
$this->validateFile($object$attribute$file);
        }
    }

    
/**
     * Internally validates a file object.
     * @param CModel $object the object being validated
     * @param string $attribute the attribute being validated
     * @param CUploadedFile $file uploaded file passed to check against a set of rules
     * @throws CException if failed to upload the file
     */
    
protected function validateFile($object$attribute$file)
    {
        
$error=(null===$file null $file->getError());
        if(
$error==UPLOAD_ERR_INI_SIZE || $error==UPLOAD_ERR_FORM_SIZE || $this->maxSize!==null && $file->getSize()>$this->maxSize)
        {
            
$message=$this->tooLarge!==null?$this->tooLarge Yii::t('yii','The file "{file}" is too large. Its size cannot exceed {limit} bytes.');
            
$this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{limit}'=>$this->getSizeLimit()));
            if(
$error!==UPLOAD_ERR_OK)
                return;
        }
        elseif(
$error!==UPLOAD_ERR_OK)
        {
            if(
$error==UPLOAD_ERR_NO_FILE)
                return 
$this->emptyAttribute($object$attribute);
            elseif(
$error==UPLOAD_ERR_PARTIAL)
                throw new 
CException(Yii::t('yii','The file "{file}" was only partially uploaded.',array('{file}'=>$file->getName())));
            elseif(
$error==UPLOAD_ERR_NO_TMP_DIR)
                throw new 
CException(Yii::t('yii','Missing the temporary folder to store the uploaded file "{file}".',array('{file}'=>$file->getName())));
            elseif(
$error==UPLOAD_ERR_CANT_WRITE)
                throw new 
CException(Yii::t('yii','Failed to write the uploaded file "{file}" to disk.',array('{file}'=>$file->getName())));
            elseif(
defined('UPLOAD_ERR_EXTENSION') && $error==UPLOAD_ERR_EXTENSION)  // available for PHP 5.2.0 or above
                
throw new CException(Yii::t('yii','A PHP extension stopped the file upload.'));
            else
                throw new 
CException(Yii::t('yii','Unable to upload the file "{file}" because of an unrecognized error.',array('{file}'=>$file->getName())));
        }

        if(
$this->minSize!==null && $file->getSize()<$this->minSize)
        {
            
$message=$this->tooSmall!==null?$this->tooSmall Yii::t('yii','The file "{file}" is too small. Its size cannot be smaller than {limit} bytes.');
            
$this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{limit}'=>$this->minSize));
        }

        if(
$this->types!==null)
        {
            if(
is_string($this->types))
                
$types=preg_split('/[s,]+/',strtolower($this->types),-1,PREG_SPLIT_NO_EMPTY);
            else
                
$types=$this->types;
            if(!
in_array(strtolower($file->getExtensionName()),$types))
            {
                
$message=$this->wrongType!==null?$this->wrongType Yii::t('yii','The file "{file}" cannot be uploaded. Only files with these extensions are allowed: {extensions}.');
                
$this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{extensions}'=>implode(', ',$types)));
            }
        }

        if(
$this->mimeTypes!==null && !empty($file->tempName))
        {
            if(
function_exists('finfo_open'))
            {
                
$mimeType=false;
                if(
$info=finfo_open(defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE FILEINFO_MIME))
                    
$mimeType=finfo_file($info,$file->getTempName());
            }
            elseif(
function_exists('mime_content_type'))
                
$mimeType=mime_content_type($file->getTempName());
            else
                throw new 
CException(Yii::t('yii','In order to use MIME-type validation provided by CFileValidator fileinfo PECL extension should be installed.'));

            if(
is_string($this->mimeTypes))
                
$mimeTypes=preg_split('/[s,]+/',strtolower($this->mimeTypes),-1,PREG_SPLIT_NO_EMPTY);
            else
                
$mimeTypes=$this->mimeTypes;

            if(
$mimeType===false || !in_array(strtolower($mimeType),$mimeTypes))
            {
                
$message=$this->wrongMimeType!==null?$this->wrongMimeType Yii::t('yii','The file "{file}" cannot be uploaded. Only files of these MIME-types are allowed: {mimeTypes}.');
                
$this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{mimeTypes}'=>implode(', ',$mimeTypes)));
            }
        }
    }

    
/**
     * Raises an error to inform end user about blank attribute.
     * Sets the owner attribute to null to prevent setting arbitrary values.
     * @param CModel $object the object being validated
     * @param string $attribute the attribute being validated
     */
    
protected function emptyAttribute($object$attribute)
    {
        if(
$this->safe
            
$object->$attribute=null;

        if(!
$this->allowEmpty)
        {
            
$message=$this->message!==null?$this->message Yii::t('yii','{attribute} cannot be blank.');
            
$this->addError($object,$attribute,$message);
        }
    }

    
/**
     * Returns the maximum size allowed for uploaded files.
     * This is determined based on three factors:
     * <ul>
     * <li>'upload_max_filesize' in php.ini</li>
     * <li>'MAX_FILE_SIZE' hidden field</li>
     * <li>{@link maxSize}</li>
     * </ul>
     *
     * @return integer the size limit for uploaded files.
     */
    
protected function getSizeLimit()
    {
        
$limit=ini_get('upload_max_filesize');
        
$limit=$this->sizeToBytes($limit);
        if(
$this->maxSize!==null && $limit>&& $this->maxSize<$limit)
            
$limit=$this->maxSize;
        if(isset(
$_POST['MAX_FILE_SIZE']) && $_POST['MAX_FILE_SIZE']>&& $_POST['MAX_FILE_SIZE']<$limit)
            
$limit=$_POST['MAX_FILE_SIZE'];
        return 
$limit;
    }

    
/**
     * Converts php.ini style size to bytes.
     *
     * Examples of size strings are: 150, 1g, 500k, 5M (size suffix
     * is case insensitive). If you pass here the number with a fractional part, then everything after
     * the decimal point will be ignored (php.ini values common behavior). For example 1.5G value would be
     * treated as 1G and 1073741824 number will be returned as a result. This method is public
     * (was private before) since 1.1.11.
     *
     * @param string $sizeStr the size string to convert.
     * @return integer the byte count in the given size string.
     * @since 1.1.11
     */
    
public function sizeToBytes($sizeStr)
    {
        
// get the latest character
        
switch (strtolower(substr($sizeStr, -1)))
        {
            case 
'm': return (int)$sizeStr 1048576// 1024 * 1024
            
case 'k': return (int)$sizeStr 1024// 1024
            
case 'g': return (int)$sizeStr 1073741824// 1024 * 1024 * 1024
            
default: return (int)$sizeStr// do nothing
        
}
    }
}
Онлайн: 1
Реклама