<?php

/**
 *--------------------------------------
 * URL解析 路由 调度
 *--------------------------------------
 * @project		: pfa
 * @author		: cblee
 * @created		: 2012-9-23
 * @copyright	: (c)2012 AsThis
 *--------------------------------------
 */

class Url extends Pfa
{
	/* URL映射到控制器 */
	public static function dispatch()
	{
		/* PHP_FILE 当前应用完整地址 */
		$urlType = C('URL.TYPE');
		if($urlType == URL_REWRITE)
		{
			$url = dirname(_PHP_FILE_);
			if($url == '/' || $url == '\\')
			{
				$url = '';
			}
			define('PHP_FILE', $url);
		}
		elseif($urlType == URL_COMPAT)
		{
			define('PHP_FILE', _PHP_FILE_.'?'.C('VAR.PATHINFO').'=');
		}
		else
		{
			define('PHP_FILE', _PHP_FILE_);
		}

		$depr = C('URL.PATHINFO_DEPR');

		self::get_pathInfo(); /* 分析PATHINFO信息 */

		if(!self::router_check())
		{
			self::router(); /* 默认URL调度 */
		}

		/* 定义常量 */
		if(C('APP.GROUP_LIST'))
		{
			define('GROUP_NAME', self::get_group(C('VAR.GROUP')));
			/* 加载分组配置文件 */
			C(require_cache(CFG_PATH.D_S.GROUP_NAME.D_S.'comm.php'));
			/* 加载分组函数文件 */
			if(is_file(LIB_COMM_PATH.D_S.GROUP_NAME.D_S.'comm.func.php'))
			{
				include LIB_COMM_PATH.D_S.GROUP_NAME.D_S.'comm.func.php';
			}
		}
		define('CTRLR_NAME', self::get_ctrlr(C('VAR.CTRLR')));
		define('ACTN_NAME', self::get_actn(C('VAR.ACTN')));
		/* 当前应用主机名 */
		define('__HOST__', 'http://'.AServer::get_env('HTTP_HOST'));
		/* 当前应用入口地址 */
		define('__ROOT__', __HOST__.ROOT);
		/* 当前应用入口地址 */
		define('__APP__', __HOST__.APP_ROOT);
		/* 网站公共文件URL */
		define('__PUBLIC__', __HOST__.ROOT.'/'.PUBLIC_DIR);
		/* 当前控制器地址 */
		$ctrlr = defined('P_CTRLR_NAME') ? P_CTRLR_NAME : CTRLR_NAME;

		if(defined('GROUP_NAME'))
		{
			$group = defined('P_GROUP_NAME') ? P_GROUP_NAME : GROUP_NAME;
			define('__GROUP__', GROUP_NAME == C('DEFAULT_GROUP') ? __APP__ : __APP__.'/'.$group);
			define('__CTRLR__', __GROUP__.'/'.$ctrlr);
		}
		else
		{
			define('__CTRLR__', __APP__.'/'.$ctrlr);
		}
		/* 当前操作地址 */
		define('__ACTN__', __CTRLR__.$depr.ACTN_NAME);
		$_REQUEST = array_merge($_POST, $_GET); /* 保证$_REQUEST正常取值 */
	}

	/* URL组装 支持不同模式和路由, $check:REWRITE时检查参数是否匹配规则 */
	public static function U($url = '', $check = true)
	{
		if(empty($url))
		{
			return '';
		}
		if(0 === strpos($url, '/'))
		{
			$url = substr($url, 1);
		}
		if(!strpos($url, '://')) /* 没有指定项目名 使用当前项目名 */
		{
			$url = APP_NAME.'://'.$url;
		}
		/* 分析URL地址 */
		$array = parse_url($url);
		$app = isset($array['scheme']) ? $array['scheme'] : APP_NAME;

		$group = '';
		if(C('APP.GROUP_LIST'))
		{
			$groupList = explode(',', strtolower(C('APP.GROUP_LIST')));
			if(isset($array['user']) and in_array(strtolower($array['user']), $groupList))
			{
				$group = $array['user'];
			}
			else
			{
				$group = GROUP_NAME;
			}
		}

		if(isset($array['path']))
		{
			$actn = substr($array['path'], 1);
			if(!isset($array['host']))
			{
				$ctrlr = CTRLR_NAME;
			}
			else
			{
				$ctrlr = $array['host'];
			}
		}
		else /* 只指定操作 */
		{
			$ctrlr = CTRLR_NAME;
			$actn = $array['host'];
		}

		/* 路径中分组和控制器使用aa_bb格式 */
		if(C('URL.CASE_IGNORE'))
		{
			$group = parse_name($group);
			$ctrlr = parse_name($ctrlr);
		}

		if(isset($array['query']))
		{
			parse_str($array['query'], $query);
			$params = $query;
		}

		/* 默认分组不显示 */
		if(0 == strcasecmp($group, C('APP.GROUP')))
		{
			$group = '';
		}
		/* 生成URL地址 */
		if(C('URL.TYPE') == URL_COMMON)
		{
			$group = !empty($group) ? C('VAR.GROUP').'='.$group.'&' : '';
			$ctrlr = C('VAR.CTRLR').'='.$ctrlr.'&';
			$actn = C('VAR.ACTN').'='.$actn;
			$params = !empty($params) ? '&'.http_build_query($params) : '';
			$url = __HOST__.str_replace(APP_NAME, $app, _PHP_FILE_).'?'.$group.$ctrlr.$actn.$params;
		}
		elseif(C('URL.TYPE') == URL_PATHINFO)
		{
			$depr = C('URL.PATHINFO_DEPR');
			$str = $depr;
			foreach($params as $var => $val)
			{
				$str .= $var.$depr.$val.$depr;
			}
			$str = substr($str, 0, -1);
			$group = !empty($group) ? $group.$depr : '';
			$ctrlr = isset($ctrlr) ? $ctrlr.$depr : '';
			$url = __HOST__.str_replace(APP_NAME, $app, _PHP_FILE_).'/'.$group.$ctrlr.$actn.$str;
			if(C('HTML.FILE_SUFFIX'))
			{
				$url .= C('HTML.FILE_SUFFIX');
			}
		}
		elseif(C('URL.TYPE') == URL_REWRITE)
		{
			/* 路由文件(route.php)优先于cfg中的配置定义 */
			$_t_route = C('ROUTE');
			$route = !empty($_t_route) ? $_t_route : C('URL.ROUTE_RULES');

			/* 路由处理 */
			$match = false;
			foreach($route as $regPattern => $value)
			{
				if(C('APP.GROUP_LIST'))
				{
					/* 未指定GROUP为默认 */
					if(false === strpos($value, '@'))
					{
						$value = strtolower(C('APP.GROUP')).'@'.$value;
					}
					$_ca = explode('@', $value, 2);
					$_group = in_array(strtolower($_ca[0]), explode(',', strtolower(C('APP.GROUP_LIST'))))
						? $_ca[0]
						: '';
					$_group = ($_group == strtolower(C('APP.GROUP'))) ? '' : $_group;
					$_ca = $_ca[1];
				}
				$_ca = explode('/', $_ca, 2);
				$_ctrlr = array_shift($_ca);
				$_actn = array_shift($_ca);

				if(strtolower($group.'@'.$ctrlr.'/'.$actn) != strtolower($_group.'@'.$_ctrlr.'/'.$_actn))
				{
					continue;
				}

				/* 存在自定义正则式 */
				if(preg_match_all("%<\w+?:.*?>%", $regPattern, $customRegMatch))
				{
					$regInfo = array();
					foreach($customRegMatch[0] as $val)
					{
						$val = trim($val,'<>');
						$regTemp = explode(':', $val, 2);
						$regInfo[$regTemp[0]] = $regTemp[1];
					}

					/* 匹配表达式参数 */
					$replaceArray = array();
					$_t_k = array();
					foreach($regInfo as $key => $val)
					{
						if(strpos($val, '%') !== false)
						{
							$val = str_replace('%', '\%', $val);
						}
						if(isset($params[$key]))
						{
							if(!$check || preg_match("%$val%", $params[$key]))
							{
								$replaceArray[] = $params[$key];
								$_t_k[] = $key;
							}
							else
							{
								continue 2;
							}
						}
						else
						{
							continue 2;
						}
					}
					if(!empty($_t_k))
					{
						foreach($_t_k as $k)
						{
							unset($params[$k]);
						}
					}
					$url = str_replace($customRegMatch[0], $replaceArray, $regPattern);
					if(C('HTML.FILE_SUFFIX'))
					{
						$url .= C('HTML.FILE_SUFFIX');
					}
					$params = http_build_query($params);
					$url .= !empty($params) ? '?'.$params : '';
					$url = str_replace(APP_NAME, $app, __APP__).'/'.$url;
					$match = true;
				}
				else
				{
					$url = str_replace(APP_NAME, $app, __APP__).'/'.$regPattern;
					if(C('HTML.FILE_SUFFIX'))
					{
						$url .= C('HTML.FILE_SUFFIX');
					}
					$match = true;
				}
			}
			/* 没匹配到路由按普通模式返回 */
			if(!$match)
			{
				$group = !empty($group) ? C('VAR.GROUP').'='.$group.'&' : '';
				$ctrlr = C('VAR.CTRLR').'='.$ctrlr.'&';
				$actn = C('VAR.ACTN').'='.$actn;
				$params = !empty($params) ? '&'.http_build_query($params) : '';
				$url = __HOST__.str_replace(APP_NAME, $app, _PHP_FILE_).'?'.$group.$ctrlr.$actn.$params;
			}
		}
		elseif(C('URL.TYPE') == URL_COMPAT)
		{
			$depr = C('URL.PATHINFO_DEPR');
			$str = $depr;
			foreach($params as $var => $val)
			{
				$str .= $var.$depr.$val.$depr;
			}
			$str = substr($str, 0, -1);
			$group = !empty($group) ? $group.$depr : '';
			$ctrlr = isset($ctrlr) ? $ctrlr.$depr : '';
			$url = __HOST__.str_replace(APP_NAME, $app, _PHP_FILE_).'?'.C('VAR.PATHINFO').'='.$group.$ctrlr.$actn.$str;
			if(C('HTML.FILE_SUFFIX'))
			{
				$url .= C('HTML.FILE_SUFFIX');
			}
			if(C('URL.CASE_IGNORE'))
			{
				$url = strtolower($url);
			}
		}
		return $url;
	}

	/* 获得服务器的PATH_INFO信息 */
	private static function get_pathInfo()
	{
		if(!empty($_GET[C('VAR.PATHINFO')]))
		{
			$path = $_GET[C('VAR.PATHINFO')]; /* 兼容 PATHINFO 参数 */
			unset($_GET[C('VAR.PATHINFO')]);
		}
		elseif(!empty($_SERVER['PATH_INFO']))
		{
			$pathInfo = $_SERVER['PATH_INFO'];
			if(0 === strpos($pathInfo, $_SERVER['SCRIPT_NAME']))
			{
				$path = substr($pathInfo, strlen($_SERVER['SCRIPT_NAME']));
			}
			else
			{
				$path = $pathInfo;
			}
		}
		elseif(!empty($_SERVER['ORIG_PATH_INFO']))
		{
			$pathInfo = $_SERVER['ORIG_PATH_INFO'];
			if(0 === strpos($pathInfo, $_SERVER['SCRIPT_NAME']))
			{
				$path = substr($pathInfo, strlen($_SERVER['SCRIPT_NAME']));
			}
			else
			{
				$path = $pathInfo;
			}
		}
		elseif(!empty($_SERVER['REDIRECT_PATH_INFO']))
		{
			$path = $_SERVER['REDIRECT_PATH_INFO'];
		}
		elseif(!empty($_SERVER["REDIRECT_URL"]))
		{
			$path = $_SERVER["REDIRECT_URL"];
			if(empty($_SERVER['QUERY_STRING']) || $_SERVER['QUERY_STRING'] == $_SERVER["REDIRECT_QUERY_STRING"])
			{
				$parsedUrl = parse_url($_SERVER["REQUEST_URI"]);
				if(!empty($parsedUrl['query']))
				{
					$_SERVER['QUERY_STRING'] = $parsedUrl['query'];
					parse_str($parsedUrl['query'], $GET);
					$_GET = array_merge($_GET, $GET);
					reset($_GET);
				}
				else
				{
					unset($_SERVER['QUERY_STRING']);
				}
				reset($_SERVER);
			}
		}
		if(C('HTML.FILE_SUFFIX') && !empty($path))
		{
			$path = preg_replace('/\.'.trim(C('HTML.FILE_SUFFIX'), '.').'$/', '', $path);
		}
		$_SERVER['PATH_INFO'] = empty($path) ? '/' : $path;
	}

	/* 解析特殊URL调度检查 */
	private static function router_check()
	{
		if(C('URL.TYPE') != URL_REWRITE)
		{
			return false; /* 非rewrite模式使用默认URL调度 */
		}
		$regx = trim($_SERVER['PATH_INFO'], '/');
		if(empty($regx))
		{
			return true; /* path_info为空则不处理 */
		}

		/* 路由文件(route.php)优先于cfg中的配置定义 */
		$_t_route = C('ROUTE');
		$route = !empty($_t_route) ? $_t_route : C('URL.ROUTE_RULES');

		/* 路由处理 */
		if(!empty($route))
		{
			$depr = C('URL.PATHINFO_DEPR');
			foreach($route as $regPattern => $ca)
			{
				/* 判断当前url是否符合某条路由规则,并且提取url参数 */
				$regPatternReplace = preg_replace("%<\w+?:(.*?)>%", "($1)", $regPattern);
				if(strpos($regPatternReplace, '%') !== false)
				{
					$regPatternReplace = str_replace('%', '\%', $regPatternReplace);
				}

				if(preg_match("%$regPatternReplace%", $regx, $matchValue))
				{
					/* 是否完全匹配整个完整url */
					$matchAll = array_shift($matchValue);
					if($matchAll != $regx)
					{
						continue;
					}

					/* 如果url存在动态参数 */
					if($matchValue)
					{
						preg_match_all("%<\w+?:.*?>%", $regPattern, $matchReg);
						foreach($matchReg[0] as $key => $val)
						{
							$val = trim($val,'<>');
							$tempArray = explode(':', $val, 2);
							$_GET[$tempArray[0]] = isset($matchValue[$key]) ? $matchValue[$key] : '';
						}
					}

					if((strpos($ca, '@') !== false) and C('APP.GROUP_LIST'))
					{
						$ca = explode('@', $ca, 2);
						$_GET[C('VAR.GROUP')] = in_array(strtolower($ca[0]), explode(',', strtolower(C('APP.GROUP_LIST'))))
							? $ca[0]
							: '';
						$ca = $ca[1];
					}
					$ca = explode('/', $ca, 2);
					$_GET[C('VAR.CTRLR')] = array_shift($ca);
					$_GET[C('VAR.ACTN')] = array_shift($ca);
					return true;
				}
			}
		}
		return false;
	}

	/* 默认URL调度 */
	private static function router()
	{
		$depr = C('URL.PATHINFO_DEPR');
		$paths = explode($depr, trim($_SERVER['PATH_INFO'],'/'));
		$var = array();
		if (C('APP.GROUP_LIST') && !isset($_GET[C('VAR.GROUP')]))
		{
			$var[C('VAR.GROUP')] = in_array(strtolower($paths[0]), explode(',', strtolower(C('APP.GROUP_LIST'))))
				? array_shift($paths)
				: '';
		}
		if(!isset($_GET[C('VAR.CTRLR')])) /* 还没有定义模块名称 */
		{
			$var[C('VAR.CTRLR')] = array_shift($paths);
		}
		$var[C('VAR.ACTN')] = array_shift($paths);
		/* 解析剩余的URL参数 */
		$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']=\'\\2\';', implode($depr, $paths));
		$_GET = array_merge($var, $_GET);
	}

	/* 获取分组 */
	private static function get_group($var)
	{
		$group = (!empty($_GET[$var]) ? $_GET[$var] : C('APP.GROUP'));
		unset($_GET[$var]);

		if(C('URL.CASE_IGNORE'))
		{
			/* index.php/aaa_bbb/index/ 识别到 AaaBbb分组 */
			define('P_GROUP_NAME', strtolower($group));
			$group = ucfirst(parse_name(P_GROUP_NAME, 1));
		}
		return strip_tags($group);
	}

	/* 获得控制器名称 */
	private static function get_ctrlr($var)
	{
		$ctrlr = (!empty($_GET[$var]) ? $_GET[$var] : C('APP.CTRLR'));
		unset($_GET[$var]);
		if(C('URL.CASE_IGNORE'))
		{
			/* index.php/aaa_bbb/index/ 识别到 AaaBbbCtrlr控制器 */
			define('P_CTRLR_NAME', strtolower($ctrlr));
			$ctrlr = ucfirst(parse_name(P_CTRLR_NAME, 1));
		}
		return strip_tags($ctrlr);
	}

	/* 获得操作名称 */
	private static function get_actn($var)
	{
		$actn = !empty($_POST[$var]) ?
			$_POST[$var] :
			(!empty($_GET[$var]) ? $_GET[$var] : C('APP.ACTN'));
		unset($_POST[$var], $_GET[$var]);
		if(C('URL.CASE_IGNORE'))
		{
			$actn = strtolower($actn);
		}
		return strip_tags($actn);
	}

	/* 私有化构造函数 */
	private function __construct(){}
}

?>