0

我正在尝试做很多人以前做过很多次的事情,但我似乎无法让它发挥作用。我已经尝试了将近 2 天,我一直在互联网上搜索一个工作示例,发现了许多非常相似的 SO 问题,但没有一个对我有用 - 其中大多数都在使用键/值方法,我只是想要值列表。


我想要的是:

我希望能够使用搜索引擎友好的 URL。由于相关站点当前工作方式的性质,我想转换此请求 URI:

/this/is/a/随机/路径

...到:

/index.php?p[]=this&p[]=is&p[]=a&p[]=random&p[]=path

这样当它到达 PHP 时,它将作为$_GET['p']. 我也希望它也能容忍斜杠,所以我会得到相同的结果:

/this/is/a/随机/路径/

我是如何尝试这样做的:

我对正则表达式还不错,而且我对 mod_rewrite 的工作原理有合理的理解,但我认为我已经消失在错误的道路上,以至于我再也看不到回去的路了。

这是我目前拥有的:

# 打开 mod_rewrite
重写引擎开启

# 允许直接加载 /static 目录中的文件
RewriteCond %{REQUEST_FILENAME} -f
重写规则 ^/?static/(.+)$ - [L]

# 递归捕获所有路径组件
RewriteCond %{REQUEST_URI} !^/?(?:index\.php)?$
重写规则 ^/?([^/]+)(?:/(.+)$|/?$) $2?p[]=$1 [QSA,L]

# 向控制器发送请求
重写规则 ^.*$ index.php [QSA]

怎么了:

第一个RewriteCond/RewriteRule对工作得很好 - 如果我请求目录中存在的文件,/static则请求保持原样并提供文件。如果该文件不存在,则它属于第二组规则,以便我可以显示我的一个性感的基于 PHP 的错误页面。

问题在于第二个RewriteCond/RewriteRule对,也可能是第三个RewriteRule。该条件应该存在以确保最终迭代不会导致将脚本名称添加到数组中-这似乎有效。这就是我认为第二个RewriteRule正在做的事情,我怀疑我在这里错过了一些明显的东西:

           ^/? # 以可选的斜杠开头的字符串
       ([^/]+) # 捕获直到下一个斜杠的所有字符
(?:/(.+)$|/?$) # 要么抓取下一个斜杠之后的所有字符,要么匹配结尾

     $2?p[]=$1 # 将捕获的路径组件推送到数组中,并将 URI 下移
       [QSA,L] # 合并上一个查询字符串,继续下一次迭代

这是 90% 的工作。我遇到的问题:

  • 数组组件的顺序是相反的。我理解为什么会这样,并且我意识到这可能是不可避免的,在 PHP 中使用array_reverse(). 我只提到它以防有人能想到我想不到的 mod_rewrite 解决方案。
  • 最后两个位置的重复路径组件会导致它失败。例如,如果我请求/home/home/some/path/path我得到一个标准的 Apache 404 说最后两个路径组件未找到(在上面/home/home/path/path两个示例中)。但是,如果我在末尾添加另一个路径组件,/home/home/something那么它会再次起作用。我无法理解造成这种情况的原因。

任何人都可以解释为什么会发生这种情况,或者提出更好的方法来做到这一点?

4

1 回答 1

1

这不是更容易吗:

 RewriteCond ${REQUEST_FILENAME} !-f
 RewriteCond ${REQUEST_FILENAME} !-d
 RewriteRule .* rewrite.php [L]

重写.php:

 <?php
 $p = array_filter(explode('/',parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)));
 // you _could_ of course do an EVIL $_GET['p'] = $p, but I prefer to leave 
 // the superglobals 'read-only'. Not touching $_GET does however mean
 // that index.php needs to be altered somewhat, allowing for a check on isset($p) 
 // and using that as input
 include 'index.php';
 ?>

在 apache 中重写一切都很好,但通常只是在 PHP 本身中解析和确定操作要容易得多,而且以后也更容易维护/更改。

问题/备注:

如果我通过路径请求文件,您的 htaccess 将允许直接访问文件,我不想这样做我不想这样做,除非它们在 /static

它现在不允许任何或多或少的访问。只有您的 index.php 和 rewrite.php 可以访问,其他任何东西都可以在文档根目录之外,文件应该驻留在您不想允许访问的位置。除非您使用此输入来盲目地将文件包含在您的index.php.... index.php在这种情况下,这样的事情会做:

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^/?static/(.+)$ - [L]

RewriteCond ${REQUEST_URI} !^/?(index\.php)?$
RewriteRule .* rewrite.php [L,QSA]

顺便说一句,没有回调的 array_filter() 是什么?就我所见,它所做的只是剥离空组件和 0 组件,我可能希望允许 0。

这是为了防止像错误/foo//bar的网址(注意 double //.

将 preg_split('#/+#', $str, -1, PREG_SPLIT_NO_EMPTY); 会更好?

如果您想允许 0 / 过滤的其他内容array_filter,那么是的,该解决方案会更好。

于 2012-06-14T21:58:07.447 回答