<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者，助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件，未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------

namespace crmeb\services\upload;

use crmeb\basic\BaseStorage;
use think\facade\Config;

/**
 * Class BaseUpload
 * @package crmeb\basic
 */
abstract class BaseUpload extends BaseStorage
{
    /**
     * 缩略图
     * @var string[]
     */
    protected $thumb = ['big', 'mid', 'small'];

    /**
     * 缩略图配置
     * @var array
     */
    protected $thumbConfig = [
        'image_thumb_status' => 0,
        'thumb_big_height' => 800,
        'thumb_big_width' => 800,
        'thumb_mid_height' => 300,
        'thumb_mid_width' => 300,
        'thumb_small_height' => 100,
        'thumb_small_width' => 100,
    ];
    /**
     * 水印配置
     * @var array
     */
    protected $waterConfig = [
        'image_watermark_status' => 0,
        'watermark_type' => 1,
        'watermark_image' => '',
        'watermark_opacity' => 0,
        'watermark_position' => 1,
        'watermark_rotate' => 0,
        'watermark_text' => '',
        'watermark_text_angle' => "",
        'watermark_text_color' => '#000000',
        'watermark_text_size' => '5',
        'watermark_text_font' => '',
        'watermark_x' => 0,
        'watermark_y' => 0
    ];
    /**
     * 图片信息
     * @var array
     */
    protected $fileInfo;
    /**
     * 下载图片信息
     */
    protected $downFileInfo;

    /**
     * 要生成缩略图、水印的图片地址
     * @var string
     */
    protected $filePath;

    /**
     * 验证配置
     * @var string
     */
    protected $validate;

    /**
     * 保存路径
     * @var string
     */
    protected $path = '';

    /**
     * 是否自动裁剪
     * @var bool
     */
    protected $authThumb = false;

    protected function initialize(array $config)
    {
        $this->fileInfo = $this->downFileInfo = new \StdClass();
        $this->thumbConfig = array_merge($this->thumbConfig, $config['thumb'] ?? []);
        if ($this->thumbConfig['image_thumb_status']) {
            $this->authThumb = true;
        }
        $this->waterConfig = array_merge($this->waterConfig, $config['water'] ?? []);
    }

    /**
     * 设置处理缩略图、水印图片路径
     * @param string $filePath
     * @return $this
     */
    public function setFilepath(string $filePath)
    {
        $this->filePath = substr($filePath, 0, 1) === '.' ? substr($filePath, 1) : $filePath;
        return $this;
    }

    /**
     * 是否自动裁剪
     * @param bool $auth
     * @return $this
     */
    public function setAuthThumb(bool $auth)
    {
        $this->authThumb = $auth;
        return $this;
    }

    /**
     * 上传文件路径
     * @param string $path
     * @return $this
     */
    public function to(string $path)
    {
        $this->path = $path;
        return $this;
    }

    /**
     * 获取文件信息
     * @return array
     */
    public function getFileInfo()
    {
        return $this->fileInfo;
    }

    /**
     * 检测是否是图片
     * @param $filePath
     * @return bool
     */
    protected function checkImage($filePath)
    {
        //获取图像信息
        $info = @getimagesize($filePath);
        //检测图像合法性
        if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) {
            return false;
        }
        return true;
    }

    /**
     * 验证合法上传域名
     * @param string $url
     * @return string
     */
    protected function checkUploadUrl(string $url)
    {
        if ($url && strstr($url, 'http') === false) {
            $url = 'http://' . $url;
        }
        return $url;
    }

    /**
     * 获取系统配置
     * @return mixed
     */
    protected function getConfig()
    {
        $config['filesize'] = Config::get($this->configFile . '.filesize', []);
        $config['fileExt'] = Config::get($this->configFile . '.fileExt', []);
        $config['fileMime'] = Config::get($this->configFile . '.fileMime', []);
        return $config;
    }

    /**
     * 设置验证规则
     * @param array|null $validate
     * @return $this
     */
    public function validate(?array $validate = null)
    {
        if (is_null($validate)) {
            $validate = $this->getConfig();
        }
        $this->validate = $validate;
        return $this;
    }

    /**
     * 验证目录是否正确
     * @param string $key
     * @return false|string
     */
    protected function getUploadPath(string $key)
    {
        $path = ($this->path ? $this->path . '/' : '') . $key;
        if ($path && $path[0] === '/') {
            $path = substr($path, 1);
        }
        return $path;
    }

    /**
     * 提取文件名
     * @param string $path
     * @param string $ext
     * @return string
     */
    protected function saveFileName(string $path = null, string $ext = 'jpg')
    {
        return ($path ? substr(md5($path), 0, 5) : '') . date('YmdHis') . rand(0, 9999) . '.' . $ext;
    }

    /**
     * 提取文件后缀以及之前部分
     * @param string $path
     * @return false|string[]
     */
    protected function getFileName(string $path)
    {
        $_empty = ['', ''];
        if (!$path) return $_empty;
        if (strpos($path, '?')) {
            $_tarr = explode('?', $path);
            $path = trim($_tarr[0]);
        }
        $arr = explode('.', $path);
        if (!is_array($arr) || count($arr) <= 1) return $_empty;
        $ext_name = trim($arr[count($arr) - 1]);
        $ext_name = !$ext_name ? 'jpg' : $ext_name;
        return [explode('.' . $ext_name, $path)[0], $ext_name];
    }

    /**
     * 获取图片地址
     * @param string $filePath
     * @param bool $is_parse_url
     * @return string
     */
    protected function getFilePath(string $filePath = '', bool $is_parse_url = false)
    {
        $path = $filePath ?: $this->filePath;
        if ($is_parse_url) {
            $data = parse_url($path);
            //远程地址处理
            if (isset($data['host']) && isset($data['path'])) {
                if (file_exists(app()->getRootPath() . 'public' . $data['path'])) {
                    $path = $data['path'];
                }
            }
        }
        return $path;
    }

    /**
     * 获取文件类型和大小
     * @param string $url
     * @param bool $isData
     * @return array
     */
    protected function getFileHeaders(string $url, $isData = true)
    {
        stream_context_set_default(['ssl' => ['verify_peer' => false, 'verify_peer_name' => false]]);
        $header['size'] = 0;
        $header['type'] = 'image/jpeg';
        if (!$isData) {
            return $header;
        }
        try {
            $headerArray = get_headers(str_replace('\\', '/', $url), true);
            if (!isset($headerArray['Content-Length'])) {
                $header['size'] = 0;
            }
            if (!isset($headerArray['Content-Type'])) {
                $header['type'] = 'image/jpeg';
            }
            if (is_array($headerArray['Content-Length']) && count($headerArray['Content-Length']) == 2) {
                $header['size'] = $headerArray['Content-Length'][1];
            }
            if (is_array($headerArray['Content-Type']) && count($headerArray['Content-Type']) == 2) {
                $header['type'] = $headerArray['Content-Type'][1];
            }
        } catch (\Exception $e) {
        }
        return $header;
    }

    /**
     * 获取上传信息
     * @return array
     */
    public function getUploadInfo()
    {
        if (isset($this->fileInfo->filePath)) {
            if (strstr($this->fileInfo->filePath, 'http') === false) {
                $url = request()->domain() . $this->fileInfo->filePath;
            } else {
                $url = $this->fileInfo->filePath;
            }
            $headers = $this->getFileHeaders($url);
            return [
                'name' => $this->fileInfo->fileName,
                'real_name' => $this->fileInfo->realName ?? '',
                'size' => $headers['size'] ?? 0,
                'type' => $headers['type'] ?? 'image/jpeg',
                'dir' => $this->fileInfo->filePath,
                'thumb_path' => $this->fileInfo->filePath,
                'thumb_path_big' => $this->fileInfo->filePathBig ?? '',
                'thumb_path_mid' => $this->fileInfo->filePathMid ?? '',
                'thumb_path_small' => $this->fileInfo->filePathSmall ?? '',
                'thumb_path_water' => $this->fileInfo->filePathWater ?? '',
                'time' => time(),
            ];
        } else {
            return [];
        }
    }

    /**
     * 获取下载信息
     * @return array
     */
    public function getDownloadInfo()
    {
        if (isset($this->downFileInfo->downloadFilePath)) {
            if (strstr($this->downFileInfo->downloadFilePath, 'http') === false) {
                $url = request()->domain() . $this->downFileInfo->downloadFilePath;
            } else {
                $url = $this->downFileInfo->downloadFilePath;
            }
            $headers = $this->getFileHeaders($url);
            return [
                'name' => $this->downFileInfo->downloadFileName,
                'real_name' => $this->downFileInfo->downloadRealName ?? '',
                'size' => $headers['size'] ?? 0,
                'type' => $headers['type'] ?? 'image/jpeg',
                'dir' => $this->downFileInfo->downloadFilePath ?? '',
                'thumb_path' => $this->downFileInfo->downloadFilePath ?? '',
                'time' => time(),
            ];
        } else {
            return [];
        }
    }

    /**
     * 检测文件内容
     * @param $fileHandle
     * @return bool|void
     * @author wuhaotian
     * @email 442384644@qq.com
     * @date 2024/4/11
     */
    public function checkFileContent($fileHandle)
    {
        $stream = fopen($fileHandle->getPathname(), 'r');
        $content = (fread($stream, filesize($fileHandle->getPathname())));
        if (is_resource($stream)) {
            fclose($stream);
        }
        if (preg_match('/think|app|php|log|phar|Socket|Channel|Flysystem|Psr6Cache|Cached|Request|debug|Psr6Cachepool|eval/i', $content)) {
            return $this->setError('文件内容不合法');
        }
    }

    /**
     * 文件上传
     * @return mixed
     */
    abstract public function move(string $file = 'file');

    /**
     * 文件流上传
     * @return mixed
     */
    abstract public function stream($fileContent, string $key = null);

    /**
     * 删除文件
     * @return mixed
     */
    abstract public function delete(string $filePath);

    /**
     * 实例化上传
     * @return mixed
     */
    abstract protected function app();

    /**
     * 拉取空间
     * @param string $region
     * @param bool $line
     * @param bool $shared
     * @return mixed
     */
    abstract public function listbuckets(string $region, bool $line = false, bool $shared = false);

    /**
     * 创建空间
     * @param string $name
     * @param string $region
     * @return mixed
     */
    abstract public function createBucket(string $name, string $region);

    /**
     * 获得区域
     * @return mixed
     */
    abstract public function getRegion();

    /**
     * 删除空间
     * @param string $name
     * @return mixed
     */
    abstract public function deleteBucket(string $name);

    /**
     * 绑定自定义域名
     * @param string $name
     * @param string $domain
     * @param string|null $region
     * @return mixed
     */
    abstract public function bindDomian(string $name, string $domain, string $region = null);

    /**
     * 设置跨域
     * @param string $name
     * @param string $region
     * @return mixed
     */
    abstract public function setBucketCors(string $name, string $region);

    /**
     * 获取上传密钥
     * @return mixed
     */
    abstract public function getTempKeys();

    /**
     * 获取缩略图
     * @return mixed
     */
    abstract public function thumb(string $filePath = '');

    /**
     * 添加水印
     * @return mixed
     */
    abstract public function water(string $filePath = '');

}
