techsir 登陆 |注册|TS首页
  首页 快活林 猿氏悟语

分析phpwind的rewrite重写控制

By: 冰客 发表于 2008-11-4 11:19:24 · 8455次点击   回复:5   
来源: 梧桐树下   作者: 梧桐树下

关于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版本的,你可以直接这样进行布署:


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

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

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

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

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

OK,我们开始进行分析。

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

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



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

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

此时,如果你打印 $_GET 数组,我们可能得到这样一种结果:
  1.    <?php
  2. Array
  3. (
  4. [fid-2_html] =>
  5. )
  6. ?>  
复制代码
现在问题出来了,我们如何将上面的参数转换成我们所需要的 :
  1. <?php
  2. Array
  3. (
  4. [fid] => 2
  5. )
  6. ?>
复制代码
而被PHP正解解释呢?

OK,接下来,我们分析这个文件:/phpwind/require/defend.php。
8455次点击
5个回复  |  直到 2008-11-4 11:19:24
   
  Reply   
冰客      2008-11-4 11:14:47
我们着重分析一下:
  1.    <?php
  2. if($db_htmifopen){
  3. $self_array = explode(\'-\',$db_ext ? substr($_SERVER[\'QUERY_STRING\'],0,strpos($_SERVER[\'QUERY_STRING\'],$db_ext)) : $_SERVER[\'QUERY_STRING\']);
  4. $s_count=count($self_array);
  5. for($i=0;$i<$s_count;$i++){
  6. $_key = $self_array[$i];
  7. $_value = $self_array[++$i];
  8. !ereg("^_",$_key) && !isset($$_key) && $$_key = addslashes(rawurldecode($_value));
  9. }
  10. }
  11. ?>
复制代码
这段代码。不难发现,通过对self_array数据组的一些整理,我们得到了想要的一些数据。你可以测试一下,你可以在你的
http://localhost/phpwind/index.php 地址中改为 http://localhost/phpwind/index-htm-one-1-two-2.html

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

小提示:其实完全可以直接用 extract 函数达上同样的效果
   
  Reply   
冰客      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 文件里我们有以下变量:
  1.   <?php
  2. $isRewrite = 1;
  3. $rewriteDir = \'-htm-\';
  4. $rewriteExt = \'.html\';
  5. ?>
复制代码
也就是启用了rewrite模板,我们在public_func.php文件中首先写入以下函数:
注:以下函数与原pw及dz系统中略有修改,列举的函数分别来自 pw,dz,molyx论坛系统。
   
  Reply   
冰客      2008-11-4 11:17:34

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

  7. if( $templateid != 1 && !file_exists($tplfile))
  8. {
  9. return template($file, \'./templates/front/default/\' ,1);
  10. }
  11. $objfile = \'cache/templates/\'.$templateid.\'_\'.$file.\'.tpl.php\';
  12. if ( !file_exists($objfile) )
  13. {
  14. require_once \'drivers/template.inc.php\';
  15. parse_template($file, $templateid, $tpldir);
  16. }

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

  23. function output()
  24. {
  25. global $isRewrite;
  26. if($isRewrite)
  27. {
  28. $content = ob_get_contents();
  29. $content = preg_replace(
  30. "/<a(s*[^>]+s*)href=([\"|\']?)([^\"\'>s]+.php?[^\"\'>s]+)([\"|\']?)/ies",
  31. "Htm_cv(\'\\3\',\'<a\\1href=\"\')",
  32. $content
  33. );

  34. ob_end_clean();
  35. echo $content;
  36. }
  37. }
复制代码
   
  Reply   
冰客      2008-11-4 11:18:07

  1. function Htm_cv($url,$tag){
  2. global $rewriteDir,$rewriteExt;
  3. if(ereg("^http|ftp|telnet|mms|rtsp|admin.php|rss.php",$url)===false){
  4. if(strpos($url,\'#\')!==false){
  5. $add = substr($url,strpos($url,\'#\'));
  6. }
  7. $url = str_replace(
  8. array(\'.php?\',\'=\',\'&\',$add),
  9. array($settings[\'rewrite_dir\'],\'-\',\'-\',\'\'),
  10. $url
  11. ).$settings[\'rewrite_ext\'].$add;
  12. }
  13. return $tag.$url.\'"\';
  14. }

  15. function init_variable()
  16. {
  17. global $settings,$_REWRITE;
  18. $return = array();
  19. if($settings[\'isrewrite\'])
  20. {
  21. $init_array = array($_GET,$_POST,$_REWRITE);
  22. }
  23. else
  24. {
  25. $init_array = array($_GET,$_POST);
  26. }
  27. foreach( $init_array AS $type) {
  28. if( is_array($type) ) {
  29. foreach ( $type AS $k => $v) {
  30. if ( is_array($type[$k]) ) {
  31. foreach ( $type[$k] AS $k1 => $v1) {
  32. $return[ clean_key($k) ][ clean_key($k1) ] = clean_value($v1);
  33. }
  34. } else {
  35. $return[ clean_key($k) ] = clean_value($v);
  36. }
  37. }
  38. }
  39. }

  40. return $return;
  41. }


复制代码
   
  Reply   
冰客      2008-11-4 11:19:24

  1. function clean_key($key)
  2. {
  3. if ($key == "") return "";
  4. return preg_replace( array("/../", "/__(.+?)__/", "/^([w.-_]+)$/"), array("", "", "$1"), $key );
  5. }

  6. function clean_value($val)
  7. {
  8. if ($val == "") return "";

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

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

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

  16. $pregfind = array ( "/\\$/", "/r/" );
  17. $pregreplace = array ( "$", "" );
  18. $val = preg_replace($pregfind, $pregreplace, $val);

  19. $val = preg_replace("/&#([0-9]+);/s", "&#\\1;", $val );
  20. if ( get_magic_quotes_gpc() ) {
  21. $val = stripslashes($val);
  22. }
  23. return preg_replace( "/\\(&#|?#)/", "\", $val );
  24. }
  25. ?>

复制代码
好了。差不多了,让我们进行测试。
添加一条新回复
您需要登录后才可以回帖 登录 | 成为会员 新浪微博登陆

标签云|手机版|科技先生 ( 京ICP备07036130号 Powered by Discuz! X )

GMT+8, 2024-12-22 23:17