<?php
// +----------------------------------------------------------------------
// | Bwsaas
// +----------------------------------------------------------------------
// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Gitee ( https://gitee.com/buwangyun/bwsaas )
// +----------------------------------------------------------------------
// | Author: buwangyun <hnlg666@163.com>
// +----------------------------------------------------------------------
// | Date: 2020-9-28 10:55:00
// +----------------------------------------------------------------------
use think\facade\Event;

// 应用公共函数文件

if (!function_exists('set_addons_info')) {
    /**
     * 设置基础配置信息.
     *
     * @param string $name 插件名
     * @param array $array 配置数据
     *
     * @return bool
     * @throws Exception
     */
    function set_addons_info($name, $array)
    {
        $file = ADDON_PATH . $name . DS . 'info.ini';
        $addon = get_addons_instance($name);
        $array = $addon->setInfo($name, $array);
        if (!isset($array['name']) || !isset($array['title']) || !isset($array['version'])) {
            throw new Exception('插件配置写入失败');
        }
        $res = [];
        foreach ($array as $key => $val) {
            if (is_array($val)) {
                $res[] = "[$key]";
                foreach ($val as $skey => $sval) {
                    $res[] = "$skey = " . (is_numeric($sval) ? $sval : $sval);
                }
            } else {
                $res[] = "$key = " . (is_numeric($val) ? $val : $val);
            }
        }
        if ($handle = fopen($file, 'w')) {
            fwrite($handle, implode("\n", $res) . "\n");
            fclose($handle);
            //清空当前配置缓存
            \think\facade\Config::set([$name => null], 'addoninfo');
        } else {
            throw new Exception('文件没有写入权限');
        }

        return true;
    }
}

if (!function_exists('set_addons_config')) {
    /**
     * 写入配置文件.
     *
     * @param string $name 插件名
     * @param array $config 配置数据
     * @param bool $writefile 是否写入配置文件
     *
     * @return bool
     * @throws Exception
     */
    function set_addons_config($name, $config, $writefile = true)
    {
        $addon = get_addons_instance($name);
        $addon->setConfig($name, $config);
        $fullconfig = get_addons_config($name, true);
        foreach ($fullconfig as $k => &$v) {
            if (isset($config[$v['name']])) {
                $value = $v['type'] !== 'array' && is_array($config[$v['name']]) ? implode(',',
                    $config[$v['name']]) : $config[$v['name']];
                $v['value'] = $value;
            }
        }
        if ($writefile) {
            // 写入配置文件
            set_addons_fullconfig($name, $fullconfig);
        }

        return true;
    }
}

if (!function_exists('set_addons_fullconfig')) {
    /**
     * 写入配置文件.
     *
     * @param string $name 插件名
     * @param array $array 配置数据
     *
     * @return bool
     * @throws Exception
     */
    function set_addons_fullconfig($name, $array)
    {
        $file = ADDON_PATH . $name . DS . 'config.php';
        if (!\buwang\util\File::is_really_writable($file)) {
            throw new Exception('文件没有写入权限');
        }
        if ($handle = fopen($file, 'w')) {
            fwrite($handle, "<?php\n\n" . 'return ' . var_export($array, true) . ";\n");
            fclose($handle);
        } else {
            throw new Exception('文件没有写入权限');
        }

        return true;
    }
}

if (!function_exists('get_sql_array')) {
    /**
     *  * 读取sql文件为数组
     *  * @param $sqlFile sql 文件路径
     *  * @param string $prefix 添加表前缀
     *  * @return array|bool
     *  */
    function get_sql_array($sqlFile)
    {
        $sql = file_get_contents($sqlFile);
        $str = preg_replace('/(--.*)|(\/\*(.|\s)*?\*\/)|(\n)/', '', $sql);

        $list = explode(';', trim($str));
        foreach ($list as $key => $val) {
            if (empty($val)) {
                unset($list[$key]);
            } else {
                $list[$key] .= ';';
            }
        }
        return array_values($list);
    }
}

if (!function_exists('bw_config')) {
    /**
     * @param string $name 配置名
     * @param null $default 配置默认值
     * @param null $member_id 租户id
     * @param null $dir 应用标识
     * @return array|mixed|null
     */
    function bw_config(string $name, $default = null, $member_id = null, $dir = null)
    {
        return app\manage\model\Config::memberAndAdminConfig($name, $default, $member_id, $dir);
    }
}

if (!function_exists('en_code')) {
    /**
     * 针对于ID的可逆加密函数,也可以用作于邀请码之类
     * @param int $code
     */
    function en_code($code)
    {
        static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
        $num = $code;
        $code = '';
        while ($num > 0) {
            $mod = $num % 35;
            $num = ($num - $mod) / 35;
            $code = $source_string[$mod] . $code;
        }
        if (empty($code[3])) {
            $code = str_pad($code, 4, '0', STR_PAD_LEFT);
        }
        return $code;
    }
}
if (!function_exists('de_code')) {
    /**
     * 针对于ID的可逆加密函数,也可以用作于邀请码之类
     * @param string $code
     */
    function de_code($code)
    {
        static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
        if (strrpos($code, '0') !== false) {
            $code = substr($code, strrpos($code, '0') + 1);
        }
        $len = strlen($code);
        $code = strrev($code);
        $num = 0;
        for ($i = 0; $i < $len; $i++) {
            $num += strpos($source_string, $code[$i]) * pow(35, $i);
        }
        return $num;
    }
}

if (!function_exists('en_mobile')) {
    /**
     * 隐藏手机号中间四位,从第三个字符隐藏4个字符
     * @param $phone
     * @param int $s
     * @param int $d
     * @return string|string[]
     */
    function en_mobile($phone, $s = 3, $d = 4)
    {
        return substr_replace($phone, '****', $s, $d);
    }
}

if (!function_exists('get_num_code')) {
    /**
     * 生成随机数
     * @param int $limit
     * @return string
     */
    function get_num_code($limit = 6)
    {
        $rand_array = range(0, 9);
        shuffle($rand_array);   //调用现成的数组随机排列函数
        $str = array_slice($rand_array, 0, $limit);//截取前$limit个
        return implode(null, $str);
    }
}

if (!function_exists('bw_img_url')) {
    /**
     * 设置附加路径
     * @param $image
     * @param string $siteUrl
     * @return bool
     */
    function bw_img_url($image, $siteUrl = '')
    {
        if (!strlen(trim($siteUrl))) $siteUrl = bw_config('web_url');
        //var_dump($siteUrl);die;
        $domainTop = substr($image, 0, 4);
        if ($domainTop == 'http') return $image;

        $image = str_replace('\\', '/', $image);
        //var_dump(bw_config('web_url'));die;
        return $siteUrl . $image;
    }
}
if (!function_exists('anonymity')) {
    /**
     * 匿名处理处理用户昵称
     * @param $name
     * @return string
     */
    function anonymity($name)
    {
        $strLen = mb_strlen($name, 'UTF-8');
        $min = 3;
        if ($strLen <= 1)
            return '*';
        if ($strLen <= $min)
            return mb_substr($name, 0, 1, 'UTF-8') . str_repeat('*', $min - 1);
        else
            return mb_substr($name, 0, 1, 'UTF-8') . str_repeat('*', $strLen - 1) . mb_substr($name, -1, 1, 'UTF-8');
    }
}


if (!function_exists('bw_data')) {
    /** 返回组合数据对象
     * @param int|array|string $groupName 选填 传数字或字符串标识则查该项组合数据 传数组则 格式为:[ '数据组ID或字符串标识','租户ID','应用标识'] 表示只查某个租户(租户ID=0 为总后台)
     * @param int|boolean|string $id 选填 传数字则只查单条组合数据 传false则返回组合数据对象,自己写查询条件。
     * @param int|null $member_id 选填 传0 则只查总后台组合数据 传租户id则查某个租户的组合数据,默认为null表示从登录信息自动取租户id,取不到就查总后台数据
     */
    function bw_data($groupName = '', $id = 0, $where = ['status' => 1], $page = null, $limit = null, $sort = 'sort desc,id desc')
    {
        return app\manage\model\ConfigGroupData::getDataList($groupName, $id, $where, $page, $limit, $sort);
    }
}

if (!function_exists('bw_value_data')) {
    /** 取配置数据组数据(引用传递方法,根据情况可以不用取返回值)  返回false则说明有错误 调用bw_value_data_errormsg()方法可获取错误信息
     * @param string $where 如果传入的是数据列表或单个数据对象则不需要接收返回结果,如果方法不返回falsee则说明引用对象值已经改变,如果传入的是id,则需要接收返回结果或将id参数当做结果
     * @param ConfigGroup $ConfigGroup 数据组对象,可不传,不传的话方法内多查一次数据库
     * @return ConfigGroupData|array|int|mixed|string|boolean
     */
    function bw_value_data(&$where, $ConfigGroup = null)
    {
        return app\manage\model\ConfigGroupData::getValueData($where, $ConfigGroup);
    }
}


if (!function_exists('bw_value_data_errormsg')) {
    /** 调用bw_value_data()方法返回false时,调用该方法取错误信息
     */
    function bw_value_data_errormsg($defaultMsg = '操作失败,请稍候再试!')
    {
        return app\manage\model\ConfigGroupData::getError($defaultMsg);
    }
}
if (!function_exists('get_session_id')) {
    /** 调用bw_value_data()方法返回false时,调用该方法取错误信息
     */
    function get_session_id()
    {
        return \think\facade\Session::getId();
    }
}

if (!function_exists('array_unique_fb')) {
    /**
     * 二维数组去掉重复值
     * @param $array
     * @return array
     */
    function array_unique_fb($array)
    {
        $out = array();
        foreach ($array as $key => $value) {
            if (!in_array($value, $out)) {
                $out[$key] = $value;
            }
        }
        $out = array_values($out);
        return $out;
    }
}
if (!function_exists('sysuri')) {
    /**
     * 生成最短URL地址
     * @param string $url 路由地址
     * @param array $vars 变量
     * @param boolean|string $suffix 后缀
     * @param boolean|string $domain 域名
     * @return string
     */
    function sysuri($url = '', array $vars = [], $suffix = false, $domain = false)
    {
        return app('systemService')->sysuri($url, $vars, $suffix, $domain);
    }
}

if (!function_exists('get_month')) {
    /**
     * 格式化月份
     * @param string $time
     * @param int $ceil
     * @return array
     */
    function get_month($time = '', $ceil = 0)
    {
        if (empty($time)) {
            $firstday = date("Y-m-01", time());
            $lastday = date("Y-m-d", strtotime("$firstday +1 month -1 day"));
        } else if ($time == 'n') {
            if ($ceil != 0)
                $season = ceil(date('n') / 3) - $ceil;
            else
                $season = ceil(date('n') / 3);
            $firstday = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')));
            $lastday = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y')));
        } else if ($time == 'y') {
            $firstday = date('Y-01-01');
            $lastday = date('Y-12-31');
        } else if ($time == 'h') {
            $firstday = date('Y-m-d', strtotime('this week +' . $ceil . ' day')) . ' 00:00:00';
            $lastday = date('Y-m-d', strtotime('this week +' . ($ceil + 1) . ' day')) . ' 23:59:59';
        }
        return array($firstday, $lastday);
    }
}

if (!function_exists('get_token')) {
    function get_token($request)
    {
        $token = $request->server('HTTP_TOKEN');//TODO:改变顺序 头 -- cookie -- session -- 参数
        // && in_array($request->header('scopes'),['member','admin'])
        if ((!$token || $token == 'null')) $token = cookie('token');
        //如果不存在,往session中取[此处取法暂时不用]
        //if (!$token || $token == 'null') $token = app('userService')->getLogin('token');
        //如果不存在,往参数中取
        if (!$token) $token = $request->request('token');
        return $token ?: '';
    }
}
//目录创建
if (!function_exists('is_mkdir')) {
    function is_mkdir($dir)
    {
        if (!is_dir($dir)) {
            // 创建目录并赋予权限
            mkdir($dir, 0777, true);
        }
    }
}
//js鉴权
if (!function_exists('auth')) {
    function auth($url)
    {
        if ($url) return true;
        else return false;
    }
}
//重新排列数组的key 从0开始
if (!function_exists('reform_keys')) {
    function reform_keys($array)
    {
        if (!is_array($array)) {
            return $array;
        }
        $keys = implode('', array_keys($array));
        if (is_numeric($keys)) {
            $array = array_values($array);
        }
        $array = array_map('reform_keys', $array);
        //框架中这么写, $array = array_map([$this,'reform_keys '],$array );
        return $array;
    }

    ;
}
//获取用户组的scopes
if (!function_exists('get_scopes')) {
    function get_scopes($request)
    {
        $scopes = $request->header('scopes');
        if (!$scopes || !in_array($scopes, BW_CLIENT_TYPE)) {
            //模板解析时重定向至登录页面
            /*-----------------------获取访问类的scopes Start--------------------------------------*/
            list($module, $controller) = [app('http')->getName(), str_replace('.', '/', $request->controller())];
            //通过反射获取当前php文件的实例
            $ref_class = new \ReflectionClass(strtr("app/{$module}/controller/{$controller}", '/', '\\'));
            //通过方法名getScopes获取指定方法并执行 getScopes需是public属性,否则需要使用setAccessible(true)方法设置方法的可访问性
            $scopes = $ref_class->getmethod('getScopes')->invoke($ref_class->newInstance(app()));


        }
        return $scopes;
    }

    ;
}
/**
 * 订单号
 */
if (!function_exists('get_uuid')) {
    function get_uuid()
    {
        $osn = date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
        return $osn;
    }
}
/**
 * 多维数组去重
 */
if (!function_exists('multipart_array_uni')) {
    function multipart_array_uni(&$my_array)
    {
        // 新建一个空的数组.
        $tmp_array = array();
        $new_array = array();

// 1. 循环出所有的行. ( $val 就是某个行)
        foreach ($my_array as $k => $val) {
            $hash = md5(json_encode($val));
            if (!in_array($hash, $tmp_array)) {
                // 2. 在 foreach 循环的主体中, 把每行数组对象得hash 都赋值到那个临时数组中.
                $tmp_array[] = $hash;
                $new_array[] = $val;
            }
        }
        $my_array = $new_array;
        return $new_array;
    }
}


if (!function_exists('set_http_type')) {
    /**
     * 修改 https 和 http
     * @param $url $url 域名
     * @param int $type 0 返回https 1 返回 http
     * @return string
     */
    function set_http_type($url, $type = 0)
    {
        $domainTop = substr($url, 0, 5);
        if ($type) {
            if ($domainTop == 'https') $url = 'http' . substr($url, 5, strlen($url));
        } else {
            if ($domainTop != 'https') $url = 'https:' . substr($url, 5, strlen($url));
        }
        return $url;
    }

}

if (!function_exists('curl_file_exist')) {
    /**
     * CURL 检测远程文件是否在
     * @param $url
     * @return bool
     */
    function curl_file_exist($url)
    {
        $ch = curl_init();
        try {
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
            $contents = curl_exec($ch);
            if (preg_match("/404/", $contents)) return false;
            if (preg_match("/403/", $contents)) return false;
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }
}

/**
 * 无限极分类,根据父类id找所有子类
 */
if (!function_exists('get_real_ip')) {
    function get_real_ip()
    {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $cip = $_SERVER['HTTP_CLIENT_IP'];
        } else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        } else if (!empty($_SERVER["REMOTE_ADDR"])) {
            $cip = $_SERVER["REMOTE_ADDR"];
        } else {
            $cip = '';
        }
        preg_match("/[\d\.]{7,15}/", $cip, $cips);
        $cip = isset($cips[0]) ? $cips[0] : 'unknown';
        unset($cips);
        return $cip;
    }
}

if (!function_exists('get_login_member_id')) {
    /** 得到当前登录的顶级租户ID
     */
    function get_login_member_id($memberId = 0)
    {
        $member_id_info = \buwang\util\Util::getLoginMemberId($memberId);//得到租户ID
        if (!$member_id_info) return $memberId;
        return $member_id_info['memberId'];//得到租户ID
    }
}

if (!function_exists('get_login_info')) {
    /** 得到当前登录信息
     */
    function get_login_info($memberId = 0)
    {
        return \buwang\util\Util::getLoginMemberId($memberId);//得到租户ID
    }
}


if (!function_exists('exception')) {
    /**
     * 抛出异常处理
     *
     * @param string $msg 异常消息
     * @param integer $code 异常代码 默认为0
     * @param string $exception 异常类
     *
     * @throws Exception
     */
    function exception($msg, $code = 0, $exception = '')
    {
        $e = $exception ?: '\think\Exception';
        throw new $e($msg, $code);
    }
}
if (!function_exists('encode_str')) {
    /**
     * 加密 UTF8 字符串
     * @param string $content
     * @return string
     */
    function encode_str($content)
    {
        list($chars, $length) = ['', strlen($string = iconv('UTF-8', 'GBK//TRANSLIT', $content))];
        for ($i = 0; $i < $length; $i++) $chars .= str_pad(base_convert(ord($string[$i]), 10, 36), 2, 0, 0);
        return $chars;
    }
}
if (!function_exists('decode_str')) {
    /**
     * 解密 UTF8 字符串
     * @param string $content
     * @return string
     */
    function decode_str($content)
    {
        $chars = '';
        foreach (str_split($content, 2) as $char) {
            $chars .= chr(intval(base_convert($char, 36, 10)));
        }
        return iconv('GBK//TRANSLIT', 'UTF-8', $chars);
    }
}

//设置应用数据表前缀
if (!function_exists('set_miniapp_database_prefix')) {
    /**
     * 设置应用数据表前缀
     * @param string $dir 应用目录名
     * @return bool
     */
    function set_miniapp_database_prefix($dir)
    {
        if (!defined('MINIAPP_DATABASE_PREFIX')) {
            //应用表前缀
            $miniapp_database_prefix = '';
            //获取应用config/version.php
            $version_file = root_path() . 'app' . DS . $dir . DS . 'config' . DS . 'version.php';
            if (file_exists($version_file)) {
                $version = include $version_file;
                isset($version['database']['prefix']) && $miniapp_database_prefix = $version['database']['prefix'];
            }
            //设置一个常量:应用表前缀
            $miniapp_database_prefix && define('MINIAPP_DATABASE_PREFIX', $miniapp_database_prefix);
        }
        return true;
    }
}

//一维数组根据$parent_id的值转为多维数组
if (!function_exists('deal_list_to_tree')) {
    /**
     * 方法 deal_list_to_tree,一维数组根据$parent_id的值转为多维数组
     *
     * @param array $data 待处理的一维数组
     * @param string $pkName 用于转化为多维数组的主键字段
     * @param string $pIdName 用于转化为多维数组的字段(根据该字段值转换)
     * @param string $childName 子级的字段名
     * @param bool $is_empty_childrens 是否返回空的子数组(childrens[])(true:是,false:否)
     * @param string $rootId 根节点$pkName值
     *
     * @return array $new_data 返回处理好的(多层级)多维数组
     *
     */
    function deal_list_to_tree($data, $pkName = 'id', $pIdName = 'parent_id', $childName = 'children_list', $is_empty_childrens = false, $rootId = '')
    {
        $new_data = [];
        foreach ($data as $sorData) {
            if ($sorData[$pIdName] == $rootId) {
                $res = deal_list_to_tree($data, $pkName, $pIdName, $childName, $is_empty_childrens, $sorData[$pkName]);
                if (!empty($res) && !$is_empty_childrens) {
                    if (array_key_exists($childName, $sorData)) {
                        if (array_key_exists($childName, $sorData)) {
                            $sorData[$childName][] = $res[0];
                        } else {
                            $sorData[$childName][] = $res;
                        }
                    } else {
                        $sorData[$childName] = $res;
                    }
                }
                $new_data[] = $sorData;
            }
        }
        return $new_data;
    }
}


//得到目录中所有静态资源的绝对路径
if (!function_exists('get_public_files')) {
    /**
     * 得到目录中所有静态资源的绝对路径
     * @param string $pathName 要搜索的目录
     * @param array $file_map 要取路径的数组
     * @return bool
     */
    function get_public_files($pathName, &$file_map)
    {
        //将结果保存在result变量中
        $result = array();
        $temp = array();
        //判断传入的变量是否是目录
        if (!is_dir($pathName) || !is_readable($pathName)) {
            return null;
        }
        //取出目录中的文件和子目录名,使用scandir函数
        $allFiles = scandir($pathName);
        //遍历他们
        foreach ($allFiles as $fileName) {
            //判断是否是.和..因为这两个东西神马也不是。。。
            if (in_array($fileName, array('.', '..'))) {
                continue;
            }
            //路径加文件名
            $fullName = $pathName . '/' . $fileName;
            //如果是目录的话就继续遍历这个目录
            if (is_dir($fullName)) {
                //将这个目录中的文件信息存入到数组中
                $result[$fullName] = get_public_files($fullName, $file_map);
            } else {
                //如果是文件就先存入临时变量
                $temp[] = $fullName;
                $pathinfo = pathinfo($fullName);
                $pathinfo['path'] = $fullName;
                $file_map[] = $pathinfo;
            }
        }
        //取出文件
        if ($temp) {
            foreach ($temp as $f) {
                $result[] = $f;
            }
        }
        return $result;
    }
}


if (!function_exists('is_write')) {

    /**
     * 判断 文件/目录 是否可写(取代系统自带的 is_writeable 函数)
     *
     * @param string $file 文件/目录
     * @return boolean
     */
    function is_write($file)
    {
        if (is_dir($file)) {
            $dir = $file;
            if ($fp = @fopen("$dir/test.txt", 'w')) {
                @fclose($fp);
                @unlink("$dir/test.txt");
                $writeable = true;
            } else {
                $writeable = false;
            }
        } else {
            if ($fp = @fopen($file, 'a+')) {
                @fclose($fp);
                $writeable = true;
            } else {
                $writeable = false;
            }
        }
        return $writeable;
    }

}
if (!function_exists('format_human_date')) {
    /**
     * 格式化 UNIX 时间戳为人易读的字符串
     *
     * @param int    Unix 时间戳
     * @param mixed $local 本地时间
     *
     * @return    string    格式化的日期字符串
     */
    function format_human_date($remote, $local = null)
    {
        $timediff = (is_null($local) || $local ? time() : $local) - $remote;
        $chunks = array(
            /*array(60 * 60 * 24 * 365, 'year'),
            array(60 * 60 * 24 * 30, 'month'),
            array(60 * 60 * 24 * 7, 'week'),
            array(60 * 60 * 24, 'day'),
            array(60 * 60, 'hour1'),
            array(60, 'minute1'),
            array(1, 'second1')*/
            array(60 * 60 * 24 * 365, '年'),
            array(60 * 60 * 24 * 30, '月'),
            array(60 * 60 * 24 * 7, '周'),
            array(60 * 60 * 24, '天'),
            array(60 * 60, '小时'),
            array(60, '分钟'),
            array(1, '秒钟')
        );

        for ($i = 0, $j = count($chunks); $i < $j; $i++) {
            $seconds = $chunks[$i][0];
            $name = $chunks[$i][1];
            if (($count = floor($timediff / $seconds)) != 0) {
                break;
            }
        }
        return "{$count}{$name}前";
    }


    if (!function_exists('addon_exist')) {
        /** 插件是否存在
         * @param $addon_name 插件目录
         * @return bool
         */
        function addon_exist($addon_name)
        {
            try {
                // 检查插件
                \buwang\service\PluginService::check($addon_name);
            } catch (Throwable $e) {
                return \buwang\service\PluginService::setError($e->getMessage(), $e->getCode());
            }
            return true;
        }
    }


    if (!function_exists('addon_error')) {
        /** 插件错误信息
         * @return string
         */
        function addon_error($default = '')
        {
            return \buwang\service\PluginService::getError($default);
        }
    }


    if (!function_exists('addon_hook')) {
        /**
         * 处理插件钩子
         * @param string $event 钩子名称
         * @param array|null $params 传入参数
         * @param bool $once 是否只返回一个结果
         * @param bool $error 没有此插件时是否抛异常
         * @return mixed
         */
        function addon_hook($event, $params = null, bool $once = false, $error = true)
        {
            try {
                if (strpos($event, ':') !== false) {
                    $event = explode(':', $event);
                    $addon_name = $event[0];
                    $event = $event[1];
                } else {
                    $addon_name = '';
                }
                $result = Event::trigger($event, $params, $once);
                if (!$result) {
                    //只抛插件异常
                    if ($error) throw new \buwang\exception\AddonException("未找到{$addon_name}插件对应的{$event}方法,调用{$event}方法失败");
                    return '';
                }
            } catch (Throwable $e) {
                //只抛插件异常
                throw new \buwang\exception\AddonException($e->getMessage(), $e->getCode());
            }
            return $result[0];
        }
    }
}

if (!function_exists('region_id_to_text')) {
    /**
     * @param int $region_id 区域编码
     * @param int $level 几级区域,默认为省市区三级编码
     * @return array
     */
    function region_id_to_text(int $region_id, int $level = 3)
    {
        if (app('cacheService')::get("region:{$level}:{$region_id}")) {
            $res = json_decode(app('cacheService')::get("region:{$level}:{$region_id}"), true);
        } else {
            $province_code = $city_code = $county_code = 0;
            $province = $city = $county = '';
            $level >= 1 && $province_code = substr($region_id, 0, 2) . '0000';
            $level >= 2 && $city_code = substr($region_id, 0, 4) . '00';
            $level >= 3 && $county_code = $region_id;

            $province_code && $province = \app\common\model\SysRegion::where('id', $province_code)->value('name');
            $city_code && $city = \app\common\model\SysRegion::where('id', $city_code)->value('name');
            $county_code && $county = \app\common\model\SysRegion::where('id', $county_code)->value('name');
            $res = [$province, $city, $county];
            //设置缓存
            app('cacheService')::set("region:{$level}:{$region_id}", json_encode($res));
        }

        return $res;
    }
}


if (!function_exists('make_dir')) {
    /**
     * 创建文件夹,如果存在多级目录。则逐级创建
     * @param string $pathname The directory path.
     * @param int $mode
     * @return bool
     */
    function make_dir($pathname, $mode = 0777)
    {
        if (is_dir($pathname)) {
            return true;
        }
        if (is_dir(dirname($pathname))) {
            return mkdir($pathname, $mode);
        }
        make_dir(dirname($pathname));
        return mkdir($pathname, $mode);
    }
}