<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------

use think\Collection;
use think\db\exception\DbException;
use think\exception\ClassNotFoundException;
use think\Model;
use think\Paginator;

// 应用公共文件

if (!function_exists('widget')) {
    /**
     * 渲染输出Widget
     * @param  string  $name  Widget名称
     * @param  array  $data  传入的参数
     * @return mixed
     * milo 2019-05-08 从TP5.1代码中拿来修改的
     */
    function widget($name, $data = [])
    {
        return action($name, $data, 'widget');
    }
}
if (!function_exists('action')) {
    /**
     * 调用模块的操作方法 参数格式 [模块/控制器/]操作
     * @param  string  $url  调用地址
     * @param  string|array  $vars  调用参数 支持字符串和数组
     * @param  string  $layer  要调用的控制层名称
     * @param  bool  $appendSuffix  是否添加类名后缀
     * @return mixed
     * milo 2019-05-08 从TP5.1代码中拿来修改的
     */
    function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
    {
        $info   = pathinfo($url);
        $action = $info['basename'];
        $module = '.' != $info['dirname'] ? $info['dirname'] : request()->controller();
        $class  = controller($module, $layer);
        if (is_scalar($vars)) {
            if (strpos($vars, '=')) {
                parse_str($vars, $vars);
            } else {
                $vars = [$vars];
            }
        }
        return app()->invokeMethod([$class, $action.config('route.action_suffix')], $vars);
    }
}
if (!function_exists('controller')) {
    /**
     * 实例化(分层)控制器 格式:[模块名/]控制器名
     * @access public
     * @param  string  $name  资源地址
     * @param  string  $layer  控制层名称
     * @param  bool  $appendSuffix  是否添加类名后缀
     * @param  string  $empty  空控制器名称
     * @return object
     * @throws ClassNotFoundException
     *
     * milo 2019-05-08 从TP5.1代码中拿来修改的
     */
    function controller($name, $layer = 'controller', $empty = '')
    {
        $class = parseClass($name, $layer);
        if (class_exists($class)) {
            return app()->make($class);
        } elseif ($empty && class_exists($emptyClass = app()->parseClass($layer, $empty))) {
            return app()->make($emptyClass);
        }

        throw new ClassNotFoundException('class not exists:'.$class, $class);
    }
}

if (!function_exists('parseClass')) {
    /**
     * 解析模块和类名
     * @access protected
     * @param  string  $name  资源地址
     * @param  string  $layer  验证层名称
     * @param  bool  $appendSuffix  是否添加类名后缀
     * @return array
     *
     * milo 2019-05-08 从TP5.1代码中拿来修改的
     */
    function parseClass($name, $layer)
    {
        if (false !== strpos($name, '\\')) {
            $class = $name;
        } else {
            if (strpos($name, '/')) {
                $names = explode('/', $name, 2);
                $name  = $names[1];
            }
            $class = app()->parseClass($layer, $name);
        }
        return $class;
    }
}


if (!function_exists('randomStr')) {
    /**
     * 获取随机字符串
     * @param  int  $type  0:数字(默认);1:全部;2:小写字母;3:大写字母;4:字母;
     * @param  int  $len  字符串长度
     * @return string
     */
    function randomStr($type = 0, $len = 5)
    {
        $strPol = "0123456789";
        if ($type == 1) {
            $strPol = "ABCDEFGHIJKLMOPQRSTUVWYZ0123456789abcdefghijklmopqrstuvwyz";
        } elseif ($type == 2) {
            $strPol = "abcdefghijklmopqrstuvwyz";
        } elseif ($type == 3) {
            $strPol = "ABCDEFGHIJKLMOPQRSTUVWYZ";
        } elseif ($type == 4) {
            $strPol = "ABCDEFGHIJKLMOPQRSTUVWYZabcdefghijklmopqrstuvwyz";
        }
        $max = strlen($strPol) - 1;
        $str = '';
        for ($i = 0; $i < $len; $i++) {
            $str .= $strPol[rand(0, $max)];
        }
        return $str;
    }
}

if (!function_exists('isMobile')) {
    //判断访问终端是否为移动端
    function isMobile()
    {
        // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
        if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
            return true;
        }
        // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
        if (isset($_SERVER['HTTP_VIA'])) {
            // 找不到为flase,否则为true
            return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
        }
        // 脑残法,判断手机发送的客户端标志,兼容性有待提高。其中'MicroMessenger'是电脑微信
        if (isset($_SERVER['HTTP_USER_AGENT'])) {
            $clientkeywords = [
                'nokia', 'sony', 'ericsson', 'mot', 'samsung', 'htc', 'sgh', 'lg', 'sharp', 'sie-', 'philips',
                'panasonic', 'alcatel', 'lenovo', 'iphone', 'ipod', 'blackberry', 'meizu', 'android', 'netfront',
                'symbian', 'ucweb', 'windowsce', 'palm', 'operamini', 'operamobi', 'openwave', 'nexusone', 'cldc',
                'midp', 'wap', 'mobile', 'MicroMessenger'
            ];
            // 从HTTP_USER_AGENT中查找手机浏览器的关键字
            if (preg_match("/(".implode('|', $clientkeywords).")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
                return true;
            }
        }
        // 协议法,因为有可能不准确,放到最后判断
        if (isset ($_SERVER['HTTP_ACCEPT'])) {
            // 如果只支持wml并且不支持html那一定是移动设备
            // 如果支持wml和html但是wml在html之前则是移动设备
            if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'],
                        'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'],
                            'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
                return true;
            }
        }
        return false;
    }
}
//根据栏目获取路径
if (!function_exists('getUri')) {
    function getUri($cate)
    {
        $url = '';
        if (!empty($cate)) {
            if ($cate['is_index']) {
                $url = '/';
            } elseif (!empty($cate['url'])) {
                $url = $cate['url'];
            } else {
                $url = url($cate['template'].'/index', ['category_id' => $cate['id']]);
            }
        }
        return $url;
    }
}

//根据文件大小转换为文字
if (!function_exists('sizeToStr')) {
    function sizeToStr($size)
    {
        if (!is_numeric($size) || $size <= 0) {
            return '';
        }
        $size = $size / 1024;
        if ($size < 1024) {
            return sprintf("%.2fK", $size);
        }
        $size = $size / 1024;
        if ($size < 1024) {
            return sprintf("%.2fM", $size);
        }
        $size = $size / 1024;
        return sprintf("%.2fG", $size);
    }
}

//根据路径获取文件名
if (!function_exists('getKeyByPath')) {
    function getKeyByPath($path)
    {
        return substr($path, strrpos($path, '/') + 1);
    }
}

//富文本中提取图片路径
if (!function_exists('getImageUrlFromText')) {
    function getImageUrlFromText($content)
    {
        preg_match_all('/<img.*?src="(.*?)".*?>/is', $content, $imgs);
        $data = [];
        if (!empty($imgs) && !empty($imgs[1])) {
            foreach ($imgs[1] as $img) {
                if (substr($img, 0, 4) != 'http') {
                    $key        = getKeyByPath($img);
                    $data[$key] = $img;
                }
            }
        }
        return $data;
    }
}

// 是否http开头
if (!function_exists('isHttpUrl')) {
    function isHttpUrl(string $url): bool
    {
        return substr(trim($url), 0, 4) == 'http';
    }
}

//富文本中提取视频路径
if (!function_exists('getVideoUrlFromText')) {
    function getVideoUrlFromText($content)
    {
        preg_match_all('/<video.*?src="(.*?)".*?>/is', $content, $videos);
        $data = [];
        if (!empty($videos) && !empty($videos[1])) {
            foreach ($videos[1] as $video) {
                if (substr($video, 0, 4) != 'http') {
                    $key        = getKeyByPath($video);
                    $data[$key] = $video;
                }
            }
        }
        return $data;
    }
}

//获取目录下的所有文件
if (!function_exists('getAllFilesByPath')) {
    function getAllFilesByPath($path, $rootPath)
    {
        if (is_dir($path) && file_exists($path)) {
            $items = scandir($path);
            $files = [];
            foreach ($items as $item) {
                if (substr($item, 0, 1) != '.' && strpos($item, '_') == false) {
                    $itemPath = $path.'/'.$item;
                    if (is_file($itemPath)) {
                        $size         = filesize($itemPath);
                        $files[$item] = [
                            'path'     => str_replace($rootPath, '/', $itemPath),
                            'realPath' => $itemPath,
                            'size'     => $size,
                            'sizeStr'  => sizeToStr($size),
                            'suffix'   => strtolower(substr($item, strrpos($item, '.') + 1))    //后缀
                        ];
                    } elseif (is_dir($itemPath)) {
                        $childFiles = getAllFilesByPath($itemPath, $rootPath);
                        if (!empty($childFiles)) {
                            $files = array_merge($files, $childFiles);
                        } else {
                            rmdir($itemPath);
                        }
                    }
                }
            }
            return $files;
        }
        return [];
    }
}

//过滤get输入
if (!function_exists('getFilter')) {
    function getFilter($value)
    {
        $getFilter = "'|(and|or)\b.+?(>|<|=|in|like)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
        $forArray  = false;
        if (is_array($value)) {
            $forFilter = implode($value);
            $forArray  = true;
        } else {
            $forFilter = $value;
        }
        if (preg_match("/".$getFilter."/is", $forFilter) == 1) {
            $value = $forArray ? [] : '';
        }
        return filterExp($value);
    }
}

//过滤post录入
if (!function_exists('postFilter')) {
    function postFilter($value)
    {
        $postFilter = "\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
        $forArray   = false;
        if (is_array($value)) {
            $forFilter = implode($value);
            $forArray  = true;
        } else {
            $forFilter = $value;
        }
        if (preg_match("/".$postFilter."/is", $forFilter) == 1) {
            $value = $forArray ? [] : '';
        }
        return filterExp($value);
    }
}

//过滤cookie数据
if (!function_exists('cookieFilter')) {
    function cookieFilter($value)
    {
        $cookieFilter = "\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
        $forArray     = false;
        if (is_array($value)) {
            $forFilter = implode($value);
            $forArray  = true;
        } else {
            $forFilter = $value;
        }
        if (preg_match("/".$cookieFilter."/is", $forFilter) == 1) {
            $value = $forArray ? [] : '';
        }
        return filterExp($value);
    }
}

if (!function_exists('filterExp')) {
    function filterExp($value)
    {
        $filter   = '/^(\s)+(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)(\s)+$/i';
        $forArray = false;
        if (is_array($value)) {
            $forFilter = implode($value);
            $forArray  = true;
        } else {
            $forFilter = $value;
        }
        if (preg_match($filter, $forFilter) == 1) {
            $value = $forArray ? [] : '';
        }
        return $value;
    }
}

if (!function_exists('arrayHtmlFilter')) {
    function arrayHtmlFilter($arr)
    {
        foreach ($arr as $k => $one) {
            if (is_array($one)) {
                $arr[$k] = arrayHtmlFilter($one);
            } else {
                $one     = trim($one);
                $arr[$k] = strip_tags($one);
            }
        }
        return $arr;
    }
}

if (!function_exists('toCamelString')) {
    /**
     * 转驼峰
     *
     * @param  string  $string
     * @param  false  $small  默认false 为true首字母小写
     * @return string
     */
    function toCamelString(string $string, bool $small = false): string
    {
        //例: xxx_yYy_zzZ 和 xxX-yyy-Zzz
        //1. 字符串转小写 xxx_yyy_zzz xxx-yyy-zzz
        //2. -和_转空格 xxx yyy zzz
        //3. 单词首字母大写 Xxx Yyy Zzz
        //4. 清除空格 XxxYyyZzz
        //处理下划线、减号 统统专程大驼峰 如xxx_yyy_zzz xxx-yyy-zzz 均转为 XxxYyyZzz
        $string = strtolower($string);
        $string = str_replace('-', ' ', $string);
        $string = str_replace('_', ' ', $string);
        $string = str_replace(' ', '', ucwords($string));
        if ($small) {
            $string = lcfirst($string);
        }
        return $string;
    }
}

if (!function_exists('unCamelize')) {
    /**
     * 驼峰命名转特定分隔符[如下划线]命名
     * @param  string  $camelCaps
     * @param  string  $separator
     * @return string
     */
    function unCamelize(string $camelCaps, string $separator = '-'): string
    {
        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1".$separator."$2", $camelCaps));
    }
}


if (!function_exists('generateRand')) {
    /**
     * 生成随机数
     *
     * @param  int  $length  长度
     * @param  string  $type  模式 默认mix混合 number纯数字 alpha字母
     * @return string
     */
    function generateRand(int $length = 8, string $type = 'mix'): string
    {
        $alphabet    = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $number      = '0123456789';
        $alphabetLen = strlen($alphabet) - 1;
        $numberLen   = 9;

        switch ($type) {
            case 'number':
                $str = $number;
                $len = $numberLen;
                break;
            case 'alpha':
                $str = $alphabet;
                $len = $alphabetLen;
                break;
            default:
                $str = $alphabet.$number;
                $len = $alphabetLen + $numberLen;
        }

        $randStr = '';
        $str     = str_shuffle($str);
        for ($i = 0; $i < $length; $i++) {
            $num     = mt_rand(0, $len);
            $randStr .= $str[$num];
        }
        return $randStr;
    }
}

if (!function_exists('generateCode')) {
    /**
     * 生成特定编码
     *
     * @param  string  $type  类型 默认mix混合 number纯数字 alpha字母
     * @param  int  $len  随机数长度
     * @return string
     */
    function generateCode(string $type = 'number', int $len = 6): string
    {
        //#时间戳+微秒+6位随机数
        $time    = microtime(true);
        $timeStr = str_replace('.', '', $time);
        return sprintf("%s%s", $timeStr, generateRand($len, $type));
    }
}

if (!function_exists('checkMobile')) {
    /**
     * 检测手机号
     *
     * @param  string  $mobile
     * @return bool
     */
    function checkMobile(string $mobile): bool
    {
        if (preg_match("/^1[3456789]{1}\d{9}$/", $mobile)) {
            return true;
        } else {
            return false;
        }
    }
}

if (!function_exists('arrayKeysFilter')) {
    /**
     * 数组键名过滤
     *
     * @param  array  $data
     * @param  array  $allowKeys
     * @return array
     */
    function arrayKeysFilter(array $data, array $allowKeys): array
    {
        $list = [];
        foreach ($data as $key => $val) {
            if (in_array($key, $allowKeys)) {
                $list[$key] = $val;
            }
        }
        return $list;
    }
}

if (!function_exists('getFilesize')) {
    /**
     * 尺寸单位转换
     *
     * @param $num
     * @return string
     */
    function getFilesize($num): string
    {
        $p      = 0;
        $format = 'B';
        if ($num > 0 && $num < 1024) {
            return number_format($num).' '.$format;
        }
        if ($num >= 1024 && $num < pow(1024, 2)) {
            $p      = 1;
            $format = 'KB';
        }
        if ($num >= pow(1024, 2) && $num < pow(1024, 3)) {
            $p      = 2;
            $format = 'MB';
        }
        if ($num >= pow(1024, 3) && $num < pow(1024, 4)) {
            $p      = 3;
            $format = 'GB';
        }
        if ($num >= pow(1024, 4) && $num < pow(1024, 5)) {
            $p      = 3;
            $format = 'TB';
        }
        $num /= pow(1024, $p);
        return number_format($num, 3).' '.$format;
    }
}

if (!function_exists('arrayNullToString')) {
    /**
     * 数组|或数据集中null值转为空字符串,并以数组格式返回
     * 通常用于api json 返回内容null转换
     *
     * @param  array  $data  【array|collection】
     * @return array
     */
    function arrayNullToString($data)
    {
        if ($data instanceof Collection || $data instanceof Model) {
            $data = $data->toArray();
        }
        // 判断是否可以遍历
        if (is_iterable($data)) {
            foreach ($data as $key => $val) {
                if ($val instanceof Collection || $data instanceof Model) {
                    $val = $val->toArray();
                }
                if (is_iterable($val)) {
                    $data[$key] = arrayNullToString($val);
                } elseif ($val === null) {
                    $data[$key] = '';
                }
            }
        } else {
            $data = [];
        }
        return $data;
    }
}

if (!function_exists('arrayKeysExcludeFilter')) {
    /**
     * 数组键名排除过滤
     *
     * @param  array  $data
     * @param  array  $excludeKeys  排除的字段
     * @return array
     */
    function arrayKeysExcludeFilter(array $data, array $excludeKeys): array
    {
        foreach ($data as $key => $val) {
            if (in_array($key, $excludeKeys)) {
                unset($data[$key]);
            }
        }
        return $data;
    }
}

if (!function_exists('getLatelyWeekDate')) {
    /**
     * 获取本周的周一 到周日的日期
     */
    function getLatelyWeekDate()
    {
        //本周一
        $oneDate     = date('Y-m-d 00:00:00', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 86400)); //w为星期几的数字形式,这里0为周日
        $oneDateTime = strtotime($oneDate);
        //返回周一到周天  1-7
        return [
            "1" => ["date" => $oneDate],
            "2" => ["date" => date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 1)))],
            "3" => ["date" => date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 2)))],
            "4" => ["date" => date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 3)))],
            "5" => ["date" => date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 4)))],
            "6" => ["date" => date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 5)))],
            "7" => ["date" => date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 6)))],
        ];
    }
}

if (!function_exists('stringDesensitization')) {
    /**
     * 字符串脱敏 默认给手机号脱敏 其他未兼容
     *
     * @param  string  $string
     * @param  string  $s
     * @param  int  $start
     * @param  int  $len
     * @return string
     */
    function stringDesensitization(string $string, string $s = '****', int $start = 3, int $len = 4): string
    {
        return substr_replace($string, $s, $start, $len);
    }
}

if (!function_exists('resourceJoin')) {
    /**
     * 资源拼接前缀  如/xxx/xxxx/xxx.jpg 拼接为前缀http://www.xxx.com/xxx/xxxx/xxx.jpg
     *
     * @param  string  $string
     * @param  string  $domain
     * @return string
     */
    function resourceJoin(string $string, string $domain): string
    {
        if (empty($string)) {
            return '';
        }

        if (isHttpUrl($string)) {
            return $string;
        }

        return $domain.$string;
    }
}
if (!function_exists('replaceStoragePath'))
{
    function replaceStoragePath ($content){
        $pregRule = "/<[img|IMG].*?src=[\'|\"][\/storage]{1}(.*?(?:[\.jpg|\.jpeg|\.png|\.gif|\.bmp]))[\'|\"].*?[\/]?>/";
        return preg_replace($pregRule, '<img src="' . request()->domain() . '/${1}" style="max-width:100%">', (string)$content  );
    }
}
if (!function_exists('list_to_tree')){
    function list_to_tree($list, $pk='id', $pid = 'pid', $child = 'child', $root = 0) {
// 创建Tree
        $tree = array();
        if(is_array($list)) {
// 创建基于主键的数组引用
            $refer = array();
            foreach ($list as $key => $data) {
                $refer[$data[$pk]] =& $list[$key];
            }
            foreach ($list as $key => $data) {
// 判断是否存在parent
                $parentId = $data[$pid];
                if ($root == $parentId) {
                    $tree[] =& $list[$key];
                }else{
                    if (isset($refer[$parentId])) {
                        $parent =& $refer[$parentId];
                        $parent[$child][] =& $list[$key];
                    }
                }
            }
        }
        return $tree;
    }
}