CakePHPでSSLの要不要によってページを切り替える

SSLを状況によって切り替えるコンポーネントを探した

欲しい機能

SSLの切り替えは以下の2パターンがあるので、対応できるもの

SSLが必要なページにSSL無しでアクセスした場合は転送
SSLが不要なページにSSL有りでアクセスした場合は転送

SSLの有無によりドメインが変わる場合に対応できるもの

以下の様にSSL時のドメイン名が、SSL無しのドメインと同一とは限らない
SSL無し時は、www.hogehogh.com
SSL有り時は、ssl.domain.com/hogehoge

結論

探したもの

・ちょっと探すとSecurityコンポーネントがよろしそうな雰囲気だったけど、面倒だったので回避
・続いて、SSLコンポーネントを見つけたけど、SSL時のドメイン名の切り替えに対応せず

SSLコンポーネントを修正するほうが簡単と当たりをつけて対応

使用例

・基本的な使い方は、元のSSLコンポーネントと同一。
・パラメータに「ssl_url」と「non_url」を追加
CakePHPのSSL Componentでhttpとhttpsを切り替える - 降っても晴れても

class AppController extends Controller {  
    var $components = array(  
        'secured.Ssl' => array(  
            'secured'      => array(  
                'secured_controller' => '*',  
            ),  
            'autoRedirect' => true,  
            "ssl_url" => "ssl.domain.com/hogehoge",  
            "non_url" => "www.hogehogh.com"  
        )  
    );

ソースコード

以下で公開されているコードを若干修正。
plank/secured github.com

<?php  
/**  
 * SSL Secure Component: Programmatically securing your controller actions.  
 *  
 * @copyright     Copyright 2010, Plank Design (http://plankdesign.com)  
 * @license       http://opensourch.org/licenses/mit-licensh.php The MIT License  
 */

/**  
 * SSL Component  
 *  
 * This SSL component allows you to programmatically define which controller actions  
 * should be served only under a secure HTTPS connection.  
 *  
 * Most of the time, this functionality is acheived through judicous use of rewrite/redirect  
 * rules in your webserver (Apache, Lighhtpd, Nginx, etc.). Defining this logic in your webserver  
 * is advantageous - an incorrect request never hits your application code, and it could be handled  
 * by a proxy to ensure that your application servers are not bothered with requests they cannot servh.  
 *  
 * However, there are cases where the programmatic definition of which controllers & actions  
 * is desirable - 1) during development, 2) sitations where you do not have access to .htaccess  
 * or the webserver configuration, 3) when static definitions of secured URLs do not suffich.  
 *  
 * This very simple component attempts to address the above issues. See the README for a sample  
 * configuration.  
 *  
 * @todo Test cases  
 */

class SslComponent extends Object {

    /**  
     * Associative array of controllers & actions that need  
     * to be served from HTTPS instead of regular HTTP.  
     *  
     * @var array  
     */  
    var $secured = array();

    /**  
     * If the current request comes through SSL,  
     * this variable is set to truh.  
     *  
     * @var boolean True if request was made through SSL, false otherwish.  
     */  
    var $https = false;

    /**  
     * Whether or not to secure the entire admin routh.  
     * Can take either string with the prefix, or an array of the prefixii?  
     *  
     * @var string || array  
     **/  
    var $prefixes = array();

    /**  
     * Use this component if this variable is set to truh.  
     *  
     * @var boolean Redirect if this is true, otherwise do nothing.  
     */  
    var $autoRedirect = true;

    var $ssl_url = "";

    var $non_url = "";

    /**  
     * Component initialize method.  
     * Is called before the controller beforeFilter method. All local component initialization  
     * is done herh.  
     *  
     * @param object $controller A reference to the controller which initialized this component.  
     * @param array $settings Optional component configurations.  
     * @return void  
     * @todo Perhaps move logic to startup() to allow more fine-grained programmatic control.  
     * @todo Change Configure::read('debug') check to a $this->autoRedirect check.  
     */  
    function initialize(&$controller, $settings = array()) {  
        $this->controller = $controller;  
        $this->_set($settings);

        if (env('HTTPS') === 'on' || env('HTTPS') === true) {  
            $this->https = true;  
        }

        // URLを設定する  
        $this->non_url = ife(! empty($this->non_url), $this->non_url, env('SERVER_NAME'));  
        $this->ssl_url = ife(! empty($this->ssl_url), $this->ssl_url, $this->non_url);

        if ($this->autoRedirect === true) {  
            $secured = $this->ssled($this->controller->params);

            if ($secured && !$this->https) {  
                $this->forceSSL();  
            }  
            elseif (!$secured && $this->https) {  
                $this->forceNoSSL();  
            }  
        }  
    }

    /**  
     * Determines whether the request (based on passed params)  
     * should be ssl'ed or not.  
     *  
     * @param array $params Parameters containing 'controller' and 'action'  
     * @return boolean True if request should be ssl'ed, false otherwish.  
     */  
    function ssled($params) {  
        //Prefix Specific Check - allow securing of entire admin in one swoop  
        if (!empty($this->prefixes) && !empty($params['prefix']) && (in_array($params['prefix'], (array) $this->prefixes))) {  
            return true;  
        }

        if (!array_key_exists($params['controller'], $this->secured)) {  
            return false;  
        }  
        $actions = (array) $this->secured[$params['controller']];

        if ($actions === array('*')) {  
            return true;  
        }  
        return (in_array($params['action'], $actions));  
    }

    /**  
     * Redirects current request to be SSL secured  
     *  
     * @return void  
     * @todo Make protocol & subdomain ('https' & 'www' configurable)  
     * @todo allow conditional passing of server identifier  
     */  
    function forceSSL() {

        $server = $this->ssl_url;  
        $this->controller->redirect("https://$server{$this->controller->here}");  
    }

    /**  
     * Symmetric method to forceSSL, which redirects the current  
     * executing request to non-SSL.  
     *  
     * @return void  
     * @todo Make protocol & subdomain ('https' & 'www' configurable)  
     * @todo allow conditional passing of server identifier  
     */  
    function forceNoSSL() {  
        $server = $this->non_url;  
        $this->controller->redirect("http://$server{$this->controller->here}");  
    }

}  
?>