美文网首页PHP开发PHP经验分享
开发工具箱之文件上传类

开发工具箱之文件上传类

作者: phpworkerman | 来源:发表于2020-10-26 10:09 被阅读0次
工具介绍

文件上传功能基本每个网站都会应用到,每种类型的文件都是一种应用场景,自己在以往的工作中遇到上传开发总是重复造轮子,这次通过对上传类的封装做到一种通用、方便扩展的处理方式。

代码示例

上传功能的应用场景不光有图片,还有文档、音视频、压缩包等类型,不同的文件上传拥有较多相同的行为,这时可以把文件上传进行抽象,不同文件类型作为子类继承实现各自的上传方法。当有新的文件类型需要扩展时,可以在不修改原有代码的情况下进行扩展,可以支持多文件同时上传。

<?php
abstract class FileUpload
{
    //文件上传大小限制
    protected $maxsize = 3 * 1024 * 1024;
    //媒体类型
    protected $allowMime = [];
    //文件扩展名
    protected $allowFileExt = [];
    //文件保存路径
    protected $savePath;
    //文件上传后名称
    protected $saveFilename;
    //文件上传后字节长度
    protected $filenameLength = 10;
    //是否开启文件重命名
    protected $isRename = true;
    //上传文件错误
    protected $error;
    //上传失败文件
    protected $failedFile = [];

    /**
     * 设置文件上传最大值设置
     * @param $maxsize int 文件大小(单位 MB)
     * @return $this
     */
    public function setMaxsize(int $maxsize)
    {
        if($maxsize > 0){
            $this->maxsize = $maxsize * 1024 * 1024;
        }

        return $this;
    }

    /**
     * 文件上传时是否重命名
     * @param $isRename bool 是否重命名
     * @param $filenameLength int 字符长度
     */
    public function isRename(bool $isRename, int $filenameLength = 10)
    {
        $this->isRename = $isRename;
        $this->filenameLength = $filenameLength;

        return $this;
    }

    /**
     * 重新设置上传文件名称
     * @param $filename string 文件名
     * @return string
     * @throws \Exception
     */
    protected function setFilename(string $filename)
    {
        if($this->isRename === false){
            $this->saveFilename = $filename;
            return $this;
        }

        $fileExt = pathinfo($filename, PATHINFO_EXTENSION);
        $randomFilename = $this->generateRandomString($this->filenameLength);
        if(!$randomFilename){
            $this->error = '文件名生成失败';
            return false;
        }

        $this->saveFilename =  $randomFilename . '.' . $fileExt;

        return $this->saveFilename;
    }

    /**
     * 生成随机字符串
     * @param $length int 字符串长度
     * @return boolean|string
     * @throws \Exception
     */
    protected function generateRandomString(int $length)
    {
        if(!is_int($length)){
            return false;
        }

        if($length < 1){
            return false;
        }

        try{
            $bytes = random_bytes($length);
        }catch(\Exception $e){
            return false;
        }

        return substr(strtr(base64_encode($bytes), '+/', '-_'), 0, $length);
    }

    /**
     * 上传文件
     * @param $files array 文件,支持多个文件
     */
    abstract public function upload($files);

    /**
     * 验证文件合法性
     * @param $file array 文件
     * @return boolean
     */
    protected function validateFile($file)
    {
        if(!is_file($file['tmp_name'])){
            $this->error = '文件不合法';
            return false;
        }

        if($file['error'] > 0){
            $this->error = '文件上传错误';
            return false;
        }

        if($file['size'] > $this->maxsize){
            $this->error = '文件不能超过' . $this->maxsize / 1024 / 1024 . 'MB';
            return false;
        }

        if(!in_array(pathinfo($file['name'],PATHINFO_EXTENSION),$this->allowFileExt,true)){
            $this->error = '文件扩展名错误';
            return false;
        }

        if(!in_array($file['type'],$this->allowMime)){
            $this->error = '文件类型错误';
            return false;
        }

        //获取文件真实类型,防止MIME伪装
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $real_ext =  finfo_file($finfo, $file['tmp_name']);
        if($real_ext != $file['type']){
            $this->error = '文件类型错误';
            return false;
        }

        return true;
    }

    /**
     * 设置允许的文件类型
     * @param $mime array 文件类型
     * @return $this
     */
    public function setAllowMime(array $mime)
    {
        if(is_array($mime)){
            $this->allowMime = $mime;
        }

        return $this;
    }

    /**
     * 设置允许的文件扩展名
     * @param $ext array 文件扩展名
     * @return $this
     */
    public function setAllowFileExt(array $ext)
    {
        if(is_array($ext)){
            $this->allowFileExt = $ext;
        }

        return $this;
    }

    /**
     * 设置文件保存路径
     * @param $savePath string 文件保存路径
     * @return $this
     */
    public function setSavePath(string $savePath)
    {
        if(is_dir($savePath)){
            $this->savePath = rtrim($savePath,'/') . '/';
        }

        return $this;
    }

    /**
     * 获取错误信息
     */
    public function getError()
    {
        return $this->error;
    }
}

class ImageUpload extends FileUpload
{
    public function __construct()
    {
        $this->setAllowMime(['image/gif','image/jpeg','image/png']);
        $this->setAllowFileExt(['png','jpg','jpeg','gif']);
    }

    /**
     * 上传文件
     * @param $files array 文件
     * @return bool
     * @throws \Exception
     */
    public function upload($files)
    {
        if(empty($files) || !is_array($files)){
            $this->error = '文件不能为空';
            return false;
        }

        foreach($files as $key => $file){
            if(!$this->validateFile($file)){
                continue;
            }

            $saveName = $this->setFilename($file['name']);
            if(!$saveName){
                continue;
            }

            $move_filename = $this->savePath . $saveName;
            $move_result = move_uploaded_file($file['tmp_name'], $move_filename);
            if(!$move_result){
                $this->failedFile[] = $file['name'];
                continue;
            }
        }

        return true;
    }
}

相关文章

网友评论

    本文标题:开发工具箱之文件上传类

    本文链接:https://www.haomeiwen.com/subject/erlumktx.html