欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简易PHP路由,支持正反向url解析支持

程序员文章站 2024-02-12 18:12:34
...

几年前实现了一个简单的正向路由,那时候不会写反向路由解析,最近通读qee v3的代码,因为其中已经扣除了路由解析这个功能,故自己结合之前的经验,发现写个简单的正反向路由解析还是蛮简单的,见代码:

 

<?php
/*
 * 静态页配置文件
 * 
 * key	为 pattern
 * 值	为 配置参数
 * 
 * 越上面的优先级越高
 */
return array(
		
	array(		
		'pattern' => 'core-{id}-{name}.html',

		'action'  => 'core/show',
		'config'	=> array(
			'id'	=> '[0-9]+',
			'name'	=> '[a-z][a-z_0-9]+'
		),
		'default'	=> array(
			'id'	=> 2,
			'name'	=> 'sfken'
		),		
	),

	array(
		'pattern' => 'admin.html',
	
		'action'  => 'admin/index',
	),

);

上面是配置文件

 

<?php
class Tool_PageStatic {
	
	private $_obj_id;	
	private $_cache;
	private $_accessor;	
	private $_config = array();
	
	private $_result = array();
		
	function __construct(array $config)
	{
		if ( empty($config['obj_id']) )
        {
        	# 对象标识 用于缓存配置文件等用,标识系统中的 ps 对象的实例标识
        	throw BaseError::invalid_parameters_error('key "obj_id" not set');
        }
        $this->_obj_id = $config['obj_id'];		
        
		$this->_accessor = val( $config , 'accessor' , 'page' );
		$this->_cache = val( $config , 'cache' , NULL );
		
		$cfopt = val( $config , 'config' , null );
		if ( !empty($cfopt) )
		{
			if ( is_array($cfopt) )
			{
				$this->loadConfig($cfopt);
			}
			if ( is_file($cfopt) )
			{
				# 如果是文件是否需要从缓存中进行读取,还是每次都要读取此处的配置文件				
			
				$cfopt = include($cfopt);
				$this->loadConfig( (array) $cfopt);
			}
		}
		
		$cfopt = null;
		
		$this->default = array(
			'action' => Config::get('app.default_action','index'),
			'nocache' => TRUE,
			'params' => array(),
		);
		
	}
	
	private function loadConfig( array $config )
	{
		foreach ( $config as $opts )
		{
			# 对于 未设置 action & pattern 的配置项 直接忽略
			if ( empty($opts['action']) || empty($opts['pattern']) ) continue;
			
			$opts['src_pattern'] = $opts['pattern'];
			
			if ( !empty($opts['config']) )
			{
				foreach($opts['config'] AS $conf_key => $conf_val)
			    {
				    $opts['pattern'] = str_replace('{'.$conf_key.'}', '('.$conf_val.')', $opts['pattern']);
			    }
			}
			else
			{
				$opts['config'] = array();
			}
			if ( empty($opts['default']) ) $opts['default'] = array();
						
			$this->_config[strtolower($opts['action'])] = $opts;
		}
		
		# 解析完成后是否可以存入缓存		
	}
	
	function getAccessor()
	{
		return $this->_accessor;
	}
	
	/**
	 * 解析 string 返回对应的action以及相应的参数
	 *
	 * @param string $string
	 * 
	 * @return array
	 */
	function parsing($string)
	{	
//		dump($this->_config);
			
		if ( empty($string) || empty($this->_config) ) return $this->default;
		
		if ( empty($this->_result[$string]) )
		{
			$d = $this->default;
			
			foreach($this->_config AS $opts)
			{
				if (preg_match('#^'.$opts['pattern'].'/?$#i', $string, $match_result))
				{
//					dump($match_result);
					
					# offset 为0 是 原字符串
			    	$offset = 1;
			    	foreach($opts['config'] AS $conf_key => $conf_val)
			    	{
			    		if(isset($match_result[$offset]))
			    		{
				    		$d['params'][$conf_key] = $match_result[$offset++];
			    		}
			    	}
					
					$d['nocache'] = val($opts,'nocache',$d['nocache']);
					$d['action'] = $opts['action'];
					break;
				}
			}
			
			$this->_result[$string] = $d;
		}
		
		return $this->_result[$string];
	}
	
	/**
	 * 生成静态的 url 地址
	 *
	 * @param string $action_name
	 * @param array $params
	 */
	function psurl( $action_name , array $params = null )
	{
		$opts = val( $this->_config , strtolower($action_name) , null );	
		if ( !empty($opts) )
		{
			$params = (array) $params;
			
			# 使用源 $opts['src_pattern']
			$url = $opts['src_pattern'];
			dump($url);
        	foreach($opts['default'] AS $d_key => $d_val)
        	{
        		if ( !empty($params[$d_key]) )
        		{
        			$d_val = $params[$d_key];
        			unset($params[$d_key]);
        		}        		
//        		$url = str_replace(':'.$d_key, $d_val, $url);
        		$url = str_replace('{'.$d_key.'}', $d_val, $url);
        	}
			return $url . '?' . http_build_query($params);
		}
		
		# 如果没有找到就生成原始的url
		return url($action_name , $params);
	}
	
}

 上面是真正的实现代码

 

下面是调用代码

<?php
/**
 * 站点静态化操作
 * 
 * /static/page/article-php-json_encode.html
 * 
 * 
 */
class Action_Static extends BaseAction 
{
	
	protected function _validate_input()
    {	
    	$engine = $this->app->tool('pagestatic');    	
    	$accessor = $engine->getAccessor();
    	
    	$this->pid = $_GET[$accessor];// page 标识
    	
    	if ( !empty($this->pid) && strlen($this->pid) < 230 )
    	{
    		// 为什么不在此处直接读缓存? 目的是实现未在配置文件中定义的过期缓存全部设为失效
    		
    		$this->pparams = (array) $engine->parsing($this->pid);// page 参数
    		
    		if ( !empty($this->pparams) )
    		{
    			return true;
    		}
    		
    	}
    	
        return false;
    }
    
    /**
     * 请求前对数据进行验证失败时调用此方法
     */
    protected function _on_validate_input_failed()
    {
    	// 记录错误日志(将 pid 记录到错误日志中)
    	
    	
    	// 跳转到首页
    	redirect( url(Config::get('app.default_action','index')) );
    }
    
    
	function execute()
	{
		$cached = val($this->pparams,'nocache',FALSE);
		
		dump($this->pparams,$this->pid);
		
		dump( $this->app->tool('pagestatic')->psurl('core/show',array(
			'id' => '449211678',
			'name' => 'kenxu',
			'age' => '29',			
//			'blog' => 'http://vb2005xu.iteye.com',			
		)) );
	}
}

 

输出结果如下:

http://sfken.xu/static/page/admin.html 写道
admin.html :
Array
(
[action] => admin/index
[nocache] => 1
[params] => Array
(
)

)

core-{id}-{name}.html

core-449211678-kenxu.html?age=29

 

http://sfken.xu/static/page/core-12306-tianchao.html 写道
core-12306-tianchao.html :
Array
(
[action] => core/show
[nocache] => 1
[params] => Array
(
[id] => 12306
[name] => tianchao
)

)

core-{id}-{name}.html

core-449211678-kenxu.html?age=29

 

在我当前的设计中 此路由功能只能算是一个工具类,用于实现 伪静态/或者页缓存用的,功能上只支持指定action的操作,如果诸位有需要,此处就算我 抛砖引玉了....

 

代码很少,也就不一一解释了