5

I'm building a site in codeigniter. I have a series of rewrite conditions & rules in the .htaccess file. The first set of rules turns SSL on or off depending on the first segment of the uri.

Then it loops through again & if it finds a match, redirects the page appropriately. If there is no match, and the uri does NOT start with any of the strings listed, it redirects you to another page. If no conditions are met, it goes to the index page.

The problem is with my first set of rules that turn SSL on & off. I want to specify that the uri must START with admin or secure. But if I add the ^ to the beginning of the string, everything breaks. Here's what I have:

RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^/?(admin|secure)
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

RewriteCond %{HTTPS} on 
RewriteCond %{REQUEST_URI} !^/?(admin|secure)
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1 [R=301,L]

...specific rewrites here
RewriteRule ^secure-form1$ secure/contract/secure-form1 [L]
RewriteRule ^secure$ secure/article/secure [L]

RewriteCond %{HTTP_HOST} ^www.example.com$ 
RewriteCond %{REQUEST_URI} !^/(admin|form|secure|page)/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/page/article/$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

If I keep the ^ symbol in the first 2 rewrite conditions (https on & off) then http://www.example.com/secure rewrites to https://www.example.com/index.php/secure/article/secure which is the last rewrite rule. The url actually changes to this in the browser.

If I take the ^ symbol out of the first 2 rewrite conditions, then it goes to the right page. But I do need to specify the beginning of the uri because there are other pages that have "secure" in the middle of the uri (and following a slash) that should NOT use SSL.

I can't figure this one out.

user1669830
  • 389
  • 1
  • 3
  • 7

2 Answers2

11

Try this one:

RewriteCond %{HTTPS} off 
RewriteCond %{HTTP_HOST} ^(.*)$ 
RewriteRule ^/?(admin|secure)$ https://%1/$1 [R=301,L]
Ωmega
  • 42,614
  • 34
  • 134
  • 203
9

Old question, I know, but there's another solution that might work better if you really want to stick with the %{REQUEST_URI} condition:

RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_URI} ^/?(admin|secure)$
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

The key difference versus the OP is the inclusion of /? to check for the presence of a forward slash at the beginning of the URI. AFAIK, different Apache installations may or may not include the opening slash in %{REQUEST_URI}.

One benefit of doing it this way is that you can apply the rule to multiple conditions:

RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_URI} ^/?admin$ [OR]
RewriteCond %{REQUEST_URI} ^/?secure$ [OR]
RewriteCond %{REQUEST_URI} ^/?top-secret$
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

For the way I think, this is easier to work with than a long chain of pipe-delimited strings. This comes at the cost of a potential efficiency loss versus a single regex, but there are some other improvements you can make to offset this:

  • Use the lexographically equal operator !=on. If you just use off it gets treated as a regex.

  • Eliminate the RewriteRule pattern, replacing it with a single caret, then use the environment vars %{HTTP_HOST} and %{REQUEST_URI}. This saves the overhead of a longer regex pattern as well as the backrefs.

njbair
  • 1,982
  • 16
  • 14
  • 1
    As you wrote, "different Apache installations may or may not include the opening slash in `%{REQUEST_URI}`". So if not, then your code is wrong, since `%{HTTP_HOST}%{REQUEST_URI}` would not contain any slash delimiter. – Ωmega Jun 02 '16 at 13:01
  • 1
    Great answer. One small problem, though. You mention that REQUEST_URI may or may not include the opening forward slash. So it then seems unusual to rely on it being included when rebuilding the URL. It would seem better to add the slash explicitly to the redirect URL and perhaps capture the path in the RewriteRule or some other solution that does not rely on REQUEST_URI including the slash, so your whole solution covers both setups. Currently, if there is no slash in the REQUEST_URI, the redirect URL will be broken, merging the host with the URI and no slash. Thanks. –  Jun 13 '16 at 01:00
  • These are good points by @Ωmega and @NigelPeck about the missing slash. I suppose I was thinking the slash could be added once you determine the needs of your environment. If you absolutely need to support both cases, one easy fix is to simply include the slash in your rewrite path, since `www.example.com//top-secret` is a valid URI. – njbair Jul 05 '16 at 19:41