Codeigniter redirect not preserving HTTPS in relat

2019-03-14 07:34发布

问题:

I have a site which has a public and a private area. The private area should be served via HTTPS. I want to redirect once to an explicit HTTPS url, and then, using relative URLS, have all the links be secure. When the user logs out, I will explicitly link to an absolute non-secure HTTP URL.

My login form is shown a non-secure site via regular HTTP. My login form posts to https://www.mysite.com/login/validate , which loads using a secure connection.

My logs show that Apache is loading the URL via HTTPS and codeigniter is doing its validation correctly.

At the end of my controller function I redirect to /myaccount using CodeIgniter's URL helper's redirect method with a relative URL.

redirect('/myaccount');

This causes codeigniter to redirect to a non-HTTPS URL.

My config base_url is non-HTTPS:

$config['base_url'] = "http://www.mysite.com"

This is because some parts of the site are secure while others are not.

Is there a way to tell CodeIgniter to preserve HTTPS when doing relative redirects? Why is it assuming I want to go to a non-HTTPS site if the current controller was loaded via HTTPS and I am doing a relative redirect?

The desired behavior for me is that if I am doing relative redirect, it should preserve the protocol through which the current request was loaded. Instead, it is switching to what the config base_url has defined, even for relative redirects.

回答1:

Use this:

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

Instead of this:

$config['base_url'] = "http://www.example.com"

This'll always redirect to where you want it. You don't even have to enter your domain name, just use it as is!


In addition to the above, I also autoload this helper:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

function is_https_on()
{
    return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on';
}

function use_ssl($turn_on = TRUE)
{
    $url = $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];

    if ( $turn_on )
    {
        if ( ! is_https_on() && $_SERVER['HTTP_HOST'] != 'localhost')
        {
            redirect('https://' . $url, 'location', 301 );
            exit;
        }
    }
    else
    {
        if ( is_https_on() )
        {
            redirect('http://' . $url, 'location', 301 );
            exit;
        }
    }
}

/* End of file https_helper.php */
/* Location: ./application/helpers/https_helper.php */

With this in place, I can set my individual pages to always use HTTPS/HTTP (either in a single method in my controller, or - if I want it to affect the whole controller - in the constructor).

I simply use:

use_ssl();

at the beginning of the script, to ascertain that it is loaded via HTTPS.

Alternatively, if I only want to serve it through HTTP, I'll use:

use_ssl(FALSE);


回答2:

There is no 'out of the box' way to handle this HTTPS / HTTP handoff in CI. What you CAN do is create a small helper (that you auto include) which will add a function like secure_url(), and quite simply returns what a base_url would, but https format.

You would have to emulate the same redirect function maybe as secure_redirect().



回答3:

you can use a protocol-relative url which will keep persistence in the linking in CI.

in your config.php instead of:

$config['base_url'] = 'http://example.com/';

put;

$config['base_url'] = '//example.com/';

information about protocol-relative links here.

i have tested this on ie11,chrom(e|ium),firefox,midori using CI form library and basic links. all the browsers honor the specification and i have seen this used in the wild without issue.

additionally CI version 3 has a is_https function built in you should be able to simple use is_https in your controller (eg in the construct) and redirect if not https, then useing the above method maintain http or https without constant redirections.

eg, to keep the entire controller as https, insert into your controller:

public function __construct()
{
    parent::__construct();
    $this->load->helper('url');
    if(! is_https()){
        redirect('https:'.base_url('/page'));
    }
    //!! $conig['base_url'] must be protocol-relative
}