【问题标题】:RewriteRule folder to index.php first then index.htmlRewriteRule 文件夹首先到 index.php,然后是 index.html
【发布时间】:2022-11-02 22:38:21
【问题描述】:

有没有办法让 httpd RewriteRule 重定向到 index.php,如果存在则 index.html?

喜欢:


    RewriteEngine on
    
    RewriteCond %{DOCUMENT_ROOT}/$1 -f [OR]
    RewriteCond %{DOCUMENT_ROOT}/$1 -d
    RewriteRule (.*) - [S=2]

    RewriteRule (.*) /index.(php|html)?q=$1 [L]
    

优先使用 php(如果存在),然后回退到 html。

if index.php: 
foo.bar/test -> foo.bar/index.php?q=test
else
foo.bar/test -> foo.bar/index.html?q=test

【问题讨论】:

  • 我想你会通过额外的RewriteCond 和index.php 和-f 来做到这一点
  • 可以使用位于 httpd.conf 文件中的DirectoryIndex index.php index.html index.htm 来完成。事实上,它可能已经存在
  • @RiggsFolly,这些天我很少使用Apache,这适用于这样的路由器脚本吗?
  • 但是当 RewriteRule 有特定的文件要处理时,不会出现错误。这可能只需要 / 而不是 /index.html 吗?

标签: php mod-rewrite


【解决方案1】:

这是理解您复制的代码的价值的一个很好的例子 - 您已经有了这一行,实际上确实如此非常接近你想要的:

RewriteCond %{DOCUMENT_ROOT}/$1 -f [OR]

要了解这意味着什么,我们可以look up RewriteCond in the Apache manual。它始于:

RewriteCond 指令定义规则条件。一个或多个 RewriteCond 可以位于 RewriteRule 指令之前。仅当 URI 的当前状态与其模式匹配并且满足这些条件时,才使用以下规则。

所以,这条线定义了一个附加要求对于以下规则。

我将从这条规则的末尾开始,因为在这种情况下它会更有意义。所以,从 [OR] 开始,它被“标志”覆盖:

'ornext|OR' (或下一个条件)
使用它来将规则条件与本地 OR 而不是隐式 AND 组合。

所以,一般必须同时应用一系列条件才能运行下一个规则;但这会将其更改为“此条件或下一个条件”。对于您要查找的用例,我们只需要一个条件:“index.php 是否存在?”所以这个标志将不相关。

接下来要看的是-f,它列在“您可以执行各种文件属性测试”标题下:

-F
是常规文件。
将TestString 视为路径名并测试它是否存在,并且是常规文件。

太好了,所以这个条件是关于存在什么文件,这就是我们想要的!但是TestString 是怎么回事,%{DOCUMENT_ROOT}/$1 是什么意思?让我们回到开头:

语法:重写条件测试字符串 条件模式 [旗帜]... TestString 是一个字符串,除了纯文本之外,它还可以包含以下扩展结构: ...

所以我们的“TestString”是%{DOCUMENT_ROOT}/$1。寻找它包含的部分,我们发现:

服务器变量:这些是 %{ NAME_OF_VARIABLE } 形式的变量

这里没有对DOCUMENT_ROOT 的详细描述,但有a link to where "most are documented",这又将我们带到this DocumentRoot manual。长话短说,它是您的 URL 将与之相关的项目的根:

服务器将请求的 URL 的路径附加到文档根制作文档的路径

这是有道理的 - Apache 无法查找“hello-world.txt”,除非它知道要查看哪个目录,因此条件是明确的。

现在回到RewriteCond 查找$1:

$1 到 $9 提供从 RewriteRule 访问模式的分组部分(在括号中),该 RewriteRule 受当前 RewriteCond 条件集的约束。

在我们正在查看的特定条件下,要查找的文件是动态的,基于进入的 URL - 条件本质上是“确实请求的文件存在.在我们的新条件下,我们不需要它。


您几乎已经拥有的另一部分是重写规则.如果我们取出(php|html) 部分,惯于工作,我们可以有这个:

RewriteRule (.*) /index.php?q=$1 [L]

无需赘述,RewriteRule 语法相当简单:第一个参数是与浏览器请求的 URL 匹配的模式;第二个参数是您希望它在内部映射到的内容。

这里发生的唯一额外部分是$1 指的是匹配的字符串,就像上面的RewriteCond 一样。在这种情况下,我们只是“捕获”了整个请求的 URL,所以如果请求的 URL 是 hello-world,那么将 $1 替换为 hello-world,最终的 URL 是 /index.php?q=hello-world


回到答案,你模拟了这个伪代码:

if index.php: 
foo.bar/test -> foo.bar/index.php?q=test
else
foo.bar/test -> foo.bar/index.html?q=test

我们可以稍微改写一下,使其更接近 Apache 语法:

condition: if index.php exists in the document root
rule: match /test and serve /index.php?q=test
else
rule: match /test and serve /index.html?q=test

我们没有提到的唯一部分是“else”。有几种方法可以做到这一点:

  • 我们可以有一个否定条件(“如果 index.php才不是存在”)
  • 我们可以在第一条规则上使用the [END] flag,表示“一旦你完成了这个,就不要再看了”
  • 我们可以使用the [S=1] flag,您的另一个现有规则已经使用它,跳过第二条规则然后继续处理

【讨论】:

  • 哇。这真的很翔实。我实际上并没有复制这家旅馆,而是试图从我很难理解的文档中学习。我让它工作了,但是,正如你可能理解的那样,我真的不明白发生了什么。仍然不太确定我是否了解如何正确执行此操作,但会继续阅读文档。
  • 再次嗨@IMSoP,我已经通读了几次,并且还尝试遵循文档。我不确定这是缺乏理解还是只是我所在位置的错误描述,但我无法掌握解决方案。请求的 URI 可以是 //domain.name/whatever,我需要确保如果项目有 index.php,它应该转到 .php?q=whatever,否则为 .html?q=whatever。据我了解您的描述,该网址似乎是静态的。
猜你喜欢
  • 1970-01-01
  • 2017-08-13
  • 1970-01-01
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
  • 2011-04-18
  • 2015-10-07
  • 2013-02-10
相关资源
最近更新 更多