前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Yii2文件/图片上传实例

Yii2文件/图片上传实例

原创
作者头像
OwenZhang
发布2022-05-26 11:09:53
1.3K0
发布2022-05-26 11:09:53
举报
文章被收录于专栏:Owen's WorldOwen's World

本文环境 Windows10,PHP7.1,Nginx1.8,Yii 2.0\ 不懂的可以评论或联系我邮箱:owen@owenzhang.com\ 著作权归OwenZhang所有。商业转载请联系OwenZhang获得授权,非商业转载请注明出处。

Yii2框架介绍

Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。 名字 Yii (读作 )在中文里有“极致简单与不断演变”两重含义, 也可看作 Yes It Is! 的缩写。

Yii 是一个通用的 Web 编程框架,即可以用于开发各种用 PHP 构建的 Web 应用。 因为基于组件的框架结构和设计精巧的缓存支持,它特别适合开发大型应用, 如门户网站、社区、内容管理系统(CMS)、 电子商务项目和 RESTful Web 服务等。

文件上传父类

类函数说明

  • 根据时间创建目录 createDir
  • 获取URL路径 getUrlPath
  • 获取文件名 getFileName
  • 获取文件大小 getFileSize
  • 获取文件类型 getFileType
  • 获取文件的Mine类型 getFileMime
  • 获取文件md5 getFileMd5
  • 获取图片的宽度 getThumbWidth
  • 获取图片的高度 getThumbHeight
  • 获取文件保存 save

具体类代码

代码语言:php
复制
<?php

namespace common\helpers;

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

class UploadHelper extends Object
{
    // 处理的model
    public $model;

    // 最大允许上传的文件大小  5Mb
    public $maxSize = 5227520;

    // 上传文件表单名称
    public $fileInputName = 'file';

    // 图片保存绝对路径
    public $savePath;

    // 文件访问路径前缀
    public $urlPathPrefix;

    // 文件后缀格式
    public $extensions;

    // 文件Mime 类型
    public $mimeTypes;

    // 上传文件处理类
    private $uploadFile;

    // 文件保存路径
    private $filePath;

    // 文件访问路径
    private $urlPath;

    // 文件大小
    private $fileSize;

    // 文件Mime类型
    private $fileMime;

    // 文件后缀
    private $fileExtension;

    // 文件名
    private $fileName;

    // 图片宽度
    private $thumbWidth;

    // 图片高度
    private $thumbHeight;

    // 文件MD5哈希值
    private $fileMd5;

    public function init()
    {
        if (empty($this->model) || !($this->model instanceof Model)) {
            throw new Exception(Yii::t('app', 'No delivery file class passed'));
        }

        // 上传文件接收
        $strField = $this->fileInputName;
        $this->model->$strField = $this->uploadFile = UploadedFile::getInstanceByName($this->fileInputName);

        if (empty($this->uploadFile)) {
            throw new Exception(Yii::t('app', 'No file uploaded'));
        }

        // 获取上传文件的后缀格式
        $extension = $this->uploadFile->extension;
        $fileMime = $this->uploadFile->type;
        $thumbExtensionArray = ['jpg', 'jpeg', 'gif', 'png', 'bmp'];
        $this->thumbWidth = $this->thumbHeight = 0;

        // 判断上传的文件是否是图片文件
        if(in_array($extension, $thumbExtensionArray)){
            $this->savePath = Yii::getAlias('@frontend/web/uploads/material/images');
            $this->urlPathPrefix = '/uploads/material/images';
            $this->extensions = $thumbExtensionArray;
            $this->mimeTypes = ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png'];
            $thumbInfo = getimagesize($this->uploadFile->tempName);
            $this->thumbWidth = isset($thumbInfo[0]) ? $thumbInfo[0] : $this->thumbWidth;
            $this->thumbHeight = isset($thumbInfo[1]) ? $thumbInfo[1] : $this->thumbHeight;
        } else {
            $this->savePath = Yii::getAlias('@frontend/web/uploads/material/files');
            $this->urlPathPrefix = '/uploads/material/files';
            $this->extensions = ['txt', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'];
            $this->mimeTypes = ['text/plain', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/pdf'];
        }

        // 验证文件类型是否在允许的范围
        if(!in_array($extension, $this->extensions) || !in_array($fileMime, $this->mimeTypes)){
            throw new Exception(Yii::t('app', 'This file type does not allow uploading'));
        }

        // 目录不存在创建
        $this->savePath = rtrim($this->savePath, '/');
        if (!file_exists($this->savePath) && !FileHelper::createDirectory($this->savePath)) {
            throw new Exception(Yii::t('app', 'No permission to create') . $this->savePath);
        }

        // 限制上传的文件小于5M
        if($this->uploadFile->size > $this->maxSize){
            throw new Exception(Yii::t('app', 'Uploaded files cannot exceed') . ($this->maxSize / 1048576) . 'Mb');
        }

        // 上传文件验证
        if (!$this->model->validate()) {
            throw new Exception($this->model->getFirstError($strField));
        }

        list($path, $datePath) = $this->createDir($this->savePath);

        // 文件名命名
        $fileName = time() . mt_rand(1000, 9999);

        $this->filePath = $path . $fileName . '.' . $this->uploadFile->getExtension();
        $this->urlPath  = rtrim($this->urlPathPrefix, '/') . '/' . $datePath . '/' . $fileName . '.' . $this->uploadFile->getExtension();
        $this->fileExtension = $extension;
        $this->fileSize = round($this->uploadFile->size / 1024, 2) . ' Kb';
        $this->fileMime = $this->uploadFile->type;
        $this->fileName = $fileName;
        $this->fileMd5 = hash_file('md5', $this->uploadFile->tempName);

    }

    /**
     * 根据时间创建目录
     */
    public function createDir($path)
    {
        $datePath = date('Y') . '/' . date('md');
        $path = $path . '/' . $datePath . '/';
        if (!file_exists($path)) {
            FileHelper::createDirectory($path);
        }

        return [$path, $datePath];
    }

    /**
     * 获取URL路径
     * @return mixed
     */
    public function getUrlPath()
    {
        return $this->urlPath;
    }

    /**
     * 获取文件名
     * @return mixed
     */
    public function getFileName()
    {
        return $this->fileName;
    }

    /**
     * 获取文件大小
     * @return mixed
     */
    public function getFileSize()
    {
        return $this->fileSize;
    }

    /**
     * 获取文件类型
     * @return mixed
     */
    public function getFileType()
    {
        return $this->fileExtension;
    }

    /**
     * 获取文件的Mine类型
     * @return mixed
     */
    public function getFileMime()
    {
        return $this->fileMime;
    }

    public function getFileMd5()
    {
        return $this->fileMd5;
    }

    /**
     * 获取图片的宽度
     * @return mixed
     */
    public function getThumbWidth()
    {
        return $this->thumbWidth;
    }

    /**
     * 获取图片的高度
     * @return mixed
     */
    public function getThumbHeight()
    {
        return $this->thumbHeight;
    }

    public function save()
    {
        return $this->uploadFile->saveAs($this->filePath);
    }
}

文件上传的漏洞和防御

漏洞描述

没有做文件的限制,导致用户上传了非法的文件,或者过大的文件导致服务器过载。用户上传木马文件等

例如以下就是木马代码

代码语言:txt
复制
<?php eval($_GET['cmd']);?>

漏洞防御

  1. 审查用户上传的文件时加入了“Content-Type”验证
  2. “Content-Type”是image/jpeg或者image/png时文件可以上传 成功
  3. 文件上传验证类
  4. 验证会话身份,用于防止csrf攻击
  5. 添加白名单的来限制上传的文件后缀和上传的来源
  6. 文件大小的限制
  7. 用户上传的源文件删除
  8. 上传过程中产生的临时文件删除
  9. imagecreatefromjpeg()和imagecreatefrompng()来过来文件的有害元数据
  10. 上传接口的数据校验
  11. 现在更多的是上传到OSS云存储上

文件上传验证类

基于安全方面的考虑,您应当增加有关允许哪些用户上传文件的限制和验证。

类函数说明

  • 验证规则 rules
  • file为文件上传的参数名 public $file;
  • image为图片上传的参数名 public $image;
  • 文件上传的文件类型 'extensions' => 'jpg', 'png', 'gif', 'txt'
  • 增加了对文件上传的限制。只能上传 .gif、.txt、.jpg、.png 文件,文件大小必须小于 50000 kB:
  • 要不要验证 mimeTypes类型 'checkExtensionByMimeType' => false,
  • 文件的Mine类型 'mimeTypes' => 'image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'text/plain',
  • 验证场景 scenarios
  • 验证属性标签 attributeLabels

具体类代码

代码语言:php
复制
<?php

namespace common\models;

use yii;
use yii\base\Model;

class UploadForm extends Model
{
    public $file;

    public $image;

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [
                ['file'],
                'file',
                'extensions' => ['jpg', 'png', 'gif', 'txt'],
                'mimeTypes' => ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'text/plain'],
                'checkExtensionByMimeType' => false,   // 要不要验证 mimeTypes 类型
                'on' => 'file',
            ],
            [
                ['image'],
                'image',
                'extensions' => ['jpg', 'png', 'gif', 'bmp'],
                'mimeTypes' => ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'image/bmp'],
                'checkExtensionByMimeType' => false,   // 要不要验证 mimeTypes 类型
                'on' => 'image',
            ]
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function scenarios()
    {
        return [
            'image' => ['image'],
            'file' => ['file'],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return [
            'file' => Yii::t('app', 'File'),
            'image' => Yii::t('app', 'Image'),
        ];
    }
}

文件上传实例接口方法

类函数说明

  • 文件上传 actionFileUpload
  • 图片上传实例方法 actionImageUpload
  • 初始化文件上传类 $model = New UploadHelper([ 'fileInputName' => 'file', 'model' => new UploadForm('scenario' => 'file'), ]);
  • 上传成功后返回结果 return $this->asJson
  • 在服务器的 PHP 临时文件夹中创建了一个被上传文件的临时副本。这个临时的副本文件会在脚本结束时消失。要保存被上传的文件,我们需要把它拷贝到另外的位置。
  • if (!$model->save()) { throw new Exception(Yii::t('app', 'File upload failed')); }代码检测了文件是否已存在,如果不存在,则把文件拷贝到名为 "upload" 的目录下。
  • 最终上传成功后 会销毁临时文件

文件上传实例方法

代码语言:php
复制
/**
     * 文件上传
     * @return yii\web\Response
     */
    public function actionFileUpload()
    {
        try {
            $model = New UploadHelper([
                'fileInputName' => 'file',
                'model' => new UploadForm(['scenario' => 'file']),
            ]);

            if (!$model->save()) {
                throw new Exception(Yii::t('app', 'File upload failed'));
            }

            return $this->asJson([
                'status' => 'ok',
                'message' => Yii::t('app', 'Uploaded successfully and saved in the attachment library'),
                'data' => [
                    'file_url' => $model->getUrlPath(),
                    'file_name' => $model->getFileName(),
                    'file_type' => $model->getFileType(),
                    'file_size' => $model->getFileSize(),
                    'file_mime' => $model->getFileMime(),
                    'file_md5' => $model->getFileMd5(),
                    'thumb_width' => $model->getThumbWidth(),
                    'thumb_height' => $model->getThumbHeight(),
                ]
            ]);
        } catch (Exception $e) {
            return $this->asJson([
                'status' => 'error',
                'message' => $e->getMessage()
            ]);
        }
    }

图片上传实例方法

代码语言:php
复制
/**
     * 图片上传
     * @return yii\web\Response
     */
    public function actionImageUpload()
    {
        try {
            $model = New UploadHelper([
                'fileInputName' => 'image',
                'model' => new UploadForm(['scenario' => 'image']),
            ]);

            if (!$model->save()) {
                throw new Exception(Yii::t('app', 'File upload failed'));
            }

            return $this->asJson([
                'status' => 'ok',
                'message' => Yii::t('app', 'Uploaded successfully and saved in the attachment library'),
                'data' => [
                    'file_url' => $model->getUrlPath(),
                    'file_name' => $model->getFileName(),
                    'file_type' => $model->getFileType(),
                    'file_size' => $model->getFileSize(),
                    'file_mime' => $model->getFileMime(),
                    'file_md5' => $model->getFileMd5(),
                    'thumb_width' => $model->getThumbWidth(),
                    'thumb_height' => $model->getThumbHeight(),
                ]
            ]);
        } catch (Exception $e) {
            return $this->asJson([
                'status' => 'error',
                'message' => $e->getMessage()
            ]);
        }
    }

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Yii2框架介绍
  • 文件上传父类
    • 类函数说明
      • 具体类代码
      • 文件上传的漏洞和防御
        • 漏洞描述
          • 漏洞防御
          • 文件上传验证类
            • 类函数说明
              • 具体类代码
              • 文件上传实例接口方法
                • 类函数说明
                  • 文件上传实例方法
                    • 图片上传实例方法
                    相关产品与服务
                    对象存储
                    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档