我想创build一个mod_rewrite RewriteRule是独立于网页的安装位置。 我想在.htaccess文件中定义重写规则。 我们以此为例:
RewriteEngine on RewriteRule ^(.*)\.html html.php
有了这个规则,我想把所有* .html请求映射到一个位于web根目录下的html.php脚本。 问题是,webroot的公共基础URL可能会改变。 所以Web根可以位于http://www.somewhere.tld/或http://www.somewhere.tld/的某个子目录中。
但在重写规则中使用相对path不起作用。 所以我必须写下其中的一个:
/html.php (When web is located in root directory of the web) /foo/bar/html.php (When web is located in foo/bar sub directory)
或者我可以设置一个RewriteBase,但我根本不想configuration这个path。 我希望apache自动做正确的事情,所以我可以复制到一些目录的网页,它只是工作,而不告诉重写规则的网站位于。我怎样才能做到这一点?
据我所知,你无法做到这一点。 你必须configurationRewriteBase。 一种方法是使用PHP脚本自动设置RewriteBase也许? 但是这将需要(至less)对.htaccess的写入权限。 但是你将不得不在.htaccess中configurationRewriteBase。
我曾经为同样的问题而苦苦挣扎。 我正在尝试独立于安装位置创build一个Web应用程序,而不使用configuration脚本或手动用户干预。 只要放下应用程序的地方,让它做到这一点。
而且看起来毕竟有一个解决scheme,至less对于Apache 2.占用四行。 解释它背后的思想需要四行以上的内容)
Tl; dr试试这个:
RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond $1#%{REQUEST_URI} ([^#]*)#(.*?)\1$ RewriteRule ^(.*)$ %2index.php [QSA,L]
这是如何和为什么
我们不能dynamic地设置RewriteBase,所以我们一劳永逸地设置服务器的根URL: RewriteBase / 。 这提供了一致性,但这也意味着我们必须自己build立到当前目录的urlpath,并将其前缀到重写的URL。
那我们在哪个目录? 假设/ some / path / app-root / virtual / stuff的REQUEST_URI 。 我们的htaccess是在应用程序的根。 如果我们抓取虚拟部分 – 虚拟/东西 – 并将其从REQUEST_URI移除,我们将留下与我们的应用程序目录的urlpath。
捕获虚拟部分很简单,可以在重写规则本身中进行。 RewriteRule ^(.*)$ ...使它在$1variables中可用。
现在我们做我们的小string操作,并从请求URI中删除虚拟部分。 我们没有string命令,但RewriteCond可以匹配string并捕获子string。 因此,我们将添加一个RewriteCond,其唯一目的是将urlpath提取到当前目录。 除此之外,“条件”应该保持不变,永远是真实的。
我们可以在RewriteCond的RewriteRule中使用$1variables,因为mod_rewrite实际上向后处理了一个规则集。 它从规则本身的模式开始,如果匹配,继续检查条件。 所以这个variables是可用的。
虽然RewriteCond中的testingstring可以使用该variables,但实际的正则expression式不能。 在条件内部,我们只能使用内部的后向引用。 所以首先,我们组装一个testingstring“[虚拟零件] [某个分隔符] [请求uri]”。 '#'字符是一个很好的分隔符,因为它不会显示在URL中。 接下来,我们将它与一个条件相匹配
([^#]*) - anything up to the separator, captures the virtual part # - the separator (.*?) - anything in the request uri up to what we've captured in group one, grabs the current directory url-path \1$ - group one again, ie the virtual part of the request uri
所以这是完整的条件: RewriteCond $1#%{REQUEST_URI} ([^#]*)#(.*?)\1$ 。
RewriteCond正则expression式中的第二个捕获组是我们的位置。 我们只需要使用%2引用将其前缀改写到重写的URL。 这就给我们留下了RewriteRule ^(.*)$ %2index.php [QSA,L] 。 瞧。
我还没有做过广泛的testing,但是我已经确定它可以与普通的虚拟主机以及大容量虚拟主机(使用VirtualDocumentRoot)一起工作。 暗示,其他别名的位置也应该是好的。
Apache 1.3
不幸的是,Apache 1.3仍然存在,它会在RewriteCond模式中窒息。 Apache 1.3不支持ungreedy修饰符( (.*?)的'?')。
但是对于Apache 2来说,它应该有所斩获。 但是,如果在您的环境中出现问题,我一定会感激您的反馈。
编辑:我刚刚在我的博客上发布了一篇关于该主题的更全面的文章(“ 在不知道RewriteBase的情况下在.htaccess文件中使用mod_rewrite ”)。 看到更多的细节。
感觉如何?
RewriteEngine on RewriteRule ^(.*)\.html $1/html.php
我的例子保留了html文件的文件名部分,例如,page1.html会被redirect到page1 / html.php。 (注意:我没有testing这个,试着自己的风险:))
此外, mod_rewrite指南有很多类似于你的问题的例子。 你有看过吗?
我发现Apache的文档是误导性的:
在.htaccess文件中使用重写引擎时,对于RewriteRule模式匹配, 将 自动删除 每个目录前缀 (对于特定目录始终相同),并在任何相对(不以斜杠或协议名称开头)replace后自动添加遇到规则集的结尾。 请参阅RewriteBase指令以获取有关哪些前缀将添加回相关的子代码的更多信息。
但是它添加的前缀是完全不同的(磁盘上的path而不是原始的URL)。 我想不出这是否是正确的行为。