冰客 发表于 2008-11-4 11:11:46

分析phpwind的rewrite重写控制

来源: 梧桐树下   作者: 梧桐树下

关于apache的url ReWrite的争议,并不在本篇文章的探讨范围之内,如果你认为rewrite对你的工作并没有任何的帮助或者你并没有权限控制apache,那么我建议你不用看这篇文章。另外,rewrite模块启用必须是在你以module方法安装php的基础下进行的。如果你并不清楚如何以module模式安装 php,请你自行阅读php文件夹中的 INSTALL 文档。


为什么选择pw来讲rewrite控制而非dz,是因为有人说过“phpwind“在技术是成功的,而dz在商业上成功的,我同意这些话。本人在阅读pw 的代码中受益非浅。并且在rewrite的控制中,pw做得远远比dz好。当然,你可以认为我在胡扯。我并不反对你对我的说法持反对意见,因为我毕竟不是权威。不过,我认为,无论你是新手,还是已经有了基础的phper,pw的源码都是应该读一下的,相信我,会带给你许多意想不到的收获。

好了,闲话不再多话,现在开始进行正题。

OK,首先我们安装一下phpwind论坛,如果你没有,请自行去下载最新版本,他的官方地址是:phpwind.net。

安装成功后,我们进行后台。我们找到 "静态目录部署" 并点击,会出现phpwind的进行部署rewrite的一些信息。先按照此说明进行 httpd.conf 文档修改。在这里请注意,如果你的apache是2.x版本的,你可以直接这样进行布署:

LoadModule rewrite_module libexec/mod_rewrite.so
RewriteEngine On
RewriteRule ^(.*)-htm-(.*)$ $1.php?$2

如果是1.x版本,请按官方说明。

重新启动你的apache后之后,你可以在 "静态目录部署" 选择中进行配置了。

是否开启静态目录部署功能:是
静态目录 : -htm-
静态目录扩展名设置 : .html
注:这里的静态目录其实就是咱们在进行 RewruteRule 中的 ^(.*)-htm- 这个地方的,你必须要保证这个重写方案与你配置的是一样的。扩展名是无所谓的。你可以随意命名。

我们回到前台,当你打开一个子论坛或者一个贴子时,你会发现,地址已经变成了 http://localhost/phpwind/thread-htm-fid-2.html 了。这个是我们这篇文章的主题。

OK,我们开始进行分析。

首先,我们分析他的构成。当我们打开 global.php 文件,找到 :<?php
$db_obstart == 1 ? ob_start(\'ob_gzhandler\') : ob_start();
?>
我们会发现,这个全局文件打开了一个ob_start,并且进行一些判断。这个是pw系统进行rewrite的一个关键。

然后我们再找到footer()函数:


<?php
function footer(){
global $db,$db_obstart,$db_footertime,$db_htmifopen,$P_S_T,$mtablewidth,$db_ceoconnect,$wind_version,$imgpath,$stylepath,$footer_ad,$db_union,$dbinfo,$timestamp;
Update_ol();
if($db){
$qn=$db->query_num;
}
$ft_gzip=($db_obstart==1 ? "Gzip enabled" : "Gzip disabled").$db_union;
if ($db_footertime == 1){
$t_array = explode(\' \',microtime());
$totaltime = number_format(($t_array+$t_array-$P_S_T),6);
$wind_spend = "Total $totaltime(s) query $qn,";
}
$ft_time=get_date($timestamp,\'m-d H:i\');
include PrintEot(\'footer\');
$output = str_replace(array(\'<!--<!---->\',\'<!---->\'),array(\'\',\'\'),ob_get_contents());
if($db_htmifopen){
$output = preg_replace(
"/<a(s*[^>]+s*)href=([\\"|\']?)([^\\"\'>s]+.php?[^\\"\'>s]+)([\\"|\']?)/ies",
"Htm_cv(\'\\3\',\'<a\\1href=\\"\')",
$output
);
}
ob_end_clean();
$db_obstart == 1 ? ob_start(\'ob_gzhandler\') : ob_start();
echo $output;
flush;
exit;
}
?>
不难看出,pw在这里进行了一个判断: $db_htmifopen,关于这个变量的来历,如果大家有兴趣,以后有机会我会再写关于pw的cache控制的文章。现在你可以直接打开你的 /phpwind/data/bbscache/config.php 文件,查看是否已经设置。这个文件是由pw的缓存函数生成。

也就是说,如果这个开关被打开,那么将通过 Htm_cv 函数开始将重新对输入进行正则替换。将所有本域下的php文件链接变成咱们通过url看到的类似于 thread-htm-fid-2.html 这样的链接。当然,这个并不是本文的重点,这只是一种替换而已。

此时,如果你打印 $_GET 数组,我们可能得到这样一种结果:   <?php
Array
(
=>
)
?>现在问题出来了,我们如何将上面的参数转换成我们所需要的 :<?php
Array
(
=> 2
)
?>而被PHP正解解释呢?

OK,接下来,我们分析这个文件:/phpwind/require/defend.php。

冰客 发表于 2008-11-4 11:14:47

我们着重分析一下:   <?php
if($db_htmifopen){
$self_array = explode(\'-\',$db_ext ? substr($_SERVER[\'QUERY_STRING\'],0,strpos($_SERVER[\'QUERY_STRING\'],$db_ext)) : $_SERVER[\'QUERY_STRING\']);
$s_count=count($self_array);
for($i=0;$i<$s_count;$i++){
$_key = $self_array[$i];
$_value = $self_array[++$i];
!ereg("^_",$_key) && !isset($$_key) && $$_key = addslashes(rawurldecode($_value));
}
}
?>
这段代码。不难发现,通过对self_array数据组的一些整理,我们得到了想要的一些数据。你可以测试一下,你可以在你的
http://localhost/phpwind/index.php 地址中改为 http://localhost/phpwind/index-htm-one-1-two-2.html

然后打印: $one,对_GET,_POST剥离过程是在/phpwind/require/defend.php 下面代码完成的   <?php
foreach($_POST as $_key=>$_value){
!ereg("^_",$_key) && !isset($$_key) && $$_key=$_POST[$_key];
}
foreach($_GET as $_key=>$_value){
!ereg("^_",$_key) && !isset($$_key) && $$_key=$_GET[$_key];
}
?>
剥离了,而我并不喜欢这种做法,同时并不希望新手使用此种方案。因为他容易造成变量冲突,如果你并没有把握处理好这些冲突,请尽量使用_GET,_POST数据进行程序写作。

小提示:其实完全可以直接用 extract 函数达上同样的效果

冰客 发表于 2008-11-4 11:16:49

OK,现在我们已经剖析了pw的处理方式,那么如果应用到我们的系统中呢?我们下面做一个实例:

首先,在你已经按上述的方式进行了rewrite的配置情况下(按pw的配置方式)。我并不喜欢pw的模板处理方式,我认为它的处理方式远远不如dz好。我们当然是取长补短了。。。

需要注意的是,我们进行控制时,是采用了 dz 的 eval function();这种方法支持。具体请看例子中的 footer.htm 文件

我们进行一下目录布署:
注:ROOT_PATH 为根目录

ROOT_PATH/index.php
ROOT_PATH/libs/template.func.php //此模板为dz的模板
ROOT_PATH/cache/config.php //此文件为系统生成的cache文件,至于怎么生成,如果大家喜欢并支持的话,我会再写关于pw的cache控制的文章
ROOT_PATH/include/public_func.php //公共函数集文件

好的,我们假定在 config.php 文件里我们有以下变量:<?php
$isRewrite = 1;
$rewriteDir = \'-htm-\';
$rewriteExt = \'.html\';
?>
也就是启用了rewrite模板,我们在public_func.php文件中首先写入以下函数:
注:以下函数与原pw及dz系统中略有修改,列举的函数分别来自 pw,dz,molyx论坛系统。

冰客 发表于 2008-11-4 11:17:34


<?php
function template( $file, $tpldir=\'\', $templateid=0 ) {
global $style,$settings;
$tpldir = $tpldir ? $tpldir : $style[\'tplpath\'];
$templateid = $templateid ? $templateid : $settings[\'apptpl\'] ;
$tplfile = $tpldir.\'/\'.$file.\'.htm\';

if( $templateid != 1 && !file_exists($tplfile))
{
return template($file, \'./templates/front/default/\' ,1);
}
$objfile = \'cache/templates/\'.$templateid.\'_\'.$file.\'.tpl.php\';
if ( !file_exists($objfile) )
{
require_once \'drivers/template.inc.php\';
parse_template($file, $templateid, $tpldir);
}

if(@filemtime($tplfile) > @filemtime($objfile)) {
require_once \'drivers/template.inc.php\';
parse_template($file, $templateid, $tpldir);
}
return $objfile;
}

function output()
{
global $isRewrite;
if($isRewrite)
{
$content = ob_get_contents();
$content = preg_replace(
"/<a(s*[^>]+s*)href=([\\"|\']?)([^\\"\'>s]+.php?[^\\"\'>s]+)([\\"|\']?)/ies",
"Htm_cv(\'\\3\',\'<a\\1href=\\"\')",
$content
);

ob_end_clean();
echo $content;
}
}

冰客 发表于 2008-11-4 11:18:07


function Htm_cv($url,$tag){
global $rewriteDir,$rewriteExt;
if(ereg("^http|ftp|telnet|mms|rtsp|admin.php|rss.php",$url)===false){
if(strpos($url,\'#\')!==false){
$add = substr($url,strpos($url,\'#\'));
}
$url = str_replace(
array(\'.php?\',\'=\',\'&\',$add),
array($settings[\'rewrite_dir\'],\'-\',\'-\',\'\'),
$url
).$settings[\'rewrite_ext\'].$add;
}
return $tag.$url.\'"\';
}

function init_variable()
{
global $settings,$_REWRITE;
$return = array();
if($settings[\'isrewrite\'])
{
$init_array = array($_GET,$_POST,$_REWRITE);
}
else
{
$init_array = array($_GET,$_POST);
}
foreach( $init_array AS $type) {
if( is_array($type) ) {
foreach ( $type AS $k => $v) {
if ( is_array($type[$k]) ) {
foreach ( $type[$k] AS $k1 => $v1) {
$return[ clean_key($k) ][ clean_key($k1) ] = clean_value($v1);
}
} else {
$return[ clean_key($k) ] = clean_value($v);
}
}
}
}

return $return;
}


冰客 发表于 2008-11-4 11:19:24


function clean_key($key)
{
if ($key == "") return "";
return preg_replace( array("/../", "/__(.+?)__/", "/^(+)$/"), array("", "", "$1"), $key );
}

function clean_value($val)
{
if ($val == "") return "";

$pregfind = array ( " ", "&", "<!--", "-->" );
$pregreplace = array ( " ", "&", "&#60;&#33;--", "--&#62;" );
$val = str_replace($pregfind, $pregreplace, $val);

$val = preg_replace( "/<script/i", "&#60;script", $val );

$pregfind = array ( ">", "<", "\\"", "!", "\'" );
$pregreplace = array ( "&gt;", "&lt;", """, "&#33;", "&#39;" );
$val = str_replace($pregfind, $pregreplace, $val);

$pregfind = array ( "/\\$/", "/r/" );
$pregreplace = array ( "$", "" );
$val = preg_replace($pregfind, $pregreplace, $val);

$val = preg_replace("/&#(+);/s", "&#\\1;", $val );
if ( get_magic_quotes_gpc() ) {
$val = stripslashes($val);
}
return preg_replace( "/\\(&#|?#)/", "\\", $val );
}
?>

好了。差不多了,让我们进行测试。
页: [1]
查看完整版本: 分析phpwind的rewrite重写控制