<?php
class param
{
    //路由配置
    public $route_config = '';
    public $route_rules = '';
    public function __construct($cfgtype = "default")
    {
        if (!MAGIC_QUOTES_GPC) {
            $_POST = uaddslashes($_POST);
            $_GET = uaddslashes($_GET);
            $_REQUEST = uaddslashes($_REQUEST);
            $_COOKIE = uaddslashes($_COOKIE);
        }
        $this->route_config = core::load_config('route', $cfgtype);
        if ($cfgtype == 'default' && $_GET['g'] != 'addons') {
            $this->init_const();
            $this->route_rules = core::load_config('route', 'routes');
            $this->get_pathinfo();
            if ($this->route_rules) {
                $ret_route = $this->route_url();
                if (!$ret_route) {
                    $this->no_route_url();
                }
            }
        }
        $_GET = yytrim($_GET);
        // $_POST = yytrim($_POST);
        // $_REQUEST = yytrim($_REQUEST);   
        //$_COOKIE = yytrim($_COOKIE); 
        return true;
    }
    //初始化系统常量
    private function  init_const()
    {
        $seocfg = getseocfg();
        if ($seocfg) {
            define('URL_MODEL', $seocfg['url_model']);
            define('URL_ROUTE', true); //路由开启	
        } else {
            define('URL_MODEL', 1);
            define('URL_ROUTE', true); //路由开启	
        }
        define('APP_SUB_DOMAIN_DEPLOY', false);
        define('URL_COMPAT',      3);   // 兼容模式
        define('URL_REWRITE',     2);   //REWRITE模式
        define('URL_PATHINFO_DEPR', "/");
        define('URL_HTML_SUFFIX', "html");
        define('URL_DENY_SUFFIX', "ico|png|gif|jpg"); // URL禁止访问的后缀设置
        define('VAR_URL_PARAMS', '_URL_'); // PATHINFO URL参数变量
        define('IS_CGI', substr(PHP_SAPI, 0, 3) == 'cgi' ? 1 : 0);
        define('IS_WIN', strstr(PHP_OS, 'WIN') ? 1 : 0);
        define('URL_PATHINFO_FETCH',     'ORIG_PATH_INFO,REDIRECT_PATH_INFO,REDIRECT_URL,REQUEST_URI,QUERY_STRING');   //用于兼容判断PATH_INFO 参数的SERVER替代变量列表
        // 项目名称
        defined('SITE_ROOT') or define('SITE_ROOT', basename(dirname($_SERVER['SCRIPT_FILENAME'])));
        if (!defined('_PHP_FILE_')) {
            if (IS_CGI) {
                //CGI/FASTCGI模式下
                $_temp  = explode('.php', $_SERVER['PHP_SELF']);
                define('_PHP_FILE_',    rtrim(str_replace($_SERVER['HTTP_HOST'], '', $_temp[0] . '.php'), '/'));
            } else {
                define('_PHP_FILE_',    rtrim($_SERVER['SCRIPT_NAME'], '/'));
            }
        }
        // 当前文件名
        if (!defined('_PHP_FILE_')) {
            if (IS_CGI) {
                //CGI/FASTCGI模式下
                $_temp  = explode('.php', $_SERVER['PHP_SELF']);
                define('_PHP_FILE_',    rtrim(str_replace($_SERVER['HTTP_HOST'], '', $_temp[0] . '.php'), '/'));
            } else {
                define('_PHP_FILE_',    rtrim($_SERVER['SCRIPT_NAME'], '/'));
            }
        }
        if (!defined('__ROOT__')) {
            // 网站URL根目录
            if (strtoupper(SITE_ROOT) == strtoupper(basename(dirname(_PHP_FILE_)))) {
                $_root = dirname(dirname(_PHP_FILE_));
            } else {
                $_root = dirname(_PHP_FILE_);
            }
            define('__ROOT__', (($_root == '/' || $_root == '\\') ? '' : $_root));
        }
    }

    public function route_g()
    {
        $g = isset($_GET['g']) && !empty($_GET['g']) ? $_GET['g'] : (isset($_POST['g']) && !empty($_POST['g']) ? $_POST['g'] : '');
        $g = $this->safe_deal($g);
        if (empty($g)) {
            return $this->route_config['g'];
        } else {
            if (is_string($g)) return $g;
        }
    }
    /**
     * 获取模型
     */
    public function route_m()
    {
        $m = isset($_GET['m']) && !empty($_GET['m']) ? $_GET['m'] : (isset($_POST['m']) && !empty($_POST['m']) ? $_POST['m'] : '');
        $m = $this->safe_deal($m);
        if (empty($m)) {
            return $this->route_config['m'];
        } else {
            if (is_string($m)) return $m;
        }
    }
    /**
     * 获取控制器
     */
    public function route_c()
    {
        $c = isset($_GET['c']) && !empty($_GET['c']) ? $_GET['c'] : (isset($_POST['c']) && !empty($_POST['c']) ? $_POST['c'] : '');
        $c = $this->safe_deal($c);
        if (empty($c)) {
            return $this->route_config['c'];
        } else {
            if (is_string($c)) return $c;
        }
    }
    /**
     * 获取事件
     */
    public function route_a()
    {
        $a = isset($_GET['a']) && !empty($_GET['a']) ? $_GET['a'] : (isset($_POST['a']) && !empty($_POST['a']) ? $_POST['a'] : '');
        $a = $this->safe_deal($a);
        if (empty($a)) {
            return $this->route_config['a'];
        } else {
            if (is_string($a)) return $a;
        }
    }
    //获取pathinfo
    private function get_pathinfo()
    {
        $urlMode  =  URL_MODEL;
        if (isset($_GET['s'])) { // 判断URL里面是否有兼容模式参数
            $_SERVER['PATH_INFO']   = $_GET['s'];
            unset($_GET['s']);
        }
        if ($urlMode == URL_COMPAT) {
            // 兼容模式判断
            define('PHP_FILE', _PHP_FILE_ . '?s=');
        } elseif ($urlMode == URL_REWRITE) {
            //当前项目地址
            $url    =   dirname(_PHP_FILE_);
            if ($url == '/' || $url == '\\')
                $url    =   '';
            define('PHP_FILE', $url);
        } else {
            //当前项目地址
            define('PHP_FILE', _PHP_FILE_);
        }
        define('APP_IN', strip_tags(PHP_FILE));
        // 分析PATHINFO信息
        if (!isset($_SERVER['PATH_INFO'])) {
            $types   =  explode(',', URL_PATHINFO_FETCH);
            foreach ($types as $type) {
                if (0 === strpos($type, ':')) { // 支持函数判断
                    $_SERVER['PATH_INFO'] =   call_user_func(substr($type, 1));
                    break;
                } elseif (!empty($_SERVER[$type])) {
                    $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ?
                        substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME']))   :  $_SERVER[$type];
                    $checkpram = stripos($_SERVER['PATH_INFO'], '?');
                    $checkpram2 = stripos($_SERVER['PATH_INFO'], '&');
                    if ($checkpram === 0 || $checkpram2 === 0) {
                        $_SERVER['PATH_INFO'] = '';
                    } else {
                        $strcheck = $checkpram === false ? ($checkpram2 === false ? false : $checkpram2) : $checkpram;
                    }
                    if ($strcheck) $_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], 0, $strcheck);
                    break;
                }
            }
        }
        if (strlen(RD) > 0) {
            $_SERVER['PATH_INFO'] = str_ireplace(RD, '', $_SERVER['PATH_INFO']);
        }
        $depr = URL_PATHINFO_DEPR;
        if (!empty($_SERVER['PATH_INFO'])) {
            $part =  pathinfo($_SERVER['PATH_INFO']);
            define('__EXT__', isset($part['extension']) ? strtolower($part['extension']) : '');
            if (__EXT__) {
                if (URL_DENY_SUFFIX && preg_match('/\.(' . trim(URL_DENY_SUFFIX, '.') . ')$/i', $_SERVER['PATH_INFO'])) {
                    send_http_status(404);
                    exit;
                }
                if (URL_HTML_SUFFIX) {
                    $_SERVER['PATH_INFO'] = preg_replace('/\.(' . trim(URL_HTML_SUFFIX, '.') . ')$/i', '', $_SERVER['PATH_INFO']);
                } else {
                    $_SERVER['PATH_INFO'] = preg_replace('/.' . __EXT__ . '$/i', '', $_SERVER['PATH_INFO']);
                }
            }
            define('__INFO__', $_SERVER['PATH_INFO']);
        } else {
            define('__INFO__', '');
        }
    }

    // 路由处理
    private  function    route_url()
    {
        $routes = $this->route_rules;
        if (!empty($routes)) {
            $regx = trim($_SERVER['PATH_INFO'], '/');
            $depr = URL_PATHINFO_DEPR;
            // 分隔符替换 确保路由定义使用统一的分隔符
            $regx = str_replace($depr, '/', $regx);
            foreach ($routes as $rule => $route) {
                if (0 === strpos($rule, '/') && preg_match($rule, $regx, $matches)) { // 正则路由
                    $return = $this->parseRegex($matches, $route, $regx);
                } else { // 规则路由
                    $len1   =   substr_count($regx, '/');
                    $len2   =   substr_count($rule, '/');
                    if ($len1 >= $len2) {
                        if ('$' == substr($rule, -1, 1)) { // 完整匹配
                            if ($len1 != $len2) {
                                continue;
                            } else {
                                $rule =  substr($rule, 0, -1);
                            }
                        }
                        $match  =  $this->checkUrlMatch($regx, $rule);
                        if ($match)   $return = $this->parseRule($rule, $route, $regx);
                    }
                }
            }
            return $return;
        }
    }

    // 检测路由规则 如果没有则按默认规则调度URL
    private function  no_route_url()
    {
        $depr = URL_PATHINFO_DEPR;
        $paths = explode($depr, trim($_SERVER['PATH_INFO'], '/'));
        if (VAR_URL_PARAMS) {
            // 直接通过$_GET['_URL_'][1] $_GET['_URL_'][2] 获取URL参数 方便不用路由时参数获取
            //$_GET[VAR_URL_PARAMS]   =  $paths;
        }
        $var  =  array();
        $var['g'] = array_shift($paths);
        if (!isset($_GET['m'])) { // 还没有定义模块名称
            $var['m']  =   array_shift($paths);
        }
        if (!isset($_GET['c'])) { // 还没有定义控制器名称
            $var['c']  =   array_shift($paths);
        }
        if (!isset($_GET['a'])) { // 还没有定义方法名称
            $var['a']  =   array_shift($paths);
        }
        // 解析剩余的URL参数
        if (version_compare(PHP_VERSION, '5.5.0', '<')) {
            preg_replace('@(\w+)\/([^\/]+)@e', '$var[\'\\1\']=strip_tags(\'\\2\');', implode('/', $paths));
        } else {
            preg_replace_callback('@(\w+)\/([^\/]+)@', function ($r) use (&$var) {
                $var[$r['1']] = strip_tags($r[2]);
            }, implode('/', $paths));
        }
        $_GET   =  array_merge($var, $_GET);
        foreach ($_GET as $k => $v) {
            $_REQUEST[$k] = $v;
        }
    }

    // 检测URL和规则路由是否匹配
    private function checkUrlMatch($regx, $rule)
    {
        $m1 = explode('/', $regx);
        $m2 = explode('/', $rule);
        $match = true; // 是否匹配
        foreach ($m2 as $key => $val) {
            if (':' == substr($val, 0, 1)) { // 动态变量
                if (strpos($val, '\\')) {
                    $type = substr($val, -1);
                    if ('d' == $type && !is_numeric($m1[$key])) {
                        $match = false;
                        break;
                    }
                } elseif (strpos($val, '^')) {
                    $array   =  explode('|', substr(strstr($val, '^'), 1));
                    if (in_array($m1[$key], $array)) {
                        $match = false;
                        break;
                    }
                }
            } elseif (0 !== strcasecmp($val, $m1[$key])) {
                $match = false;
                break;
            }
        }
        return $match;
    }
    // 解析规则路由
    // '路由规则'=>'[分组/模块/操作]?额外参数1=值1&额外参数2=值2...'
    // '路由规则'=>array('[分组/模块/操作]','额外参数1=值1&额外参数2=值2...')
    // '路由规则'=>'外部地址'
    // '路由规则'=>array('外部地址','重定向代码')
    // 路由规则中 :开头 表示动态变量
    // 外部地址中可以用动态变量 采用 :1 :2 的方式
    // 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'),
    // 'new/:id'=>array('/new.php?id=:1',301), 重定向
    private function parseRule($rule, $route, $regx)
    {
        // 获取路由地址规则
        $url   =  is_array($route) ? $route[0] : $route;
        // 获取URL地址中的参数
        $paths = explode('/', $regx);
        // 解析路由规则
        $matches  =  array();
        $rule =  explode('/', $rule);
        foreach ($rule as $item) {
            if (0 === strpos($item, ':')) { // 动态变量获取
                if ($pos = strpos($item, '^')) {
                    $var  =  substr($item, 1, $pos - 1);
                } elseif (strpos($item, '\\')) {
                    $var  =  substr($item, 1, -2);
                } else {
                    $var  =  substr($item, 1);
                }
                $matches[$var] = array_shift($paths);
            } else { // 过滤URL中的静态变量
                array_shift($paths);
            }
        }
        if (0 === strpos($url, '/') || 0 === strpos($url, 'http')) { // 路由重定向跳转
            if (strpos($url, ':')) { // 传递动态参数
                $values  =  array_values($matches);
                if (version_compare(PHP_VERSION, '5.5.0', '<')) {
                    $url  =  preg_replace('/:(\d+)/e', '$values[\\1-1]', $url);
                } else {
                    $url = preg_replace_callback('/:(\d+)/', function ($r) use (&$values) {
                        return $values[$r[1] - 1];
                    }, $url);
                }
            }
            header("Location: $url", true, (is_array($route) && isset($route[1])) ? $route[1] : 301);
            exit;
        } else {
            // 解析路由地址
            $var  =  $this->parseUrl($url);
            // 解析路由地址里面的动态参数
            $values  =  array_values($matches);
            foreach ($var as $key => $val) {
                if (0 === strpos($val, ':')) {
                    $var[$key] =  $values[substr($val, 1) - 1];
                }
            }
            $var   =   array_merge($matches, $var);
            // 解析剩余的URL参数
            if ($paths) {
                if (version_compare(PHP_VERSION, '5.5.0', '<')) {
                    preg_replace('@(\w+)\/([^\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', implode('/', $paths));
                } else {
                    preg_replace_callback('@(\w+)\/([^\/]+)@', function ($r) use (&$var) {
                        $var[strtolower($r['1'])] = strip_tags($r[2]);
                    }, implode('/', $paths));
                }
            }
            // 解析路由自动传入参数
            if (is_array($route) && isset($route[1])) {
                parse_str($route[1], $params);
                $var   =   array_merge($var, $params);
            }
            foreach ($var as $k => $v) {
                $_GET[$k] = $v;
                $_REQUEST[$k] = $v;
            }
            $_GET   =  array_merge($var, $_GET);
        }
        return true;
    }

    // 解析规范的路由地址
    // 地址格式 [分组/模块/操作?]参数1=值1&参数2=值2...
    private function parseUrl($url)
    {
        $var  =  array();
        if (false !== strpos($url, '?')) { // [分组/模块/操作?]参数1=值1&参数2=值2...
            $info   =  parse_url($url);
            $path   = explode('/', $info['path']);
            parse_str($info['query'], $var);
        } elseif (strpos($url, '/')) { // [分组/模块/操作]
            $path = explode('/', $url);
        } else { // 参数1=值1&参数2=值2...
            parse_str($url, $var);
        }
        if (isset($path)) {
            $var['g'] = array_shift($path);
            if (!empty($path)) {
                $var['m'] = array_shift($path);
            }
            if (!empty($path)) {
                $var['c']  = array_shift($path);
            }
            if (!empty($path)) {
                $var['a']  = array_shift($path);
            }
        }
        return $var;
    }
    // 解析正则路由
    // '路由正则'=>'[分组/模块/操作]?参数1=值1&参数2=值2...'
    // '路由正则'=>array('[分组/模块/操作]?参数1=值1&参数2=值2...','额外参数1=值1&额外参数2=值2...')
    // '路由正则'=>'外部地址'
    // '路由正则'=>array('外部地址','重定向代码')
    // 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式
    // '/new\/(\d+)\/(\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'),
    // '/new\/(\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), 重定向
    private function parseRegex($matches, $route, $regx)
    {
        // 获取路由地址规则
        $url   =  is_array($route) ? $route[0] : $route;
        if (version_compare(PHP_VERSION, '5.5.0', '<')) {
            $url   =  preg_replace('/:(\d+)/e', '$matches[\\1]', $url);
        } else {
            $url = preg_replace_callback('/:(\d+)/', function ($r) use (&$matches) {
                return $matches[$r[1]];
            }, $url);
        }
        if (0 === strpos($url, '/') || 0 === strpos($url, 'http')) { // 路由重定向跳转
            header("Location: $url", true, (is_array($route) && isset($route[1])) ? $route[1] : 301);
            exit;
        } else {
            // 解析路由地址
            $var  =  $this->parseUrl($url);
            // 解析剩余的URL参数
            $regx =  substr_replace($regx, '', 0, strlen($matches[0]));
            if ($regx) {
                if (version_compare(PHP_VERSION, '5.5.0', '<')) {
                    preg_replace('@(\w+)\/([^,\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', $regx);
                } else {
                    preg_replace_callback('@(\w+)\/([^,\/]+)@', function ($r) use (&$var) {
                        $var[strtolower($r['1'])] = strip_tags($r[2]);
                    }, $regx);
                }
            }
            // 解析路由自动传入参数
            if (is_array($route) && isset($route[1])) {
                parse_str($route[1], $params);
                $var   =   array_merge($var, $params);
            }
            foreach ($var as $k => $v) {
                $_GET[$k] = $v;
                $_REQUEST[$k] = $v;
            }
            $_GET   =  array_merge($var, $_GET);
        }
        return true;
    }

    /**
     * 安全处理函数
     * 处理m,a,c
     */
    private function safe_deal($str)
    {
        return str_replace(array('/', '.'), '', $str);
    }
}
