My own approach to this issue is a derived base-class from CController for my application’s controllers, and adding a property that allows each controller to specify whether it needs SSL or not:
/**
* Base class for all controllers in the application
*/
class Controller extends CController
{
/**
* @var mixed if true, SSL is required - if false, SSL is not allowed - if null, both are acceptable
*/
public $https = false;
/**
* Integrate GAuthorizationFilter
*/
public function filters()
{
return array(
array('GSchemaFilter', 'https'=>$this->https),
);
}
}
/**
* This filter enforces HTTP or HTTPS protocol for the request, by aborting and redirecting
* the request to the same URL, but with the correct protocol specifier applied.
*
* You can globally bypass this filter using define('NO_SSL', true) in your configuration
* file - this is useful while developing/testing on a machine that does not have an SSL
* certificate installed.
*/
class GSchemaFilter extends CFilter
{
/**
* @var mixed if true, SSL is required - if false, SSL is not allowed - if null, both are allowed
*/
public $https=null;
/**
* Apply schema-based filtering
*/
public function preFilter($filterChain)
{
if (defined('NO_SSL') && NO_SSL)
return true;
if ($this->https===false)
$this->requireSchema('http');
if ($this->https===true)
$this->requireSchema('https');
return true;
}
/**
* Aborts the request, redirects and switches schema, if required.
*
* @param string the required schema for this request, e.g. 'http' or 'https'
*/
protected function requireSchema($schema)
{
$secure = Yii::app()->getRequest()->getIsSecureConnection();
$c = Yii::app()->getController();
if (($schema==='http' && $secure) || ($schema==='https' && !$secure))
$c->redirect($c->createAbsoluteUrl('', $_GET, $schema), true);
}
}
This will automatically redirect and switch protocols as required by your controllers - so for example, your login or checkout controller in a store might have $https=true which would prevent them from loading insecurely on the server-side. I like this approach better than trying to make sure the URLs are correct.
Note that HTTP POST from a secure to a non-secure page (or vice-versa) will not work. This is by design, since this would cause a warning in most browsers anyway. And typically this doesn’t cause any problems, as this setting is per-controller. In other words, the first time you hit CheckoutController::actionIndex() it’ll redirect to switch to SSL - and if you go back to ProductController::actionIndex() it’ll redirect to switch it off again.
I’m using this on several live sites for some years now, and it works well
For local development/testing without an SSL certificate, define(‘NO_SSL’,true) will disable this filter.