SslRequirementComponent の実装

Ruby on Rails には SSLRequirement というプラグインがある。これはあるコントローラにおける各アクションが、http または https のいずれでアクセスするべきか指定できる便利なプラグインである。CakePHP にも同様のプラグインがあるかもしれないが、勉強をかねて、自力で同様のコンポーネントを実装してみた。名付けて SslRequirementComponent。

使い方

このエントリの最後にあるソースコードssl_requirement.php という名前で app/controllers/components に保存する。(ssl_requirement_component.php という名前じゃないからね!!)そして、コントローラの中から

<?php

class UsersController extends AppController { 
    var $components = array('SslRequirement');
    
    var $ssl_required_actions = array('login', 'signup');
    var $ssl_allowed_actions = array('my_messages');

   function login() {
     ...
   }
   
   function signup() {
     ...
   }
   
   function my_messages() {
    ...
   }
   
   function index() {
    ...
   }
 }
 


のように書く。

アクションへのアクセスが、指定されたとおり http または https プロトコルで行われることを保障する。このコンポーネントがロードされたコントローラでは、原則として、リクエストは http でアクセスされる。(何も指定がなければ、https アクセスは同一 URL に対する http アクセスへリダイレクトされる)


コントローラのメンバ変数 $ssl_required_actions と $ssl_allowed_actions にそれぞれ、

  1. https アクセス以外は受け付けないアクション (ssl_required_actions)
  2. http と https の両方を許容するアクション (ssl_allowed_actions)

を記述することができる。

これだけで、login, signup アクションに関しては、必ず https でアクセスされることが保障される。my_messages アクションは http/https どちらでもよい。index アクションに関しては何の指定もないので、かならず http アクセスされる。

ソースコード

<?php

class SslRequirementComponent extends Object {
	
	var $components = array('RequestHandler');
	var $controller;

	function initialize(&$controller) {
		$this->controller = $controller;
		$this->ensureProperProtocol();
	}
	
	// https リクエスト以外を受け付けないか?
	function isSSLRequired() {
		if(isset($this->controller->ssl_required_actions)) {
		 	return in_array($this->controller->action, $this->controller->ssl_required_actions);
		} else {
			return false;
		}
	}
	
	// https リクエストを許容するか?
	function isSSLAllowed() {
		if(isset($this->controller->ssl_allowed_actions)) {
			return in_array($this->controller->action, $this->controller->ssl_allowed_actions);
		} else {
			return false;
		}
	}
	
	function ensureProperProtocol() {
		if($this->isSSLAllowed()) {
			return;
		}
		
		if($this->isSSLRequired() && !$this->RequestHandler->isSSL()) {
			$url = 'https://' . $_SERVER['HTTP_HOST'] . $this->controller->here;
			// 第3パラメータを true にすることで、この場で処理を終了して、レスポンスを返す。
			$this->controller->redirect($url, null, true);
		} elseif($this->RequestHandler->isSSL() && !$this->isSSLRequired()) {
			$url = 'http://' . $_SERVER['HTTP_HOST'] . $this->controller->here;
			$this->controller->redirect($url, null, true);
		}
	}

}

つぶやき

CakePHP のほうが Ruby on Rails よりシンプルでいいかも。もちろん CakePHPRuby on Rails のような強力さはないんだけど。でもフレームワークソースコードは読みやすいので、適当に改造して使ってしまえば、フレームワークソースコードが美しすぎて近づきがたい Rails よりむしり便利だったりして。ウェブアプリを作るうえで、PHP も悪くないもんだな。(もちろん Ruby へ愛は変わらないが)