15

I'm using Codeigniter and following these instructions to force ssl but all requests are being redirected to

http://staging.example.com/index.php/https:/staging.example.com

My .htaccess is:

### Canonicalize codeigniter URLs

# Enforce SSL https://www. 
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

###
# Removes access to the system folder by users.
# Additionally this will allow you to create a System.php controller,
# previously this would not have been possible.
# 'system' can be replaced if you have renamed your system folder.
RewriteCond %{REQUEST_URI} ^system.*
RewriteRule ^(.*)$ /index.php/$1 [L]

# Checks to see if the user is attempting to access a valid file,
# such as an image or css document, if this isn't true it sends the
# request to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
Community
  • 1
  • 1
Ben
  • 4,301
  • 6
  • 37
  • 61

5 Answers5

21

You could do it in code instead of using htaccess.

You can create a helper function that will redirect the page to be over SSL, which you call from your controller.

In your helper;

function force_ssl() {
    if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
        $url = "https://". $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
        redirect($url);
        exit;
    }
}

Then in your controller;

class Whatever extends CI_Controller {

    function __construct() {
        parent::__construct();
        $this->load->helper(array('your_ssl_helper'));
    }

    public function index() {
        force_ssl();
        ...
    }
}
eldarerathis
  • 35,455
  • 10
  • 90
  • 93
Rooneyl
  • 7,802
  • 6
  • 52
  • 81
  • 2
    From my point of view, the protocol is something the server should handle without the application having anything to with it, if that is possible (respecting the app-requirements). Clients may use either HTTP or HTTPS, or maybe even [SPDY](https://en.wikipedia.org/wiki/SPDY). – feeela Nov 14 '12 at 20:51
  • I think this is a very elegant solution for CI. Although I can appreciate feeela's point of view, I find that controlling this from within your app is consistent with the CI workflow and style. Similarly, other common .htaccess tasks are handled withing CI's routing feature. – Oliver Holmberg Feb 21 '14 at 16:08
  • I need to change the constant from $_SERVER['HTTPS'] != "on" to $_SERVER['HTTPS'] != "1" for this to work in my system. – YudhiWidyatama Feb 23 '15 at 05:07
19

I think, instead of

RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

you should have something like

RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

do have the rewrite rule match. Your link is currently produced by the third rule.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
feeela
  • 29,399
  • 7
  • 59
  • 71
9

Use this

RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.yourdomain.com/$1 [R=301,L]

instead of

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
It worked yesterday.
  • 4,507
  • 11
  • 46
  • 81
0

Presumably you have RewriteEngine On somewhere above this code...

RewriteCond %{REQUEST_URI} ^system.*

probably isn't going to be triggered. REQUEST_URI should start with / (unlike RewriteRule), so you probably want

RewriteCond %{REQUEST_URI} ^/system

I'm not sure that

RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

will reliably match, with ^. I would try the following:

RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [L,R=301]

Incidentally, HTTP_HOST is normally whatever the visitor typed in, so www. is not guaranteed, if that's what you want. You will need a separate step to force www..

Phil Perry
  • 2,126
  • 14
  • 18
0

I wrote the following class for this purpose. I prefer having stuff like this in code over a configuration file, so that the behaviour cannot be modified by a bad config (i.e. a page is truly "forced" to SSL).

The function must be called at an early stage in your site's loading process.

class SecurityHelper extends MX_Controller
{
    // CONTROLLERS FORCED TO SSL
    private $arrHttps = array(
        'products/shipping',
        'products/billing'
    );

    // CONTROLLERS ACCESSIBLE FROM BOTH
    private $arrAgnostic = array (
        'products/getcart'
    );

    function redirectSsl()
    {
        // SSL MODULES
        if(in_array(uri_string(), $this->arrHttps))
        {
            // ONLY REDIRECT IF NECESSARY
            if ($_SERVER['HTTPS'] != "on")
            {
                // REDIRECTING TO SSL
                $newUrl = str_replace('http://', 'https://', base_url($_SERVER['REQUEST_URI']));
                redirect($newUrl);
            }
        }
        // NON-SSL MODULES
        else
        {
            // IF AGNOSTIC, DON'T REDIRECT
            if(in_array(uri_string(), $this->arrAgnostic))
                return;

            // ONLY REDIRECT IF NECESSARY
            if ($_SERVER['HTTPS'] == "on")
            {
                $newUrl = str_replace('https://', 'http://', base_url($_SERVER['REQUEST_URI']));
                redirect($newUrl);
            }
        }
    }
}

Hope it helps.

mils
  • 1,878
  • 2
  • 21
  • 42