Yii2 上传文件解析 -- 表单上传 VS restful 上传

1 表单上传 和 restful 上传

1.1 建立一个模型 models/UploadForm.php

namespace app\models;

use yii\base\Model;
use yii\web\UploadedFile;


class UploadForm extends Model
{
    /**
     * @var  单个文件上传对应的属性
     */
    public $single;
    
    /**
     * @var  多个文件上传对应的属性
     */
    public $multiple

    /**
     * @return array the validation rules.
     */
    public function rules()
    {
        return [
              [['single'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
             [['multiple'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg','maxFiles' => 4],
        ];
    }
}
    //单个文件上传对应方法
    public function upload()
    {
        if ($this->validate()) {
            $newName = 'uploads/' . $this->single->baseName . '.' . $this->single->extension;
            $this->single->saveAs($newName);
            return true;
        } else {
            return false;
        }
    }
    
    //多个文件上传对应方法
    public function uploadMultiple()
    {
        if ($this->validate()) 
        { 
            foreach ($this->multiple as $file) {
            
                $newName = 'uploads/' . $file->baseName . '.' . $file->extension;
                $file->saveAs($newName);
            }
            return true;
        } else {
            return false;
        }
    }

1.2 建立一个视图文件 site/upload.php

<?php
use yii\widgets\ActiveForm;
?>

<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
 
<div style="margin-bottom:  30px;">
         <!--   单个文件上传按钮,主要用于 restful       -->
        <input name="single-file"  type="file">
        <!--   多个文件上传按钮,主要用于 restful     -->
        <input name="multi-file[]"  type="file" multiple="true"> 
</div> 
 
 <!--   单个文件上传按钮     -->
 <?= $form->field($model, 'single')->fileInput() ?>
 
  <!--   多个文件上传按钮     -->
 <?= $form->field($model, 'multiple[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>

 <button>Submit</button>

<?php ActiveForm::end() ?>

1.3 建立控制器文件 SiteController

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;

class SiteController extends Controller
{
    public function actionUpload()
    {
        $model = new UploadForm();

        if (Yii::$app->request->isPost) {
            /**
            **  使用ActiveForm 上传 
            **/
            //获取单个文件用 getInstance
            $model->single = UploadedFile::getInstance($model, 'single');
            $model->upload();
            
            //获取多个文件用 getInstances
            $model->multiple = UploadedFile::getInstances($model, 'multiple');
            $model->uploadMultiple();
            
            unset($model->single,$model->multiple);
            
            /**
            **  使用原生文件上传控件,主要用于 restful 文件上传
            **/
            
            //获取单个文件用 getInstanceByName
            $model->single = UploadedFile::getInstanceByName('single-file');
            $model->upload();
            
            //获取多个文件用 getInstancesByName
            $model->multiple = UploadedFile::getInstancesByName('multi-file');
            $model->uploadMultiple();
            
            unset($model->single,$model->multiple);
            
            
        }

        return $this->render('upload', ['model' => $model]);
    }
}

2 原理解析

2.1 代码分析

yii\web\UploadedFile::getInstance 最终调用 yii\web\UploadedFile::getInstanceByName
yii\web\UploadedFile::getInstances 最终调用yii\web\UploadedFile::getInstancesByName

yii\web\UploadedFile::getInstanceByName | yii\web\UploadedFile::getInstancesByName 都是查找 yii\web\UploadedFile::loadFiles() 生成的 $files 数组

public static function getInstance($model, $attribute)
{
    $name = Html::getInputName($model, $attribute);
    return static::getInstanceByName($name);
}
public static function getInstances($model, $attribute)
{
    $name = Html::getInputName($model, $attribute);
    return static::getInstancesByName($name);
}

public static function getInstanceByName($name)
{
    $files = self::loadFiles();
    return isset($files[$name]) ? new static($files[$name]) : null;
}

    
public static function getInstancesByName($name)
{
    $files = self::loadFiles();
    if (isset($files[$name])) {
        return [new static($files[$name])];
    }
    $results = [];
    foreach ($files as $key => $file) {
        if (strpos($key, "{$name}[") === 0) {
            $results[] = new static($file);
        }
    }
    return $results;
}

2.2 未经处理的 $_FILES 数组

echo '<pre>';
print_r($_FILES);

Array
(
    [single-file] => Array
        (
            [name] => 2017-08-01 10-11-45 的屏幕截图.png
            [type] => image/png
            [tmp_name] => /tmp/php2yWOZU
            [error] => 0
            [size] => 203247
        )

    [multi-file] => Array
        (
            [name] => Array
                (
                    [0] => 2017-08-01 10-11-45 的屏幕截图.png
                    [1] => 2017-07-31 02-24-02 的屏幕截图.png
                )

            [type] => Array
                (
                    [0] => image/png
                    [1] => image/png
                )

            [tmp_name] => Array
                (
                    [0] => /tmp/php40QPDr
                    [1] => /tmp/phpPRAVhY
                )

            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                )

            [size] => Array
                (
                    [0] => 203247
                    [1] => 182599
                )

        )

    [UploadForm] => Array
        (
            [name] => Array
                (
                    [single] => 2017-07-30 21-35-10 的屏幕截图.png
                    [multiple] => Array
                        (
                            [0] => 2017-07-28 22-20-00 的屏幕截图.png
                            [1] => 2017-07-25 22-04-50 的屏幕截图.png
                        )

                )

            [type] => Array
                (
                    [single] => image/png
                    [multiple] => Array
                        (
                            [0] => image/png
                            [1] => image/png
                        )

                )

            [tmp_name] => Array
                (
                    [single] => /tmp/phpCfL5Vu
                    [multiple] => Array
                        (
                            [0] => /tmp/phpNTGjA1
                            [1] => /tmp/php7EbKey
                        )

                )

            [error] => Array
                (
                    [single] => 0
                    [multiple] => Array
                        (
                            [0] => 0
                            [1] => 0
                        )

                )

            [size] => Array
                (
                    [single] => 150132
                    [multiple] => Array
                        (
                            [0] => 588277
                            [1] => 658391
                        )

                )

        )

)

2.3 处理过后的数组

yii\web\UploadedFile::loadFiles() 处理过后的 yii\web\UploadedFile::$_files 数组

Array
(
    [single-file] => Array
        (
            [name] => 2017-08-01 10-11-45 的屏幕截图.png
            [tempName] => /tmp/php2yWOZU
            [type] => image/png
            [size] => 203247
            [error] => 0
        )

    [multi-file[0]] => Array
        (
            [name] => 2017-08-01 10-11-45 的屏幕截图.png
            [tempName] => /tmp/php40QPDr
            [type] => image/png
            [size] => 203247
            [error] => 0
        )

    [multi-file[1]] => Array
        (
            [name] => 2017-07-31 02-24-02 的屏幕截图.png
            [tempName] => /tmp/phpPRAVhY
            [type] => image/png
            [size] => 182599
            [error] => 0
        )

    [UploadForm[single]] => Array
        (
            [name] => 2017-07-30 21-35-10 的屏幕截图.png
            [tempName] => /tmp/phpCfL5Vu
            [type] => image/png
            [size] => 150132
            [error] => 0
        )

    [UploadForm[multiple][0]] => Array
        (
            [name] => 2017-07-28 22-20-00 的屏幕截图.png
            [tempName] => /tmp/phpNTGjA1
            [type] => image/png
            [size] => 588277
            [error] => 0
        )

    [UploadForm[multiple][1]] => Array
        (
            [name] => 2017-07-25 22-04-50 的屏幕截图.png
            [tempName] => /tmp/php7EbKey
            [type] => image/png
            [size] => 658391
            [error] => 0
        )

)

可见 :
对于未使用ActiveForm 的 single-file, 要 获取文件实例 使用 yii\web\UploadedFile::getInstanceByName('single-file'),
对于未使用ActiveForm 的 multiple-file, 要 获取文件实例 使用 yii\web\UploadedFile::getInstancesByName('multi-file')。

对于使用ActiveForm 的 single, 要 获取文件实例,使用yii\web\UploadedFile::getInstance($model, 'single');

对于使用ActiveForm 的 multiple-file, 要 获取文件实例, 使用 yii\web\UploadedFile::getInstances('multiple')

2.4 修改 actionUpload() 输出 文件实例子

public function actionUpload()
{
   
    $model = new UploadForm();

    if (Yii::$app->request->isPost) 
    {
            
        echo '<pre>';
        
        //使用 ActiveForm 
        $model->single = UploadedFile::getInstance($model, 'single');
        $model->multiple = UploadedFile::getInstances($model, 'multiple');
        print_r($model->single);
        print_r($model->multiple);
        
        echo  "\r\n--------------------------------------------\r\n";
        
        //未使用 ActiveForm 
        $singleFile = UploadedFile::getInstanceByName('single-file');
        $multipleFiles = UploadedFile::getInstancesByName('multi-file');
     
        print_r($singleFile);
        print_r($multipleFiles);
        
        echo '</pre>';
        die;
    }

    return $this->render('upload', ['model' => $model]);
}

2.5 获取结果

yii\web\UploadedFile Object
(
    [name] => 2017-07-30 21-35-10 的屏幕截图.png
    [tempName] => /tmp/phpwfOx2M
    [type] => image/png
    [size] => 150132
    [error] => 0
)
Array
(
    [0] => yii\web\UploadedFile Object
        (
            [name] => 2017-07-28 22-20-00 的屏幕截图.png
            [tempName] => /tmp/phpmkO8qv
            [type] => image/png
            [size] => 588277
            [error] => 0
        )

    [1] => yii\web\UploadedFile Object
        (
            [name] => 2017-07-25 22-04-50 的屏幕截图.png
            [tempName] => /tmp/phpIyCVPd
            [type] => image/png
            [size] => 658391
            [error] => 0
        )

)

---------------------------------------------------------------------------------------
yii\web\UploadedFile Object
(
    [name] => 2017-08-01 10-11-45 的屏幕截图.png
    [tempName] => /tmp/phpiUvdRD
    [type] => image/png
    [size] => 203247
    [error] => 0
)
Array
(
    [0] => yii\web\UploadedFile Object
        (
            [name] => 2017-08-01 10-11-45 的屏幕截图.png
            [tempName] => /tmp/phpUtMzfm
            [type] => image/png
            [size] => 203247
            [error] => 0
        )

    [1] => yii\web\UploadedFile Object
        (
            [name] => 2017-07-31 02-24-02 的屏幕截图.png
            [tempName] => /tmp/phpYdi1D4
            [type] => image/png
            [size] => 182599
            [error] => 0
        )

)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,494评论 18 139
  • 在Yii里上传文件通常使用yii\web\UploadedFile类,它把每个上传的文件封装成UploadedFi...
    liudai123阅读 1,102评论 0 0
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,678评论 6 342
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,327评论 0 17
  • 红楼梦里说:“女儿是水做的骨肉,男人是泥做的骨肉。我见了女儿,我便清爽;见了男子,便觉浊臭逼人。”女儿,总能触动心...
    一滴露水阅读 295评论 4 4