<?php
/**
 * +------------------------------------------------------------
 * | 文件 (files/controller/Api.php)
 * +------------------------------------------------------------
 * | @author: zhx (10630650@qq.com)
 * | @create_time: 2018-03-09 22:58:48
 * +------------------------------------------------------------
 * | @copyright: CIM (https://cimxx.com)
 * +------------------------------------------------------------
 * | @last_modified_by: zhx
 * | @last_modified_time: 2018-10-27 15:06:29
 * +------------------------------------------------------------
 * | @todo:
 * +------------------------------------------------------------
 */

namespace app\files\controller;

use think\facade\Env;

class Api extends Module
{

    private $modules;
    private static $engine;

    public function initialize()
    {
        parent::initialize();
        self::$engine = config('')['files']['engine'];
        $this->modules = input('param.module', '') ?: self::$sys['module'];
    }

    //文件上传
    public function upload($config = [], $return = 1, $field = '')
    {
        $this->load_config($config, $field);
        $this->type = input('type', '');
        $types = config('')['files']['types'];
        $mimes = array_values(array_intersect_key(config('')['files']['mimes'], array_fill_keys((is_int(self::$config['type']) ? $types[self::$config['type']] : self::$config['type']), 1)));
        $files = request()->file();
        if (empty($files)) {
            return;
        }
        $file = [];
        foreach ($files as $k => $v) {
            if (is_array($v)) {
                $file = array_merge($file, $v);
            } else {
                $file[] = $v;
            }
        }
        $result = [
            'success_count' => 0,
            'fail_count' => 0,
            'success' => [],
            'fail' => [],
        ];
        foreach ($file as $k => $v) {
            $status = 0;
            if ($v->isFile()) {
                $md5 = $v->hash('md5');
                $md5_check = model('app\files\model\Files')->where('md5', '=', $md5)->find();
                if (!empty($md5_check) && !in_array($field, ['avatar'])) {
                    //文件已存在
                    $status = 1;
                    $result['success_count']++;
                    $result['success'][] = [
                        'message' => '上传成功',
                        'type' => $md5_check['type'],
                        'size' => $md5_check['size'],
                        'url' => $this->_init_thumb($md5_check['path'], 1),
                        'path' => $md5_check['path'],
                        'ext' => $md5_check['ext']
                    ];
                    continue;
                }
                if ($v->isValid()) {
                    if ($v->checkMime($mimes)) {
                        if ($v->checkSize(self::$config['size'] * 1024)) {
                            $extension = empty(self::$config['ext']) ? (strtolower(pathinfo($v->getInfo('name'), PATHINFO_EXTENSION))) : self::$config['ext'];
                            $type = $this->check($extension) ? 0 : 1;
                            //$this->resize($v->getRealPath(), $v->getMime());
                            /*存储引擎*/
                            switch (self::$engine['name']) {
                                //七牛存储
                                case'qiniu':
                                    $file_path = $v->getRealPath();
                                    $temp_path = ltrim(str_replace(config('')['files']['path'], '', self::$config['path']), DIRECTORY_SEPARATOR) ?: (date('Ymd') . '/');
                                    $temp_name = empty(self::$config['file_name']) ? (md5(date('YmdHis') . rand(1, 99999)) . '.' . $extension) : (self::$config['file_name'] . '.' . $extension);
                                    $file_name = str_replace(DIRECTORY_SEPARATOR, '/', $temp_path) . $temp_name;
                                    $rs = $this->qiniu($v, $file_path, $file_name);
                                    break;
                                //阿里oss存储
                                case 'oss':
                                    break;
                                default :
                                    //本地存储
                                    $file_path = self::$config['path'];
                                    $file_name = empty(self::$config['file_name']) ? true : (self::$config['file_name'] . '.' . $extension);
                                    $rs = $this->localhost($v, $file_path, $file_name);
                                    break;
                            }
                            /*存储引擎*/
                            if ($rs) {
                                $result['success_count']++;
                                $status = 1;
                                $data[$k] = [
                                    'type' => $type,
                                    'path' => $rs['path'],
                                    'size' => $rs['size'],
                                    'ext' => $extension,
                                    'md5' => $md5,
                                    'create_time' => time()
                                ];
                                $result['success'][] = [
                                    'message' => '上传成功',
                                    'type' => $data[$k]['type'],
                                    'size' => $data[$k]['size'],
                                    'url' => $rs['url'],
                                    'path' => $data[$k]['path'],
                                    'ext' => $data[$k]['ext']
                                ];
                            } else {
                                $msg = '文件上传失败';
                            }
                        } else {
                            $msg = '当前大小不符合规格';
                        }
                    } else {
                        $msg = '当前类型不符合要求';
                    }
                } else {
                    $msg = '非法文件';
                }
            } else {
                $msg = '非法文件';
            }
            if (!$status) {
                $result['fail_count']++;
                $info = $v->getInfo();
                $result['fail'][] = [
                    'name' => $info['name'],
                    'msg' => $msg
                ];
            }
        }
        if (!empty($data)) {
            model('\app\files\model\Files')->insertAll(array_values($data), true);
        }
        if (request()->isAjax() && $result['success_count'] + $result['fail_count'] == 1) {
            $result = [
                'code' => $status,
                'msg' => $status ? '上传成功' : $result['fail'][0]['msg'],
                'data' => $status ? $result['success'][0] : []
            ];
        }
        return $return ? json($result) : $result;
    }

    /**
     * 重置图片大小
     * @param $path
     */
    function resize($path, $mime)
    {
        if ($mime != 'image/gif') {
            if (empty(self::$config['width']) && empty(self::$config['height']))
                return;
            $image = \think\Image::open($path);
            if (!self::$config['width'])
                self::$config['width'] = ceil($image->width() / ($image->height() / self::$config['height']));
            if (!self::$config['height'])
                self::$config['height'] = ceil($image->height() / ($image->width() / self::$config['width']));
            if ($image->width() > self::$config['width'])
                $image->thumb(self::$config['width'], self::$config['height'], 3);
            if (self::$config['mark'] && $image->width() > 200 && self::$config['width'] > 200)
                if (is_file(config('')['files']['mark'])) {
                    $image->water(config('')['files']['mark'], self::$config['mark'], 80);
                }
            $image->save($path, null, 90);
        }
    }

    /**
     * 生成缩略图
     * @param $path 原图路径
     * @return string 缩略图路径
     * $type变量说明 具体可见
     * //常量，标识缩略图等比例缩放类型
     * const THUMB_SCALING   = 1;
     * //常量，标识缩略图缩放后填充类型
     * const THUMB_FILLED    = 2;
     * //常量，标识缩略图居中裁剪类型
     * const THUMB_CENTER    = 3;
     * //常量，标识缩略图左上角裁剪类型
     * const THUMB_NORTHWEST = 4;
     * //常量，标识缩略图右下角裁剪类型
     * const THUMB_SOUTHEAST = 5;
     * //常量，标识缩略图固定尺寸缩放类型
     * const THUMB_FIXED     = 6;
     */
    function thumb($path)
    {
        //生成缩略图
        if (!empty(self::$config['thumb']) && is_array(self::$config['thumb']) && count(self::$config['thumb']) <= 2) {
            if (!is_file(self::$config['path'] . $path))
                return;
            $image = \think\Image::open(self::$config['path'] . $path);
            $path = self::$config['path'] . 'thumb' . DIRECTORY_SEPARATOR . $path;
            if (!file_exists(dirname($path))) @mkdir(dirname($path), 0777, true);
            $type = ($image->width() <= self::$config['thumb'][0]) ? 1 : 3;
            $image->thumb(self::$config['thumb'][0], self::$config['thumb'][1], $type)->save($path);
            return $path;
        }
    }

    /** 读取模块缓存配置
     * @param $size 默认大小
     * @param $type 默认格式
     * @param $filed
     * @return mixed 配置数组
     */
    private function load_config($config = [], $field = '')
    {
        $field = $field ?: input('param.field', '');
        $cid = input('param.cid', '');
        if (empty($config)) {
            if ($cid) {
                $columns = load_columns([
                    'tree' => 0,
                    'status' => ''
                ]);
                if (!empty($columns[$cid])) {
                    $config = [
                        'upload' => $columns[$cid]['setting']['upload'] ?? [],
                    ];
                }
            } else {
                $config_path = Env::get('app_path') . $this->modules . '/config/app.php';
                if (!is_file($config_path)) return;
                $config = include($config_path);
            }
        } else {
            self::$config['path'] = empty($config['path']) ? '' : $config['path'];
        }
        if (!isset($config['upload'])) {
            //return $this->error('非法操作');
        }
        if (!empty($config['upload'])) {
            if (!empty($config['upload'][$field])) {
                $config['upload'] = array_replace($config['upload'], $config['upload'][$field]);
            }
            self::$config = array_replace(self::$config, $config['upload']);
            self::$config['path'] = config('')['files']['path'] . DIRECTORY_SEPARATOR . self::$config['path'];
        } else {
            self::$config['path'] = config('')['files']['path'];
        }
    }

    /**
     * 检测图像文件
     * @return bool
     */
    public function check($extension)
    {
        /* 对图像文件进行严格检测 */
        if (in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png'])) {
            return true;
        }
        return false;
    }

    /**
     * 根据url获取图片
     */
    public function get_src($url = '')
    {
        if ($url) {
            $this->load_config();
            $file = http($url);
            if (!empty($file)) {
                $path = self::$config['path'] . DIRECTORY_SEPARATOR . date('Ymd') . DIRECTORY_SEPARATOR;
                // 判断类型
                if (!empty(stripos($file, 'jpeg'))) {
                    $ext = '.jpg';
                } elseif (!empty(stripos($file, 'gif'))) {
                    $ext = '.gif';
                } elseif (!empty(stripos($file, 'png'))) {
                    $ext = '.png';
                }
                if (empty($ext)) return json(['code' => 0, 'msg' => '不允许的文件类型']);
                if (!file_exists($path)) mkdir($path, 0755, 1);
                $name = md5(microtime(1)) . $ext;
                @file_put_contents($path . $name, $file);
                $this->thumb($path . $name);
                $data = [
                    'type' => $type = $this->check(ltrim($ext, '.')) ? 0 : 1,
                    'path' => date('Ymd') . '/' . $name,
                    'size' => strlen($file),
                    'ext' => ltrim($ext, '.'),
                    'md5' => md5_file($path . $name),
                    'create_time' => time()
                ];
                model('\app\files\model\Files')->insert($data);
                return json(['code' => 1, 'msg' => '文件上传成功', 'data' => [
                    'success_count' => 1,
                    'fail_count' => 0,
                    'success' => [
                        [
                            'message' => '上传成功',
                            'type' => $data['type'],
                            'size' => $data['size'],
                            'url' => $this->_init_thumb($data['path'], 1),
                            'path' => $data['path'],
                            'ext' => $data['ext']
                        ]
                    ],
                    'fail' => [],
                ]]);
            }
            return json(['code' => 0, 'msg' => '文件不存在']);
        }
    }

    /**
     * 更新附件信息
     */
    function update_file_info($attr = [], $source = [])
    {
        $update_data = [];
        if (!empty($source)) {
            //删除附件表原有对应关系
            foreach ($source as $sk => $sv) {
                $validate = $this->validate($sv, ['data_id' => 'require', 'path' => 'require', 'fields' => 'require']);
                if ($validate === true) {
                    $file_data = model('app\files\model\Files')->where('path', 'in', (array)$sv['path'])->select();
                    foreach ($file_data as $fk => $fv) {
                        $extend = isset($update_data[$fv['path']]) ? $update_data[$fv['path']]['extend'] : $fv['extend'];
                        if (!empty($extend)) {
                            $extend = object_to_array($extend);
                            if (!empty($extend[$this->modules][$sv['fields']])) {
                                $extend_data = array_unique(array_values(array_diff($extend[$this->modules][$sv['fields']], (array)$sv['data_id'])));
                                if (empty($extend_data)) {
                                    unset($extend[$this->modules][$sv['fields']]);
                                    if (empty($extend[$this->modules])) unset($extend[$this->modules]);
                                } else {
                                    $extend[$this->modules][$sv['fields']] = $extend_data;
                                }
                                $update_data[$fv['path']] = [
                                    'path' => $fv['path'],
                                    'extend' => empty($extend) ? null : $extend
                                ];
                            }
                        }
                    }
                }
            }
        }
        if (!empty($attr)) {
            //更新附件表对应关系
            foreach ($attr as $k => $v) {
                $validate = $this->validate($v, ['data_id' => 'require', 'path' => 'require', 'fields' => 'require']);
                if ($validate === true) {
                    $file_data = model('app\files\model\Files')->where('path', 'in', (array)$v['path'])->select();
                    foreach ($file_data as $kk => $vv) {
                        $extend = isset($update_data[$vv['path']]) ? $update_data[$vv['path']]['extend'] : $vv['extend'];
                        $extend = empty($extend) ? [] : object_to_array($extend);
                        $extend = array_merge_recursive($extend, [
                            $this->modules => [
                                $v['fields'] => [(string)$v['data_id']]
                            ]
                        ]);
                        $extend[$this->modules][$v['fields']] = array_unique(array_values($extend[$this->modules][$v['fields']]));
                        $update_data[$vv['path']] = ['path' => $vv['path'], 'extend' => $extend];
                    }
                }
            }
        }
        if (!empty($update_data)) model('app\files\model\Files')->allowField(true)->saveAll(array_values($update_data));
    }

    /**
     * 删除无用附件
     */
    function delete()
    {
        db('files')->where('extend', 'eq', null)->delete();
        return json(['code' => 1, 'msg' => '附件删除成功']);
    }

    /**
     * 本地上传
     */
    function localhost($file, $path, $name)
    {
        $rs = $file->move($path, $name);
        if ($rs) {
            //生成缩略图
            $this->thumb($rs->getSavename());
            //处理大小，水印
            $this->resize($rs->getPathname(), $rs->getMime());
            $result = [
                'path' => $path = trim(str_replace("\\", "/", str_ireplace(config('')['files']['path'], '', $rs->getPathname())), '/'),
                'size' => $rs->getSize(),
                'ext' => $rs->getExtension(),
                'url' => $this->request->domain() . '/' . basename(config('')['files']['path']) . '/' . $path
            ];
            return $result;
        } else {
            return 0;
        }
    }

    /**
     * 七牛上传
     */
    function qiniu($file, $path, $name)
    {
        $qiniu = new Qiniu($path, $name, $file);
        return $qiniu->upload();
    }

    /**
     * oss上传
     */
    function oss($file, $path, $name)
    {

    }

    /**
     * 根据路径处理图片
     */
    public function _init_thumb($val, $domain = 0, $thumb = 0)
    {
        if ($val) {
            if (self::$engine['name'] == 'qiniu') {
                return config('files.qiniu')['domain'] . '/' . $val;
            } else {
                $domain = $domain ? $this->request->domain() : '';
                if ($thumb && is_file(config('files.path') . DIRECTORY_SEPARATOR . 'thumb' . DIRECTORY_SEPARATOR . $val)) $val = 'thumb/' . $val;
                if (file_exists(config('files.path') . '/' . $val)) {
                    return $domain . config('files.url') . $val;
                } else {
                    if (strpos($val, 'avatar') !== false) {
                        return $domain . config('files.avatar');
                    }
                    return $domain . config('files.nopic');
                }
            }
        }
        return ($domain ? $this->request->domain() : '') . config('files.nopic');
    }

    /**
     * 返回文件原路径
     */
    public function original_thumb($val = '')
    {
        if ($val) {
            $val = str_replace($this->request->domain(), '', $val);
            if ($val == config('files.url') . config('files.nopic') || $val == config('files.nopic')) {
                return '';
            } else {
                if (config('files.engine')['name'] == 'qiniu') {
                    return ltrim($val, config('files.qiniu')['domain'] . '/');
                } else {
                    if (strpos($val, config('files.url')) !== false) $val = ltrim($val, config('files.url'));
                    return $val;
                }
            }
        }
        return '';
    }

}
