I have a rule that translates old-style urls into new style. It works ok as long as I use the same order of parameters in the query:
RewriteCond %{QUERY_STRING} ^country=([a-z]{2})&id=([0-9]+)$ [NC]
RewriteRule ^(.*)$ http://%1.localhost/%2? [R=301,L]
So url localhost/index.php?country=us&id=1234 would go to us.localhost/1234
But the problem is that using localhost/index.php?id=1234&country=us (note that arguments are now swapped in order) then the rule of course doesn't apply.
I thought about changing the rule to handle arguments separately, like this:
RewriteCond %{QUERY_STRING} country=([a-z]{2}) [NC]
RewriteCond %{QUERY_STRING} id=([0-9]+) [NC]
RewriteRule ^(.*)$ http://%1.localhost/%2? [R=301,L]
But when entering localhost/index.php?id=1234&country=us I get 1234.localhost/us which is not what I expect (I'd expect first cond to give me %1 and second cond %2 but it seems the order isn't determined this way)
Is there any easy way to achieve this? Of course I could write two separate rules each handling each case, but was wondering if some generic approach could be used (think if we had 3 parameters then permutations would make this unmanageable)
From the documentation, it looks like you can only reference rules from the last match:
RewriteCond backreferences: These are backreferences of the form %N (0 <= N <= 9). %1 to %9 provide access to the grouped parts (again, in parentheses) of the pattern, from the last matched RewriteCond in the current set of conditions. %0 provides access to the whole string matched by that pattern.
I've been racking my brains on a good way to do this and the best I can come up with is to use multiple rules to extract the data into environment variables and then reference those at the end for your final rewrite.
Something like this:
RewriteCond %{QUERY_STRING} country=([a-z]{2}) [NC]
RewriteRule ^(.*)$ - [E=URL_COUNTRY:%1]
RewriteCond %{QUERY_STRING} id=([0-9]+) [NC]
RewriteRule ^(.*)$ - [E=URL_ID:%1]
RewriteRule ^(.*)$ http://%{ENV:URL_COUNTRY}.localhost/%{ENV:URL_ID}? [R=301,L]
Related
Basically, I am sent a query string that I need to reformat into a URL where the values are divided by slashes and where the dots are cleared out of one of the values. I can do either of those things, but when I try to chain them together it doesn't work.
Here is the original URL
https://www.example.com/?id1=5&id2=7&id3=9&id4=7&id5=source.website.com&id6=5
Here is what I have right now ...
# Takes the dots and replaces name of server
RewriteCond %{QUERY_STRING} ^(.*source.website.com.*)$
RewriteCond %{QUERY_STRING} (.*id5=).*(id6=.*)$
RewriteRule ^(.*) %1newwebsitecom&%2?
# Rewrites Query to URL
RewriteCond %{QUERY_STRING} ^id1=(\w+)&id2=(\w+)&id3=(\w+)&id4=(\w+)&id5=([a-zA-Z0-9\.\%]+)&id6=(\w+)
RewriteRule ^(.*) https://www.example.com/dir/%1/%2/%3/%5/%6?
Separately, both of these work. However, the second rule simply takes the query and performs the actions as if the first never took place. How do I get around that?
Have you tried merging the two rules?
I've tested this rule set on htaccess.madewithlove.be and it seems to achieve the desired results.
RewriteCond %{QUERY_STRING} ^(.*source.website.com.*)$
RewriteCond %{QUERY_STRING} (.*id5=).*(id6=.*)$
RewriteCond %{QUERY_STRING} ^id1=(\w+)&id2=(\w+)&id3=(\w+)&id4=(\w+)&id5=([a-zA-Z0-9\.\%]+)&id6=(\w+)
RewriteRule ^(.*) https://www.example.com/dir/%1/%2/%3/%4/newwebsitecom/%6?
I am setting a cookie using rewrite rules, and that is working (simplified for the sake of brevity):
RewriteCond %{QUERY_STRING} set_cookie=1 [NC]
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI}?skip=1 [QSA,NE,NC,L,CO=test_%{HTTP_HOST}:tmp:%{HTTP_HOST}:5:/]
This one sets a cookie with the name test_{host_name}. Now I want to read that cookie value the next request. I tried this (and some variants), but that does not seem to work.
RewriteCond %{QUERY_STRING} skip [NC]
RewriteCond %{HTTP_COOKIE} ^.*test_%{HTTP_HOST}=tmp.*$ [NC]
RewriteRule ^(.*)$ - [L]
When I was googling, I found an article that stated the following:
If you are wondering, "Why not use %{HTTP_HOST} instead of corz.org,
create universal code?", as far as I know, it's not possible to test
one server variable against another with a RewriteCond without using
Atomic Back References and some serious POSIX 1003.2+ Jiggery-Pokery.
I guess that's my problem, but I am sort of at a loss on how to solve it. Any help is greatly appreciated.
Regards,
Joost.
There's a useful trick in this area. It is simple regex, but a unique kind of mod_rewrite style.
Note I am not too careful about the matching here especially in the first condition -- this is for illustration in the 2nd condition:
RewriteEngine ON
RewriteCond %{HTTP_COOKIE} test_([^;]*)=tmp.*$
RewriteCond %1<>%{HTTP_HOST} ^(.+)<>\1
RewriteRule .* - [F]
The novel part (for mod_rewrite) is that you can only use variables/backrefs in the first argument, but you can use backrefs (for the current expression, not the preceding one) in the 2nd parameter.
The little <> is just something unlikely to appear as a separator.
I have found a solution. This part in my original question
RewriteCond %{QUERY_STRING} skip [NC]
RewriteCond %{HTTP_COOKIE} ^.*test_%{HTTP_HOST}=tmp.*$ [NC]
RewriteRule ^(.*)$ - [L]
should be replaced by the following
RewriteCond %{QUERY_STRING} skip [NC]
RewriteCond %{HTTP_HOST}##%{HTTP_COOKIE} ^([^#]*)##.*test_\1=tmp.* [NC]
RewriteRule ^(.*)$ - [L]
Only the second RewriteCond has changed. Its left hand side (%{HTTP_HOST}##%{HTTP_COOKIE}) concatenates the http host and cookie values, using ## as glue (## doesn't really mean something, it's just unlikely to be used in a normal host or cookie string).
The right hand side (^([^#]*)##.*test_\1=tmp.*) matches everything to the first "#", which is the host name, and then checks if it can be found somewhere in the cookie values, preceded by "test_" and followed by "=tmp".
I'm working on a virtual domain system. I have a wildcard DNS set up as *.loc, and I'm trying to work on my .htaccess file. The following code works:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www.)?example\.loc$ [NC]
RewriteCond %{REQUEST_URI} !^/example/
RewriteRule (.*) /example/$1 [L,QSA]
But, I want this to work with anything I put in. However, I need the %{REQUEST_URI} checked against the text found as the domain. I tried using this code:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www.)?([a-zA-Z0-9-]*.)?([a-zA-Z0-9-]+)\.loc$ [NC]
RewriteCond %{REQUEST_URI} !^/%3/
RewriteRule (.*) /%3/$1 [L,QSA]
But the line RewriteCond %{REQUEST_URI} !^/%3/ causes my code to throw an Internal Server Error. I understand this is because of the %N in my code but is there a way I can work with it? I need this line, otherwise, my code fails from internal redirects.
I hope this makes sense to someone. All I need is to be able to backreference a RewriteCond in a following RewriteCond.
There's 2 things that you are doing wrong here.
First, your %{HTTP_HOST} regex is no good. You need to escape the . dots otherwise they'll be treated as "any character that's not a newline". This essentially makes the %3 backreference the last character of the hostname before the TLD (e.g. http://blah.bar.loc, %3 = r).
Second, you can't use backreferences in the regex of a RewriteCond, only the left side string, it's sort of a weird limitation. However, you can use the \1 references, in the regex so that you can construct a clever left side string to match against. Something like %3::%{REQUEST_URI} and then you can match like this: !^(.*?)::/\1/?. This regex essentially says: "match and group the first block of text before the ::, then make sure the block of text following the :: starts with /(first block)".
So your rules should look like this:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?([a-zA-Z0-9-]*\.)?([a-zA-Z0-9-]+)\.loc$ [NC]
RewriteCond %3::%{REQUEST_URI} !^(.*?)::/\1/?
RewriteRule (.*) /%3/$1 [L,QSA]
I have queries of this form going towards my server:
http://my.host.com/moo?p=1&s=2&targetURL=http://foo.com/sub/more/query
What I need to do is replace a part of the parameter of this query, specifically I need to replace http://foo.com/sub/ with http://bar.com/, preserving all the other parameters in this query and also preserving the parameters of http://foo.com/sub/more/query. I would be content with just replacing it in targetURL, so I tried this:
RewriteCond %{REQUEST_URI} ^/moo
RewriteRule ^/moo(.*)targetURL=http://foo.com/sub(.*)$ http://other.host.com/moo$1targetURL=http://bar.com$2 [L,R]
RewriteRule ^/moo(.*)$ http://other.host.com/moo$1 [L,R]
But the first query just never matches. Any help?
EDIT: To make clear, I have this:
http://my.host.com/moo?p=1&s=2&targetURL=http://foo.com/sub/more/query
and I want it to become this:
http://other.host.com/moo?p=1&s=2&targetURL=http://bar.com/more/query
Try this:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^my\.host\.com [NC]
RewriteCond %{QUERY_STRING} ^(.*)targetURL=http://foo.com/sub/(.*)$
RewriteRule ^/?moo$ http://other.host.com/moo?%1targetURL=http://bar.com/%2 [L,R=301]
You need to match the targetURL=http://foo.com/sub/ part from within the %{QUERY_STRING} variable using a RewriteCond. The query string isn't part of the URI when a RewriteRule matches against it. You can then use the %1 and %2 back references to reference the groupings matched in the query string.
Try this version which i tested and works for me.
<i>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^my\.host\.com/moo [NC,OR]
RewriteCond %{QUERY_STRING} ^p\=1\&s=2\&targetURL\=http\:\/\/foo.com/sub/more/query$ [NC,OR]
RewriteRule ^/(.*) http://other.host.com/moo?p=1&s=2&targetURL=http://bar.com/more/query/$1 [R=301,L]
</IfModule>
How can I make that if the QUERY_STRING matches something it would use that rule?
Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteRule ^(.*)/?$ index.php?uri=$1 [L,QSA]
RewriteCond %{QUERY_STRING} uri=admin
ReqriteRule ^admin\?(.*)/?$ index.php?uri=admin&q=$1 [L,QSA]
Eg. http://localhost/admin?poll/new
After the ? should be the paramater q, the the query would be uri=admin&q=poll/new
Any idea on how I could do this?
Thanks.
Well, it happens that your problem is more simple than the link I gave you as you do not want any analysis on the query string content.
If you use this single line:
RewriteRule ^admin index.php?uri=admin&q= [L,QSA]
Where QSA mean append the query string to the result. You will obtain an internal redirection to:
index.php?uri=admin&q=&poll/new
Which is not OK, this is because the way you use argument (admin?poll/new) is not the standard way. So it seems we'll need to capture the query string content and put it by hand on the rewriteRule. This should work (if you need it only for /admin url):
RewriteCond %{REQUEST_FILENAME} admin [NC]
RewriteCond %{QUERY_STRING} (.*) [NC]
RewriteRule .* index.php?uri=admin&q=%1 [L]
Where %1 is the first parenthesis match in the RewriteCond :(.*), meaning everything in the query string, the query string being anything after the question mark. So in fact this allows admin?poll/new but also admin?poll/new&foo=toto, giving index.php?uri=admin&q=poll/new&foo=bar