php实现文件上传功能

php实现文件上传功能

实现步骤
  • 1.多文件上传格式化

    file=>[‘name’=>[0=>’xx’,1=>’xx’],’type’=>[0=>’xx’,1=>’xx’]
    格式化为:0=>[name=>’xx’,type=>’xx’]

  • 2.检测可能发生的错误

    1.上传文件错误(http://php.net/manual/zh/features.file-upload.php)


    2.自定义限定错误(文件上传类型,大小,后缀名,是否是通过post上传)

  • 3.创建父目录和子目录、子文件名

  • 4.移动文件到指定目录
  • 5.返回上传信息
使用
<?php

require "Upload.php";
$config = [
    'max_file_size' => 2097152,
    'allow_mimes' => ['image/png', 'image/jpeg', 'image/jpg', 'image/gif',],
    'allow_ext' => ['jpg', 'png', 'gif', 'jpeg'],
    'root' => 'upload',
    'sub_path' => 'sub',
    'auto_sub_dir' => true,
    'auto_sub_name' => false,
    'save_sub_rule' => [
        function ($value){
                return $value.'world';},
                 'hello'],
];

$up = new Upload($config);
$res = $up->run();
// $res:
      'code' => int 2000
      'msg' => string '上传成功' (length=12)
      'data' => 
        array (size=8)
          'name' => string 'xxx.jpeg' (length=26)
          'key' => string 'file' (length=4)
          'type' => string 'image/jpeg' (length=10)
          'error' => int 0
          'size' => int 123
          'ext' => string 'jpg' (length=3)
          'mime' => string 'image/jpeg' (length=10)
          'path' => string '' (length=48)
代码
<?php

class Upload
{
    private $_config = [
        'max_file_size' => 2097152,
        'allow_mimes' => [],
        'allow_ext' => [],
        'root' => 'uploads',
        'sub_path' => '',
        'auto_sub_dir' => true,
        'auto_sub_name' => true,
        'save_sub_rule' => ['date' , 'Y-m-d'],
    ];

    private $_msg = '没有错误';
    private $_fileInfo;
    private $_cur_path;

    public function __construct(array $config = [])
    {
        $this->_config = array_merge($this->_config, $config);
        $this->_fileInfo = new finfo();
    }

    public function __get(string $name): string
    {
        if (!isset($this->_config[$name]) || empty($this->_config[$name])) {
            $this->_msg = "获取失败,该配置选项不存在";
            return $this->_msg;
        }
        return $this->_config[$name];
    }

    public function __set(string $name, string $value)
    {
        if (isset($this->_config[$name])) {
            $this->_config[$name] = $value;
        } else {
            $this->_msg = "设置失败,该配置选项不存在";
        }
    }

    public function getError(): string
    {
        return $this->_msg;
    }

    public function run(): array
    {
        $files = $_FILES;
        $result = [
            'code' => 4000,
            'msg' => "上传失败",
            'data' => [],
        ];
        if (empty($files)) {
            $this->_msg = "没有上传文件";
            return $result;
        }

        $formatted_files = $this->format($files);
        if (empty($formatted_files) || !is_array($formatted_files)) {
            return $result;
        }
        foreach ($formatted_files as $item => $formatted_file) {
            $result2[$item] = [
                'code' => 4000,
                'msg' => "上传失败",
                'data' => [],
            ];
            if (!$this->check($formatted_file)) {
                $result2[$item]['msg'] = $this->_msg;
                continue;
            }

            //创建或检测父目录
            if (!$this->_config['root'] || !$this->createDir($this->_config['root'])) {
                $this->_msg = '父目录创建失败或未填写父目录';
                $result2[$item]['msg'] = $this->_msg;
                continue;
            }
            //子目录
            $parent_path = $this->_config['root'];
            if ($this->_config['auto_sub_dir']) {
                if (!$this->createSubDir($parent_path)) {
                    $result2[$item]['msg'] = $this->_msg;
                    continue;
                }
            } else {
                if ($this->_config['sub_path'] && $this->createDir($parent_path . DIRECTORY_SEPARATOR . $this->_config['sub_path'])) {
                    $this->_cur_path = $parent_path . DIRECTORY_SEPARATOR . $this->_config['sub_path'];
                } else {

                    $this->_cur_path = $parent_path;
                }
            }

            //文件名称
            $destination = $this->_cur_path . DIRECTORY_SEPARATOR;
            if (!$this->_config['auto_sub_name']) {
                $filename = $formatted_file['name'];
                $destination .= $filename;
            } else {
                $filename = $this->getUniName();
                $destination .= $filename . '.' . $formatted_file['ext'];
            }

            if (!move_uploaded_file($formatted_file['tmp_name'], $destination)) {
                $this->_msg = "权限不足或其他原因,无法移动文件到指定目录" . $destination;
                $result2[$item]['msg'] = $this->_msg;
                continue;
            }
            //success
            unset($formatted_file['tmp_name']);
            $formatted_file['path'] = $destination;
            $result2[$item]['data'] = $formatted_file;
            $this->_msg = "上传成功";
            $result2[$item]['code'] = 2000;
            $result2[$item]['msg'] = $this->_msg;
        }

        return $result2??$result;
    }

    public function check(array $file): bool
    {
        $flag = false;
        if (empty($file)) {
            $this->_msg = "上传文件为空";
            return $flag;
        }

        if (!is_array($file)) {
            $this->_msg = "非法的上传文件";
            return $flag;
        }

        if (!$this->getFileError($file['error'])) {
            return $flag;
        }

        if (!is_uploaded_file($file['tmp_name'])) {
            $this->_msg = "非法文件上传";
            return $flag;
        }

        if (!$this->checkMime($file['mime'])) {
            $this->_msg = "非法的mime类型";
            return $flag;
        }
        if (!$this->checkExt($file['ext'])) {
            $this->_msg = "非法的扩展名";
            return $flag;
        }
        if (!$this->checkSize($file['size'])) {
            $this->_msg = "上传文件大小符合要求";
            return $flag;
        }
        $flag = true;
        return $flag;
    }


    public function checkMime(string $mine): bool
    {
        return !$this->_config['allow_mimes'] ?: in_array($mine, $this->_config['allow_mimes']);
    }

    public function checkSize(int $size): bool
    {
        return ($this->_config['max_file_size'] > $size && $this->_config['max_file_size'] > 0);
    }

    public function checkExt(string $ext): bool
    {
        return !$this->_config['allow_ext'] ?: in_array($ext, $this->_config['allow_ext']);
    }


    public function getFileMime(string $name): string
    {
        return strtolower($this->_fileInfo->file($name, FILEINFO_MIME_TYPE));
    }

    public function getFileExt(string $name): string
    {
        return strtolower(pathinfo($name, PATHINFO_EXTENSION));
    }

    public function getUniName(): string
    {
        return md5(uniqid(microtime(true), true));
    }

    public function createDir(string $path): bool
    {
        return file_exists($path) ?: mkdir($path, 0777, true);
    }

    public function createSubDir(string $parent_path): bool
    {
        $rule = $this->_config['save_sub_rule'];
        if (empty($rule)) {
            $this->_msg = "请填写子目录规则";
            return false;
        }
        $value = array_values($rule);
        $sub_path = call_user_func($value[0],$value[1]);
        $parent_path = str_replace('/', '', $parent_path);
        $parent_path = str_replace('\\', '', $parent_path);
        $this->_cur_path = $parent_path . DIRECTORY_SEPARATOR . $sub_path;
        if (!$this->createDir($this->_cur_path)) {
            $this->_msg = "创建子目录失败";
            return false;
        }
        return true;
    }

    public function getFileError(string $no): bool
    {
        $flag = false;
        switch ($no) {
            case 0:
                $flag = true;
                $this->_msg = "文件上传成功";
                break;
            case 1:
                $this->_msg = "上传的文件超过的php.ini中upload_max_size中限制的值";
                break;
            case 2:
                $this->_msg = "上传的文件超过了HTML表单中max_file_size选项限制的值";
                break;
            case 3:
                $this->_msg = "文件只有部分被上传";
                break;
            case 4:
                $this->_msg = "没有文件被上传";
                break;
            case 6:
                $this->_msg = "找不到临时文件";
                break;
            case 7:
                $this->_msg = "文件写入失败";
                break;
        }

        return $flag;
    }


    public function format(array $files): array
    {
        $formatted = [];
        $order = 0;
        foreach ($files as $item => $value) {
            if (is_array($value['name'])) {
                $order = count($value['name']);
                $keys = array_keys($value);
                for ($i = 0; $i < $order; $i++) {
                    foreach ($keys as $key) {
                        $formatted[$i][$key] = $value[$key][$i];
                        $formatted[$i]['key'] = $item;
                    }
                    $formatted[$i]['ext'] = !$value['name'][$i] ?: $this->getFileExt($value['name'][$i]);
                    $formatted[$i]['mime'] = !$value['name'][$i] ?: $this->getFileMime($value['tmp_name'][$i]);
                }
            } else {
                $formatted[$order] = $value;
                $formatted[$order]['key'] = $item;
            }
        }

        return $formatted;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值