2018-11-13 15:22:59 1697次浏览 5条回答 0 悬赏 10 金钱

最近在开发一个图片上传和文件上传的功能。我写了个文件上传的模型 FileUpload,里面有一个允许文件上传的格式变量 $allowType = ['jpg', 'png', 'gif'];,里面一个init()方法对上传过来的文件进行处理,还有一个 save() 的方法,对文件进行保存处理。然后我在控制器写了两个方法,一个是图片上传的方法ImageUpload(),另一个是文件上传的方法 FileUpload()。然后我在 FileUpload() 这个方法内,对$allowType 增加了一个txt,即 $allowType=['jpg', 'png', 'gif', 'txt'];,代码如下:

public function actionFileUpload()
{
    Yii::$app->response->format = Response::FORMAT_JSON;
    $model = New FileUpload();
    $model->fileInputName = 'name';
    $model->mimetype = ['jpg', 'png', 'gif', 'txt'];
    $model->allowType = ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'text/plain'];
    $model->savePath = Yii::getAlias('@frontend/web/upload/file');

    if($model->save()){
        return [
            'code' => 1,
            'msg' => $model->getMessage(),
            'data' => [
                'url' => $model->getUrlPath()
            ]
        ];
    }else{
        return [
            'code' => 0,
            'msg' => $model->getMessage()
        ];
    }
}

可是发现txt的文件还是没法上传,就是 $model->allowType 这样不会对模型里面的 $allowType 重新赋值,它依旧只是认得它自带的值,难道只能模型传值给控制器,而控制器不能对模型重新赋值吗?

附上FileUpload模型的相关代码:
`namespace common\models;

use yii;
use yii\base\Object;
use yii\helpers\FileHelper;
use yii\web\UploadedFile;

class FileUpload extends Object
{

// 最大可上传大小
public $maxsize = 1024100000;
// 可上传的文件类型
public $mimetype = ['jpg', 'png', 'jpeg', 'gif', 'bmp'];
// 允许的类型
public $allowType = ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png'];

// 上传表单 file name
public $fileInputName = 'file';
// 图像保存根位置
public $savePath;
// 上传文件
private $_uploadFile;
// 文件路径
private $filePath;
// 访问路径
private $urlPath;
// 返回状态
private $res = false;
// 返回信息
private $message;

public function init()
{
    if (!$this->fileInputName){
        $this->message = 'fileInputName属性不能为空';
        return [
            'code' => 0,
            'msg' => $this->message,
        ];
    }

    if (!$this->savePath) {
        $this->savePath = Yii::getAlias('@frontend/web/upload/images');
    }

    $this->savePath = rtrim($this->savePath,'/');

    if(!file_exists($this->savePath)){
        if(! FileHelper::createDirectory($this->savePath)){
            $this->message = '没有权限创建'.$this->savePath;
            return [
                'code' => 0,
                'msg' => $this->message,
            ];
        }
    }

    $this->_uploadFile = UploadedFile::getInstanceByName($this->fileInputName);

    // 获取文件名
    $fileName = $this->_uploadFile->baseName;
    // 获取文件格式
    $fileType = $this->_uploadFile->type;
    // 获取文件后缀
    $fileExtension = $this->_uploadFile->extension;
    // 获取文件大小
    $fileSize = $this->_uploadFile->size;
    // 获取文件错误
    $fileError = $this->_uploadFile->error;

    if(!$this->_uploadFile){
        $this->message = '没有找到上传文件';
        return [
            'code' => 0,
            'msg' => $this->message,
        ];
    }
    if($fileError){
        $this->message = '文件上传失败';
        return [
            'code' => 0,
            'msg' => $this->message,
        ];
    }

    if($fileSize > $this->maxsize){
        $this->message = '上传的文件大小受限制';
        return [
            'code' => 0,
            'msg' => $this->message,
        ];
    }

    if(!in_array($fileExtension, $this->mimetype) || !in_array($fileType, $this->allowType)){
        $this->message = '该文件类型不允许上传';
        return [
            'code' => 0,
            'msg' => $this->message,
        ];
    }

    $YearDir = date('Y',time());
    $MonthDayDir = date('md',time());
    if(!file_exists($this->savePath.'/'.$YearDir.'/'.$MonthDayDir)){
        FileHelper::createDirectory($this->savePath.'/'.$YearDir.'/'.$MonthDayDir);
    }
    $randomName = mt_rand(1000, 9999);
    $newTimestamp = time();

    $this->filePath = $this->savePath.'/'.$YearDir.'/'.$MonthDayDir.'/'.$newTimestamp.$randomName.'.'.$fileExtension;
    $this->urlPath = '/upload/images/'.$YearDir.'/'.$MonthDayDir.'/'.$newTimestamp.$randomName.'.'.$fileExtension;

}

public function save()
{
    if($this->_uploadFile->saveAs($this->filePath)){
        $this->res = true;
    }else{
        $this->res = false;
    }
    if($this->res){
        $this->message = '文件上传成功!';
    }else{
        $this->message = '文件上传失败!';
    }
    return $this->res;
}

public function getMessage(){
    return $this->message;
}

public function getUrlPath(){
    return $this->urlPath;
}

}`

最佳答案

  • liujingxing 发布于 2018-11-14 09:45 举报

    因为你的 FileUpload 继承的 Object 类,Object 类在实例化的时候,就会调用init() 方法

    public function __construct($config = [])
    {
        if (!empty($config)) {
            Yii::configure($this, $config);
        }
        $this->init();
    }
    

    所以你现在的报错是在new FileUpload() 就报错了, 你下面修改类的属性都还没有执行,并不是不能修改!
    如果你要修改类的属性,直接在new FileUpload() 时候传递一个数组就可以了(属性对应属性值)

    $model = New FileUpload([
                'fileInputName' => 'name',
                'allowType'     => ['jpg', 'png', 'gif', 'txt'],
                'mimetype'      => ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'text/plain'],
                'savePath'      => Yii::getAlias('@frontend/web/upload/file')
            ]);
    

    这样就可以了!

    另外:个人建议 FileUpload 需要将功能拆分,上传验证交给 model, FileUpload 只负责调用 model 验证,以及处理上传路径问题

    附代码:

    1. 上传model
    <?php
    
    namespace frontend\models;
    
    use yii\base\Model;
    
    class UploadForm extends Model
    {
        public $name;
    
        public $file;
    
        /**
         * 设置验证场景
         *
         * @return array
         */
        public function scenarios()
        {
            return [
                'name' => ['name'],
                'file' => ['file'],
            ];
        }
    
        /**
         * {@inheritdoc}
         */
        public function rules()
        {
            // 我这里是偷懒的写法,就是多个上传字段,使用一个上传验证类, 只要添加验证场景和验证字段规则就好了
            return [
                [
                    ['name'],
                    'file',
                    'extensions' => ['jpg', 'png', 'gif', 'txt'],
                    'maxSize'    => 1024100000,
    //                'checkExtensionByMimeType' => false, // 要不要验证 mimeTypes 类型
                    'mimeTypes'  => ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'text/plain'],
                    'on'         => 'name',
                ],
                [
                    ['file'],
                    'image',
                    'extensions' => ['jpg', 'png', 'gif'],
                    'maxSize'    => 1024100000,
                    'on'         => 'file',
                ]
            ];
        }
    }
    
    1. FileUpload 代码
    <?php
    
    namespace frontend\models;
    
    use yii;
    use yii\base\Object;
    use yii\helpers\FileHelper;
    use yii\web\UploadedFile;
    
    class FileUpload extends Object
    {
        /**
         * @var \yii\base\Model 处理的model
         */
        public $model;
    
        /**
         * @var string 上传文件表单名称
         */
        public $fileInputName = 'file';
    
        /**
         * @var string 图片保存绝对路径
         */
        public $savePath;
    
        /**
         * @var string 文件访问路径前缀
         */
        public $urlPathPrefix = '/upload/images';
    
        /**
         * @var UploadedFile 上传文件处理类
         */
        private $uploadFile;
    
        /**
         * @var string 文件保存路径
         */
        private $filePath;
    
        /**
         * @var string 文件访问路径
         */
        private $urlPath;
    
        /**
         * @return array|void
         * @throws yii\base\Exception
         */
        public function init()
        {
            if (!$this->savePath) {
                $this->savePath = Yii::getAlias('@frontend/web/upload/images');
            }
    
            // 目录不存在创建
            $this->savePath = rtrim($this->savePath, '/');
            if (!file_exists($this->savePath) && !FileHelper::createDirectory($this->savePath)) {
                throw  new yii\base\Exception('没有权限创建' . $this->savePath);
            }
    
            if (empty($this->model) || !($this->model instanceof Model)) {
                throw  new yii\base\Exception('没有传递上传文件类');
            }
    
            // 上传文件接收
            $strField               = $this->fileInputName;
            $this->model->$strField = $this->uploadFile = UploadedFile::getInstanceByName($this->fileInputName);
            if (empty($this->uploadFile)) {
                throw  new yii\base\Exception('没有上传文件');
            }
    
            // 上传文件验证
            if (!$this->model->validate()) {
                throw  new yii\base\Exception($this->model->getFirstError($strField));
            }
    
            list($path, $datePath) = $this->createDir($this->savePath);
            $fileName = time() . mt_rand(1000, 9999) . '.' . $this->uploadFile->getExtension();
    
            $this->filePath = $path . $fileName;
            $this->urlPath  = rtrim($this->urlPathPrefix, '/') . '/' . $datePath . '/' . $fileName;
        }
    
        /**
         * 根据时间创建目录
         *
         * @param $path
         *
         * @return array
         *
         * @throws yii\base\Exception
         */
        public function createDir($path)
        {
            $datePath = date('Y') . '/' . date('md');
            $path     = $path . '/' . $datePath . '/';
            if (!file_exists($path)) {
                FileHelper::createDirectory($path);
            }
    
    
            return [$path, $datePath];
        }
    
        public function save()
        {
            return $this->uploadFile->saveAs($this->filePath);
        }
    
        public function getUrlPath()
        {
            return $this->urlPath;
        }
    }
    
    1. 控制器调用
    public function actionFileUpload()
        {
            try {
                $model = New FileUpload([
                    'fileInputName' => 'name',
                    'model'         => new UploadForm(['scenario' => 'name']),
                    'savePath'      => Yii::getAlias('@frontend/web/upload/file'),
                    'urlPathPrefix' => '/upload/file'
                ]);
    
                if (!$model->save()) {
                    throw new \Exception('上传文件失败');
                }
    
                return $this->asJson([
                    'code' => 1,
                    'msg'  => '上传文件成功',
                    'data' => ['url' => $model->getUrlPath()]
                ]);
            } catch (\Exception $e) {
                return $this->asJson(['code' => 0, 'msg' => $e->getMessage()]);
            }
        }
    
    1 条回复
    回复于 2018-11-14 15:31 回复

    遇到大神了,谢谢你,按你的方法,可以了,感激~

    , 觉得很赞
  • 回答于 2018-11-13 15:40 举报

    你是想数据库保存数组?

    1 条回复
    回复于 2018-11-13 15:58 回复

    跟数据库没有关系,我是想把模型里面定义的变量,在控制器上重新赋值,然后再传回模型进行相关的处理和保存。

  • 回答于 2018-11-13 15:45 举报

    FileUpload代码贴一下,无论是模型还是控制器,都只是PHP的class,不存在模型的值只能在控制器中修改之类的问题

    3 条回复
    回复于 2018-11-13 16:01 回复

    已经补充了模型的代码了,麻烦在帮我理一理哈。就是我无论在控制器怎么给模型的变量赋值,模型都是用它自带的值进行处理,并不鸟控制器的赋值。

    回复于 2018-11-13 16:08 回复

    大兄弟,你看看你的controller代码

        $model->allowType = ['jpg', 'png', 'gif', 'txt'];
        $model->allowType = ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'text/plain'];
    

    下面的allowType覆盖上面的allowType了,自然没办法上传.txt文件

    回复于 2018-11-13 16:28 回复

    不好意思,写错了,上面那个是$model->mimetype = ['jpg', 'png', 'gif', 'txt']; 不是$model->allowType = ['jpg', 'png', 'gif', 'txt'];,这一样没法上传txt

  • 回答于 2018-11-13 17:28 举报

    你是怎么看$model->allowType没有被赋值的,能看看你的debug方式吗

    1 条回复
    回复于 2018-11-13 17:43 回复

    因为txt类型的文件没法被上传,显示格式出错呀。

  • 回答于 2018-11-14 10:19 举报

    我想说得是你不用担忧在控制器里不能给model赋值的问题,肯定是被后续覆盖了。
    另外,看到继承的还是Object,Object现在php7.1里的关键字。你的Yii2版本该升级了。

    1 条回复
    回复于 2018-11-14 15:32 回复

    我的YII2已经是最新的哦

您需要登录后才可以回答。登录 | 立即注册
clao
见习主管

clao

注册时间:2018-08-03
最后登录:2022-01-25
在线时长:9小时19分
  • 粉丝1
  • 金钱80
  • 威望20
  • 积分370

热门问题