<?php

class Dever
{
    private static $register = array
    (
        'page' => array('Pagination\\Paginator', 'getPage'),
        'total' => array('Pagination\\Paginator', 'getTotal'),
        'html' => array('Pagination\\Paginator', 'getHtml'),

        'url' => array('Http\\Url', 'get'),
        'location' => array('Http\\Url', 'location'),
        'upload' => array('Http\\Url', 'upload'),
        'pic' => array('Http\\Url', 'upload'),
        'uploadRes' => array('Http\\Url', 'uploadRes'),
        'https' => array('Http\\Url', 'https'),
        'local' => array('Http\\Url', 'local'),
        'link' => array('Http\\Url', 'link'),
        'curl' => array('Http\\Curl', 'get'),

        'uri' => array('Routing\\Uri', 'get'),
        'post' => array('Routing\\Input', 'post'),
        'input' => array('Routing\\Input', 'get'),
        'preInput' => array('Routing\\Input', 'prefix'),
        'setInput' => array('Routing\\Input', 'set'),
        'shell' => array('Routing\\Input', 'shell'),

        'alert' => array('Output\\Export', 'alert'),
        'out' => array('Output\\Export', 'out'),
        'outDiy' => array('Output\\Export', 'diy'),
        'pageInfo' => array('Output\\Export', 'page'),
        'debug' => array('Output\\Debug', 'wait'),
        'sql' => array('Output\\Debug', 'sql'),
        'error' => array('Output\\Debug', 'error'),

        'load' => array('Loader\\Import', 'load'),
        'import' => array('Loader\\Project', 'import'),
        'apply' => array('Loader\\Import', 'apply'),
        'lang' => array('Loader\\Lang', 'get'),
        'langConfig' => array('Loader\\Lang', 'config'),
        'getLang' => array('Loader\\Lang', 'getCur'),
        'db' => array('Data\\Model', 'load'),
        'upinto' => array('Data\\Model', 'upinto'),

        'setStep' => array('Routing\\Step', 'set'),
        'getStep' => array('Routing\\Step', 'get'),

        'config' => array('Loader\\Config', 'get'),
        'data' => array('Loader\\Config', 'data'),
        'project' => array('Loader\\Project', 'load'),

        'view' => array('Template\\View', 'get'),
        'render' => array('Template\\View', 'html'),

        'lace' => array('Template\\Common', 'lace'),
        'first' => array('Template\\Common', 'first'),
        'last' => array('Template\\Common', 'last'),
        'other' => array('Template\\Common', 'other'),
        'sort' => array('Template\\Common', 'sort'),
        'a' => array('Template\\Common', 'a'),
        'img' => array('Template\\Common', 'img'),
        'assets' => array('Template\\Common', 'assets'),
        'table' => array('Template\\Common', 'table'),
        'tbody' => array('Template\\Common', 'tbody'),
        'show' => array('Template\\Common', 'show'),
        'card' => array('Template\\Common', 'card'),
        'ul' => array('Template\\Common', 'ul'),
        'dom' => array('Template\\Common', 'dom'),
        'timeline' => array('Template\\Common', 'timeline'),

        'token' => array('Http\\Api', 'get'),
        'checkToken' => array('Http\\Api', 'check'),
        'login' => array('Http\\Api', 'login'),
        'loginResult' => array('Http\\Api', 'checkLogin'),
        'checkLogin' => array('Http\\Api', 'checkLogin'),
        'nonce' => array('Http\\Api', 'nonce'),

        'rule' => array('String\\Regular', 'rule'),
        'id' => array('String\\Helper', 'id'),
        'idtostr' => array('String\\Helper', 'idtostr'),
        'strtoid' => array('String\\Helper', 'strtoid'),
        'uuid' => array('String\\Helper', 'uuid'),
        'order' => array('String\\Helper', 'order'),
        'order_tmp' => array('String\\Helper', 'order_tmp'),
        'hide' => array('String\\Helper', 'hide'),
        'cut' => array('String\\Helper', 'cut'),
        'code' => array('String\\Helper', 'code'),
        'uid' => array('String\\Helper', 'uid'),
        'rand' => array('String\\Helper', 'rand'),
        'filter' => array('String\\Helper', 'filter'),
        'parseEditor' => array('String\\Helper', 'parseEditor'),
        'per' => array('String\\Helper', 'per'),
        'timestamp' => array('String\\Helper', 'timestamp'),

        'qqvideo' => array('String\\Helper', 'qqvideo'),
        'ishtml' => array('String\\Helper', 'ishtml'),
        'replace' => array('String\\Helper', 'replace'),
        'strlen' => array('String\\Helper', 'strlen'),
        'addstr' => array('String\\Helper', 'addstr'),
        'encode' => array('String\\Encrypt', 'encode'),
        'decode' => array('String\\Encrypt', 'decode'),

        'cache' => array('Cache\\Handle', 'load'),
        'counter' => array('Cache\\Handle', 'counter'),
        'clearHeaderCache' => array('Routing\\Route', 'clearHeaderCache'),

        'tcp' => array('Server\\Swoole', 'getInstance'),

        'path' => array('Support\\Path', 'get'),
        'pathDay' => array('Support\\Path', 'day'),
        'pathMonth' => array('Support\\Path', 'month'),
        'pathId' => array('Support\\Path', 'id'),

        'mobile' => array('Support\\Env', 'mobile'),
        'weixin' => array('Support\\Env', 'weixin'),
        'zero' => array('Support\\Env', 'zero'),
        'header' => array('Support\\Env', 'header'),
        'ua' => array('Support\\Env', 'ua'),
        'ip' => array('Support\\Env', 'ip'),
        'os' => array('Support\\Env', 'os'),
        'browser' => array('Support\\Env', 'browser'),
        
        'daemon' => array('Support\\Command', 'daemon'),
        'cron' => array('Support\\Command', 'cron'),
        'run' => array('Support\\Command', 'run'),
        'kill' => array('Support\\Command', 'kill'),
        'process' => array('Support\\Command', 'process'),

        'excelExport' => array('Support\\Excel', 'export'),
        'excelImport' => array('Support\\Excel', 'import'),

        'log' => array('Log\\Oper', 'add'),
        'getLog' => array('Log\\Oper', 'get'),
    );

    private static $define = array();

    public static $markdown;

    public static $save;

    public static $global;

    public static $submit_state = 1;
    /**
     * register
     * @param string $name
     * @param array $param
     *
     * @return mixed
     */
    public static function __callStatic($name, $param = array())
    {
        if (isset(self::$register[$name])) {
            $class = 'Dever\\' . self::$register[$name][0];
            $method = self::$register[$name][1];
            return call_user_func_array(array($class, $method), $param);
        } elseif (isset(self::$define[$name])) {
            if (is_array(self::$define[$name])) {
                $class = self::$define[$name][0];
                $method = self::$define[$name][1];
            } else {
                 $class = self::$define[$name];
                 $method = $name;
            }
            
            return call_user_func_array(array($class, $method), $param);
        }
    }

    /**
     * 注册方法
     * @param string $method
     * @param array $function
     *
     * @return array
     */
    public static function reg($method, $function)
    {
        self::$define[$method] = $function;
    }

    /**
     * 判断是否包含
     * @param string $value
     * @param string $source
     *
     * @return array
     */
    public static function in($value, $index)
    {
        $key = $value . '_' . $index;
        if (isset(self::$global['in'][$key])) {
            return self::$global['in'][$key];
        }
        if (is_array($index)) {
            $index = implode(',', $index);
        }
        $index .= ',';
        if (strpos($value, ',')) {
            $temp = explode(',', $value);
            foreach ($temp as $k => $v) {
                $state = self::in($v, $index);
                if ($state == true) {
                    break;
                }
            }

            return self::$global['in'][$key] = $state;
        } else {
            if (strpos($index, $value . ',') !== false) {
                return self::$global['in'][$key] = true;
            }
            return self::$global['in'][$key] = false;
        }
    }

    /**
     * 创建临时文件
     * @param string $name
     * @param string $content
     *
     * @return array
     */
    public static function tmp($name, $content)
    {
        $name = tempnam(Dever::path(Dever::data() . 'tmp'), $name);
        file_put_contents($name, $content);
        ob_start();
        require $name;
        $content = ob_get_contents();
        ob_end_clean();
        unlink($name);
        return $content;
    }

    /**
     * 过滤emoji
     * @param string $str
     *
     * @return array
     */
    public static function emoji($str)
    {
        return $str;
        if (function_exists('mb_convert_encoding')) {
            //$str = mb_convert_encoding($str, 'UTF-8');
        }
       
        $str = preg_replace_callback(
            '/./u',
            function (array $match) {
                return strlen($match[0]) >= 4 ? '' : $match[0];
            },
            $str
        );

        return $str;
    }

    /**
     * 获取_param
     * @param string $name
     * @param string $param
     *
     * @return array
     */
    public static function param($name, $param)
    {
        $result = false;
        if (isset($param['add_' . $name])) {
            $result = $param['add_' . $name];
        } elseif (isset($param['set_' . $name])) {
            $result = $param['set_' . $name];
        } elseif (isset($param['option_' . $name])) {
            $result = $param['option_' . $name];
        } elseif(isset($param[$name])) {
            $result = $param[$name];
        }
        if (!$result && $result != 0) {
            $result = Dever::input($name, false);
        }
        if ($result && $result == 'null') {
            $result = '';
        }
        return $result;
    }

    public static function mdate($num, $type = 2)
    {
        $date = $num;
        $num = time() - $num;

        if ($num <= 0) {
            if ($type == 2) {
                return '1秒前';
            } else {
                return '1S';
            }
        }

        $config = array
            (
            //array(31536000, 'Y', '年'),
            //array(2592000, 'T', '个月'),
            //array(604800, 'W', '星期'),
            array(86400, 'D', '天'),
            array(3600, 'H', '小时'),
            array(60, 'M', '分钟'),
            array(1, 'S', '秒'),
        );

        if ($type == 2) {
            foreach ($config as $k => $v) {
                $value = intval($num / $v[0]);
                if ($v[1] == 'D' && $value >= 7) {
                    break;
                }
                if ($value != 0) {
                    return $value . $v[2] . '前';
                }
            }

            return date('Y-m-d H:i:s', $date);
        } else {
            $result = '';

            foreach ($config as $k => $v) {
                if ($num > $v[0]) {
                    $value = intval($num / $v[0]);
                    $num = $num - $v[0] * $value;
                    $result .= $value . $v[1] . ' ';
                }
            }

            return $result;
        }
    }

    public static function ddate($num)
    {
        $date = date('Ymd');
        $cdate = date('Ymd', $num);

        if ($cdate == $date) {
            return date('H:i', $num);
        } else {
            $value = intval((time() - $num) / 86400);
            if ($value == 1) {
                return '昨天' . date('H:i', $num);
            } else {
                $year = date('Y');
                $cyear = date('Y');
                if ($year == $cyear) {
                    return date('m月d日H:i', $num);
                } else {
                    return date('Y-m-d H:i', $num);
                }
            }
        }

        return date('Y-m-d H:i', $num);
    }

    public static function maketime($v)
    {
        if (!$v) {
            return '';
        }

        if (is_numeric($v)) {
            return $v;
        }

        if (is_array($v)) {
            $v = $v[1];
        }

        if (strstr($v, 'T')) {
            $v = str_replace(array('T', 'Z'), ' ', $v);
        }

        if (strstr($v, ' ')) {
            $t = explode(' ', $v);
            $v = $t[0];
            $s = explode(':', $t[1]);
        } else {
            $s = array(0, 0, 0);
        }

        if (!isset($s[1])) {
            $s[1] = 0;
        }

        if (!isset($s[2])) {
            $s[2] = 0;
        }

        if (strstr($v, '-')) {
            $t = explode('-', $v);
        } elseif (strstr($v, '/')) {
            $u = explode('/', $v);
            $t[0] = $u[2];
            $t[1] = $u[0];
            $t[2] = $u[1];
        }

        if (!isset($t)) {
            $t = array(0, 0, 0);
        }

        if (!isset($t[1])) {
            $t[1] = '-1';
        }

        if (!isset($t[2])) {
            $t[2] = '01';
        }

        $v = mktime($s[0], $s[1], $s[2], $t[1], $t[2], $t[0]);

        return $v;
    }

    public static function udate($format = 'u', $utimestamp = null)
    {
        if (is_null($utimestamp)) {
            $utimestamp = microtime(true);
        }
        $timestamp = floor($utimestamp);
        $milliseconds = round(($utimestamp - $timestamp) * 1000000);
        return date(preg_replace('`(?<!\\\\)u`', $milliseconds, $format), $timestamp);
    }

    public static function proxy($method = false, $param = false)
    {
        if ($method) {
            if (Dever::config('host')->proxy) {
                $method = urlencode($method);
                return Dever::url(Dever::config('host')->proxy . 'proxy_method=' . $method . '&' . $param);
            }
            return self::url($method . '?' . $param);
        }
        $data = self::input();

        foreach ($data as $k => $v) {
            self::setInput($k, $v);
        }

        return self::load(urldecode($data['proxy_method']), array('CHECK' => true));
    }

    public static function script()
    {
        $script = 'var config={};config.init=false;config.host="' . self::url('') . '";config.type="' . Dever\Routing\Uri::$type . '";config.current="' . self::url() . '";config.upload="' . self::config('host')->upload . '";config.uploadRes="' . self::config('host')->uploadRes . '";config.assets="' . self::config('host')->assets . '";config.script="' . self::config('host')->script . '";';

        if (self::config('host')->css) {
            $script .= 'config.css="' . self::config('host')->css . '";';
        }
        if (self::config('host')->js) {
            $script .= 'config.js="' . self::config('host')->js . '";';
        }
        if (self::config('host')->images) {
            $script .= 'config.images="' . self::config('host')->images . '";';
        }
        if (self::config('host')->proxy) {
            $script .= 'config.proxy="' . self::config('host')->proxy . '";';
        }
        if (self::config('host')->manage) {
            $script .= 'config.manage_assets="' . self::config('host')->manage . '";';
        }
        if (self::config('host')->base) {
            $script .= 'config.workspace="' . self::config('host')->base . '";';
        }
        if (self::config('template')->layout) {
            $script .= 'config.layout = "' . self::config('template')->layout . '";$(document).ready(function()
                        {
                            $(document).pjax("a", "' . self::config('template')->layout . '", {"timeout":8000});

                            $(document).on("submit", "#form1", function (event) {event.preventDefault();$.pjax.submit(event, "' . self::config('template')->layout . '", {"push": true, "replace": false, timeout:8000, "scrollTo": 0, maxCacheLength: 0});});

                            $(document).on("pjax:start", function()
                            {
                                NProgress.start();
                            });
                            $(document).on("pjax:end", function()
                            {
                                NProgress.done();
                            });
                        });';
        }
        return $script;
    }

    /**
     * 加载分享前端组件
     * @param string $key
     *
     * @return string
     */
    public static function share($project, $uid, $share_url, $title, $img, $desc, $link = false, $button = false)
    {
        if (!$uid) {
            $uid = -1;
        }

        $host = self::config('host')->script;
        $html = '<script src="'.$host.'lib/share/weixin.js" ></script><script src="'.$host.'dever/share.js" ></script>';

        $html .= '<script type="text/javascript">';
        $html .= '$(function()';
        $html .= '{';
        $html .= 'var uid = ' . $uid . ';';
        $html .= 'var project = ' . $project . ';';
        $html .= 'var url = "' . $share_url . '?api.";';
        $html .= 'var param = {};';
        $html .= 'param.title = "' . $title . '";';
        $html .= 'param.img = "' . $img . '";';
        $html .= 'param.desc = "' . $desc . '";';

        if ($link) {
            $html .= 'param.url = "' . $link . '";';
        } else {
            $html .= 'param.url = location.href;';
        }

        if ($button) {
            $html .= 'var button = "' . $link . '";';
        } else {
            $html .= 'var button = false;';
        }

        $html .= 'Dever_Share.Init(uid, project, url, param, button);';
        $html .= '})';
        $html .= '</script>';
        return $html;
    }

    /**
     * queue队列，需要队列组件 dever package queue
     * @param string $key
     *
     * @return string
     */
    public static function queue($key = 'default', $value = false)
    {
        self::import('queue');
        if ($value) {
            if ($value == 'len') {
                $result = self::len($key);
            } else {
                $result = self::push($value, $key);
            }
        } else {
            $result = self::pop($key);
        }
        
        return $result;
    }

    /**
     * 通过Redis队列来实现的锁操作
     * @param string $key
     *
     * @return string
     */
    public static function lock($key = 'default', $total = false)
    {
        self::import('queue');
        if ($total && $total > 0) {
            # 写入
            $len = self::len($key);
            if ($len < $total) {
                $count = $total - $len;
                for($i=1; $i <= $count; $i++) {
                    self::push($i, $key);
                }
            } else {
                return false;
            }
        } else {
            $state = self::pop($key);
            if (!$state) {
                return false;
            }
        }
        
        return true;
    }

    /**
     * json_encode编码
     * @param string $value
     *
     * @return string
     */
    public static function json_encode($value, $pic_state = true)
    {
        //$value = json_encode($value, JSON_UNESCAPED_UNICODE + JSON_FORCE_OBJECT);
        //$value = json_encode($value, JSON_UNESCAPED_UNICODE + JSON_NUMERIC_CHECK);
        $value = json_encode($value, JSON_UNESCAPED_UNICODE);
        if (strpos($value, '<null>')) {
            $value = str_replace('<null>', '', $value);
        }
        $webp = self::input('webp', -1);
        $pic = self::config('base')->pic;
        if ($webp > 0) {
            $value = self::upload($value, 'wp' . $webp);
        } else {
            if ($pic && $pic_state) {
                $value = self::upload($value, $pic);
            } else {
                $value = self::uploadRes($value);
            }
        }
        $value = self::https($value);

        return $value;
    }

    /**
     * json_decode解码
     * @param string $value
     *
     * @return string
     */
    public static function json_decode($value)
    {
        return json_decode($value, true);
    }

    /**
     * 数据库数组编码
     * @param string $value
     *
     * @return string
     */
    public static function array_encode($value)
    {
        return self::base64_encode(self::json_encode($value));
    }

    /**
     * 数据库数组解码
     * @param string $value
     *
     * @return string
     */
    public static function array_decode($value)
    {
        if (strstr($value, '{')) {
            return self::json_decode($value);
        }
        return self::json_decode(self::base64_decode($value, true));
    }

    /**
     * emoji强制编码（如果不支持utf8mb4就用这个吧）
     * @param string $value
     *
     * @return string
     */
    public static function base64_encode($value)
    {
        return base64_encode($value);
    }

    /**
     * emoji强制解码
     * @param string $value
     *
     * @return string
     */
    public static function base64_decode($value)
    {
        return base64_decode($value);
    }

    /**
     * 图片base64编码
     * @param string $value
     *
     * @return string
     */
    public static function pic_base64_encode($img_file, $type = 1)
    {
        $img_base64 = '';
        if (file_exists($img_file)) {
            $app_img_file = $img_file; // 图片路径
            $img_info = getimagesize($app_img_file); // 取得图片的大小，类型等

            //echo '<pre>' . print_r($img_info, true) . '</pre><br>';
            $fp = fopen($app_img_file, "r"); // 图片是否可读权限

            if ($fp) {
                $filesize = filesize($app_img_file);
                $content = fread($fp, $filesize);
                $file_content = chunk_split(base64_encode($content)); // base64编码
                switch ($img_info[2]) {           //判读图片类型
                    case 1: $img_type = "gif";
                        break;
                    case 2: $img_type = "jpg";
                        break;
                    case 3: $img_type = "png";
                        break;
                }

                if ($type == 1) {
                    $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content;//合成图片的base64编码
                } else {
                    $img_base64 = $file_content;//合成图片的base64编码
                }

            }
            fclose($fp);
        }

        return $img_base64;
    }

    /**
     * 获取文件后缀
     * @param string $file
     *
     * @return string
     */
    public static function ext($file)
    {
        return pathinfo($file, PATHINFO_EXTENSION);
    }

    /**
     * markdown解析
     * @param string $value
     *
     * @return string
     */
    public static function markdown($value)
    {
        self::$markdown = self::$markdown ? self::$markdown : new \Parsedown();

        # 一个回车就换行
        self::$markdown->setBreaksEnabled(true);

        # 过滤掉所有特殊代码
        return self::$markdown->text($value);
    }

    /**
     * setup 安装引导程序
     * @param string $value
     *
     * @return string
     */
    public static function setup()
    {
        $host = DEVER_APP_HOST;

        $path = DEVER_APP_PATH . '../';

        $dir = scandir($path);

        foreach ($dir as $k => $v) {
            if ($v != '.' && $v != '..' && is_dir($path . $v)) {
                $url = str_replace(array('www', 'main'), $v, $host);
                if (is_file($path . $v . '/index.php')) {
                    Dever::curl($url);

                    echo $url . ' 安装成功！<br />' . "\r\n";
                }
            }
        }

        return '感谢您使用Dever！';
    }

    /**
     * dyna 动态解析功能
     * @param string $key
     * @param array $data
     *
     * @return mixed
     */
    public static function odyna($key = false, $data = array(), $type = '')
    {
        return (object) self::dyna($key, $data, $type);
    }

    /**
     * dyna 动态解析功能
     * @param string $key
     * @param array $data
     * @param string $type
     *
     * @return mixed
     */
    public static function dyna($key = false, $data = array(), $type = '')
    {
        if (isset(self::$global['dyna'][$key])) {
            return self::$global['dyna'][$key];
        }
        $config = self::config('dyna')->cAll;

        if ($type && isset($config[$type])) {
            $config = $config[$type];
        }

        if (empty($config[$key])) {
            return $key;
        }
        if (!$data) {
            self::$global['dyna'][$key] = $config[$key];
            return $config[$key];
        }

        if (is_array($config[$key])) {
            foreach ($config[$key] as $k => $v) {
                $v = '$value = "' . $v . '";';
                eval($v);
                if (isset($value)) {
                    $config[$key][$k] = $value;
                }
            }
        } else {
            $v = '$value = "' . $config[$key] . '";';
            eval($v);
            if (isset($value)) {
                $config[$key] = $value;
            }
        }

        self::$global['dyna'][$key] = $config[$key];

        return $config[$key];
    }

    /**
     * session 使用session，默认为cookie
     * @param string $key
     * @param string $value
     * @param string $type
     *
     * @return mixed
     */
    public static function session($key, $value = false, $timeout = 3600, $type = 'cookie', $encode = true)
    {
        if (!isset(self::$save[$key])) {
            self::$save[$key] = new \Dever\Session\Oper(DEVER_APP_NAME, $type);
        }

        if ($value) {
            if ($value == 'delete') {
                return self::$save[$key]->un($key);
            } else {
                return self::$save[$key]->add($key, $value, $timeout, $encode);
            }
            
        } else {
            return self::$save[$key]->get($key, $encode);
        }
    }

    /**
     * session_start()
     *
     * @return mixed
     */
    public static function session_start()
    {
        if (!self::config('base')->session) {
            @header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');
            $server = self::config('database')->session;
            if ($server) {
                $link = 'tcp://'.$server['host'].':'.$server['port'] . '?persistent=1&weight=1&timeout=1&retry_interval=15';
                if (isset($server['password']) && $server['password']) {
                    $link .= '&auth='.$server['password'];
                }
                @ini_set('session.save_handler', $server['type']);
                @ini_set('session.save_path', $link);
            } elseif (self::config('base')->sessionPath) {
                @ini_set('session.save_path', self::config('base')->sessionPath);
            }
            @ini_set('session.gc_maxlifetime', 86400);
            # 解决post页面返回上一页问题
            if (self::config('template')->session_cache) {
                //@session_cache_limiter('private');//这个有问题
                //@header("Cache-control: private");//这个也不行
            }
            
            if (self::config('host')->cookie) {
                ini_set('session.cookie_domain', self::config('host')->cookie);
            }
            @session_start();

            self::config('base')->session = true;
        }
    }

    /**
     * submit 验证是否重复，生成重复验证信息
     *
     * @return mixed
     */
    public static function submit($key = false)
    {
        $key = self::submit_key($key);
        if (self::$submit_state == 1) {
            $token = self::session($key, Dever::uuid(), 3600, 'session', false);
            self::$submit_state = 2;
        } else {
            $token = self::session($key, false, 3600, 'session', false);
        }
        return array('key' => $key, 'token' => $token);
    }

    /**
     * submit_check 验证是否重复
     * @param string $token
     * @param string $uuid true 自动为后续的alert添加uuid
     *
     * @return mixed
     */
    public static function submit_check($key = false, $token = false, $uuid = false)
    {
        $key = self::submit_key($key);
        
        if ($uuid) {
            self::config('base')->create_alert_uuid = true;
        }
        $dever_submit = self::session($key, false, 3600, 'session', false);
        self::session($key, 'delete', 3600, 'session', false);
        if (self::input('dever_submit', $token) != $dever_submit) {
            Dever::alert('请不要重复提交');
        }
    }

    /**
     * submit_key 验证是否重复 获取key
     * @param string $key
     *
     * @return mixed
     */
    public static function submit_key($key = false)
    {
        if (!$key) {
            $key = md5(self::url());
        }

        $key = 'ds_' . $key;
        return $key;
    }

    /**
     * defaultValue 过滤默认值
     * @param string $value
     *
     * @return mixed
     */
    public static function defaultValue($v)
    {
        if (!$v) {
            return $v;
        }
        $v = str_replace('-1', '', $v);
        $v = str_replace(',,,', ',', $v);
        $v = str_replace(',,', ',', $v);
        if ($v == ',') {
            $v = '';
        } elseif (!strstr($v, ',')) {
            $v .= ',';
        }
        return $v;
    }

    /**
     * score 积分组件
     * @param string $value
     *
     * @return mixed
     */
    public static function score($uid, $key, $name = '', $content = '', $score = false, $num = false, $type = false, $type_id = false)
    {
        if (self::project('score')) {
            self::load('score/lib/core')->log($uid, $key, $name, $content, $score, $num, $type, $type_id);
        }
    }

    /**
     * 判断文件是否存在，支持本地及远程文件
     * @param  String  $file 文件路径
     * @return Boolean
     */
    public static function is_file($file)
    {
        // 远程文件
        if(strtolower(substr($file, 0, 4))=='http'){

            $header = get_headers($file, true);

            return isset($header[0]) && (strpos($header[0], '200') || strpos($header[0], '304'));

        // 本地文件
        }else{
            return is_file($file);
        }
    }

    /**
     * 获取refer和设置refer
     */
    public static function refer($project = 'main', $method = 'set')
    {
        if ($method == 'set') {
            return 'refer=' . self::encode(self::url(false, $project));
        } else {
            $refer = self::input('refer');
            if ($refer) {
                $refer = self::decode($refer);
            } else {
                $refer = Dever::url('home', $project);
            }

            $param = Dever::input('refer_param');
            if ($param) {
                $refer .= '&' . $param;
            }
            return $refer;
        }
    }

    /**
     * 获取后台的项目权限
     */
    public static function top($key = false)
    {
        if (!$key) {
            $key = self::config('base')->top;
        }
        return self::load('manage/auth.getTop', $key);
    }

    /**
     * 获取后台的项目权限
     */
    public static function tops($key = false)
    {
        if (!$key) {
            $key = self::config('base')->top;
        }
        $auth = false;
        if (DEVER_APP_NAME == 'manage') {
            $auth = self::auth();
            if ($auth['top'] && $auth['top'] != 'all') {
                $data = Dever::db('manage/top')->getData(array('ids' => $auth['top']));
                if ($data) {
                    $result = array();
                    foreach ($data as $k => $v) {
                        if (strstr($v['key'], $key)) {
                            $result[] = $v['value'];
                        }
                    }
                    return implode(',', $result);
                }
            }
            return false;
            
        } else {
            return self::input($key);
        }
        
        /*
        if ($auth && $auth['top'] != 'all') {
            $key = str_replace('/', '-', $key);
            $auth['top'] = str_replace($key . '_', '', $auth['top']);
            print_r($auth['top']);die;
            return $auth['top'];
        }
        return false;
        */
    }

    /**
     * 获取后台的项目权限
     */
    public static function auth()
    {
        return self::load('manage/auth.info');
    }

    /**
     * 对字符串执行指定次数替换
     * @param  Mixed $search   查找目标值
     * @param  Mixed $replace  替换值
     * @param  Mixed $subject  执行替换的字符串／数组
     * @param  Int   $limit    允许替换的次数，默认为-1，不限次数
     * @return Mixed
     */
    public static function str_replace($search, $replace, $subject, $limit=-1)
    {
        if ($limit == -1) {
            return str_replace($search, $replace, $subject);
        }
        if (is_array($search)) {
            foreach ($search as $k=>$v) {
                $search[$k] = '`'. preg_quote($search[$k], '`'). '`';
            }
        } else {
            $search = '`'. preg_quote($search, '`'). '`';
        }
        return preg_replace($search, $replace, $subject, $limit);
    }

    /**
     * 获取自定义数据
     */
    public static function diy_data($source_table, $table, $id_name, $limit = 8, $uid = false, $reorder = 'reorder', $uid_name = 'uid')
    {
        $uid = self::input($uid_name, $uid);
        $result = array();
        $temp = explode('/', $source_table);
        $key = $temp[1];
        $my_key = 'my_' . $key;

        # 获取总的数据
        $result[$key] = Dever::db($source_table)->limit();
        # 获取当前用户选择的数据
        $where[$uid_name] = $uid;
        $where['limit'] = '0,' . $limit;
        $result[$my_key] = Dever::db($table)->limit($where);

        # 没有自定义数据
        if (!$result[$my_key]) {
            $result[$my_key] = Dever::db($source_table)->limit(array('limit' => $where['limit']));
        } else {
            # 自定义的数量
            $count = count($result[$my_key]);
            if ($count < $limit) {
                # 不够数量，要从默认的数据表里补充一下
                $limit = $limit - $count;
                foreach ($result[$my_key] as $k => $v) {
                    $data[$v[$id_name]] = $v;
                }
                $i = 1;
                foreach ($result[$key] as $k => $v) {
                    if (!isset($data[$v['id']]) && $limit >= $i) {
                        $result[$my_key][] = $v;
                        $i++;
                    }
                }

                if ($reorder) {
                    $reorder = array_column($result[$my_key], 'reorder');
                    array_multisort($reorder, SORT_DESC, $result[$my_key]);
                }
            }
        }

        return $result;
    }

    /**
     * 自定义数据设置
     */
    public static function diy_set($source_table, $table, $id_name, $uid = false, $ids = false, $uid_name = 'uid')
    {
        $source = Dever::db($source_table)->state();
        if (!$source) {
            return array();
        }
        $uid = Dever::input($uid_name, $uid);
        $ids = Dever::input('ids', $ids);

        if (!$ids) {
            return array();
        }

        if (!is_array($ids)) {
            $ids = explode(',', $ids);
        }
        
        $result = array();
        $time = time();
        $db = Dever::db($table);
        foreach ($source as $k => $v) {
            $where[$uid_name] = $uid;
            $where[$id_name] = $v['id'];
            $info = $db->one($where);
            if (in_array($v['id'], $ids)) {
                if (!$info) {
                    unset($v['id']);
                    unset($v['cdate']);
                    $info = array_merge($v, $where);
                    $info['state'] = 1;
                    $info['id'] = $db->insert($info);
                    $info['cdate'] = $time;
                } else {
                    $db->update(array('where_id' => $info['id'], 'state' => 1));
                }
                $info['update_id'] = $info[$id_name];
                $result[] = $info;
            } elseif ($info) {
                $db->update(array('where_id' => $info['id'], 'state' => 2));
            }
        }
        return $result;
    }

    /**
     * 自定义数据更新
     */
    public static function diy_up($source_table, $table, $id_name, $col, $uid = false, $id = false, $uid_name = 'uid')
    {
        if (!is_array($col)) {
            $col = explode(',', $col);
        }
        $update = array();
        foreach ($col as $k => $v) {
            $info = Dever::input($v);
            if ($info) {
                $update[$v] = $info;
            }
        }
        $uid = Dever::input($uid_name, $uid);
        $id = Dever::input('update_id', $id);

        if (!$id) {
            return array();
        }

        $db = Dever::db($table);
        $result = array();
        if ($update) {
            $where[$uid_name] = $uid;
            $where[$id_name] = $id;
            $result = $db->one($where);
            if ($result) {
                $update['where_id'] = $result['id'];
                $db->update($update);
                $result = array_merge($result, $update);
            } else {
                $info = Dever::db($source_table)->one($id);
                $result = array_merge($info, $update);
                $result = array_merge($result, $where);
                unset($result['id']);
                unset($result['cdate']);
                $db->insert($result);
            }
            $result['update_id'] = $id;
        }
        return $result;
    }

    /**
     * 坐标点搜索 后续封装进来
     */
    public static function point()
    {
        'select t.num,t.city,t.wgs84_lng,t.wgs84_lat,
          TRUNCATE(st_distance_sphere(point (113.8064049, 22.7300434),point(t.wgs84_lng,t.wgs84_lat)),2) as distance
            from moran_point t
            where t.city = \'深圳\' 
            HAVING distance > 0 and distance < 3500
            ORDER BY distance;';
        return '';
    } 

    # 笛卡尔积
    public static function cartesian($data)
    {
        $len = count($data);
        $result = array();
        if ($len == 1) {
            foreach ($data[0] as $k => $v) {
                if (is_array($v)) {
                    foreach ($v as $k1 => $v1) {
                        $v[$k1] = array($v1);
                    }
                }
                
                $result[] = $v;
            }
        } else {
            $k = 0;
            $result = $data[0];
            for ($i = 1; $i < $len; $i++) {
                $arr = $result;
                $result = [];
                foreach ($arr as $v) {
                    foreach($data[$i] as $v1) { 
                        if(!is_array($v)) {
                            $v = array($v);
                        }
                        if(!is_array($v1)){
                            $v1 = array($v1);
                        }
                        $result[] = array_merge_recursive($v, $v1);
                    }
                }
            }
        }
        

        return $result;
    }

    # 多维数组排序
    public static function array_order($array, $key, $sort)
    {
        $reorder = array_column($array, $key);
        array_multisort($reorder, $sort, $array);

        return $array;
    }

    # 计算距离
    public static function distance($lng1, $lat1, $lng2, $lat2, $miles = true)
    {
        $pi80 = M_PI / 180;
        $lat1 *= $pi80;
        $lng1 *= $pi80;
        $lat2 *= $pi80;
        $lng2 *= $pi80;
        $r = 6372.797;
        $dlat = $lat2 - $lat1;
        $dlng = $lng2 - $lng1;
        $a = sin($dlat/2)*sin($dlat/2)+cos($lat1)*cos($lat2)*sin($dlng/2)*sin($dlng/2);
        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
        $km = $r * $c;
        return ($miles ? ($km * 0.621371192) : $km);
    }

    # 获取距离sql
    public static function distanceSql($lng, $lat)
    {
        return 'round((st_distance(point(lng, lat), point('.$lng.', '.$lat.'))*111195)/1000, 2) as distance';
    }

    # 获取毫秒
    public static function msectime()
    {
        list($msec, $sec) = explode(' ', microtime());
        $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
        return $msectime;
    }

    # 获取第几周
    public static function getWeek($time)
    {
        $week = abs(ceil((date('j', $time) - [0,6,5,4,3,2,1][date('w', strtotime(date('Y-m-01')))]) / 7));

        return $week + 1;
    }

    # 更新复杂的关联结构
    public static function upLinkage(&$update, $id, $data, $name, $table, $where_id, $where_other_id, $update_id)
    {
        $up = self::param($name, $data);
        if ($up) {
            $up = self::json_decode($up);

            if ($up) {
                foreach ($up as $k1 => $v1) {
                    if ($v1['value']) {
                        foreach ($v1['value'] as $k => $v) {
                            if ($v['state'] == 1) {
                                $w = array();
                                $w[$where_other_id] = $v['id'];
                                $w[$where_id] = $id;
                                $info = self::db($table)->one($w);

                                $w[$update_id] = $v1['id'];
                                if (!$info) {
                                    self::db($table)->insert($w);
                                } else {
                                    $w['where_id'] = $info['id'];
                                    $w['state'] = 1;
                                    self::db($table)->update($w);
                                }
                            } else {
                                unset($up[$k1]['value'][$k]);
                            }
                        }
                    }
                }

                $update[$name] = self::json_encode($up);
            }
        }
    }

    # 后台搜索
    public static function search($table, $where = array(), $method = 'search')
    {
        $keyword = Dever::input('keyword');

        $cate = Dever::input('cate');
        if ($cate) {
            $where['cate_id'] = $cate;
        }

        $yes = Dever::input('yes');

        if ($yes) {
            $yes = Dever::db($table)->{$method.'_find'}(array('ids' => $yes));
        }
        if (!$keyword) {
            //$where['limit'] = '0,20';
            $data = Dever::db($table)->$method($where);
        } else {
            $where['name'] = $keyword;
            $data = Dever::db($table)->$method($where);
        }

        $result = array();
        if ($yes) {
            foreach ($yes as $k => $v) {
                if (isset($data[$k])) {
                    unset($data[$k]);
                }
                $yes[$k]['selected'] = true;
            }
            $data = $yes + $data;

            $data = array_merge($data, array());
        } else {
            $data = array_merge($data, array());
        }

        if (!$data) {
            Dever::alert('暂无数据');
        }

        return $data;
    }

    # 获取周的开始时间和结束时间
    public static function week($num = 0, $prefix = '-')
    {
        if ($num > 0) {
            $time = strtotime($prefix . $num.' week');
        } else {
            $day = Dever::input('day');
            if ($day) {
                $time = Dever::maketime($day);
            } else {
                $time = time();
            }
        }
        list($year, $month, $day, $week) = explode('-', date('Y-m-d-w', $time));

        $start = ($day-$week+1) . ' 00:00:00';
        $end = ($day-$week+7) . ' 23:59:59';

        $start = Dever::maketime($year . '-' . $month . '-' . $start);
        $end = Dever::maketime($year . '-' . $month . '-' . $end);

        return array($start, $end);
    }

    # 获取月的开始时间和结束时间
    public static function month($num = 0, $prefix = '-')
    {
        if ($num > 0) {
            $time = strtotime($prefix . $num.' month');
        } else {
            $day = Dever::input('day');
            if ($day) {
                $time = Dever::maketime($day);
            } else {
                $time = time();
            }
        }
        list($year, $month, $end) = explode('-', date('Y-m-t', $time));

        $start = '01 00:00:00';
        $end = $end . ' 23:59:59';

        $start = Dever::maketime($year . '-' . $month . '-' . $start);
        $end = Dever::maketime($year . '-' . $month . '-' . $end);
        return array($start, $end);
    }

    # 获取天的开始时间和结束时间
    public static function day($num = 0, $prefix = '-')
    {
        if ($num > 0) {
            $time = strtotime($prefix . $num.' day');
        } else {
            $day = Dever::input('day');
            if ($day) {
                $time = Dever::maketime($day);
            } else {
                $time = time();
            }
        }
        list($year, $month, $day) = explode('-', date('Y-m-d', $time));

        $start = $day . ' 00:00:00';
        $end = $day . ' 23:59:59';

        $start = Dever::maketime($year . '-' . $month . '-' . $start);
        $end = Dever::maketime($year . '-' . $month . '-' . $end);
        return array($start, $end);
    }

    public static function showDay($day)
    {
        if (strstr($day, '-')) {
            return $day;
        }
        if (strlen($day) == 10) {
            return date('Y-m-d', $day);
        }
        
        return substr($day, 0, 4) . '-' . substr($day, 4);
    }

    # 编码转换
    public static function convert($string, $to = 'GBK', $source = 'UTF-8')
    {
        return mb_convert_encoding($string, $to, $source);
    }

    # 解析换行
    public static function split($string, $search = "\r\n", $index = -1)
    {
        if (strstr($string, $search)) {
            $result = explode($search, $string);
        } else {
            $result = array($string);
        }
        if ($index && $index >= 0) {
            if (isset($result[$index])) {
                return $result[$index];
            } else {
                return '';
            }
        }
        return $result;
    }

    # 将数组进行组合
    public static function build($request = array(), $type = 'sha1', $suffix = '', $empty = true)
    {
        ksort($request);

        $signature_string = '';
        foreach ($request as $k => $v) {
            if (strstr($v, 'http') && !strstr($v, '%')) {
                $v = urlencode($v);
            }
            if (!$empty) {
                $signature_string .= $k . '=' . $v . '&';
            } elseif (strlen($v) && $v != 'empty') {
                $signature_string .= $k . '=' . $v . '&';
            }
        }
        if ($suffix != '&') {
            $signature_string = substr($signature_string, 0, -1) . $suffix;
        }
        
        return $type($signature_string);
    }

    public static function search_button()
    {
        $button = self::input('search_button');
        if ($button) {
            $button = explode('~', $button);
            $temp = explode(',', $button[1]);
            $col = array();
            foreach ($temp as $k => $v) {
                $col[] = 'sum('.$v.') as ' . $v;
            }
            if ($button[2] == 'day') {
                $string = '%Y-%m-%d';
                $time = "FROM_UNIXTIME(".$button[0].",'".$string."')";
            } elseif ($button[2] == 'week') {
                $string = '%Y-%m-%d';
                $time = "(YEARWEEK(FROM_UNIXTIME(".$button[0].",'".$string."'), 1))";
            } elseif ($button[2] == 'month') {
                $string = '%Y-%m';
                $time = "FROM_UNIXTIME(".$button[0].",'".$string."')";
            }

            $group = $time;
            if (isset($button[3]) && $button[3]) {
                $group .= ',' . $button[3];
            }

            $col = "*, min(".$button[0].") as time, ".$time." as ".$button[0].",".implode(',', $col)."|id";
            return array($group, $col);
        }

        return false;
    }

    public static function mb_str_pad($input, $pad_length, $pad_string = ' ', $pad_type = STR_PAD_RIGHT, $encoding = 'UTF-8')
    {
        $input_length = (strlen($input) + mb_strlen($input, $encoding))/2;
        $pad_string_length = mb_strlen($pad_string, $encoding);

        if ($pad_length <= 0 || ($pad_length - $input_length) <= 0) {
            return $input;
        }

        $num_pad_chars = $pad_length - $input_length;

        switch ($pad_type) {
            case STR_PAD_RIGHT:
                $left_pad = 0;
                $right_pad = $num_pad_chars;
                break;

            case STR_PAD_LEFT:
                $left_pad = $num_pad_chars;
                $right_pad = 0;
                break;

            case STR_PAD_BOTH:
                $left_pad = floor($num_pad_chars / 2);
                $right_pad = $num_pad_chars - $left_pad;
                break;
        }

        $result = '';
        for ($i = 0; $i < $left_pad; ++$i) {
            $result .= mb_substr($pad_string, $i % $pad_string_length, 1, $encoding);
        }
        $result .= $input;
        for ($i = 0; $i < $right_pad; ++$i) {
            $result .= mb_substr($pad_string, $i % $pad_string_length, 1, $encoding);
        }

        return $result;
    }

    /**
     * 将数值金额转换为中文大写金额
     * @param $amount float 金额(支持到分)
     * @param $type   int   补整类型,0:到角补整;1:到元补整
     * @return mixed 中文大写金额
     */
    public static function convertNum($amount, $type = 1) {
        // 判断输出的金额是否为数字或数字字符串
        if(!is_numeric($amount)){
            return "要转换的金额只能为数字!";
        }

        // 金额为0,则直接输出"零元整"
        if($amount == 0) {
            return "零元整";
        }

        // 金额不能为负数
        if($amount < 0) {
            return "要转换的金额不能为负数!";
        }

        // 金额不能超过万亿,即12位
        if(strlen($amount) > 12) {
            return "要转换的金额不能为万亿及更高金额!";
        }

        // 预定义中文转换的数组
        $digital = array('零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖');
        // 预定义单位转换的数组
        $position = array('仟', '佰', '拾', '亿', '仟', '佰', '拾', '万', '仟', '佰', '拾', '元');

        // 将金额的数值字符串拆分成数组
        $amountArr = explode('.', $amount);

        // 将整数位的数值字符串拆分成数组
        $integerArr = str_split($amountArr[0], 1);

        // 将整数部分替换成大写汉字
        $result = '';
        $integerArrLength = count($integerArr);     // 整数位数组的长度
        $positionLength = count($position);         // 单位数组的长度
        for($i = 0; $i < $integerArrLength; $i++) {
            // 如果数值不为0,则正常转换
            if($integerArr[$i] != 0){
                $result = $result . $digital[$integerArr[$i]] . $position[$positionLength - $integerArrLength + $i];
            }else{
                // 如果数值为0, 且单位是亿,万,元这三个的时候,则直接显示单位
                if(($positionLength - $integerArrLength + $i + 1)%4 == 0){
                    $result = $result . $position[$positionLength - $integerArrLength + $i];
                }
            }
        }

        // 如果小数位也要转换
        if($type == 0) {
            // 将小数位的数值字符串拆分成数组
            $decimalArr = str_split($amountArr[1], 1);
            // 将角替换成大写汉字. 如果为0,则不替换
            if($decimalArr[0] != 0){
                $result = $result . $digital[$decimalArr[0]] . '角';
            }
            // 将分替换成大写汉字. 如果为0,则不替换
            if($decimalArr[1] != 0){
                $result = $result . $digital[$decimalArr[1]] . '分';
            }
        }else{
            $result = $result . '整';
        }
        return $result;
    }

    # 分析文本中的链接
    public static function getLink($text)
    {
        preg_match("/(https:|https:)(\/\/[A-Za-z0-9_#?.&=\/]+)([".chr(0xb0)."-".chr(0xf7)."][".chr(0xa1)."-".chr(0xfe)."])?(\s)?/i", $text, $result);

        if (isset($result[0])) {
            return $result[0];
        }
        return false;
    }

    # 获取url中的内容并输出缓冲
    public static function ob_content($url)
    {
        ob_start();
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_exec($ch);
        $content = ob_get_contents();
        ob_end_clean();
        curl_close($ch);

        return $content;
    }

    public static function status($config, $value, $style = false)
    {
        if (isset($config[$value]) && $config[$value]) {
            if (is_array($config[$value])) {
                if ($style) {
                    return '<font style="'.$config[$value]['style'].'">' . $config[$value]['name'] . '</font>';
                }
                return $config[$value]['name'];
            } else {
                return $config[$value];
            }
        }
        return '';
    }

    public static function walk($data, $parent_id = 0, $id_key = 'id', $child_key = 'children', $parent_key = 'parent_id')
    {
        $result = array();
        $i = 0;
        foreach ($data as $k => $v)
        {   
            if ($v[$parent_key] == $parent_id) {

                $result[$i] = $v;
                unset($data[$k]);
                $result[$i][$child_key] = self::walk($data, $v[$id_key], $id_key, $child_key, $parent_key);
                $i++;
            }
        }
        return $result;
    }

    # 获取后台批量更新的数据
    public static function mul($id)
    {
        $mul_type = self::config('base')->mul_type;
        $data = self::config('base')->mul_data;
        if ($mul_type == 2 && $data) {
            return $data;
        } elseif ($id) {
            return explode(',', $id);
        }
        return array();
    }

    # 数组批量加前缀
    public static function prefix($array, $prefix)
    {
        $result = array();
        array_walk($array, function ($value, $key) use ($prefix, &$result) {
            $result[$prefix . $key] = $value;
        });

        return $result;
    }

    # 处理数字展示位数 $type 1是直接展示位数，2是千分位用逗号隔开，3是四舍五入 $number 如果是数组，key值为0是要进行展示位数的字段名，1是数组
    public static function number($number, $num = 2, $type = 1)
    {
        if (is_array($number)) {
            foreach ($number[0] as $k => $v) {
                $number[1][$v] = self::number($number[1][$v], $num, $type);
            }
            return $number[1];
        }
        
        if ($type == 2) {
            return number_format($number, $num);
        }
        if ($type == 3) {
            return round($number, $num);
        }
        return sprintf("%.".$num."f", $number);
    }

    public static function cdate($date, $info, $split = '<br />')
    {
        $result = array();
        foreach ($date as $k => $v) {
            if (isset($info[$v]) && $info[$v]) {
                $result[$k] = date("Y-m-d H:i", $info[$v]);
            } else {
                $result[$k] = '-';
            }
        }
        return implode($split, $result);
    }

    public static function getOrderNum($prefix, $table, $col = 'order_num')
    {
        $where[$col] = self::order($prefix);
        $state = self::db($table)->one($where);
        if (!$state) {
            return $where[$col];
        } else {
            return self::getOrderNum($prefix, $table, $col);
        }
    }

    public static function setAlias($project, $alias)
    {
        if (!self::config('base')->alias) {
            self::config('base')->alias = array();
        }
        $config[$project] = $alias;
        self::config('base')->alias = array_merge(self::config('base')->alias, $config);
    }
}
