Skip to main content

Hidden features of mod_rewrite


There seem to be a decent number of mod_rewrite threads floating around lately with a bit of confusion over how certain aspects of it work. As a result I've compiled a few notes on common functionality, and perhaps a few annoying nuances.



What other features / common issues have you run across using mod_rewrite ?


Source: Tips4allCCNA FINAL EXAM

Comments

  1. Where to place mod_rewrite rules

    mod_rewrite rules may be placed within the httpd.conf file, or within the .htaccess file. if you have access to httpd.conf, placing rules here will offer a performance benefit (as the rules are processed once, as opposed to each time the .htaccess file is called).

    Logging mod_rewrite requests

    logging may be enabled from within the httpd.conf file (including <Virtual Host>):

    # logs can't be enabled from .htaccess
    # loglevel > 2 is really spammy!
    RewriteLog /path/to/rewrite.log
    RewriteLogLevel 2


    Common use cases


    to funnel all requests to a single point:

    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-f # ignore existing files
    RewriteCond %{REQUEST_FILENAME} !-d # ignore existing directories
    RewriteRule ^(.*)$ index.php?query=$1 # map requests to index.php and append
    # as a query string

    handling 301/302 redirects:

    RewriteEngine on
    RewriteRule ^oldpage.html$ /newpage.html [R=302] # 302 Redirect
    RewriteRule ^oldpage2.html$ /newpage.html [R=301] # 301 Redirect


    note: external redirects are implicitly 302 redirects:

    # this rule:
    RewriteRule ^somepage.html$ http://google.com
    # is equivalent to:
    RewriteRule ^somepage.html$ http://google.com [R]
    # and:
    RewriteRule ^somepage.html$ http://google.com [R=302]

    forcing SSL

    RewriteEngine on
    RewriteCond %{SERVER_PORT} 80
    RewriteRule ^(.*)$ https://mysite.com/$1 [R,L]

    common flag usage:


    [R] force a redirect (default 302)
    [R=301] force a 301 redirect
    [L] stop rewriting process (see note below in common pitfalls)
    [NC] case insensitive matches


    you can mix and match flags:

    RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]



    Common pitfalls


    mixing mod_alias style redirects with mod_rewrite

    # Bad
    Redirect 302 /somepage.html http://mysite.com/otherpage.html
    RewriteEngine on
    RewriteRule ^(.*)$ index.php?query=$1

    # Good (use mod_rewrite for both)
    RewriteEngine on
    RewriteRule ^somepage.html$ /otherpage.html [R=302,L] # 302 redirect, and stop processing
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php?query=$1 # handle other redirects


    note: you can mix mod_alias with mod_rewrite, but it involves more work than just handling basic redirects as above.
    context affects syntax

    within .htaccess files, a leading slash is not used in the pattern:

    # given: GET /directory/file.html

    # .htaccess
    # result: /newdirectory/file.html
    RewriteRule ^directory(.*)$ /newdirectory$1

    # .htaccess
    # result: no match!
    RewriteRule ^/directory(.*)$ /newdirectory$1

    # httpd.conf
    # result: /newdirectory/file.html
    RewriteRule ^/directory(.*)$ /newdirectory$1

    # Works in both contexts:
    RewriteRule ^/?directory(.*)$ /newdirectory$1

    [L] is not last! (sometimes)

    within the .htaccess context, [L] will not force mod_rewrite to stop. it will continue to trigger internal sub-requests:

    RewriteRule ^dirA$ /dirB [L] # processing does not stop here
    RewriteRule ^dirB$ /dirC # /dirC will be the final result


    our rewrite log shows the details:

    rewrite 'dirA' -> '/dirB'
    internal redirect with /dirB [INTERNAL REDIRECT]
    rewrite 'dirB' -> '/dirC'

    ReplyDelete
  2. The deal with RewriteBase:

    You almost always need to set RewriteBase. If you don't, apache guesses that your base is the physical disk path to your directory. So start with this:

    RewriteBase /

    ReplyDelete
  3. if you need to 'block' internal redirects / rewrites from happening in the .htaccess, take a look at the

    RewriteCond %{ENV:REDIRECT_STATUS} ^$


    condition, as discussed here.

    ReplyDelete
  4. Equation can be done with following example:

    RewriteCond %{REQUEST_URI} ^/(server0|server1).*$ [NC]
    # %1 is the string that was found above
    # %1<>%{HTTP_COOKIE} concatenates first macht with mod_rewrite variable -> "test0<>foo=bar;"
    #RewriteCond search for a (.*) in the second part -> \1 is a reference to (.*)
    # <> is used as an string separator/indicator, can be replaced by any other character
    RewriteCond %1<>%{HTTP_COOKIE} !^(.*)<>.*stickysession=\1.*$ [NC]
    RewriteRule ^(.*)$ https://notmatch.domain.com/ [R=301,L]


    Dynamic Load Balancing:

    If you use the mod_proxy to balance your system, it's possible to add a dynamic range of worker server.

    RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC]
    RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]

    ReplyDelete
  5. Another great feature are rewrite-map-expansions. They're especially useful if you have a massive amout of hosts / rewrites to handle:

    They are like a key-value-replacement:

    RewriteMap examplemap txt:/path/to/file/map.txt


    Then you can use a mapping in your rules like:

    RewriteRule ^/ex/(.*) ${examplemap:$1}


    More information on this topic can be found here:

    http://httpd.apache.org/docs/2.0/mod/mod%5Frewrite.html#mapfunc

    ReplyDelete

Post a Comment

Popular posts from this blog

Why is this Javascript much *slower* than its jQuery equivalent?

I have a HTML list of about 500 items and a "filter" box above it. I started by using jQuery to filter the list when I typed a letter (timing code added later): $('#filter').keyup( function() { var jqStart = (new Date).getTime(); var search = $(this).val().toLowerCase(); var $list = $('ul.ablist > li'); $list.each( function() { if ( $(this).text().toLowerCase().indexOf(search) === -1 ) $(this).hide(); else $(this).show(); } ); console.log('Time: ' + ((new Date).getTime() - jqStart)); } ); However, there was a couple of seconds delay after typing each letter (particularly the first letter). So I thought it may be slightly quicker if I used plain Javascript (I read recently that jQuery's each function is particularly slow). Here's my JS equivalent: document.getElementById('filter').addEventListener( 'keyup', function () { var jsStart = (new Date).getTime()...

Is it possible to have IF statement in an Echo statement in PHP

Thanks in advance. I did look at the other questions/answers that were similar and didn't find exactly what I was looking for. I'm trying to do this, am I on the right path? echo " <div id='tabs-".$match."'> <textarea id='".$match."' name='".$match."'>". if ($COLUMN_NAME === $match) { echo $FIELD_WITH_COLUMN_NAME; } else { } ."</textarea> <script type='text/javascript'> CKEDITOR.replace( '".$match."' ); </script> </div>"; I am getting the following error message in the browser: Parse error: syntax error, unexpected T_IF Please let me know if this is the right way to go about nesting an IF statement inside an echo. Thank you.