简易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
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
Array
(
[action] => core/show
[nocache] => 1
[params] => Array
(
[id] => 12306
[name] => tianchao
)
)
core-{id}-{name}.html
core-449211678-kenxu.html?age=29
在我当前的设计中 此路由功能只能算是一个工具类,用于实现 伪静态/或者页缓存用的,功能上只支持指定action的操作,如果诸位有需要,此处就算我 抛砖引玉了....
代码很少,也就不一一解释了
上一篇: DataGear 表格图表常用配置示例
下一篇: 数据可视化
推荐阅读