Search code examples
apachemod-rewrite

Complicated rules for mod_rewrite


creating correct instructions for mod_rewrite. It seems to be very difficult.

I need exactly the following:

  1. Redirect from www.example.com to example.com.

    • www.example.com/hello ==> example.com/hello
    • www.example.com/abc/def ==> example.com/abc/def

    etc., and then other rules should be applied.

  2. Direct access (no rewrite) to some specified files and folders (such as robots.txt, images/, etc.)

    Maybe

    RewriteCond %{REQUEST_URI} !^/(robots.txt|favicon.ico|images|documents|~.\*)
    

    Am I right? So, URLs like

    • example.com/robots.txt ==> example.com/robots.txt
    • example.com/documents/file1.pdf ==> example.com/documents/file1.pdf

    should remain as is and shouldn't be rewritten.

  3. Another transformation:

    • example.com/index.php?anythinghere ==> example.com/a/index.php?anythinghere
  4. But if we type URLs example.com and example.com/ Apache should call index.php in the root folder (example.com/index.php)

    example.com ==> example.com/index.php example.com/ ==> example.com/index.php

  5. I have MVC script, and if we type the following URLs:

    1. example.com/controller or example.com/controller/ or example.com/controller//
    2. example.com/controller/function or example.com/controller/function/
    3. `example.com/controller/function/parameter or example.com/controller/function/param1/param2/param3

    and if controller is one of predefined words in the list, say, "index", "news", "contacts" (maybe it will be expanded up to few hundreds of words), then we should call index.php, rewriting URLs the following way:

  • example.com/controller ==> example.com/index.php?q=controller
  • example.com/controller/ ==> example.com/index.php?q=controller/
  • example.com/controller// ==> example.com/index.php?q=controller//
  • example.com/controller/function ==> example.com/index.php?q=controller/function
  • example.com/controller/function/ ==> example.com/index.php?q=controller/function/
  • example.com/controller/function/parameter ==> example.com/index.php?q=controller/function/parameter
  • example.com/controller/function/param1/param2/param3 ==> example.com/index.php?q=controller/function/param1/param2/param3
  1. And, finally, if all previous rules weren't applied, we should rewrite
  • example.com/anythinghere ==> example.com/a/index.php?anythinghere

Hope Apache doesn't use mod_rewrite recursively, or I will have huge troubles with different index.phps.


Solution

  • For the first rewrite, you can put these lines in .htaccess:

    RewriteCond %{HTTP_HOST} ^www.site.com$ [NC]
    RewriteRule ^(.*)$ http://site.com/$1 [R=301]
    

    It's very important to put R=301 in order to make it a permanent redirect, so that search engines won't see www.site.com and site.com as two different sites.

    For the second rewrite many options are available. Perhaps will be more useful for you to make apache serve all the files that actually exist (such as images and pdf documents) and to rewrite those URLs that mean some MVC commands.

    If you think so, you can cover your fifth rewrite, and write this:

    RewriteCond %{SCRIPT_FILENAME} !-d  
    RewriteCond %{SCRIPT_FILENAME} !-f 
    
    RewriteRule ^/news$ ./index.php?news  [L]
    RewriteRule ^/news/(.*)$ ./index.php?news/$1  [L]
    

    And so on for each controller you have. If you plan to have hundreds of controllers, then I think you should rethink the design of your system, or make them subcontrollers of a few main controllers, so these main controller can be written in this .htaccess file.

    Also important is L, which tells apache it is the last line executed (last one if matched the condition), so you avoid recursion (among other things if I remember well).

    To cover the third one:

    RewriteRule ^/index.php?(.*)$ ./a/index.php?$1  [L]
    

    To cover the sixth and last one:

    RewriteRule ^/(.*)$ ./a/index.php?$1  [L]
    

    So, covering the rewrites 1, 2, 3, 5 and 6 we can have:

    RewriteEngine On
    
    # First rewrite
    RewriteCond %{HTTP_HOST} ^www.site.com$ [NC]
    RewriteRule ^(.*)$ http://site.com/$1 [R=301]
    
    # Second and fifth rewrite
    RewriteCond %{SCRIPT_FILENAME} !-d  
    RewriteCond %{SCRIPT_FILENAME} !-f 
    
    RewriteRule ^/news$ ./index.php?news  [L]
    RewriteRule ^/news/(.*)$ ./index.php?news/$1  [L]
    
    # Third rewrite
    RewriteRule ^/index.php?(.*)$ ./a/index.php?$1  [L]
    
    # Sixth rewrite
    RewriteRule ^/(.*)$ ./a/index.php?$1  [L]