YUI2.7.0+PHP5でモーダル表示のログイン処理を作る(その2)

ログイン処理をもう少し実用向けにしてみたい。
以前、どこかのサイトで「認証はページに帰属させる」という記事を読んだ記憶がある。認証処理はアクションに帰属させるのが一般的であろうが、Ajaxを前提とした場合、ページに帰属させることで、少なくとも利用範囲が広がることは間違いない。
javascriptがオフにされていたら…」という(昔からある)懸念事項はあるが、この懸念はサーバーサイドプログラミングで発生したレトリックであって、Ajax利用する行為そのものと矛盾をきたす(なので、考えない)。

既に作成したプログラムに少し追加をして、以下のことができるようにする。

  • 画面表示をする際に、クライアントのログイン状況をチェックする。
  • 非認証モードと、認証モードをサーバー側で設定できるようにする。
  • 認証モードのとき、ログイン状況をチェックしてログインしていなければ、ログイン画面を表示してログインを促す(クライアントは、ログインをしなければならない状況となる)。
  • 非認証モードのときは、上記処理を解除する。

サーバー側では、以下のように認証方式を設定する(Config.php)。AUTH_TYPE=='NONE'としたときが非認証モード、AUTH_TYPE='PANEL'としたときが認証モードとする。

/*
*  認証モードの設定
*    使いたい認証モード以外はコメントアウト。
*/

//	define("AUTH_TYPE","NONE"); // 認証なし
	define("AUTH_TYPE","PANEL"); // 認証あり


以下が、認証モードを選んだ場合のログイン画面。ログインしない限り、以下の画面から解放されない。前回のログイン用ダイアログには「キャンセルボタン」があったが、ログインを強制させるために削除してある。


以下が非認証モードを選んだ場合のログイン画面。認証を行わないのだから、「Login」を行うためのボタン(リンク)類を画面から削除している。


以下にプログラムを示す。今回新たに作ったのは、以下の2つ。

サーバーの認証タイプ(Config.php;上記)と、クライアントのログイン状況から、クライアントの挙動を制御するレスポンスを返却するPHPプログラム。 loginCheck.php
上記リクエストをサーバーに送り、レスポンスの種類によって、画面の制御を行うJavascript test_loginCheck1.html


まずは、loginCheck.php

認証タイプ ログイン状況 レスポンス
NONE - null
PANEL ログイン済み(セッションにEmailアドレスが入っている) Emailアドレスを返却
PANEL ログインしていない login is required.という文字列を返却
<?php
/* 
 * ログイン済みかどうかのチェックを行う。
 *      
 *		author	; t.odaka
 *		date	; 2009/5/11
*/
	require("../Myznala/Config.php");

	$ret=null;

	if(AUTH_TYPE=='NONE'){
	}else if(AUTH_TYPE=='PANEL'){
		session_start();
		if(isset($_SESSION['Email'])) {
			$ret = $_SESSION['Email'];
		}else{
			$ret = "login is required.";
		}
	}
	
	// 出力
	header("Content-Type:text/html");
	echo($ret);
	
	return;
?>


以下に、Javasriptを含むHTMLの全文を示す。loginCheck.phpからの返却値がEmailアドレスかどうか判断するために、以前作成したMyValidatorを利用している。また、XHR(Ajax)で呼ぶ、loginCheck.php以外のサーバープログラム(login1.php、logout1.php)は以前に作成したものと同様である。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> 
<head> 
	<meta http-equiv="Pragma" content="no-cache">
	<meta http-equiv="Cache-Control" content="no-cache">
	<meta http-equiv="Expires" content="Thu, 01 Dec 1994 16:00:00 GMT">
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
	<meta http-equiv="Content-Style-Type" content="text/css">
	<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>Login</title> 
 
<style type="text/css"> 
</style> 

<link rel="stylesheet" type="text/css" href="../scripts/lib/yui/build/fonts/fonts-min.css" /> 
<link rel="stylesheet" type="text/css" href="../scripts/lib/yui/build/container/assets/skins/sam/container.css" /> 

<script type="text/javascript" src="../scripts/lib/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script> 
<script type="text/javascript" src="../scripts/lib/yui/build/container/container.js"></script> 
<script type="text/javascript" src="../scripts/lib/yui/build/connection/connection-min.js" ></script>

<!--// MyValidatorの読み込み -->
<script type="text/javascript" src="../scripts/myznala.js">
</script> 
<style type="text/css" id="defaultstyle">
#main {
	margin: 2px;
	padding: 3px;
}

.ez_error {
	/* red(エラー用) */
	color:#ff0000;
}

td {
	padding:2px;
}

#logindialog {
	visibility:hidden;
}

#login {
	visibility:hidden;
}

#loginname {
	visibility:hidden;
}

</style>

<script type="text/javascript">

ModalLogin = function() {
	var Event	= YAHOO.util.Event;
	var Dom		= YAHOO.util.Dom;
	var Connect	= YAHOO.util.Connect;
	
	var loginPanel;
	var valObj;

	/*
	* Login/Logoutのリンクをクリックした時のハンドラ
	*/
	var clickHdlr = function(_evt){
		Event.preventDefault(_evt);
		// id=loginはトグルにする
		if(Dom.hasClass('login','my_logout')){
			loginHdlr();
		}else{
			logoutHdlr();
		}
	}
	
	/******************************************************
	* Login時のハンドラ
	*/
	var loginHdlr = function(){

		Dom.get('msg').innerHTML = '';
		Dom.get('res').innerHTML = '';
		Dom.get('auth1').value = '';
		Dom.get('auth2').value = '';

    	// Panelオブジェクトは、ページスコープで一回だけ生成する。
        if (!loginPanel) {
			// ログイン用のモーダルパネルを生成する。
        	loginPanel = new YAHOO.widget.Panel("loginpannel",  
			{ 
                       	fixedcenter: true, 
                       	close: false, 
                       	draggable: false, 
			// 一番上に出す。
                       	zindex:4,
			// Modal指定。
                       	modal: true,
			// showされるまでは見えない。
               		visible: false
       			} 
        	);

		// loginDialogを定義する
        	loginPanel.setHeader("Login");
        	loginPanel.setBody(Dom.get("logindialog"));
        	loginPanel.render(document.body);
	}
        // ログインダイアログの表示
       	Dom.setStyle("logindialog","visibility","visible");
        loginPanel.show();
	};

	/******************************************************
	* ログインダイアログでログインボタンをクリックした時のハンドラ
	*/
	var loginClickHdlr = function(){
		// エラーメッセージのクリア
		Dom.get('msg').innerHTML = '';

		var _url	= 'login1.php';
		var _parm 	= 'auth1=' + Dom.get('auth1').value + 
					'&' + 'auth2=' + Dom.get('auth2').value;
		// 戻ってきたときのために、メッセージ表示用エレメントのidをセットする。
		var _arg ={
			'resId'	: 'msg'
		};
		loginCallback.argument = _arg;
		// ajaxで検証
		Connect.asyncRequest('POST',_url,
					loginCallback, _parm);
	}
	
	/*
	* Login時のコールバック
	*/
	var loginCallback = {
    	        success : function(_obj) {
			var _resId = _obj.argument.resId;
			// XHRの戻り値の取得(エラーメッセージ)
			var _ret = _obj.responseText;

			// 戻り値がE-Mailアドレスかどうか検証
			var _wkRet = valObj.validate('ja','isEmail',_ret);

			//alert(_wkRet['isEmail'].length);
			// エラー時の処理
			if('isEmail' in _wkRet){
				// エラーのハンドル(皆さん適当に)
				// エラーが複数のときは複数行にして表示する。
				if(Dom.get(_resId).innerHTML.length > 0){
					Dom.get(_resId).innerHTML += ' &nbsp ' +_ret;
				}else{
					Dom.get(_resId).innerHTML = _ret;
				}
			}else{
				// ログイン成功
				loginPanel.hide();
		     	Dom.setStyle("logindialog","visibility","hidden");
				// エラーメッセージのクリア
				Dom.get('msg').innerHTML = '';
				// Logoutを表示
				Dom.removeClass('login','my_logout');
				Dom.addClass('login','my_login');
				Dom.get('login').innerHTML = "Logout";
				Dom.get('loginname').innerHTML = _ret;
			}
		},
		
     	        failure : function(_obj) {
 			var _resId = _obj.argument.resId;

 			var _ret = 'ステータス: ' + _obj.status + 'ステータステキスト: ' +
 						_obj.statusText + '読み込みに失敗しました。';
 			// エラーのハンドル(皆さん適当に)
 			Dom.get(_resId).innerHTML = _ret;	     
 		}
	 };

	/******************************************************
	* Logout時のハンドラ
	*/
	var logoutHdlr = function(){
		// Loginを表示
		Dom.removeClass('login','my_login');
		Dom.addClass('login','my_logout');
		Dom.get('login').innerHTML = "Login";
		Dom.get('loginname').innerHTML = '';
		// エラーメッセージのクリア
		Dom.get('msg').innerHTML = '';

		// session削除のためのajax
		var _url	= 'logout1.php';
		// ajaxで検証
		Connect.asyncRequest('POST',_url,
						logoutCallback);
		
	}

	/*
	* Logout時のコールバック
	*/
	var logoutCallback = {
	    	success : function(_obj) {},
	     	failure : function(_obj) {
	 		var _ret = 'ステータス: ' + _obj.status + 'ステータステキスト: ' +
	 					'Logoutに失敗しました';
	 		// エラーのハンドル(皆さん適当に)
	 		Dom.get('res').innerHTML = _ret;	     
	 		}
		 };

	/******************************************************
	* login済みかどうかをチェックするinitial処理のハンドラ
	*
	*/

	var loginCheckHdlr = function(){

		// session testのためのajax
		var _url	= 'loginCheck.php';
		// ajaxで検証
		Connect.asyncRequest('POST',_url,
				loginCheckCallback);
		
	}

	/*
	* login済みかどうかをチェックするajaxのコールバック
	*/
	var loginCheckCallback = {
	    	success : function(_obj) {
			// XHRの戻り値の取得(エラーメッセージ)
			var _ret = _obj.responseText;

			// 認証ありの場合
			if(_ret != null && _ret.length > 0){
				// 戻り値がE-Mailアドレスかどうか検証
				var _wkRet = valObj.validate('ja','isEmail',_ret);
					
		     	        Dom.setStyle("login","visibility","visible");
		     	        Dom.setStyle("loginname","visibility","visible");
					
				if('isEmail' in _wkRet){
				        // Emailアドレスではない場合
					// ログインを促す。
					loginHdlr();				
				}else{
					// Emailアドレスの場合
					// Logoutを表示
					Dom.removeClass('login','my_logout');
					Dom.addClass('login','my_login');
					Dom.get('login').innerHTML = "Logout";
					Dom.get('loginname').innerHTML = _ret;
				}
			}else{
			// 非認証の場合
			}
		},
			
	     	failure : function(_obj) {
	 		var _ret = 'ステータス: ' + _obj.status + 'ステータステキスト: ' +
	 					'Testに失敗しました';
	 		// エラーのハンドル(皆さん適当に)
			alert('_ret');
		}
	};
	
	return{
    	init: function() {

		// ログインダイアログを表示するハンドラー
	        Event.on("login", 
	    	       	"click", 
	    	       	clickHdlr);

	        // ダイアログ内のLoginボタンのハンドラー
	        Event.on("loginbutton", 
        		"click", 
        		loginClickHdlr);

	        // 認証方式と、login状況のcheck。
			loginCheckHdlr();
			
    		// 検証オブジェクトの初期化
			valObj 	= 	new MyValidator();
		}
	};
}();

//DOMが完全にloadされたら、サンプルを初期化する。
YAHOO.util.Event.onDOMReady(
	//DomReadyイベントで発火するハンドラ
	ModalLogin.init,
	//ハンドラに渡すオブジェクト
	ModalLogin,
	//ハンドラは、上記のオブジェクトのスコープをもつ。   
	true
);

</script>
</HEAD>

<BODY class="yui-skin-sam">
test_loginCheck1.html
<br>
<div id="container">
<p>
Login/Logoutのサンプルです。<br/>
画面起動時に、サーバーの設定により「認証が必要かどうかの判断」を行います。
</p>
<ul>
<li>認証が必要な場合; 認証用のパネルを表示します。
<li>認証が不要な場合;初期画面を表示します。
</ul>
<a id="login" href="#" class="my_logout">Login</a> &nbsp <div id="loginname"></div>
<div id="res" class="ez_error"></div>

<br>

<!-- Login画面生成用のDiv -->
<div id="logindialog">
	<form action="#">
		<table border="0">
		<tr><td>E-Mail</td>
			<td><input id="auth1" type="text" size="30"></td></tr>
		<tr><td>Password</td>
			<td><input id="auth2" type="password" size="30"></td></tr>
		<tr><td colspan="2">
			<input id="loginbutton" type="button" value="Login"> &nbsp
		</td></tr>
		</table>

	</form>
	<div id="msg" class="ez_error"></div>
	<a HREF="mailto:dummy@dummy.com">パスワードを忘れた場合には。</a>
</div>

</div>
</BODY>
</HTML>