Php 将规则重写为新URL,并在内部重写为旧URL

Php 将规则重写为新URL,并在内部重写为旧URL,php,apache,.htaccess,mod-rewrite,url-rewriting,Php,Apache,.htaccess,Mod Rewrite,Url Rewriting,我的目标是从以下路径重定向用户: /foo/index.php /foo/ 到 并让/index从/foo/index.php加载原始内容 这在.htaccess中是否可能 到目前为止,我已经尝试: RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L] RewriteRule ^index$ /foo/index.php [QSA,L] RewriteRule ^index$ /foo/index.php [QSA,L,S=1] Rewri

我的目标是从以下路径重定向用户:

/foo/index.php
/foo/

并让
/index
/foo/index.php
加载原始内容

这在
.htaccess
中是否可能

到目前为止,我已经尝试:

RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]
RewriteRule ^index$ /foo/index.php [QSA,L]
RewriteRule ^index$ /foo/index.php [QSA,L,S=1]
RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]
但这会进入一个无限的重定向循环。我认为为URI添加一个
RewriteCond
会有所帮助,但是从以下方面:

注意:条件是在
重写规则的模式匹配后处理的

所以显然,
RewriteCond
在我的用例中没有多大用处

从中可以看出,
S
标志似乎就是我要寻找的:

如果当前规则匹配,此标志强制重写引擎按顺序跳过下一个num规则。使用此选项创建伪if-then-else构造:then子句的最后一条规则变为skip=N,其中N是else子句中的规则数

所以我试过:

RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]
RewriteRule ^index$ /foo/index.php [QSA,L]
RewriteRule ^index$ /foo/index.php [QSA,L,S=1]
RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]
不过,由于我有
L
标志,因此
S
标志似乎有点多余。然而,在我看来,这个逻辑似乎是正确的,尽管这仍然是一个无限的重定向循环

现在我正在使用PHP的变通方法。首先,Apache在内部将新URL重写为旧URL,然后在PHP中检查
$\u服务器['REQUEST\u URI']
是否与脚本开头的新格式匹配,否则将执行301重定向到新URL


不过,我想知道这是否可能仅与
.htaccess
有关?或者,如果有人能解释我如何/为什么用上面的重写规则得到一个无限循环,我将不胜感激。

问题是,规则位于
.htaccess
文件中,并且正如所说的,该文件在每次重新布线循环后都会重新解析,让我们假设它可能适用于不同目录中的
.htaccess
。因此,您的
L
标志都是徒劳的

我环顾四周,如果您真的无法将重写规则放在主apache配置中,我可以提供以下提示:因为服务器变量
在重写运行之间请求
没有更新,因此可以从那里推断出“浏览器可见URL”,并在这种情况下防止重写:

# external redirect to /index (unless browser already shows /index plus query params)
RewriteCond %{THE_REQUEST} !^\w+\ /index(\?.*)?\ HTTP/1..$
RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]

# internal redirect for /index
RewriteRule ^index$ /foo/index.php [QSA,L]

我原以为还有一个变量保持不变,但现在我找不到它。可能是其他人吗?

问题在于规则位于
.htaccess
文件中,并且就像所说的那样,该文件在每次重新布线循环后都会重新解析,让我们假设它可能适用于不同目录中的
.htaccess
。因此,您的
L
标志都是徒劳的

我环顾四周,如果您真的无法将重写规则放在主apache配置中,我可以提供以下提示:因为服务器变量
在重写运行之间请求
没有更新,因此可以从那里推断出“浏览器可见URL”,并在这种情况下防止重写:

# external redirect to /index (unless browser already shows /index plus query params)
RewriteCond %{THE_REQUEST} !^\w+\ /index(\?.*)?\ HTTP/1..$
RewriteRule ^foo/(index\.php)?$ /index [R=301,QSA,L]

# internal redirect for /index
RewriteRule ^index$ /foo/index.php [QSA,L]

我原以为还有一个变量保持不变,但现在我找不到它。也许是其他人?

+1,正如您所说,唯一合乎逻辑的解释是,
L
实际上并没有结束重写,而是开始了一个新的重写循环?但是,如果我像你说的那样把这些放在主配置上,它会解决这个问题吗?现在开始测试。哦,是的,我以前应该阅读完整的
L
标志文档。我已经更新了您的正则表达式,使其始终在请求路径名的开头匹配
/index
RewriteCond%{the_request}^\w+\/index(?:\?*)
它现在运行得很好,谢谢。另外,更具体地说,我们可以尝试匹配旧格式:
RewriteCond%{the_REQUEST}^GET\/foo/*
-只匹配
GET
请求,因为
POST
数据在重定向时会丢失,所以POST URL仍然可以使用旧的URL,这样在POST请求相关的情况下,就可以很容易地发现和更新内部链接。如果将给定路径内的所有URL重定向到根目录,则匹配目录的
RewriteCond%{The_REQUEST}
也很有用,但这超出了问题的范围,更不用说了
=]
+1,正如您所说,唯一合乎逻辑的解释是,
L
实际上并没有结束重写,而是开始了一个新的重写循环?但是,如果我像你说的那样把这些放在主配置上,它会解决这个问题吗?现在开始测试。哦,是的,我以前应该阅读完整的
L
标志文档。我已经更新了您的正则表达式,使其始终在请求路径名的开头匹配
/index
RewriteCond%{the_request}^\w+\/index(?:\?*)
它现在运行得很好,谢谢。另外,更具体地说,我们可以尝试匹配旧格式:
RewriteCond%{the_REQUEST}^GET\/foo/*
-只匹配
GET
请求,因为
POST
数据在重定向时会丢失,所以POST URL仍然可以使用旧的URL,这样在POST请求相关的情况下,就可以很容易地发现和更新内部链接。如果将给定路径内的所有URL重定向到根目录,则匹配目录的
RewriteCond%{The_REQUEST}
也很有用,但这超出了问题的范围,更不用说了<代码>=]