HTTPS RewriteCond with two / routes - mod-rewrite

i have n URL like this:
http://name.co/othername/xname
http://name.co/othername/yname
So name.co/othername are equal. Just the 'xname' is changing to a different.
I need a redirect to the HTTPS Side.
I tried this:
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
but the result was not correct. it would be nice if someone could help me

REQUEST_URI will exclude the query string. Also, you need flags, at least [R] and usually [L] as well. You will probably want a 301 redirect in this case, unless you think you are likely to turn this off later. Try replacing the RewriteRule you have with:
RewriteRule (.*) https://%{SERVER_NAME}/$1 [R=301,L]
The R flag means to actually send a redirect to the browser as opposed to just changing how the URL is handled insternally; the L flag means this is the last directive that should be processed; it shortcuts the rest of the processing and avoids any additional changes made by other rules.

Related

mod-rewrite rules executing out of order

Okay, so I have two separate mod-rewrite rules in my vhost block. The first rule redirects a customer offsite if they come in thru an affiliate URL such as example.com/1234.html and the second rule forces the URL to always contain www dot like www.example.com.
# Affiliate Links
RewriteRule ^([0-9]+)\.html$ http://affiliates.example.com/log.php?id=$1 [R=302,L]
# Ensure we are always on www dot
RewriteCond %{HTTP_HOST} ^example\.loc [NC]
RewriteRule (.*) http://www.example.com$1 [R=301,L]
The rules themselves work great. The problem is that if the first rule applies I want it to immediately redirect, however it seems as if the second rule is hoisted to the top because it always takes precedence. What do I need to change so that these execute in order?
You've stated that this is in a vhost block. In that context (as opposed to, for example, an .htaccess file) URLs always start with '/'
Thus
RewriteRule ^([0-9]+)\.html$ http://affiliates.example.com/log.php?id=$1 [R=302,L]
should instead be
RewriteRule ^/([0-9]+)\.html$ http://affiliates.example.com/log.php?id=$1 [R=302,L]
(ie, with the leading slash), otherwise it will never match anything.

Mod Rewrite + QSA : Same querystring param in rewrite target and in querystring - Force use of target possible?

We have the following rewrite rule:
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?rewrite=$1 [L,QSA]
We were wondering if there was a way to have the ?rewrite=$1 take precedence over one that is passed via the query string in the request uri?
Because as it stands now, due to the QSA flag (which we do need btw) if the following url is hit:
http://www.domain.com/this_rewrite_will_match_the_above_rule?rewrite=some_value
The value of $_GET['rewrite'] in PHP will be some_value, and not this_rewrite_will_match_the_above rule.
Before we go in and start modifying the rewrites and adding a RewriteCond to match the query string, etc etc... We were hoping there was a flag to set so that the target url (index.php?rewrite=$1 in this case) took precedence over the passed query string values.
Hope this makes sense.
Thanks.
Slightly hackish
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%{QUERY_STRING}&rewrite=$1 [L]
This works because, in php, the second rewrite=... overwrite the first.
I have searched for some mechanics to override single querystring parameters in an Apache rewrite multiple times and quite intensely, but it looks like there is no option to do that, even with the latest Apache version (2.4.3 at the time of this writing).
But there is an alternative that makes use of the fact that the PHP querystring parser only returns the last of multiple idententical querystring parameters.
Example:
http://www.domain.com/index.php?id=123&id=456
This will return the following single (!) entry in $_GET:
array(1) {
["id"]=>
string(3) "456"
}
So you can solve your problem by simply appending any override parameters to the end of your existing querystring (without removing them within the querystring). The last occurrence of a repeated parameter is the one that makes it into the $_GET array.
Unfortunately the QSA switch is not suitable for this technique, as it always appends the original parameters to the end of the new querystring. There is no switch that would preprend the old parameters. So you have to take a little detour with a RewriteCond to catch and prepend the original querystring yourself instead of using QSA:
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%1&rewrite=$1 [L]
The only function of the RewriteCond is to capture the querystring in %1. The regexp (.*) of the condition is always matched, so the following RewriteRule is always executed.
With this technique your above testcase will rewrite to...
http://www.domain.com/index.php?rewrite=some_value&rewrite=this_rewrite_will_match_the_above_rule
...which will be interpreted by the PHP querystring parser to
$_GET["id"] => "this_rewrite_will_match_the_above_rule"
...which is what you want.
Please be aware that this will work only if you take your querystring values from PHP's $_GET array. It will not necessarily work if you parse the content of $_SERVER["QUERY_STRING"] yourself or if you use any other programming language.
I have opted to create an answer of my own, because its slightly cleaner then the examples provided by Jpsy and Gerben.
Credit where credit is due, their suggestions are what got me here, I only expanded on them:
So, our final solution includes 2 rules.
# check if querystring is not empty (this is the addition vs other answers)
RewriteCond %{QUERY_STRING} !^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%{QUERY_STRING}&rewrite=$1 [L]
if the above query string fails (mainly, the querystring is empty) this rule will apply.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?rewrite=$1 [L]
The reason I opted to go for this dual rule setup is to avoid having the php server variables polluted with "?&rewrite=...." if the query string is empty.
Thanks to jpsy and gerben for the help.
I used the following instructions:
RewriteRule ([^\?]*)\?(.*) $1?$2 [N] (1)
RewriteCond %{QUERY_STRING} (.*?)&?(rewrite=[^&]+)&?(.*)
RewriteRule ^(.*)$ $1?%1&%3 [N] (2)
RewriteRule ^(.*)$ $1?domain=newValue [L,QSA] (3)
The trick is done by the [N] flag in the first two rules, which causes to rewrite engine to re-process the output.
Rule (1) simple rewrites the url as it is. I needed it because I'm using mod_rewrite togheter with mod_proxy_ajp and in the first iteration the query string is not splitted from the url. After the execution of the first line, the url is unchanged but the engine will split the path from the query string.
Rule (2) iterates and removes all occurrences of the parameter "rewrite" from the query string.
Rule (3) sets the new value for the parameter and appends whichever query string survives from the replacement done by rule (2).

RewriteRule domain which contains '?'

I want to have RewriteRule where domain's /page/test or /page/test/ go to www.domain.com. Only for this two example.
I try:
RewriteRule ^/page/test/?$ http://www.domain.com [R=301,L,NC]
This will be good but I have other pages like /page/test/?D_test
and when I put RewriteRule, redirect also /page/test/?D_test. Problem is '?'. How should I write my rule to don't rewrite another page's to www.domain.com ? for example
/page/test/?D_test /page/test/(.*)
I'm not sure I understand your question. You are either asking how can I redirect all the traffic including the query string to the domain and take off the query string. In that case I usually do it this way:
RewriteRule ^/page/test/?$ http://www.domain.com? [R=301,L,NC]
If you want to make it so it doesn't redirect if there is a query string then you have to use a rewrite conditional.
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^/page/test/?$ http://www.domain.com? [R=301,L,NC]

Basic help with mod_rewrite conditions

Hi. I am new to mod_rewrite and was wondering if it was possible to do the following:
RewriteRule ^([^/]*)$ index.php?slug=$1
This rule will point only at index.php but if I wanted to do another rule that pointed a specific slug to a different script, i.e.
RewriteRule ^a-new-page$ different.php
This would not work because the first rule has declared anything that is entered should point at index.
Is there a way to force the new rule for that specific slug?
Yes, it is possible -- just place such specific rule before generic/broad one (the order in which rules are declared matters):
RewriteRule ^a-new-page$ different.php
RewriteRule ^([^/]*)$ index.php?slug=$1
Also please pay attention to the broad rules -- they may enter into a rewrite loop (after rewrite new URL goes into next iteration, and if rule is not written right it may enter endless loop which Apache will have to forcedly terminate and your user will see an 500 error page instead). Better rule will be:
# specific rule
RewriteRule ^a-new-page$ different.php [L,QSA]
# broad rule (will be triggered if requested resource is not a file or directory)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)$ index.php?slug=$1 [L,QSA]
[L] tells Apache to stop rewriting if this rule matches
[QSA] tells to append query string to a new URL (useful if you have URL parameters: e.g. tracking data, page parameters etc).
Useful Link: http://httpd.apache.org/docs/current/rewrite/

Isapi Rewrite: from www to non-www and at the same time from http to https

i have tried it all!
this:
RewriteCond %{HTTP_HOST} ^www\.(.*)
RewriteRule ^.*$ https://%1/$1 [R=301,L]
works only if i don't put the http at the beggining
how do make that to work:
if there is http redirect to https
if there is www redirect to non-www
and ofcourse both on the same time
http://www.domain.com -> https://domain.com
www.domain.com --> https://domain.com
http://domain.com --> https://domain.com
with every subfolders after and query!
I assume you also want
https://www.domain.com -> https://domain.com
Did you ever get this working? I'm having trouble getting a test https site going to double-check this.
In the meantime, I do see a couple things, so try this instead (this assumes isapi_rewrite v3, which it looks like you're using):
RewriteCond %{HTTP_HOST} ^www\.(.*)
RewriteRule ^(.*)$ https://%1$1 [NC,R=301]
This adds parentheses to the RewriteRule to capture the url for the $1.
Then the slash between the %1$1 isn't needed, since there's one at the start of the $1 capture.
I like to use NC for not case-sensitive, and the R rule is a final rule, so you don't need the L for last.
EDIT
I revisited this answer, to update/clarify a couple of secondary issues in my original answer above. These don't change the main solution above, which was to add the parentheses to do the capture.
Original:
Then the slash between the %1$1 isn't needed, since there's one at the start of the $1 capture.
This actually depends where the rules are, and whether there's a RewriteBase statement. Common shared-host configurations don't have the leading slash here in the rules, so the slash would be needed. If you're not sure, you can try with and without.
Original:
I like to use NC for not case-sensitive, and the R rule is a final rule, so you don't need the L for last.
It turns out it is useful to have L with R for performance, as [NC,R=301,L]. I had actually asked this at Helicon Tech a year before this question, but had forgetten it:
http://www.helicontech.com/forum/14826-Does_Redirect_need_Last.html
From their response:
... the reason for us to use [L] in 301 redirect rules is that redirect occurs not that
immediately. Even though the rule is matched futher rules will be proccessed (run through), unless you have [L]....

Resources