如何在使用通配符的目录指令中使用apache2 mod_rewrite ?

时间:2022-06-13 11:18:17

I have written a web application which I run under a dedicated server for hosting the web application. Instances of this web application are available at different domains, and each domain has its own copy of the web application files, allowing for customization as necessary.

我已经编写了一个web应用程序,我在一个专门的服务器下运行,以托管web应用程序。这个web应用程序的实例可以在不同的域中使用,每个域都有自己的web应用程序文件的副本,可以根据需要进行定制。

I'm running Apache/2.2.16 under Debian Squeeze.

我在Debian压缩下运行Apache/2.2.16。

I do all of the configuration under a VirtualHost directive and do not use .htaccess files.

我在VirtualHost指令下执行所有配置,不使用.htaccess文件。

To simplify the apache configuration, I am wanting to maintain a single Directory directive like such:

为了简化apache配置,我希望维护一个类似这样的单一目录指令:

<Directory "/srv/www/*/public/">
  RewriteEngine on
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteCond %{REQUEST_URI} !=/robots.txt
  RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]
</Directory>

However, the RewriteRule produces the wrong results because while using the wildcard Directory value, it fails to strip the per-directory prefix. Here is the output of the rewrite log:

但是,RewriteRule会产生错误的结果,因为在使用通配符目录值时,它不能去掉每个目录的前缀。这是重写日志的输出:

[rid#b9832078/initial] (3) [perdir /srv/www/*/public/] applying pattern '^(.+)$' to uri '/srv/www/domain1/public/login'
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-f' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-d' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b9832078/initial] (2) [perdir /srv/www/*/public/] rewrite '/srv/www/domain1/public/login' -> '/index.php?q=/srv/www/domain1/public/login'
[rid#b9832078/initial] (3) split uri=/index.php?q=/srv/www/domain1/public/login -> uri=/index.php, args=q=/srv/www/domain1/public/login
[rid#b9832078/initial] (1) [perdir /srv/www/*/public/] internal redirect with /index.php [INTERNAL REDIRECT]
[rid#b9847440/initial/redir#1] (3) [perdir /srv/www/*/public/] applying pattern '^(.+)$' to uri '/srv/www/domain1/public/index.php'
[rid#b9847440/initial/redir#1] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/index.php' pattern='!-f' => not-matched
[rid#b9847440/initial/redir#1] (1) [perdir /srv/www/*/public/] pass through /srv/www/domain1/public/index.php

The problem is that the RewriteRule 'uri' is the filesystem path rather than the url path, which results in the query string being incorrect: q=/srv/www/domain1/public/login

问题是RewriteRule 'uri'是文件系统路径,而不是url路径,这导致查询字符串不正确:q=/srv/www/domain1/public/login。

Explicitly specifying the Directory path like such:

显式地指定目录路径:

<Directory "/srv/www/domain1/public/">
  RewriteEngine on
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteCond %{REQUEST_URI} !=/robots.txt
  RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]
</Directory>

Works just fine, and here is the output of the rewrite log showing the correct behavior (the difference being the new first additional line providing the correct input to the rest of the rewrite resulting in the correct query string: q=login):

工作正常,这里是重写日志的输出,显示正确的行为(区别是新的第一个额外的行,它提供了正确的输入,从而得到正确的查询字符串:q=login):

[rid#b9868048/initial] (3) [perdir /srv/www/domain1/public/] strip per-dir prefix: /srv/www/domain1/public/login -> login
[rid#b9868048/initial] (3) [perdir /srv/www/domain1/public/] applying pattern '^(.+)$' to uri 'login'
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-f' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-d' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b9868048/initial] (2) [perdir /srv/www/domain1/public/] rewrite 'login' -> '/index.php?q=login'
[rid#b9868048/initial] (3) split uri=/index.php?q=login -> uri=/index.php, args=q=login
[rid#b9868048/initial] (1) [perdir /srv/www/domain1/public/] internal redirect with /index.php [INTERNAL REDIRECT]
[rid#b987d5f8/initial/redir#1] (3) [perdir /srv/www/domain1/public/] strip per-dir prefix: /srv/www/domain1/public/index.php -> index.php
[rid#b987d5f8/initial/redir#1] (3) [perdir /srv/www/domain1/public/] applying pattern '^(.+)$' to uri 'index.php'
[rid#b987d5f8/initial/redir#1] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/index.php' pattern='!-f' => not-matched
[rid#b987d5f8/initial/redir#1] (1) [perdir /srv/www/domain1/public/] pass through /srv/www/domain1/public/index.php

I expect I'm running into a bug with Apache, but if that isn't the case, what am I doing wrong?

我希望我遇到了Apache的bug,但如果不是这样,我做错了什么?

While I appreciate input to changing the approach to another workable solution, I'd accept an answer that solves it in the approach I've taken (eg not using .htaccess) unless it can be shown this approach is not solvable.

虽然我感谢输入改变了另一个可行的解决方案的方法,但我还是接受了一个解决方案(如不使用.htaccess),除非可以证明这种方法是不可解决的。

So is there something that has to change to the RewriteCond/Rules when used within a wildcard Directory?

那么,在通配符目录中使用的RewriteCond/规则是否需要更改?

Side note for the curious: For further simplification I use a single VirtualHost using VirtualDocumentRoot - however this is unrelated as this issue is replicated with using 'DocumentRoot' and testing under a single domain.

注意:为了进一步简化,我使用了一个使用VirtualDocumentRoot的虚拟主机——然而,这个问题与使用“DocumentRoot”和在一个域中进行测试的问题是不相关的。

EDIT

编辑

Ok, I've revisited this based on regilero's answer and here is what occurs - moving the Rewrite, as is, out of the Directory results in a slight initial problem of the query string changing from "login" to "/login", this is fixed by modifying the RewriteRule to be: RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA] which fixes my previous "inexplicably fails" comment.

好的,我已经根据regilero的答案重新访问过了,这里是发生了什么——移动重写,就像,out of the Directory导致了从“login”到“/login”的查询字符串的一个轻微的初始问题,这是通过修改RewriteRule来确定的:RewriteRule /(.+)$ /index.php?q=$1 [L,QSA],它修正了我之前的“莫名其妙失败”的评论。

Following that, all static files fail to load, here is the rewrite log showing this problem:

接下来,所有静态文件都无法加载,这里是重写日志,显示了这个问题:

[rid#b7bc7fa0/initial] (2) init rewrite engine with requested uri /login
[rid#b7bc7fa0/initial] (3) applying pattern '^/(.+)$' to uri '/login'
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!-f' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!-d' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b7bc7fa0/initial] (2) rewrite '/login' -> '/index.php?q=login'
[rid#b7bc7fa0/initial] (3) split uri=/index.php?q=login -> uri=/index.php, args=q=login
[rid#b7bc7fa0/initial] (2) local path result: /index.php
[rid#b7bc7fa0/initial] (2) prefixed with document_root to /srv/www/domain1/public/index.php
[rid#b7bc7fa0/initial] (1) go-ahead with /srv/www/domain1/public/index.php [OK]
[rid#b7be6b80/initial] (2) init rewrite engine with requested uri /static/css/common.css
[rid#b7be6b80/initial] (3) applying pattern '^/(.+)$' to uri '/static/css/common.css'
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!-f' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!-d' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!=/favicon.ico' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!=/robots.txt' => matched
[rid#b7be6b80/initial] (2) rewrite '/static/css/common.css' -> '/index.php?q=static/css/common.css'
[rid#b7be6b80/initial] (3) split uri=/index.php?q=static/css/common.css -> uri=/index.php, args=q=static/css/common.css
[rid#b7be6b80/initial] (2) local path result: /index.php
[rid#b7be6b80/initial] (2) prefixed with document_root to /srv/www/domain1/public/index.php
[rid#b7be6b80/initial] (1) go-ahead with /srv/www/domain1/public/index.php [OK]

But like I said in my comment to regilero's answer, this is solved by prefixing the RewriteCond directives TestString with %{DOCUMENT_ROOT}. However, using %{DOCUMENT_ROOT} does not work when using VirtualDocumentRoot.

但是就像我在对regilero的回答中说的那样,通过使用%{DOCUMENT_ROOT}来前缀RewriteCond指令TestString来解决这个问题。但是,在使用VirtualDocumentRoot时,使用%{DOCUMENT_ROOT}并不起作用。

It does not seem right to me that the %{DOCUMENT_ROOT} prefix should be necessary.

在我看来,%{DOCUMENT_ROOT}前缀应该是必要的。

EDIT

编辑

REQUEST_FILENAME

REQUEST_FILENAME

The full local filesystem path to the file or script matching the request, if this has already been determined by the server at the time REQUEST_FILENAME is referenced. Otherwise, such as when used in virtual host context, the same value as REQUEST_URI.

文件或脚本与请求匹配的完整本地文件系统路径,如果这已经由服务器在REQUEST_FILENAME引用时确定。否则,如在虚拟主机上下文中使用,与REQUEST_URI相同。

which explains the need for the DOCUMENT_ROOT prefix.

这就解释了对DOCUMENT_ROOT前缀的需要。

I've updated the rewrite rules to this:

我已经更新了重写规则:

RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteCond %{REQUEST_URI} !^/static/
RewriteRule ^/(.+)$ /index.php?q=$1 [PT,L,QSA]

Which works ok (Note: the PT flag is necessary to avoid prematurely translating the url path to a file system path when using VirutalDocumentRoot). The main change in behavior here is that a RewriteCond will be necessary for all entry points into the application - similar to the /static line.

这是可行的(注意:在使用VirutalDocumentRoot时,要避免过早地将url路径转换为文件系统路径)。这里行为的主要变化是,RewriteCond对于所有进入应用程序的入口都是必需的——类似于/静态行。

EDIT

编辑

Here is my final incarnation of Rewrite directives in the VirtualHost outside of any Directory directives:

这里是我在任何目录指令之外的VirtualHost中重写指令的最终化身:

RewriteEngine on
RewriteCond %{REQUEST_URI} !^/static/
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^/(.+)$ /index.php?q=$1 [NS,PT,L,QSA]
RewriteRule ^/$ /index.php [NS,PT,L,QSA]

I've added the NS flag to avoid an extra internal evaluation and added the second RewriteRule directive in favor of using mod_dir and DirectoryIndex. My application expects no q= parameter for the root url, else a single RewriteRule of RewriteRule ^/(.*)$ /index.php?q=$1 [NS,PT,L,QSA] would be sufficient if the application was updated to accept an empty q= parameter for the root url. I may do that in the future.

我添加了NS标志以避免额外的内部评估,并添加了第二个RewriteRule指令,支持使用mod_dir和DirectoryIndex。我的应用程序期望没有q =根url参数,其他单RewriteRule RewriteRule ^ /(. *)美元/ index . php ?如果应用程序被更新以接受根url的空q=参数,则q=$1 [NS,PT,L,QSA]就足够了。我以后可能会这么做。

1 个解决方案

#1


7  

Very nice and detailled question.

非常好,细节问题。

You have quite certainly hit a bug, or at least an undocumented rewriteRule domain. Documentation states that:

您肯定遇到了一个bug,或者至少是一个未归档的rewriteRule域。文件状态:

  • The rewrite engine may be used in .htaccess files and in sections, with some additional complexity.
  • 重写引擎可以在.htaccess文件和部分中使用,并具有一些额外的复杂性。
  • To enable the rewrite engine in this context, you need to set "RewriteEngine On" and "Options FollowSymLinks" must be enabled. If your administrator has disabled override of FollowSymLinks for a user's directory, then you cannot use the rewrite engine. This restriction is required for security reasons.
  • 要在此上下文中启用重写引擎,必须启用“RewriteEngine On”和“Options FollowSymLinks”。如果您的管理员已经禁用了用户目录的FollowSymLinks,那么您就不能使用重写引擎。出于安全考虑,此限制是必需的。
  • When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is automatically removed for the RewriteRule pattern matching and automatically added after any relative (not starting with a slash or protocol name) substitution encounters the end of a rule set. See the RewriteBase directive for more information regarding what prefix will be added back to relative substutions.
  • 当使用重写引擎在. htaccess文件中每目录单独前缀(这始终是相同的一个特定的目录中)是RewriteRule模式匹配和自动删除后自动添加任何相对(而不是从一个斜杠或协议名称)替换遇到规则集的结束。有关更多信息,请参见RewriteBase指令对前缀将回到相对substutions。

So no mention of the fact <Directory> instruction with wildcards won't be able to strip the per-directory prefix. And playing with RewriteBase won't help you, it's done to rebuild final Url not alter the perdir work.

因此,没有提到这个事实,即使用通配符的目录>指令不能去掉每个目录的前缀。和RewriteBase一起玩不会对你有帮助,它是为了重建最终的Url而不是改变perdir的工作。

But as you can see on the start there's the "with some additional complexity" sentence. Directory manipulations done by mod-rewrite are slower and more complex than general out-of-directory RewriteRules. This is stated as well in this documentation, mainly because of the perdir strip manipulation. And this means you can also write your rewriteRule out of the <Directory> section, in your VirtualHost.

但从一开始你就能看到,这句话有“附加的复杂性”。由mod-重写完成的目录操作比一般的out- Directory RewriteRules更慢,也更复杂。在此文档中也说明了这一点,主要是因为perdir脱机操作。这意味着您还可以在VirtualHost中在 部分中编写您的rewriteRule。

  • it will be faster
  • 它会更快
  • it will not be hit by this bug
  • 它不会被这个错误击中。
  • it may have some side effects if some non-existing files should'nt be mapped to your index.php?q=$1 rule in some other directories. But I'm quite sure this is not a problem in your case.
  • 如果某些不存在的文件不能映射到您的index.php,可能会产生一些副作用。在其他目录中,q=$1规则。但我很确定这不是你的问题。

So simply write (without the wildcard directory):

所以简单地写(没有通配符目录):

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]

And it should work, let me known if this leads to new problems.

它应该会起作用,让我知道这是否会导致新的问题。

Edit:

编辑:

Ok, forogot the fact REQUEST_FILENAME is not yet complelty defined in VirtualHost context, it's documented, it's 'normal', when the condition is applied the file search on the real path is not done yet, this is why you must add the document root. So in fact your final solution should be :

好的,forogot的事实是,REQUEST_FILENAME还不是在VirtualHost环境中定义的,它是有文档的,它是“正常的”,当条件被应用到实际路径上的文件搜索还没有完成,这就是为什么你必须添加文档根。所以实际上你的最终解决方案应该是:

RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]

I tried a second one, avoiding DOCUMENT_ROOT, by using late evaluation of REQUEST_FILENAME ( %{LA-U:REQUEST_FILENAME} contains the final path, which is in fact the full path to index.php in case of non existent files), but the only way I got it working is by adding a second Rule and a Or condition in the second, less simple, so the first solution is certainly better (KISS).

我尝试了第二个,避免了DOCUMENT_ROOT,通过使用REQUEST_FILENAME的延迟评估(%{LA-U:REQUEST_FILENAME}包含最终路径,这实际上是索引的完整路径。在不存在文件的情况下使用php),但是我唯一的方法是在第二个规则中添加第二个规则和条件,不那么简单,所以第一个解决方案肯定更好(KISS)。

  RewriteCond %{LA-U:REQUEST_FILENAME} !-f [OR]
  RewriteCond %{LA-U:REQUEST_FILENAME} !/index.php
  RewriteCond %{LA-U:REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteCond %{REQUEST_URI} !=/robots.txt
  RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]

  RewriteCond %{LA-U:REQUEST_FILENAME} /index.php
  RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]

#1


7  

Very nice and detailled question.

非常好,细节问题。

You have quite certainly hit a bug, or at least an undocumented rewriteRule domain. Documentation states that:

您肯定遇到了一个bug,或者至少是一个未归档的rewriteRule域。文件状态:

  • The rewrite engine may be used in .htaccess files and in sections, with some additional complexity.
  • 重写引擎可以在.htaccess文件和部分中使用,并具有一些额外的复杂性。
  • To enable the rewrite engine in this context, you need to set "RewriteEngine On" and "Options FollowSymLinks" must be enabled. If your administrator has disabled override of FollowSymLinks for a user's directory, then you cannot use the rewrite engine. This restriction is required for security reasons.
  • 要在此上下文中启用重写引擎,必须启用“RewriteEngine On”和“Options FollowSymLinks”。如果您的管理员已经禁用了用户目录的FollowSymLinks,那么您就不能使用重写引擎。出于安全考虑,此限制是必需的。
  • When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is automatically removed for the RewriteRule pattern matching and automatically added after any relative (not starting with a slash or protocol name) substitution encounters the end of a rule set. See the RewriteBase directive for more information regarding what prefix will be added back to relative substutions.
  • 当使用重写引擎在. htaccess文件中每目录单独前缀(这始终是相同的一个特定的目录中)是RewriteRule模式匹配和自动删除后自动添加任何相对(而不是从一个斜杠或协议名称)替换遇到规则集的结束。有关更多信息,请参见RewriteBase指令对前缀将回到相对substutions。

So no mention of the fact <Directory> instruction with wildcards won't be able to strip the per-directory prefix. And playing with RewriteBase won't help you, it's done to rebuild final Url not alter the perdir work.

因此,没有提到这个事实,即使用通配符的目录>指令不能去掉每个目录的前缀。和RewriteBase一起玩不会对你有帮助,它是为了重建最终的Url而不是改变perdir的工作。

But as you can see on the start there's the "with some additional complexity" sentence. Directory manipulations done by mod-rewrite are slower and more complex than general out-of-directory RewriteRules. This is stated as well in this documentation, mainly because of the perdir strip manipulation. And this means you can also write your rewriteRule out of the <Directory> section, in your VirtualHost.

但从一开始你就能看到,这句话有“附加的复杂性”。由mod-重写完成的目录操作比一般的out- Directory RewriteRules更慢,也更复杂。在此文档中也说明了这一点,主要是因为perdir脱机操作。这意味着您还可以在VirtualHost中在 部分中编写您的rewriteRule。

  • it will be faster
  • 它会更快
  • it will not be hit by this bug
  • 它不会被这个错误击中。
  • it may have some side effects if some non-existing files should'nt be mapped to your index.php?q=$1 rule in some other directories. But I'm quite sure this is not a problem in your case.
  • 如果某些不存在的文件不能映射到您的index.php,可能会产生一些副作用。在其他目录中,q=$1规则。但我很确定这不是你的问题。

So simply write (without the wildcard directory):

所以简单地写(没有通配符目录):

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]

And it should work, let me known if this leads to new problems.

它应该会起作用,让我知道这是否会导致新的问题。

Edit:

编辑:

Ok, forogot the fact REQUEST_FILENAME is not yet complelty defined in VirtualHost context, it's documented, it's 'normal', when the condition is applied the file search on the real path is not done yet, this is why you must add the document root. So in fact your final solution should be :

好的,forogot的事实是,REQUEST_FILENAME还不是在VirtualHost环境中定义的,它是有文档的,它是“正常的”,当条件被应用到实际路径上的文件搜索还没有完成,这就是为什么你必须添加文档根。所以实际上你的最终解决方案应该是:

RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]

I tried a second one, avoiding DOCUMENT_ROOT, by using late evaluation of REQUEST_FILENAME ( %{LA-U:REQUEST_FILENAME} contains the final path, which is in fact the full path to index.php in case of non existent files), but the only way I got it working is by adding a second Rule and a Or condition in the second, less simple, so the first solution is certainly better (KISS).

我尝试了第二个,避免了DOCUMENT_ROOT,通过使用REQUEST_FILENAME的延迟评估(%{LA-U:REQUEST_FILENAME}包含最终路径,这实际上是索引的完整路径。在不存在文件的情况下使用php),但是我唯一的方法是在第二个规则中添加第二个规则和条件,不那么简单,所以第一个解决方案肯定更好(KISS)。

  RewriteCond %{LA-U:REQUEST_FILENAME} !-f [OR]
  RewriteCond %{LA-U:REQUEST_FILENAME} !/index.php
  RewriteCond %{LA-U:REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteCond %{REQUEST_URI} !=/robots.txt
  RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]

  RewriteCond %{LA-U:REQUEST_FILENAME} /index.php
  RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]