mod_rewrite is ignoring rules in subdirectories

2019-09-02 11:40发布

问题:

Wanted rewrite behaviour (internal rewrite!)

http://<subdomain>.domain.tld/<path> -> /<subdomain>/<path>
http://www.domain.tld/path/file.php  -> /www/path/file.php
http://project.domain-tld/index.php  -> /project/index.php

Folder structure:

/                        root
    .htaccess
    /www                 www.domain.tld
        index.php
        /www
            file.php
        /foo
            /bar
                file.php
    /project             project.domain.tld
        index.php
        someRandomFiles
    /somesubdomain       somesubdomain.domain.tld
        index.php
        someRandomFiles
    /anothersubdomain    anothersubdomain.domain.tld
         index.php
         someRandomFiles

Full .htaccess

# Unicode
AddDefaultCharset utf-8

# Activate mod_rewrite
RewriteEngine on
RewriteBase /

# Subdomains
#  Extract (required) subdomain (%1), and first path element (%3), discard port number if present (%2)
RewriteCond %{HTTP_HOST}<>%{REQUEST_URI} ^([^.]+)\.janbuschtoens\.de(:80)?<>/([^/]*) [NC]
#  Rewrite only when subdomain not equal to first path element (prevents mod_rewrite recursion)
RewriteCond %1<>%3 !^(.*)<>\1$ [NC]
#  Rewrite to /subdomain/path
RewriteRule ^(.*) /%1/$1 [L]

My .htaccess seems to work. You can live test it here:

  • http://test.janbuschtoens.de/ rewrites to /test/
  • http://www.janbuschtoens.de/ rewrites to /www/

But there is some strange behaviour in subdirectories. mod_rewrite seems to ignore the rule if the first directory in the requested path has the same name as the subdomain itself. For example:

  • http://www.domain.tld/foo/bar/file.php -> /www/foo/bar/file.php - Fine!
  • http://www.domain.tld/ -> /www/ - Fine!
  • http://www.domain.tld/www/ -> /www/ - Should be: /www/www/
  • http://www.domain.tld/www/www/ -> /www/www/ - Should be: /www/www/www/

For another live test:

  • http://test.janbuschtoens.de/ rewrites to /test/
  • http://test.janbuschtoens.de/test/ rewrites to /test/

It seems like the rule gets ignored.

回答1:

This is the only good rule that I was able come up with, otherwise after initial rewriting (which is very easy) it goes into the loop (and that is the problem). For example: www.domain.com/www/123.png gets properly redirected into /www/www/123.png, but then goes to the next loop, where it get's redirected to /www/www/www/123.png and then again and again.

This rule ONLY gets invoked if FINAL filename DOES EXIST.

RewriteCond %{HTTP_HOST} ^(.+)\.domain\.com$
RewriteCond %{DOCUMENT_ROOT}/%1/$1 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/%1/$1 -d
RewriteRule ^(.*)$ /%1/$1 [QSA,L]

For example: if you request www.domain.com/www/123.png, and file/folder WEBSITEROOT/www/www/123.png exist, then it will be rewritten, otherwise nothing.

The same here: if you request meow.domain.com/ .. but have no WEBSITEROOT/meow/ folder on your drive, it gets nowhere.

Please note, this still will not help much if you have subfolder with the same name as subdomain. For example: if you request www.domain.com it should be rewritten to WEBSITEROOT/www/ ... but if you also have WEBSITEROOT/www/www/ then (because of loop) it will be rewritten to WEBSITEROOT/www/www/ instead.

Unfortunately I have not found the way how to bypass it. If you wish -- you can try combining your rules with mine.