In htaccess, are the following conditions exactly the same?
RewriteCond %{HTTPS}s ^on(s)|
vs
RewriteCond %{HTTPS}s ^on(s) [or]
Is the pipe symbol simply a shorter way for using [or]?
Is the pipe symbol simply a shorter way for using [or]
No it is not. pipe (alternation) with no matching text after | is provided in RewriteCond to always return true but [or] will attempt to evaluate next RewriteCond when HTTPS is not on.
Related
I'm using Helicon Ape on a Windows Server to create htaccess files.
Originally, part of a larger set of conditions, I had this condition set to return 403 if the url contained (). However it is causing false positives in case of mailchimp tracking codes that end up getting wrapped in ()
RewriteCond %{QUERY_STRING} ^.*(\[|\]|\(|\)|<|>).* [NC,OR]
For example in the below URL
http://domain.com/page/11/page-name?ct=t(Newsletter_Tracking)
As an alternative, I was attempting to remove the parenthesis and redirect to a "cleaned version".
I tried a few different things that I found in SO but none worked.
So far the closest thing that I could get to working is this:
RewriteCond %{REQUEST_URI} [\(\)]+ [OR]
RewriteCond %{QUERY_STRING} [\(\)]+
RewriteRule ^(.*)[\(]+([^\)]*)[\)]+(.*)$ $1$2$3 [R=301,L]
The problem with the above code is that works if the () were in the URL but not the query string. It doesn't redirect and clean the querystring.
So this would work:
http://domain.com/page/11/pag(e-name)
but this wouldn't:
http://domain.com/page/11/page-name?ct=t(Newsletter_Tracking)
Your assistance is appreciated
Thank You.
You can use the following rule :
RewriteCond %{THE_REQUEST} /page/11/page-name\?ct=t\(Newsletter_Tracking\)\sHTTP [NC]
RewriteRule ^ %{REQUEST_URI}? [L,R]
If the querystring is dynamic, try:
RewriteCond %{THE_REQUEST} /page/11/page-name\?ct=.+\(.+\)\sHTTP [NC]
RewriteRule ^ %{REQUEST_URI}? [L,R]
Using #starkeen 's example, I was able to create a working solution.
This code handles the Query String separate from the URL. It cleans the URL but removes the query string.
RewriteCond %{REQUEST_URI} [\(\)]+
RewriteRule ^(.*)[\(]+([^\)]*)[\)]+(.*)$ $1$2$3 [R=301,L]
RewriteCond %{QUERY_STRING} [\(\)]+
RewriteRule ^ %{REQUEST_URI}? [R=301,L]
I'm trying to get a series of rewrite conditions working, with the logic being this
if condition1 or
(condition2 and condition3) or
..
This is what I have in the .htaccess:
RewriteCond %{HTTP_USER_AGENT} "iphone" [OR,NC]
RewriteCond %{HTTP_USER_AGENT} "android&mobile" [OR,NC]
RewriteCond %{HTTP_USER_AGENT} "iemobile" [NC]
Unfortunately, it looks like the and operator isn't working as I thought it would.
(as you might guess, the idea is to detect android phones but not tablets)
Is there a way to write that and condition to achieve the results I'm looking for?
Thanks.
Unfortunately, the [OR] flag doesn't work as nice enough for it to be useful, it only works for either all "or"'d or all "and"'d conditions. It's not very predictable. What you may need to do is separate them out to several rules and either use the S flag to skip stuff or the pass-through.
Maybe something along the lines of:
# Prevent rewrite looping
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
# if "iphone" OR
RewriteCond %{HTTP_USER_AGENT} "iphone" [NC]
RewriteRule ^ - [S=3]
# "android" AND "mobile", OR
RewriteCond %{HTTP_USER_AGENT} "android" [NC]
RewriteCond %{HTTP_USER_AGENT} "mobile" [NC]
RewriteRule ^ - [S=2]
# "iemobile"
RewriteCond %{HTTP_USER_AGENT} "iemobile" [NC]
RewriteRule ^ - [S=1]
# skip everything, none of the conditions match
RewriteRule ^ - [L]
# apply the rule
RewriteRule ^ /do-something [L]
Looks like a mess but that's mod_rewrite for you.
The first rule is to prevent any sort of internal rewrite looping. The "# skip everything" rule is the one that gets applied if none of the 3 conditions match, it essentially does nothing excepts stops any rewriting. If you have other rules after all of this stuff that you want to get applied, you can replace the L flag with S=1.
The last rule is the rule that gets applied if any of the 3 conditions matches.
When I have multiple RewriteCond chained together, only the capture groups of the last RewriteCond can be referenced with %0-%9.
In the following problem the parameters in the query string of the url can be in any order. To parse them into a fancy url I would need to match each parameter in the query string individually:
RewriteCond %{QUERY_STRING} param1=([^&]+)
RewriteCond %{QUERY_STRING} param2=([^&]+)
RewriteCond %{QUERY_STRING} param3=([^&]+)
RewriteRule ^foo$ bar/%1/%2/%3/ [R]
Like I pointed out... this doesn't work. To fix this, I could reference the capture group of the previous RewriteCond in the next RewriteCond and 'propagate' each parameter to the actual RewriteRule:
RewriteCond %{QUERY_STRING} param1=([^&]+)
RewriteCond %1&%{QUERY_STRING} ^([^&]*)&.*param2=([^&]+)
RewriteCond %1&%2&%{QUERY_STRING} ^([^&]*)&([^&]*)&.*param3=([^&]+)
RewriteRule ^foo$ bar/%1/%2/%3/ [R]
This should work, but for each additional parameter it get's messier. An other solution could possibly be parsing one parameter and redirecting the client after each parameter (resulting in a lengthy chain of redirects, which I would like to avoid).
Is there an cleaner way of accessing the capture groups of all RewriteCond's in the RewriteRule (e.g. is it possible to name them or assign them to a variable so I can reference them somewhere else?)
You could try constructing the target URL inside the rewrite conditions:
RewriteCond ##%{QUERY_STRING} (.*)##(|.*&)param1=([^&]+)
RewriteCond %1/%3##%{QUERY_STRING} (.*)##(|.*&)param2=([^&]+)
RewriteCond %1/%3##%{QUERY_STRING} (.*)##(|.*&)param3=([^&]+)
RewriteCond %1/%3##%{QUERY_STRING} (.*)##(|.*&)param4=([^&]+)
RewriteCond %1/%3##%{QUERY_STRING} (.*)##(|.*&)param5=([^&]+)
RewriteCond %1/%3##%{QUERY_STRING} (.*)##(|.*&)param6=([^&]+)
RewriteRule ^foo$ /bar%1/%3? [L,R]
When I try to request:
/foo?param1=a¶m2=b¶m6=3¶m3=4¶m5=5¶m4=6
I get redirected to:
/bar/a/b/4/6/5/3
Adding any additional required query string parameters won't make it look any more messy than it already is.
After experimenting some more, it would be possible to parse all parameters as environment variables and use them like that. I doubt it is very efficient though and I think any use-case that would need such a construction would be better of using a php page router. For fancy url's Jon Lin's solution would probably work better. It does however sort-of mimic what I had in mind.
I'll, however, put the code in here for demonstration:
#Parse all query key-value pairs to an environment variable with the q- prefix
RewriteCond %{QUERY_STRING} ^([^=]*)=([^&]*)(&(.*)|$)$
RewriteRule ^(.*)$ $1?%4 [E=q-%1:%2,N]
#If 'param1' existed in the query string...
RewriteCond %{ENV:q-param1} !^$
RewriteRule ^foo$ bar/%{ENV:q-param1} [END]
or even...
#Keep the original query string
RewriteCond %{ENV:qstring} ^$
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule .* - [E=qstring:#%1]
#parse the query parameters to environment variables
RewriteCond %{ENV:qstring} ^#([^=]*)=([^&]*)(&(.*)|$)$
RewriteRule ^(.*)$ - [E=q-%1:%2,E=qstring:#%4,N]
#See that the original query string is still intact
RewriteCond %{ENV:q-param1} !^$
RewriteRule ^foo$ bar/%{ENV:q-param1} [QSA]
I am looking for a solution where i can define the muliple match statement whitin the single RewriteCond statement,
The scenario is i want to redirect to home page if any of this string comes in the url:
/it/, /de/, /fr/
I tried to wrote it like this:
This is throwing SERVER ERROR:
RewriteCond ^(/it/ | /de/ | /fr/ )
RewriteRule 'myhomepageurl'
I also tried this way too:
RewriteCond /it/ [OR]
RewriteCond /de/ [OR]
RewriteCond /fr/ [OR]
RewriteRule 'myhomepageurl'
This was giving unexpected results page loding infinite and admin was blocked. So i finaly took this way:
RewriteCond /it/
RewriteRule 'myhomepageurl'
RewriteCond /de/
RewriteRule 'myhomepageurl'
RewriteCond /fr/
RewriteRule 'myhomepageurl'
I am just curious about the single statement that can do this in single shot.
Thanks
Your first example is failing because of the spaces; a better regex would be something like
RewriteCond ^/(it|de|fr)/
RewriteRule 'myhomepageurl'
Either way, you should read When Not To Use Rewrite and use one of the simpler forms suggested there, e.g.
RedirectMatch /(it|de|fr)/ /myhomepageurl
Try this:
RewriteCond %{REQUEST_URI} /(en|de|it)/
RewriteRule .* myhomepageurl [R=301,L]
I am trying to create a mod_rewrite rule to direct people to a sub-folder. Currently the code looks as follows:
RewriteEngine On
RewriteCond %{HTTP_HOST} abcsite.com$ [OR,NC]
RewriteCond %{HTTP_HOST} ^!www\.abcsite\.*$
RewriteCond %{REQUEST_URI} !^/abc/.*$
RewriteRule (.*)$ /abc/$1 [L]
The redirect works if the user types www.abcsite.com, but not if they type abc.com. Is there something that I am missing or should do differently to make sure the user goes to the correct folder (regardless of how they type the URL)?
Side note: The htaccess file that I am dealing with is a Joomla file, so all contents of it deal with another Joomla site. I appreciate the help.
Because you have conditions for that.
RewriteCond %{HTTP_HOST} abcsite.com$ [OR,NC]
RewriteCond %{HTTP_HOST} ^!www\.abcsite\.*$
RewriteCond %{REQUEST_URI} !^/abc/.*$
All above rules will pass only its abcsite.com
You add following rules also then it work for abc.com too.
RewriteCond %{HTTP_HOST} abc.com$ [OR,NC]
RewriteCond %{HTTP_HOST} ^!www\.abc\.*$
RewriteCond %{REQUEST_URI} !^/abc/.*$
RewriteRule (.*)$ /abc/$1 [L]
There's a stray ! in your second condition. A ! in front of the pattern means that the condition is true when the regex doesn't match (like in the third condition). A ! inside the pattern is just a literal symbol.
The host conditions should be something like:
RewriteCond %{HTTP_HOST} ^abcsite\.com$ [OR,NC]
RewriteCond %{HTTP_HOST} ^www\.abcsite\.com$ [NC]
And in fact, they can be joined into a single condition (note, no [OR] here):
RewriteCond %{HTTP_HOST} ^(www\.)?abcsite\.com$ [NC]
Your third condition is intended to prevent redirect loops (/foo → /abc/foo → /abc/abc/foo → …). What it says is that the rule isn't applied if the request URL starts with /abc/. However, your actual redirect is an internal redirect: if a user accesses abcsite.com/foo, the server internally rewrites this to /webroot/abc/foo, but REQUEST_URI stays the same, /foo.
The reason this doesn't cause a redirect loop as it is is likely rewrite rules in abc/.htaccess which override this one once the redirect is done.
What should be checked instead in the third condition is the path matched by the rewrite rule:
RewriteCond $1 !^abc/
RewriteRule (.*) /abc/$1 [L]