【问题标题】:Recursive path component collection with mod_rewrite使用 mod_rewrite 的递归路径组件集合
【发布时间】:2012-06-17 23:44:35
【问题描述】:

我正在尝试做很多人以前做过很多次的事情,但我似乎无法让它发挥作用。我已经尝试了将近 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% 的工作。我遇到的问题:

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

谁能解释为什么会发生这种情况,或者提出更好的方法来做到这一点?

【问题讨论】:

  • 你绝对必须在 htaccess 中做到这一点,或者你不能仅仅在 PHP 中 $_SERVER['REQUEST_URI'] 的斜线周围爆炸吗?
  • @NevStokes 你能详细说明一下吗?主要是关于我如何确保所有请求都以index.php 结尾,同时仍然允许引用存在的文件的/static URI 不受影响?如果可以使它起作用,这听起来确实是一个有吸引力的选择-因为它不受LimitInternalRecursion/MaxRedirects限制。
  • 你为什么不在你的 PHP 脚本中这样做呢? /index.php?p=/this/is/a/random/path
  • @Qtax 我开始认为我的but I think I have disappeared so far up the wrong road that I can no longer see the way back 声明可能比我想象的更真实!我现在只是在玩它,我想这就是答案。

标签: regex .htaccess mod-rewrite recursion url-rewriting


【解决方案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...中。在这种情况下,可以这样做:

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

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

顺便问一下,没有回调的 array_filter() 是干什么用的?据我所知,它所做的只是剥离空组件和 0 组件,我可能希望允许 0。

这是为了防止像 /foo//bar 这样的错误网址导致空的“幽灵”(注意双重 //

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

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

【讨论】:

  • 不错/错误,但我确实希望比文件更具选择性。如果我通过路径请求文件,您的 htaccess 将允许直接访问文件,除非它们位于 /static 目录中,否则我不想这样做。顺便问一下,没有回调的array_filter() 是什么?据我所知,它所做的只是剥离空组件和0 组件,我可能希望允许0s。 preg_split('#/+#', $str, -1, PREG_SPLIT_NO_EMPTY); 会更好吗?
  • 嗯....我将在其中编辑答案,在 cmets 中它会变得有点不可读...
  • 我想我肯定会称之为答案,谢谢。我需要对控制 index.php 进行一些重构,但我相信我可以让它满意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多