Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Table of Contents


    Preface (read this if nothing else)
    Introduction
    Conventions & Definitions [used in this document]
    Resources & References
    Installation, Testing, Required & Recommended Settings
    per-server (httpd.conf) vs per-directory (.htaccess)
    Internal Rewrites vs External Redirects
    Internal Processing Explained (includes differences b/w .htaccess, <VirtualHost>, <Directory>, <Location>, and <Files>)
    Troubleshooting

    Example 1: /foo.html -> /foo.php (pseudo-hiding PHP)
    Example 2: /foo.html -> foo.html (but parsed as PHP)
    Example 3: /foo -> search.php?terms=foo (search on 404)
    Example 4: /value1/value2 -> foo.php?name1=value1&name2=value2 (known # and order)
    Example 5: /nameN/valueN -> /foo.php?nameN=valueN (unknown # of name=value pairs)
    Example 6: domain.com/foo.html -> www.domain.com/foo.html (forcing "www")
    Example 7: http://domain.com -> https://domain.com (forcing "https")

    Please PM jharnois if you have an example to add. Additional examples should not be slight variations of current examples.

    Comments on this post

    • SimonGreenhill agrees : Excellent Information.
    • computer agrees : a most informative thread! well done!
    • Axweildr agrees : Maith thú an buachaill
    • funkyfoof agrees : very good work
    • Markisdee disagrees : sorry, i have to oppose the bandwagon
    • edwinbrains agrees
    • medianox agrees : You touch my heart, kid.
    • B-Con agrees : You are a shining example of everything I should be, but am not :p
    • kicken agrees : Something for me to read now
    • jabba_29 agrees
    • codergeek42 agrees
    • M.Hirsch agrees
    • kz00 agrees : thanks i love you
    • gimp agrees
    • FlyingSmurf agrees : nice
    • lucas agrees : This is excellent!
    • lnxgeek agrees : Nice job, thanks.
    • Immortal1490 agrees : Awesome!
    • Thr3ddy agrees : Forgot to give props when I first read this. Great great great stuff
    • medialint agrees
    • BrandonMUS agrees : Bookmarked!
    • paulh1983 agrees : excellent article for a novice
    • chadsmith729 agrees : You are my hero. Honestly. Wow you deserve an award or something. ;)
    • haid agrees : Word.
    • helloakash agrees : Superb! I think, this is the max rep for one post (21)
    • JordanT agrees
    • BlackDenton agrees
    • ishnid agrees
    • NevadaSam agrees : Very good stuff!
    • execute agrees : I am a nerd, You are a geek ....
    • b3n agrees : Same as.
    • spilo101 agrees : Beautiful guide!
    • ryon420 agrees : Bookmarked.
    • LinuxPenguin agrees : Can't believe I haven't repped this immensely useful post. I need it today ;)
    • Nilpo agrees
    • Bobby123 agrees : Thank you.
    • requinix agrees : wow, apparently I never repped for this thread
    • sarav_dude agrees : w00t !!!
    • aitken325i agrees
    • jimmyborofan agrees : I still find the mod rewrite rule confusing but this post has helped a lot in understanding and managing new web apps
    • Fraggl agrees : confusing stuff...awesome explaination, good work
    Last edited by jharnois; October 23rd, 2006 at 08:03 AM. Reason: Fixed link to Example 7
  2. #2
  3. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Preface


    mod_rewrite does not make /script.php?foo=bar become /script/foo/bar/ in the browser nor does it change your HTML to point to /script/foo/bar/. YOU MUST DO THIS PART YOURSELF. mod_rewrite is then used to make the pseudo-request for /script/foo/bar/ show the contents of /script.php?foo=bar

    Regardless of why you're here, you're probably thinking, "do I have to read all of this?" If you're lucky enough to take an example and have it work immediately, or skilled enough to tweak it until it does, then no. Otherwise, yes.

    We have tried to make this as concise as possible, but mod_rewrite is very complex, very powerful, and can be used in many different contexts, each having the potential to create many nauances. The easiest way to learn is by example, examples require explanations, and those examples and explanations take space.

    Comments on this post

    • Markisdee agrees : +14 rep for this thread.
    • flash101 agrees : Excelent Guide. Good Work.
    • medialint agrees : purple blob ya' :-)
    Last edited by jharnois; May 16th, 2006 at 05:25 PM. Reason: Added purple paragraph to cover common misconception.
  4. #3
  5. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Introduction


    mod_rewrite is an Apache module for URL manipulation and rewriting. It is extremely powerful and has the potential to solve any problem and be used in any situation. This power, however, is created by its complexity, and this complexity makes it difficult for new users.

    This guide provides the reader with a basic understanding of how mod_rewrite works by providing and explaining examples of the most commonly requested rewrites, most of which have been taken from this forum.

    This guide does NOT provide comprehensive information on regular expressions (see *** below), nor does it cover Apache configuration not related to mod_rewrite, although it will link to the relevant documentation.

    *** The regular expressions used in rewrites are used to determine what is rewritten, not how it is rewritten. While you may not find an example that matches your needs verbatim, a quick modification to the regular expression will get you what you need. However, the example will provide you with the information on how the match is rewritten.

    The following two rule sets differ only in what files are matched, not how the match is rewritten.[code=rewrite all HTML files]RewriteRule ^(.+)\.html$ $1.php[/code][code=rewrite HTML files with numeric name (eg 1.html)]RewriteRule ^([0-9]+)\.html$ $1.php[/code]

    Comments on this post

    • ishnid agrees : Needed this thread today. Nice one.
    Last edited by jharnois; August 1st, 2005 at 12:15 AM.
  6. #4
  7. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Conventions & Definitions [used in this document]


    RewriteEngine On is assumed. Examples will not have the aforementioned directive, but all examples need it. It should be placed before any other Rewrite* directives.

    Capatilized words in italics are directive parameters and match those in the documentation for that directive.

    Indented paragraphs offer a more detailed explanation, including supporting examples where applicable, for a particular point in the preceeding parent paragraph.


    Rewrite* directives
    Any of the directives listed here that are allowed in the current context.

    rule set
    Any combination of Rewrite* directives with valid arguments. Rule sets are displayed in CODE blocks. All related rule sets are displayed in a single CODE block, in which case each rule set is grouped, then separated from other groups by one or more blank lines.

    example(s)
    URLs displayed in CODE blocks in the form URL1 -> URL2 (note, if applicable), where URL1 is the original request and URL2 is the result of a single RewriteRule. If a rule set has multiple RewriteRule directives, the associated example will have multiple URL1 -> URL2s, one for each directive, and, unless otherwise stated, in the same order as those directives. Only one example is displayed per CODE block.
    Last edited by jharnois; January 4th, 2007 at 11:08 PM.
  8. #5
  9. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Resources & References


    The following documents contain additional information, examples, explanations, etc. You should familiarize yourself with each of these documents; they are appropriately referenced throughout this document. At the very least, skim each of these to get an idea of what mod_rewrite can do and where you would go to find an example.
    Please PM jharnois if you have a URL that you think should be added.

    Comments on this post

    • drewread agrees
    • l8rm8e agrees : Cheat sheet moved to http://www.addedbytes.com/apache/mod_rewrite-cheat-sheet/
    Last edited by jharnois; September 3rd, 2010 at 06:59 PM. Reason: Replaced cheat sheet link with one from comments.
  10. #6
  11. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Installation, Testing, Required & Recommended Settings


    1. open install_directory/conf/httpd.conf
    2. uncomment or add the following line
      Code:
      LoadModule rewrite_module modules/mod_rewrite.so
    3. Apache 1.3 users may need to uncomment or add the following line:
      Code:
      AddModule mod_rewrite.c
    4. restart Apache

    NOTE: the use of mod_rewrite requires Apache 1.3 or Apache 2.0+
    To test if mod_rewrite is enabled, attempt to turn the rewrite engine on using the following:
    NOTE: to prevent an error from affecting your entire domain, it is recommended that you create a sub-directory in your web root and run this test in that folder by using its .htaccess file.
    [code=/home/foo/public_html/rewrite-test/.htaccess
    ]RewriteEngine On[/code]Now view domain.com/rewrite-test/ in your browser. If you get a 500 Internal Server Error, mod_rewrite is not enabled. Check your server's error log.
    NOTE: When placing Rewrite* directives in .htaccess, you must have FileInfo privileges. In other words, AllowOverride FileInfo must be in httpd.conf for the directory (or one of its parents) in which .htaccess exists.
    NOTE: When placing Rewrite* directives in .htaccess, you must enable FollowSymLinks. In other words, Options FollowSymLinks must be in httpd.conf for the directory (or one of its parents) in which .htaccess exists, or you must add it to .htaccess.
    Last edited by jharnois; August 1st, 2005 at 12:18 AM.
  12. #7
  13. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    per-server (httpd.conf) vs per-directory (.htaccess)


    Rewrite* directives can be used in two places: per-server via the server's configuration file, httpd.conf, and per-directory via the access file, .htaccess.
    NOTE: .htaccess is the default access file on all Apache servers; it can be or could have been changed using the AccessFileName directive.
    You should put your Rewrite* directives in httpd.conf if you have access to it, otherwise, use .htaccess (see *** below). When using httpd.conf, you can place the Rewrite* directives directly in httpd.conf, a VirtualHost, <Directory>, <Location>, or <Files> (see Interal Processing Explained for mod_rewrite related differences).
    NOTE: not all Rewrite* directives are allowed in all contexts.
    *** According to the documentation on .htaccess, it's always more efficient and secure to use httpd.conf instead of .htaccess. Using mod_rewrite in .htaccess is potentially more inefficient than other modules/directives because, according to Internal Processing » API Phases, by the time Apache gets to the point in an HTTP request where it reads .htaccess files, it's officially too late for a rewrite to occur. To solve this, mod_rewrite undoes some of Apache's work, does what it needs, then asks Apache to start its work over again.
    The examples provided in this document will reference .htaccess because fewer users have access to httpd.conf. httpd.conf users will need to put the provided examples in the appropriate context in httpd.conf. It is assumed, though maybe inaccurately so, that those with access to httpd.conf will have the proper understanding to place the Rewrite* directives in the correct place and make the necessary adjustments (see Internal Processing Explained for mod_rewrite related differences).

    In the following two examples, the rewrite engine is turned on. The first demonstrates doing so in a per-directory context using .htaccess while the second demonstrates doing so in a per-server context using a <Directory> located in httpd.conf. The result is the same.[code=/home/foo/public_html/.htaccess]RewriteEngine On[/code][code=httpd.conf]<Directory /usr/foo/public_html>
    RewriteEngine On
    </Directory>[/code]

    Comments on this post

    • cybersaga agrees : This one's my favourite. It's number 7.
    Last edited by jharnois; August 1st, 2005 at 12:39 AM.
  14. #8
  15. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Internal Rewrites vs External Redirects


    An internal rewrite shows the contents of one file while displaying the location or pseudo-location of another file in the browser's address bar. These are common for optimizing URLs for search engines because they can effectively hide a query string. They cannot be used to show the contents of a file on a different server or domain.

    In the following example, all HTML requests will show the results of the PHP file with the same name.
    Code:
    RewriteRule ^(.+)\.html$ $1.php
    Code:
    domain.com/foo.html -> domain.com/foo.php
    An external redirect will change the browser's address bar to the resulting URL. You should only use an external redirect when the target file is located on a different server or domain, or when you need to provide a server status code. mod_rewrite's [R] flag performs both of these tasks.

    In the following example, all HTML requests on this domain are redirected to the HTML file with the same name on anotherdomain.
    Code:
    RewriteRule ^(.+\.html)$ http://anotherdomain.com/$1 [R]
    Code:
    domain.com/foo.html -> anotherdomain.com/foo.html
    NOTE: External redirects can also be obtained using Apache's mod_alias through the Redirect and RedirectMatch directive. These do not require mod_rewrite to be enabled. If you find yourself using a RewriteRule that results in an external redirect, and there is no corresponding RewriteCond, Redirect or RedirectMatch is the recommended alternative.

    In the following example, RedirectMatch is used to create an external redirect equivalent to the previous mod_rewrite rule set.
    Code:
    RedirectMatch ^(.+\.html)$ http://anotherdomain.com$1
  16. #9
  17. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Internal Processing Explained


    Because mod_rewrite works internally and often invisibly, it is extremely important to understand what is going on when Apache encounters a rule set. This understanding will help you determine the proper rules and conditions and troubleshoot any problems.

    Processing Order

    Please read Internal Processing » Ruleset Processing before continuing. Then, read it again, slower this time, making an effort to understand exactly what each sentence is telling you in relation to any examples provided in the documentation. I realize this sounds elementary, but it is essential to understanding mod_rewrite.

    In the following rule set, we rewrite all GIF requests to the corresponding JPG file with the same name. In the following rule set, each request is checked to see if it ends with ".gif". If it does not, the rule is skipped. If it does, the request is rewritten to show the same file, but with a ".jpg" extension instead of a ".gif" extension.
    Code:
    RewriteRule ^(.+)\.gif$ $1.jpg
    Code:
    domain.com/foo.gif -> domain.com/foo.jpg
    Code:
    domain.com/bar/baz.gif -> domain.com/bar/baz.jpg
    In the following rule set, we rewrite all JPG requests in the "png" directory to the corresponding PNG file with the same name. In the following rule set, each request is checked to see if it ends with a ".jpg" extension. If it does not, the rule is skipped. If it does, the REQUEST_URI (eg, "/png/foo.jpg") is tested to see if it begins with "/png/". If it does not, the condition ends and the rule is skipped (unless the RewriteCond is followed by the [OR] flag, in which case the next RewriteCond is tested). If it does, the request is rewritten to show the same file, but with a ".png" extension instead of a ".jpg" extension. Pay special attention to the order in which the Rewrite* directives apply: the RewriteRule's Pattern is matched against the current request (or the previously rewrite when multiple RewriteRule directives exist), then the RewriteCond's CondPattern is tested against its TestString, and then, only if the condition is true, the RewriteRule's Substitution is applied.
    Code:
    RewriteCond %{REQUEST_URI} ^/png/
    RewriteRule ^(.+)\.jpg$ $1.png
    Code:
    domain.com/foo.jpg -> domain.com/foo.jpg
    Code:
    domain.com/png/foo.jpg -> domain.com/png/foo.png
    NOTE: There is no need to prepend "/png/"; mod_rewrite will do this for you.
    Combining the previous two rule sets will have these results: a request for a GIF file outside the "png" directory will result in the corresponding JPG file with the same name being shown, but a requst for a GIF file inside the "png" directory will result in the corresponding PNG file with the same name being shown. Why? The first RewriteRule rewrites the GIF file to a JPG file, then the second RewriteRule rewrites the JPG file to a PNG file, but only if that JPG file is in the png diretory, because only then will the RewriteCond be true. Remember, the first RewriteRule applies to all GIF files, including those in the "png" directory.
    Code:
    domain.com/png/foo.gif -> domain.com/png/foo.jpg
    domain.com/png/foo.jpg -> domain.com/png/foo.png
    Pattern Matching

    It is also important to understand what, exactly, Pattern will match in a RewriteRule. When using .htaccess, Pattern is relative to the location of .htaccess. For example, using the following file structure and rule set ...
    Code:
    /home/foo/public_html/.htaccess
    /home/foo/public_html/foo.php
    /home/foo/public_html/real/
    /home/foo/public_html/real/directory/
    [code=/home/foo/public_html/.htaccess]RewriteRule ^(.+)\.html$ foo.php?qs=$1[/code]... requests will be rewritten as follows:
    Code:
    domain.com/bar.html -> domain.com/foo.php?qs=bar.html
    Code:
    domain.com/real/directory/bar.html -> domain.com/foo.php?qs=real/directory/bar.html
    But, moving the same .htaccess file to /home/foo/public_html/real/directory/.htaccess and removing the Rewrite* directives from /home/foo/public_html/.htaccess will produce these results:
    Code:
    domain.com/bar.html -> Server Error: 404 Not Found
    Code:
    domain.com/real/directory/bar.html -> domain.com/foo.php?qs=bar.html
    In order to get /real/directory/bar.html, one would need to use %{REQUEST_URI} in a RewriteCond:[code=/home/foo/public_html/real/directory/.htaccess]RewriteCond %{REQUEST_URI} ^(.+)$
    RewriteRule ^.+\.html$ foo.php?qs=%1[/code]
    Code:
    domain.com/real/directory/bar.html -> domain.com/foo.php?qs=/real/directory/bar.html
    Pattern Matching » .htaccess vs <VirtualHost> vs <Directory> vs <Location> vs <Files>

    When using <VirtualHost>, <Directory>, <Location>, or <Files> (or relatives) in httpd.conf (or .htaccess if allowed), Pattern is matched against different strings. Using the following directory structure and rule set:
    Code:
    /home/foo/public_html
    Code:
    RewriteRule ^(.*)$ /foo.php?qs=$1
    The following contexts return the indicated values for "qs":[code=.htaccess]foo.html[/code][code=<VirtualHost>]/foo.html[/code]
    NOTE: in this example, <VirtualHost> also includes the following directive:
    Code:
    DocumentRoot /home/foo/public_html
    [code=<Directory /home/foo/public_html>]foo.html[/code][code=<Location>]/home/foo/public_html/foo.html[/code][code=<Files>]/home/foo/public_html/foo.html[/code]

    Comments on this post

    • clm2206 agrees : Great post, thanks for yor time!!
    Last edited by jharnois; November 17th, 2005 at 01:39 AM. Reason: Added .htaccess context.
  18. #10
  19. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Troubleshooting


    There are two common errors when working with mod_rewrite: 500 Internal Server Error; 404 Not Found.

    500 errors are caused when mod_rewrite is not enabled and you attempt to turn the RewriteEngine On, when there is a syntax error in your Rewrite* directives, you attempt to use a Rewrite* directive in an incorrect context, or your Rewrite* directives cause an infinite loop (Apache assumes this is an error). When you get a 500 error, check your server's error logs.

    404 errors are caused when a request is rewritten to a file that does not exist. This is quite obvious, but what is not obvious is what non-existent file was requested as the result of the rewrite. 404 errors can be tricky to troubleshoot, especially when you have multiple RewriteRule directives, because it's difficult to know which RewriteRule directive was applied and which wasn't and what exactly the final request was. With simple rewrites, you may only need to check your server's error logs. More complicated rewrites will require the use of the RewriteLog and RewriteLogLevel directives.
    NOTE: RewriteLog and RewriteLogLevel can only be used in httpd.conf.
    Last edited by jharnois; August 14th, 2005 at 01:00 PM. Reason: Added reason for 500 error.
  20. #11
  21. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Example 1: /foo.html -> /foo.php


    Code:
    RewriteRule ^(.+)\.html$ $1.php [L]
    Code:
    domain.com/foo.html -> domain.com/foo.php
    This rule set internally rewrites all HTML requests to the PHP file with the same name by matching anything prior to an .html extension and rewriting the request using that match affixed with a .php extension. The [L] flag indicates no RewriteRule should be processed after this one.

    This is commonly requested as a way to hide the use of PHP.
    NOTE: PHP is exposed in the HTTP headers by default.
  22. #12
  23. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Example 2: /foo.html -> foo.html (but parsed as PHP)


    Code:
    RewriteRule ^(.+\.html)$ $1 [T=application/x-httpd-php]
    Code:
    domain.com/foo.html -> domain.com/foo.html
    This rule set internally rewrites all HTML requests to the same HTML file, but also forces that HTML file to be parsed as PHP. The [T=mime-type] flag indicates what mime-type should be used for the rewritten request.

    This is commonly requested as a way to prevent having to rename all HTML files to PHP files after a site has been upgraded from static HTML to dynamic PHP.
    NOTE: A better solution might be to put the following line in .htaccess instead of using mod_rewrite.
    Code:
    AddType application/x-httpd-php .php .html
    The only advantage to mod_rewrite over the above code is that mod_rewrite allows the addition of RewriteCond directives or a more specific regular expression to specify which HTML files should be parsed as PHP.
  24. #13
  25. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Example 3: /foo -> search.php?terms=foo


    Code:
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.+)$ search.php?terms=$1 [L]
    Code:
    domain.com/find -> domain.com/search.php?terms=find (if /find is not a directory)
    Code:
    domain.com/foo.html -> domain.com/search.php?terms=foo.html (if foo.html does not exist)
    This rule set internally rewrites all requests that do not exist on the server as a file or directory to a search script that has access to the non-existen request via the query string by testing each request against the request's system filename. %{REQUEST_FILENAME} is a server variable containing "the full local filesystem path to the file or script matching the request" (eg, /home/foo/public_html/find in the first example). -f tests the %{REQUEST_FILENAME} to see if it's an existing file; -d tests to see if it's a directory. The exclamation point negates the tests.

    This is commonly requested as a way to catch all non-existent requests instead of sending the normal 404 Not Found server error.

    Related Threads: Replace Image Error Icon
    Last edited by jharnois; October 22nd, 2005 at 12:08 PM.
  26. #14
  27. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Example 4: /value1/value2 -> foo.php?name1=value1&name2=value2 (known # and order)


    Code:
    RewriteRule ^([^/]+)/([^/]+)/?$ foo.php?name1=$1&name2=$2
    Code:
    domain.com/foo/bar -> domain.com/foo.php?name1=foo&name2=bar
    This rule set internally rewrites pseudo-folders that are intended to be values in a name=value pair in a query string by placing matched values in a specific position in that query string. To add more values, simply repeat "/([^/]+)" in the Pattern and add the corresponding &nameN=$N to the Substitution
    NOTE: In order to use this method, one needs to know the number and order of the values being used in order to properly match that value with the correct name during the rewrite.
    NOTE: This method is limited to nine pseudo-folder values.
    This is commonly requested as a way to display hierarchial pseudo-folders for search engines.
    Code:
    domain.com/Georgia/Atlanta -> domain.com/info.php?state=Georgia&city=Atlanta
    Related Threads: mod rewrite help

    Comments on this post

    • Sepodati agrees : Good work!
    • codergeek42 agrees : Outstanding. Thank you for a wonderful tutorial. :)
    • B-Con agrees : Excellent. :)
    • ishnid agrees : Needed this again today.
    Last edited by jharnois; October 22nd, 2005 at 12:07 PM. Reason: Fixed Rule to allow optional trailing slash.
  28. #15
  29. mod_dev_shed
    Devshed Supreme Being (6500+ posts)

    Join Date
    Sep 2002
    Location
    Atlanta, GA
    Posts
    14,817
    Rep Power
    1099

    Example 5: /nameN/valueN -> /foo.php?nameN=valueN (unknown # of name=value pairs)


    Code:
    RewriteCond %{QUERY_STRING} ^$
    RewriteRule ^(.+)/([^/]+)/([^/]+)$ $1?$2=$3 [QSA,E=TEST:$1]
    
    RewriteCond %{ENV:TEST} ^(.+)/([^/]+)/([^/]+)$
    RewriteRule ^.*$ %1?%2=%3 [QSA,E=TEST:%1,N]
    
    RewriteCond %{ENV:TEST} ^([^/]+)/(.+)$ [OR]
    RewriteCond %{REQUEST_URI} ^/([^/]+)/(.+)$
    RewriteRule ^.*$ foo.php?%1=%2 [QSA,L]
    Code:
    domain.com/name1/value1/name2/value2/nameN/valueN -> domain.com/foo.php?name1=value1&name2=value2&nameN=valueN
    This rule set internally rewrites an infinite number of name/value pseudo-folders into name=value query string pairs. This is accomplished by initially creating an environment variable, then "looping" through that environment variable, rewriting it on each loop, until it's no longer valid (eg, the loop returns false), and finally rewriting the request. It will require several explanations and examples to completely understand.
    In terms of extremely over-simplified code, it's the equivalent to this:
    Code:
    $i = 0;
    while($i < $n)
      {
      $i++;
      }
    print $i;
    When a request is made for a single name/value pseudo-folder, the first RewriteRule is skipped b/c the Pattern doesn't match the initial request (the pattern requires characters (.+) and a preceeding forward slash (/) to match), so the [E] flag is never encountered, so the TEST environment variable gets no value. This causes the second RewriteCond to fail because the CondPattern does not match the TestString (the environment variable), which in turn causes the second RewriteRule to fail. The third RewriteCond also fails for the same reason the second RewriteCond did, but the fourth RewriteCond does not fail, the name and value are matched, and the request is rewritten using those matches.
    Code:
    domain.com/name1/value1 -> 
    test name1/value1 with ^(.+)/([^/]+)/([^/]+)$: fails
    environment variable TEST = ''
    
    test name1/value1 with ^.*$: passes
    test environment variable value '' with ^(.+)/([^/]+)/([^/]+)$: fails
    
    test name1/value1 with ^.*$: passes
    test environment variable value '' with ^([^/]+)/(.+)$: fails OR
    test request uri value /name1/value1 with ^/([^/]+)/(.+)$: passes
    domain.com/foo.php?name1=value1
    A request for multiple name/value pseudo-folders is a little more involved. The first RewriteRule will only be effective the first time around (yes, I said first time) and is used to initially set the TEST environment variable. This first RewriteRule does two things: it rewrites the original request with a query string for the last name/value pair, and it sets the TEST environment variable to the original request less the last name/value pseudo-folders. The second RewriteRule is designed to always match the request (remember, according to Internal Processing, the second RewriteRule works on the rewritten result of the first RewriteRule) and run the second RewriteCond. The second RewriteCond checks the TEST environment variable created by the first RewriteRule to see if it has multiple name/value pseudo-folders remaining. If it does, the request is again rewritten with a query string for that last name/value pair, and the TEST environment variable is rewritten. The [QSA] flag tells mod_rewrite that this found name/value pair should be appended to the previously found name/value pair instead of replacing it. The [N] flag tells mod_rewrite to start over at the first RewriteRule (remember, I said the first RewriteRule would be visited again). This time, however, the first RewriteRule is skipped because QUERY STRING now has a value (mod_rewrite internally creates QUERY STRING when we rewrite a requst with a query string). This process of working with the rewritten request in the second RewriteRule and skipping the first RewriteRule is repeated until the second RewriteCond's CondPattern no longer matches the TEST environment variable, which occurs when only one name/value pair remains. What happens then has already been explained above.
    Code:
    domain.com/name1/value1/name2/value2/name3/value3 -> 
    test name1/value1/name2/value2/name3/value3 with ^(.+)/([^/]+)/([^/]+)$: passes
    test QUERY STRING with ^$: passes
    name1/value1/name2/value2?name3=value3 ->
    environment variable TEST = name1/value1/name2/value2
    environment variable QUERY STRING = name3=value3 (mod_rewrite implicitly handles)
    
    test name1/value1/name2/value2 with ^.*$: passes
    test environment variable value 'name1/value1/name2/value2' with ^(.+)/([^/]+)/([^/]+)$: passes
    name1/value1?name2=value2 ->
    environment variable TEST = name1/value1
    environment variable QUERY STRING = name2=value2&name3=value3 ([QSA] flag appends)
    
    *** [N] flag restarts process ***
    
    test name1/value1 with ^.*$: passes
    test environment variable value 'name1/value1' with ^([^/]+)/(.+)$: passes
    domain.com/foo.php?name1=value1&name2=value2&name3=value3 ([QSA] flag again)
    NOTE: RewriteMap could also be used to accomplish this goal by passing the request to an external script.
    NOTE: ForceType is another alternative.
    This is commonly requested as a way to display search engine friendly name=value query string pairs when the order and quantity is unknown and/or varying.

    Related Threads: Mod_rewrite, example 5 help, value1/value2/value3 to standard querystring

    If you know of less complicated rule set, please PM jharnois.

    Comments on this post

    • jabba_29 agrees : Excellent
    • ChiefWigs1982 agrees : That's the st*ff
    Last edited by jharnois; January 5th, 2007 at 08:50 AM. Reason: Added related thread.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo