Forum Moderators: phranque

Message Too Old, No Replies

.htaccess - get multiple vars from query, write cookie and redir

I need help getting .htaccess to get a varying number of vars from query

         

vandedeenterprise

11:07 pm on Dec 16, 2014 (gmt 0)

10+ Year Member



Hi WW,

I'm trying to get a varying number of variables from the query string, write them in a cookie and redirect removing query string. I got it working with only 1 variable but sometimes I need to get 2 or 3. Here's the code that works with 1 variable:

RewriteCond %{QUERY_STRING} ^(tag|aid|flu)=([a-z0-9]+)$ [NC] # look for interesting variables in url
RewriteRule ^(.*)$ $1? [CO=%1:%2:example.com:14400:/,R=301,L] # capture url strip for vars, write cookie, redir

but clearly this is not going to work if the requested url is example.com?tag=xx&aid=yyy&flu=bbb or with just 2 variables. I just can't seem to wrap my head around how to do this. Also it would be nice if the order of the variables didn't matter.

Thanks in advance :)

lucy24

11:47 pm on Dec 16, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



It can be done, but after a point it gets complicated and convoluted. The big snag is that captures from a RewriteCond can only be reused in the target if it's the very last Condition*, so you can't run a string of conditions like
RewriteCond %{QUERY_STRING} (^|&)thisparam=([^&]*)($|&)

for each possible parameter name.

The fact that you're using parameters implies that your pages already have some dynamic component, probably involving php. You will probably find it much simpler to say something like

RewriteCond %{QUERY_STRING} (^|&)(tag|aid|flu)=
RewriteRule ^(index\.php)?$ /fixup.php [L]


and then let fixup.php issue the redirect and write the cookies, if needed. Add conditions if needed to prevent an infinite loop.

Note also that the pattern of the rule should be constrained to requests that might actually have these parameters. For my example I made up "/index.php"; substitute whatever applies to your site. At a minimum, constrain it to requests for pages
RewriteRule (^|/|\.php)$ etcetera


That's assuming these are page parameters. Queries attached to stylesheets or images are not unheard of. But you don't often see the same parameters as for page requests.


* Yes, yes, OK, or possibly any one of an [OR]-delimited list of Conditions if there is nothing after the list.

vandedeenterprise

12:13 am on Dec 17, 2014 (gmt 0)

10+ Year Member



Hi lucy, thank you for your answer. Not sure I totally got what you mean but I have actually managed to get it working with some new info from other forum.

I have included the code currently working and a bit more of my .htaccess so you can see what else it going on:

RewriteCond %{QUERY_STRING} (?:^|&)aid=([a-z0-9]+)(?:&|$) [NC]
RewriteRule ^ - [CO=aid:%1:example.com:14400:/]
RewriteCond %{QUERY_STRING} (?:^|&)tag=([a-z0-9]+)(?:&|$) [NC]
RewriteRule ^ - [CO=tag:%1:example.com:14400:/]
RewriteCond %{QUERY_STRING} (?:^|&)flu=([a-z0-9]+)(?:&|$) [NC]
RewriteRule ^ - [CO=flu:%1:example.com:14400:/]
RewriteCond %{QUERY_STRING} (?:aid|tag|flu)=.+ [NC]
RewriteRule ^(.*)$ $1? [R=301,L]

RewriteRule ^([a-z]+)/(cat1|cat2|cat3|cat4)(|/)$ $1/?$2=show [NC,L]
RewriteRule ^([a-z]+)/([a-z0-9-_]+)(|/)$ / $1/?load=$2[NC,L]


Any comments are welcome, but it seems to work for me.

lucy24

2:29 am on Dec 17, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Oh, yes, that will work. It's an unusual ordering, because you have to put the [CO=blahblah] rules (without even an [L] flag) before the [R=301,L] rules. But the result is clean: cookies get set, and there's only one redirect.

Now, personally I would say
[^&]+
instead of
[a-z0-9]+ [NC]
This covers absolutely all possible parameter values. But the difference is probably not crucial.

In the target of your internal rewrites (the last two rules), start with / (leading slash). This is safer than relying on a RewriteBase.

Most important: Do, please, use something for the "pattern" selector instead of the bare ^. Otherwise the server has to backtrack and evaluate conditions on every single request ever-- even if it's for something like a stylesheet or robots.txt that will never have the parameters.

Incidentally, a target in the form
/blahblah/?querystring

will work. But it forces the server to go look up your DirectoryIndex file every time. So you may as well say /index.php explicitly. And then you can take this "index.php" and plug it into the pattern of all the earlier rules-- the ones that set cookies.

vandedeenterprise

6:47 am on Dec 17, 2014 (gmt 0)

10+ Year Member



Hi again, think I got all your points except this:

Most important: Do, please, use something for the "pattern" selector instead of the bare ^.

Please explain further or maybe just give example? Are you talking about the rules that set's cookies ?

lucy24

8:24 am on Dec 17, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Are you talking about the rules that set cookies ?

Yes: the ones that currently look like this:
RewriteRule ^ - [CO=aid:%1:example.com:14400:/]


In mod_rewrite, conditions are only evaluated if the pattern in the rule potentially matches. Since the "pattern" in each of these rules is simply "^" (meaning "any request"), the server has to stop and evaluate the RewriteCond on every single request, ever.

If instead the pattern says something like
RewriteRule index\.php - [CO=aid:%1:example.com:14400:/]

then the server only has to evaluate the condition when the request is for the specific file "index.php". (Substitute the actual name of the physical file involved.)

:: making a note to remember the cookie-setting rules, because the rule ordering is just the kind of thing that's so simple, I would never have thought of it :( ::