Apache 用url作为参数将每个请求重写为一个文件

Apache 用url作为参数将每个请求重写为一个文件,apache,.htaccess,mod-rewrite,Apache,.htaccess,Mod Rewrite,我正在用PHP编写一个小型CMS,需要将所有请求重定向到该文件(在我的例子中称为CMS.PHP)。比如说 /~ps0ke/ -> /~ps0ke/cms.php?path=index.html /~ps0ke/projects/cms.html -> /~ps0ke/cms.php?path=projects/cms.html 等等。如果en/位于目录前面,则还会设置一个lang参数。这并不重要,因为在我添加多语言支持之前,我的问题就已经存在了。现在,我正在使用Apache和以下.

我正在用PHP编写一个小型CMS,需要将所有请求重定向到该文件(在我的例子中称为
CMS.PHP
)。比如说

/~ps0ke/ -> /~ps0ke/cms.php?path=index.html
/~ps0ke/projects/cms.html -> /~ps0ke/cms.php?path=projects/cms.html
等等。如果
en/
位于目录前面,则还会设置一个
lang
参数。这并不重要,因为在我添加多语言支持之前,我的问题就已经存在了。现在,我正在使用Apache和以下
.htaccess
实现重写:

RewriteEngine On
RewriteBase /~ps0ke/

# Serve index.html via cms.php when base dir or index.html is requested. Also
# set the language.
RewriteRule ^((en)/)?(index.html)?$ cms.php?lang=$2&path=index.html [NC,L]

# Serve everything else via cms.php. Also set the language.
# Serving from the page subdirectory is due to a problem with all-wildcard
# RewriteRule. This might be fixed.
RewriteRule ^((en)/)?page/(.*)$ cms.php?lang=$2&path=$3 [NC,L,B]
您可能会注意到,
RewriteBase
和实际路径之间还有一个额外的
page/
。我这么做是因为我只是为了

RewriteRule ^((en)/)?(.*)$ cms.php?lang=$2path=$3 [NC,L,B]
根本不起作用。我不明白为什么。当我使用上述规则时,输出
$\u GET
结果

Array
(
    [lang] => 
    [path] => cms.php
)
不管实际的GET路径是什么,总是将
path
GET变量设置为脚本的名称。我只是不明白为什么

我不想包含
page/
前缀的原因是它保持向后兼容性。CMS专门为普通文件结构提供服务,并仅从文件系统构建其导航等。因此,最好在GET路径中表示实际的文件结构。因此,即使有人再次删除CMS,链接仍然可以工作

我在Apache手册条目中为使用的选项提供了更简单的参考:

NC|nocase

使用[NC]标志会使重写规则在 不区分大小写的方式。也就是说,它不在乎字母是否正确 在匹配的URI中显示为大写或小写

B(转义反向引用)

[B]标志指示重写规则以转义非字母数字 应用转换之前的字符

L|last

[L]标志导致mod_rewrite停止处理规则集。在里面 在大多数上下文中,这意味着如果规则匹配,就没有其他规则 将被处理。这对应于Perl中的最后一个命令,或者 C中的break命令。使用此标志指示当前 应立即应用该规则,而不考虑进一步的规则


任何帮助(修复或解释)都将不胜感激!提前谢谢

由于您的规则执行了两次,所以您遇到了这个问题。您可以通过避免重写所有资源(js、图像、css等)以及不让它再次运行来阻止它

你的规则是这样的:

RewriteEngine On
RewriteBase /~ps0ke/

# avoid any rules for resources and 2nd time:
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_URI} \.(?:jpe?g|gif|bmp|png|tiff|css|js)$ [NC,OR]
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]

# Serve index.html via cms.php when base dir or index.html is requested. Also
# set the language.
RewriteRule ^((en)/)?(index.html)?$ cms.php?lang=$2&path=index.html [NC,L,QSA]

# Serve everything else via cms.php. Also set the language.
# Serving from the page subdirectory is due to a problem with all-wildcard
# RewriteRule. This might be fixed.
RewriteRule ^((en)/)?(.*)$ cmas.php?lang=$2path=$3 [NC,L,QSA]

谢谢,这正是我需要的。我还有两个额外的要求:1:是否有一种方法可以在.htaccess中不明确提及扩展名的情况下为任何类型的文件提供服务?当我注释掉那一行时,除了图像服务之外,一切都如预期的那样工作。我的脚本能够提供二进制数据,因此不需要显式地提供。第二件事是:在请求指向目录的URL时,不知何故,我得到了某种重定向(即使index.html是以静默方式提供的)。我的链接总是指向干净的URL
/~ps0ke/tests/image/
,但使用Chrome或Firefox,我会登录到
/~ps0ke/tests/image/?lang=&path=tests%2fimage
等页面。我真的不知道这可能来自哪里,使用
curl--head
不会显示任何重定向头。如果你有办法解决这个问题,那就太棒了。我想对最终用户完全隐藏丑陋的实现。确定检查我的“立即编辑”目录重写问题将得到解决。在新浏览器中测试。另外,我建议不要从评论中添加新的要求。再次感谢您的时间。我将编辑我的问题,以在最后包括所有额外的请求(如果这是一种方式?我对StackOverflow比较陌生)。不幸的是,您的编辑解决了一个问题,但引入了另一个问题。GET参数现在不再显示。到目前为止一切正常,但如果目录中没有
index.html
,Apache会提供自己的
+索引
目录索引。关闭
索引只会给我一个403。我不想重写目录URL并附加
index.html
,因为这是最好由PHP脚本处理的逻辑。有什么建议吗?:)