Forum Moderators: phranque

Message Too Old, No Replies

Canonical dynamic URIs

How to make sure the query string NEVER shows.

         

nowpc

10:52 am on Apr 16, 2009 (gmt 0)

10+ Year Member



Hi all,

Presumably this is a question that'll come up a lot, so please bear with me. Using bought forum code, we can have something like the following URIs:

1) forum.php?this=that&another=thing

2) forum.php?this/that/another/thing

What I want is the second URI to work, and it does, great. The problem is that the first URI, including the query string with the ?=& still works too, and obviously I want it NOT to, but to redirect.

I guess there will be a simple .htaccess solution? Effectively, how do I make sure that URI 1) NEVER shows up, only URI 2?

Thanks in advance for any help!

Neil.

jdMorgan

1:09 pm on Apr 16, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



We cover this several times per week, but here it is again -- It's faster to type the code than to go search for the best thread link...

RewriteCond %{THE_REQUEST} ^[A-Z]+\ /forum\.php\?([^=]+)=([^&]+)&([^=]+)=([^&\ ]+)\ HTTP/
RewriteRule ^forum\.php$ http://www.example.com/forum.php/%1/%2/%3/%4? [R=301,L]

As posted, the RewriteCond pattern requires exactly two non-blank name/value pairs in the query string. This may not be exactly what you want, but when coding with an imprecise requirements specification it's usually better to go with 'restrictive matching' at first, in order to avoid unintended side-effects.

By checking the original client request, we prevent the 'infinite' rewrite/redirect looping that would otherwise occur as the result of interaction between this redirect and the internal rewrite which is currently installed and used by your forum's 'SEO-friendly URL' code to map the 'friendly' URLs to your script filepath+query.

This assumes that you've already got other working mod_rewrite code in your example.com/.htaccess file. If not, then you'll likely need several more rules to canonicalize the domain name and to redirect direct requests for "/index.xyz" to "/", etc.

If you don't currently have other rules in /.htaccess, then you will also need either both of these lines or only the second line, placed ahead of the code posted above. You'll have to test to see if you need both lines or only one.


Options +FollowSymLinks
RewriteEngine on

Jim

[edit:] Corrected code as noted below. [/edit]

[edited by: jdMorgan at 12:36 pm (utc) on April 17, 2009]

nowpc

1:52 pm on Apr 16, 2009 (gmt 0)

10+ Year Member



Hi Jim, thanks very much for the help - I guessed it would be a repeater topic. Still, keeps it fresh in your mind, eh? ;)

So, I tried the code, and it works perfectly as I described the problem - but there's a slight complication! :O} The thing is that there are a variable number of parameters passed, between 0 and 4. You of course already know my next question... how to tweak the code to deal with this?!

jdMorgan

2:00 pm on Apr 16, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You might want to take a shot at modifying the code yourself, so as to use this as an opportunity to learn. That's the actual purpose of this forum. Links to background information are cited in our Forum Charter.

If you have no luck, then please post your best-effort code, and provide an example of all valid "unfriendly" URL variations and their desired replacements in the same format you used in your first post, so that our contributing members can answer quickly and correctly and without drawing out the thread too long.

Thanks,
Jim

nowpc

2:46 pm on Apr 16, 2009 (gmt 0)

10+ Year Member



Ok, fair comment Jim. I'll get back later with my attempts. :)

jdMorgan

3:32 pm on Apr 16, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



To help this along, the simplest solution is to replicate the rule above, and modify the copies for 4, 3, 1, and zero name/value pairs. Put the rules in order from most to least pairs, top to bottom, for neatness. Or, since the patterns are mutually-exclusive, you can put them in order from most likely to be invoked to least-likely for best performance, based on your observed server stats.

It might possible to "do it all" with one rule, but the result would be an overly-complicated rule that runs more slowly that five individual ones. Also, you may run out of available back-references (parenthesized sub-expressions and the %1-%9 tokens used to de-reference their matched contents). And trying to read it later and figure out how it works will be difficult. So in these cases, I prefer the "self-documenting" advantage of separate rules.

I noted and corrected an error in my code above: The "$" tokens in the back-references should have been "%" symbols, since they refer back to the parenthesized RewriteCond sub-expressions. Need more coffee... :)

Jim

nowpc

10:33 am on Apr 17, 2009 (gmt 0)

10+ Year Member



HI again.

> Need more coffee...

LOL - I've had a few myself the past day or so now! :)

Thanks for pointing out the code issues - I think I spotted another one or two (!) but all is now working, shown here.

The forums exist in a subdirectory /forums. The following is in the .htaccess file for the /forums folder.

RewriteCond %{THE_REQUEST} ^[A-Z]+\ /forums/forumcode\.php\?([^=]+)=([^&]+)\ HTTP/
RewriteRule ^forumcode\.php$ http://www.example.com/forums/forumcode.php/%1/%2? [R=301,L]

This works for a single pair - notice I had to move the ? in the RewriteRule to AFTER the /%1/%2 to prevent the appending of the old query string. Also, having played around a bit, I discovered missed brackets in the first example. Corrected it looks like this:

RewriteCond %{THE_REQUEST} ^[A-Z]+\ /forum\.php\?([^=]+)=([^&]+)&([^=]+)=([^&\ ]+)\ HTTP/
RewriteRule ^forum\.php$ http://www.example.com/forum.php%1/%2/%3/%4? [R=301,L]

Switched around for my .htaccess it looks like this:

RewriteCond %{THE_REQUEST} ^[A-Z]+\ /forums/forumcode\.php\?([^=]+)=([^&]+)&([^=]+)=([^&\ ]+)\ HTTP/
RewriteRule ^forumcode\.php$ http://www.example.com/forums/forumcode.php/%1/%2/%3/%4? [R=301,L]

And the next line...

RewriteCond %{THE_REQUEST} ^[A-Z]+\ /forums/forumcode\.php\?([^=]+)=([^&]+)&([^=]+)=([^&\ ]+)&([^=]+)=([^&\ ]+)\ HTTP/
RewriteRule ^forumcode\.php$ http://www.example.com/forums/forumcode.php/%1/%2/%3/%4/%5/%6? [R=301,L]

And so on ad nauseum. :)

Thanks a million Jim, it would have taken me a lot longer than a day without your help. Greatly appreciated - although, you may be very concerned to know that I've another rewrite issue brewing, and I might well be posting it today! :D

Neil.