Search code examples
phpapache.htaccesscodeignitermod-rewrite

htaccess redirect to https not working in codeigniter 3


I found a lot of similar answers but so far I could not solve the right thing that I want. It seems very easy or maybe somebody already answered but for me it's not working.

I've solved redirect to https on TLD (http://example.com to https://www.example.com and https://example.com to https://example.com)

But my htaccess code doesn't redirect to https://www.example.com/whatever from http://example.com/whatever or https://example.com/whatever.

In other words, everything must be redirected to https://www

Here's my .htaccess:

RewriteCond $1 !^(index\\.php|resources|robots\\.txt)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]

RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

I'm using codeigniter 3.11, in config.php

$config['base_url'] = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") ? "https" : "http");
$config['base_url'] .= "://".$_SERVER['HTTP_HOST'];
$config['base_url'] .= str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']);

Is there any mistake on my .htaccess?


Solution

  • I've solved redirect to https on TLD (http://example.com to https://www.example.com and https://example.com to https://example.com)

    (I assume you mean https://www.example.com/ in the last URL. And by "TLD" you really mean the "root directory" (or "document root" or "homepage").)

    The only reason this works is that the first rule (the internal rewrite to index.php - the front-controller) is not triggered when requesting the document root. (index.php is served by mod_dir instead in this case.)

    However, you don't appear to have tested http://www.example.com/ (HTTP + www) which would have resulted in a broken redirect to https://www.www.example.com (doubling the www).

    RewriteCond $1 !^(index\\.php|resources|robots\\.txt)
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php?/$1 [L,QSA]
    
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    

    Your rules are in completely the wrong order. The canonical redirects need to be before your rewrite to the CI front-controller, otherwise they are simply never processed for requests to non-assets (since the request is routed to index.php first - the CI front-controller).

    However, the canonical redirects themselves are also in the wrong order (and/or incorrect) since a request for http://www.example.com/ (HTTP + www) would be erroneously redirected to https://www.www.example.com/ (as already mentioned above).

    Aside: You also have erroneous double backslashes in the regex (CondPattern) of the first condition (RewriteCond directive). This would match a literal backslash - which will never happen, so the first condition is always successful (since it's a negated expression).

    Your rules should be something like this instead:

    # Canonical redirects
    
    # non-www to www (and HTTPS)
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    
    # HTTP to HTTPS
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    
    
    # Front-controller
    RewriteCond $1 !^(index\.php|resources|robots\.txt)
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule (.*) index.php?/$1 [L,QSA]
    

    This assumes you are not implementing HSTS by minimising the number of canonical redirects. (If you do implement HSTS then you need to reverse the two rules - canonical redirects - above as you need to redirect from HTTP to HTTPS on the same host first - which would potentially result in two redirects when requesting HTTP + non-www.)

    I also modified the HTTP to HTTPS redirect to be consistent with your non-www to www rule, ie. to use the REQUEST_URI server variable instead of a backreference. For some reason you were using a backreference in one and REQUEST_URI in the other, with different regex. ^ is more efficient than .* here as you simply need the rule to be successful, you don't need to actually match anything.