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

趣向を変えて、YUI2.7.0のPanelを使って、モーダル(modal)表示のログイン画面を作ってみた。

ログインは、

  • E-Mailアドレス
  • パスワード

で行うことにし、この情報は、CSV形式でサーバーに置く(以下)。

dummy@dummy.com,password

画面の動きは以下のようにする。初期画面は簡単なもの(以下)。


上の画面で、Loginと書いたアンカーをクリックすると、以下のログイン画面が表示される。


以下は、上のログイン画面でログインに失敗したときのスナップショット。エラーであることが、入力フィールド下に表示される。


ログインに成功すると、以下のように、Loginと表示されたアンカーがLogoutに変わる。このアンカーを押すと、表示がLoginに切り替わる(=トグルになっている)。


入力されたE-Mailアドレスとパスワードは、Ajax(XHR, YUIのConnectionManager)でサーバーへPOSTし、PHPプログラムで検証して、結果をクライアント(Javascript)へ戻す。

プログラムは以下の3つ。

ログイン情報(users.txt)を検索するPHPオブジェクト LoginTextDao.class.php
上記のPHPプログラムを呼び出すPHPプログラム login.php
モーダル画面の生成、login.phpの呼び出しを行うJavascriptを含むHTML test_login1.html


以下が、LoginTextDao.class.php。先のログで作成した、BaseTextDao.phpをExtendして作成した。

<?php
/**
 * LoginTextDao.class.php
 * 
 * (C) 2009, tetsuya.odaka(EzoGP).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* 
 * users.txtのためのDao
 * 
 * 		author	;	t.odaka
 * 		date	;	2009/5/7
 * 
 */
require_once('BaseTextDao.class.php');

class LoginTextDao extends BaseTextDao {
	/*
	* プロパティー 
	*/
	var $Email, $Password;

        /* 
	 * デフォルトのコンストラクタ 
	 */
	function __construct() {
		parent::__construct();
	}

	/* 
	 * Getter 
	 */
	function getEmail(){return $this->Email;}
	function getPassword(){return $this->Password;}
	
	/* 
	 * Setter 
	 */
	function setEmail($_str){$this->Email = $_str;}
	function setPassword($_str){$this->Password = $_str;}
	
	/*
 	* findByUniqueKey
 	*   主キーをもとに、データを取得する。
	*   パラメータ
	*   $_fp	:	this->FileNameのファイルポインタ
 	*  	戻り値	:	見つかったらLoginTextDaoオブジェクト、なかったらnull.
 	*/
	function findByUniqueKey($_fp, $_key){
		
		while($_rarray = fgetcsv($_fp,1024)){
			if($_rarray[0] == $_key){
				$_retObj = new LoginTextDao();
				$_retObj->setEmail($_rarray[0]);
				$_retObj->setPassword($_rarray[1]);
				return $_retObj;
			}
		}
		return null;
	}
}
?>


以下が、LoginTextDao.class.phpを呼び出すプログラム(login.php)。認証情報をいれたCSVファイルは、dataディレクトリ下に「users.txt」という名で持つ。また、入力値のサニタイズのために、以前に作成したMyConverter.class.phpを使用した。

<?php
/* 
 * ログインダイアログからのajax送信を受け取るサンプル
 *      
 *		author	; t.odaka
 *		date	; 2009/5/7
*/
	
	require_once("LoginTextDao.class.php");
	require_once("../Myznala/MyConverter.class.php");
	
	// リクエストデータの取り出し
	switch($_SERVER['REQUEST_METHOD']) {
		case 'GET'	: $rMethod = &$_GET; break;
		case 'POST'	: $rMethod = &$_POST; break;
		default:
	}

	// パラメータをサニタイズして配列に入れる。
	$cObj = new MyConverter();
	$reqParm = array();
	foreach ($rMethod as $key => $value) {
		$key	=$cObj->sanitize($key,'UTF-8');
		$value	=$cObj->sanitize($value,'UTF-8');
		$m_log->debug($key.'; '.$value); // Debugログ
		$reqParm[$key]=$value;
	}
	
	// データの更新と削除
	$pObj = new LoginTextDao();
	$pObj->setFileName('data/users.txt');
	// users.txtをopen.
	$fp = $pObj->fileOpen('r');
	
	$ret;
	$retObj = $pObj->findByUniqueKey($fp, $reqParm['auth1']);
	// ユーザーの存在証明
	if($retObj == null){
		$ret = 'ユーザーとパスワードが一致しません.';
	// パスワードの一致証明
	}else if($retObj->getPassword() != $reqParm['auth2']){
		$ret = 'ユーザーとパスワードが一致しません.';
	}
	
	// users.txtをclose.
	$pObj->fileClose($fp,'r');
	
	// 出力
	header("Content-Type:text/html");
	echo($ret);
	
	return;
?>


最後に、javascriptの全文を含むHTMLを示す。

<!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>

<style type="text/css" id="defaultstyle">
#main {
	margin: 2px;
	padding: 3px;
}

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

td {
	padding:2px;
}

#logindialog {
	visibility:hidden;
}

</style>

<script type="text/javascript">

ModalLogin = function() {
	var Event	= YAHOO.util.Event;
	var Dom		= YAHOO.util.Dom;
	
	// ログインダイアログ
	var loginPanel;

	/*
	* ログインダイアログでキャンセルボタンをクリックした時のハンドラ
	*/
	var calselClickHdlr = function(){
	        // ダイアログを消す
	        loginPanel.hide();
     	        Dom.setStyle("logindialog","visibility","hidden");
		// エラーメッセージのクリア
		Dom.get('msg').innerHTML = '';
	}

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

		var _url	= 'login.php';
		var _parm 	= 'auth1=' + Dom.get('auth1').value + 
					'&' + 'auth2=' + Dom.get('auth2').value;
		// 戻ってきたときのために、メッセージ表示用エレメントのidをセットする。
		var _arg ={
			'resId'	: 'msg'
		};
		loginCallback.argument = _arg;
		// ajaxで検証
		YAHOO.util.Connect.asyncRequest('POST',_url,
						loginCallback, _parm);
	}
	

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

	Dom.get('msg').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();
        
	};
	
	/*
	* Login時のコールバック
	*/
	var loginCallback = {
    	        success : function(_obj) {
			var _resId = _obj.argument.resId;
			// XHRの戻り値の取得(エラーメッセージ)
			var _ret = _obj.responseText;

			// エラー時の処理
			if(_ret.length > 0){
				// エラーのハンドル(皆さん適当に)
				// エラーが複数のときは複数行にして表示する。
				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";
			}
		},
		
     	        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('msg').innerHTML = '';
	}
	
	return{
    	init: function() {

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

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

		}
	};
}();

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

</script>
</HEAD>

<BODY class="yui-skin-sam">
test_login1.html
<br>
<div id="container">
<p>
Login/Logoutのサンプルです。<br/>
</p>
<a id="login" href="#" class="my_logout">Login</a>

<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
			<input id="canselbutton" type="button" value="Cansel">
		</td></tr>
		</table>

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

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