<?php
if (!defined('puyuetian')) {
    exit('403');
}

class upload
{
    // 上传配置信息
    protected $config = [
        // 是否允许上传文件
        'open'      => 1,
        // 一次最多上传的文件数,0为不限制
        'count'     => 0,
        // 文件允许的最大大小,b,0为不限制
        'size'      => 0,
        // 文件存储的路径,相对于www目录
        'savepath'  => 'uploadfiles/',
        // 存储的文件名,不存在则随机
        'filename'  => '',
        // 允许上传的文件后缀,为空为不限制
        'suffix'    => '',
        // 若存在相同文件返回已上传的同文件
        'no_repeat' => 1,
    ];
    // 待上传的文件信息
    protected $file = [
        'name'     => 'unknow',
        'type'     => 'unknow',
        'size'     => 0,
        'tmp_name' => 'unknow',
        'error'    => '',
    ];
    // 待上传的文件总数
    protected $count = 0;
    // 错误信息
    protected $error = '';
    // 上传成功后的文件信息
    protected $fileinfo = [];
    // 上传错误系统信息
    protected $upload_error_text = [];
    // 待上传的文件对象
    protected $upload_objects = [];

    // 实例化上传类,可设置配置
    public function __construct($config = [])
    {
        // 错误信息
        $this->upload_error_text = [
            1 => '上传的文件超过了php.ini中upload_max_filesize选项限制的值',
            2 => '上传文件的大小超过了HTML表单中MAX_FILE_SIZE选项指定的值',
            3 => '文件只有部分被上传',
            4 => '没有文件被上传',
        ];
        // 初始化配置
        $this->config([
            // 一次最多上传的文件数,0为不限制
            'count'     => set('uploadfilecount'),
            // 文件允许的最大大小,b,0为不限制
            'size'      => set('uploadfilesize') * 1024,
            // 文件存储的路径,相对于www目录
            'savepath'  => 'uploadfiles/files/' . user('id') . '/' . date('Ymd/'),
            // 存储的文件名,不存在则随机
            'filename'  => '',
            // 允许上传的文件后缀,为空为不限制
            'suffix'    => str_replace('|', ',', set('uploadfiletypes')),
            // 若存在相同文件返回已上传的同文件
            'no_repeat' => set('smartupload'),
        ]);
        $this->config($config);
    }

    // 获取待上传的文件对象
    /*
     * @param $file 待上传的文件对象，为input对象的name
     */
    public function file($file)
    {
        // print_r($file);
        // exit;
        if (!isset($_FILES[$file])) {
            $this->error = '没有选择文件';
            return $this;
        }
        if (!$this->config['open']) {
            $this->error = '本站未开启上传';
            return $this;
        }
        $a = $_FILES[$file];
        $b = [];
        if (!is_array($a['error'])) {
            foreach ($a as $k => $v) {
                $a[$k] = [$v];
            }
        }
        foreach ($a['error'] as $k => $v) {
            $b[] = $this->_file([
                'name'     => $a['name'][$k],
                'type'     => $a['type'][$k],
                'size'     => $a['size'][$k],
                'tmp_name' => $a['tmp_name'][$k],
                'error'    => $v,
            ]);
        }
        $this->count = count($b);
        if ($this->config['count'] && $this->count > $this->config['count']) {
            $this->error = '一次上传数量超过了最大值' . $this->config['count'];
            return $this;
        }
        // if (1 == $this->count) {
        //     return $b[0];
        // }
        $this->upload_objects = $b;
        return $b;
    }

    // 初始化单个文件对象
    protected function _file($file)
    {
        $a       = new upload($this->config);
        $a->file = $file;
        if ($file['error']) {
            $a->error = $a->upload_error_text($file['error']);
            return $a;
        }
        if ($a->config['size'] && $file['size'] > $a->config['size']) {
            $a->error = '文件大小超过了最大值' . formatBytes($a->config['size']);
            return $a;
        }
        $filesuffix = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if ($a->config['suffix']) {
            $suffix = $a->config['suffix'];
            if (!is_array($suffix)) {
                $suffix = explode(',', strtolower($suffix));
            }
            if (!in_array($filesuffix, $suffix)) {
                $a->error = '文件类型不被允许' . $file['name'];
                return $a;
            }
        }
        return $a;
    }

    // 设置上传配置
    /*
     * @param $key 配置信息的名称，该参数可数组
     * @param $value 值
     */
    public function config($key, $value = null)
    {
        if (is_array($key) && null === $value) {
            foreach ($key as $k => $v) {
                $this->config[$k] = $v;
            }
        } elseif (is_string($key)) {
            $this->config[$key] = $value;
        }
        return $this;
    }

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

    //获取待上传文件的信息
    public function getfile($info = null)
    {
        if (!$info) {
            return $this->file;
        }
        return $this->file[$info];
    }

    //获取上传成功的文件信息
    public function fileinfo($info = null)
    {
        if (!$info) {
            return $this->fileinfo;
        }
        return $this->fileinfo[$info];
    }

    // 获取系统错误信息
    protected function upload_error_text($key)
    {
        return isset($this->upload_error_text[$key]) ? $this->upload_error_text[$key] : '未知错误';
    }

    // 保存上传的文件
    /*
     * @param $savepath 文件保存的路径
     * @param $ext_data 存入数据库的额外数据（数组），false为不写入数据库
     */
    public function move($savepath = null)
    {
        //判断是否发生了错误
        if ($this->error) {
            return false;
        }
        $file = $this->file;
        // 是否设置了保存路径
        if (!$savepath) {
            $savepath = $this->config['savepath'];
        }
        $idcode = md5_file($file['tmp_name']);
        //是否存在该文件
        if ($this->config['no_repeat']) {
            $data = table('upload')->where([
                'idcode' => $idcode,
            ])->find();
            if ($data) {
                $dir_path       = "uploadfiles/{$data['target']}s/{$data['uid']}/" . substr($data['datetime'], 0, 8) . "/";
                $filename       = substr($data['datetime'], 8) . "_{$data['rand']}.{$data['suffix']}";
                $filepath       = $dir_path . $filename;
                $this->fileinfo = [
                    'dir_path'   => $dir_path,
                    'filename'   => $filename,
                    'filepath'   => $filepath,
                    'filesize'   => filesize(PK_WWWROOT . $filepath),
                    'filetype'   => filetype(PK_WWWROOT . $filepath),
                    'id'         => $data['id'],
                    'md5_file'   => $data['idcode'],
                    'uploadtime' => $data['uploadtime'],
                ];
                return $this->fileinfo;
            }
        }
        $time       = date('His', time());
        $rand       = CreateRandomString(6);
        $filename   = "{$time}_{$rand}";
        $filesuffix = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        $filename .= '.' . $filesuffix;
        $savepath = PK_WWWROOT . trim(trim($savepath, '/'), '\\') . '/' . $filename;
        $dir_path = dirname($savepath);
        if (!file_exists($dir_path) && !mkdir($dir_path, 0777, true)) {
            $this->error = '目录创建失败';
            return false;
        }
        if (!move_uploaded_file($file['tmp_name'], $savepath)) {
            $this->error = '上传失败' . json_encode($file['tmp_name'], 320);
            return false;
        }
        // 获取文件的相对路径
        $dir_path = substr($dir_path, strlen(PK_WWWROOT));
        $dir_path = trim(str_replace(['\\', '//'], '/', $dir_path), '/') . '/';
        $filepath = $dir_path . $filename;
        // 记录该文件
        $data = [
            'target'        => 'file',
            'uid'           => user('id'),
            'datetime'      => date('YmdHis'),
            'rand'          => $rand,
            'suffix'        => $filesuffix,
            'idcode'        => $idcode,
            'jifen'         => 0,
            'tiandou'       => 0,
            'downloadcount' => 0,
            'name'          => '',
            'uploadtime'    => time(),
        ];
        $db               = table('upload')->data($data);
        $data['id']       = $db->insertGetId();
        $data['filepath'] = $filepath;
        $data['dir_path'] = $dir_path;
        $data['filename'] = $filename;
        $data['md5_file'] = $data['idcode'];
        $data['filetype'] = filetype(PK_WWWROOT . $filepath);
        $data['filesize'] = filesize(PK_WWWROOT . $filepath);
        $this->fileinfo   = $data;
        return $data;
    }

    // 保存上传的文件，多个对象移动
    /**
     * @param $savepath 文件保存的路径
     * @param $ext_data 存入数据库的额外数据（数组），false为不写入数据库
     */
    public function moves($savepath = null)
    {
        $objs  = $this->upload_objects;
        $datas = [];
        foreach ($objs as $obj) {
            $data         = ['code' => 1];
            $data['data'] = $obj->move($savepath);
            $data['msg']  = 'ok';
            if (!$data['data']) {
                $data['code'] = 0;
                $data['data'] = [];
                $data['msg']  = $obj->error();
            }
            $datas[] = $data;
        }
        return $datas;
    }
}
