読者です 読者をやめる 読者になる 読者になる

Furudateのブログ

プログラミングやネットワーク系の知識・技術がメインのブログ。技術メモ帳的な感じになるかと。岩手から発信していきます。

【JavaScript】【PHP】jQueryでフォームダイアログを表示して裏でmysql処理

JavaScript PHP

こんにちは。

今回は、jQueryでフォームをダイアログで出すこと、そして、ダイアログのボタンを押したら裏でPHPを用いてmysql処理をし、ログイン処理を行いたいと思います。

これがあるとログインフォームなどの簡単なフォームを作らなくていいし、画面も無駄に増えなくていい感じです。

jQueryを用いたダイアログ表示

まずはダイアログを表示させたいと思います。今回はフォーム付きのダイアログです。
まず、以下のものを用意します。

今回jQuery UIを使いますが、ダウンロードファイルには、デモページが同封されていますので、そこのソースコードを参考にしましょう!ダイアログ以外にも色々とあります。

また、jQuery UIのファイルについては、"jquery-ui-1.10.3.custom/js/jquery-ui-1.10.3.custom.js", "jquery-ui-1.10.3.custom/development-bundle/themes/base/" の中にあるCSSファイル、そしてimagesディレクトリの中の画像を使うことになります。

CSSファイルについてはめんどくさかったら全部自分のサーバに入れてもらって構いません。
ただ、今回のようにダイアログの機能のみを使いたい場合は、不要なファイルが多くなります。
この場合は、関連付けられているファイルのみを自分のサーバに入れたほうが良いのですが、色々と関連付けられているためぶっちゃけめんどくさいです。
そこで、"jquery-ui-1.10.3.custom/css/ui-lightness" にある jquery-ui-1.10.3.custom.css(あるいはminのほう)を使うと、ひとつのCSSファイルでダイアログ機能を使うことが出来ます。
この場合は、imagesディレクトリはcssファイルと同じ場所にあるものを使って下さい。

よって、最低限必要なファイルは以下の通りになります。

  • jqueryファイル
  • jquery-ui-1.10.3.custom.js(またはminのほう)
  • jquery-ui-1.10.3.custom.css(またはminのほう)
  • 上のCSSファイルと同じディレクトリにあるimagesの中の画像ファイル

なお、上記のCSSファイルを使うとデモページと若干ダイアログのレイアウトが異なります。
デモページのレイアウトを使いたい場合は、baseの中にあるCSSファイル全てと、同じ場所にあるimagesの中にある画像ファイルをサーバにインポートすると良いと思います。

本記事では、jquery-ui-1.10.3.custom.cssをインポートしてやっていきたいと思います。


さて、準備が整ったところでいよいよコードを書いていきます。
今回はhtmlファイルに全て書いていきます。
メールアドレスとパスワードを入力するダイアログを表示していきたいと思います。
また、バリデーションもやりたいと思います。

<!doctype html>
<html lang="jp">
<head>
	<meta charset="utf-8">
	<title>jQuery UI Dialog</title>
	
	<script src="./js/jquery-1.10.2.min.js"></script>
	<script src="./js/jquery-ui-1.10.3.custom.min.js"></script>
	<link rel="stylesheet" href="./css/jquery-ui-1.10.3.custom.min.css" type="text/css" />
	
	<style>
		.ui-dialog { font-size: 62.5%; }
		label, input { display:block; }
		input.text { margin-bottom:12px; width:95%; padding: .4em; }
		fieldset { padding:0; border:0; margin-top:25px; }
	</style>
	<script>
	$(function() {
		<!-- ダイアログのフォーム要素取得 -->
		var email = $( "#email" ),
		password = $( "#password" ),
		confPassword = $("#confPassword"),
		allFields = $( [] ).add( email ).add( password ).add(confPassword),
		tips = $( ".validateTips" );

		function updateTips( t ) {
			tips
				.text( t )
				.addClass( "ui-state-highlight" );
			setTimeout(function() {
				tips.removeClass( "ui-state-highlight", 1500 );
			}, 500 );
		}
		// 文字の長さ指定
		// @param o フォーム要素
		// @param n フォーム名
		function checkLength( o, n, min, max ) {
			if ( o.val().length > max || o.val().length < min ) {
				o.addClass( "ui-state-error" );
				updateTips(n + "は" +
					min + "文字以上" + max + "文字以下で入力してください。" );
				return false;
			} else {
				return true;
			}
		}
		// 文字パターン
		function checkRegexp( o, regexp, n ) {
			if ( !( regexp.test( o.val() ) ) ) {
				o.addClass( "ui-state-error" );
				updateTips( n );
				return false;
			} else {
				return true;
			}
		}
		
		// パスワード確認
		function checkPassword(){
			if (password.val() === confPassword.val())
				return true;
			else{
				confPassword.addClass("ui-state-error");
				updateTips("パスワードが一致していません。再度入力してください");
				return false;
			}
		}
		
		// ここでダイアログのオプション指定
		$( "#dialog-form" ).dialog({
			autoOpen: false, // trueにすると画面がロードされた時に自動でダイアログがオープンされます。
			height: 300, // 大きさ指定
			width: 350,
			modal: true, // モーダルダイアログ(ダイアログが開いている間は他の操作が出来ない)指定
			show: "explode", // 開く時と閉じるときのアニメーション指定です。
			hide: "explode",
			buttons: { // ここで各ボタンを押した時の処理を書きます。
				"パスワード再発行": function() {
					var bValid = true;
					allFields.removeClass( "ui-state-error" );
					// 文字の長さをバリデーション
					bValid = bValid && checkLength( email, "email", 6, 80 );
					bValid = bValid && checkLength( password, "password", 5, 16 );
					bValid = bValid && checkPassword();
					
					// E-mailの文字パターンバリデーション
					bValid = bValid && checkRegexp( email, /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, "入力内容が正しくありません。 例:hoge@hoge.com" );

					// バリデートが通った時の処理
					if ( bValid ) {
						alert("OK");
						$( this ).dialog( "close" );
					}
				},
				"キャンセル": function() {
					$( this ).dialog( "close" );
				}
			},
			close: function() {
				allFields.val( "" ).removeClass( "ui-state-error" );
			}
		});
		// ここでボタンを押した時にダイアログをOPENにしています
		$( "#create-user" )
			.button()
			.click(function() {
				$( "#dialog-form" ).dialog( "open" );
		});
	});
	</script>
</head>
<body>

<div id="dialog-form" title="メールアドレス登録">
	<p class="validateTips">全てが必須項目です</p>

	<form>
	<fieldset>
		<label for="email">Email</label>
		<input type="text" name="email" id="email" value="" class="text ui-widget-content ui-corner-all" />
		<label for="password">Password</label>
		<input type="password" name="password" id="password" value="" class="text ui-widget-content ui-corner-all" />
		<label for="confPassword">confPassword</label>
		<input type="Password" name="confPassword" id="confPassword" class="text ui-widget-content ui-corner-all" />
	</fieldset>
	</form>
</div>

<button id="create-user">Create new user</button>
</body>
</html>


解説はソースコードのコメントにできる限り書きました。
これを実行し、ボタンを押すとこのようなダイアログが出ると思います。

f:id:Furu222:20131009021233p:plain

ちゃんとバリデーションもできています。

f:id:Furu222:20131009021247p:plain


このダイアログの詳しい使い方やサンプルはこちらに色々と書いてありますので、参照してみて下さい。


ダイアログを表示して裏でmysql処理

次に上記のjQueryPHPを連携させて、HTML側から送られたPOSTの値を使ったログイン機能を実装したいと思います。

今回は、DBには既にハッシュ化されたパスワードがあるものとします。
また、ダイアログはパスワードを記入するのみの簡単なフォームにします。

それではコードを書いていきましょう。


test.php(メイン画面です)

<?php session_start() ?>
<!doctype html>
<html lang="jp">
<head>
	<meta charset="utf-8">
	<title>jQuery UI Dialog</title>
	
	<script src="./js/jquery-1.10.2.min.js"></script>
	<script src="./js/jquery-ui-1.10.3.custom.min.js"></script>
	<link rel="stylesheet" href="./css/jquery-ui-1.10.3.custom.min.css" type="text/css" />
	
	<style>
		.ui-dialog { font-size: 62.5%; }
		label, input { display:block; }
		input.text { margin-bottom:12px; width:95%; padding: .4em; }
		fieldset { padding:0; border:0; margin-top:25px; }
	</style>
	<script>
	$(function() {
		<!-- ログインダイアログ -->
		password = $( "#password" ),
		allFields = $( [] ).add( password ),
		tips = $( ".validateTips" );

		function updateTips( t ) {
			tips
				.text( t )
				.addClass( "ui-state-highlight" );
			setTimeout(function() {
				tips.removeClass( "ui-state-highlight", 1500 );
			}, 500 );
		}
		// 文字の長さ指定
		function checkLength() {
			if (password.val().length == "") {
				password.addClass( "ui-state-error" );
				updateTips("何も入力されていません。パスワードを入力してください。");
				return false;
			} else {
				return true;
			}
		}

		$( "#dialog-form" ).dialog({
			autoOpen: false,
			height: 300,
			width: 350,
			modal: true,
			show: "explode",
			hide: "explode",
			buttons: {
				"ログイン": function() {
					var bValid = true;
					allFields.removeClass( "ui-state-error" );
					// 文字の長さをバリデーション
					bValid = bValid && checkLength();

					// バリデートが通った時の処理
					if ( bValid ) {
						// PHPファイルにPOST
						$.post("login.php", {"password":password.val()}, function(data, status){
							if (data === "OK"){
								location.reload();
								$( this ).dialog( "close" ); // ダイアログを閉じる
							}else if (data === "NG"){ // パスワードが違うとき
								password.addClass( "ui-state-error" );
								updateTips("パスワードが違います。再入力してください。");
							}else{
								password.addClass( "ui-state-error" );
								updateTips("エラーが発生しました。もう一度入力してみてください。");
							}
						}, "text");
					}
				},
				"キャンセル": function() {
					$( this ).dialog( "close" );
				}
			},
			close: function() {
				allFields.val( "" ).removeClass( "ui-state-error" );
			}
		});

		$( "#login" )
			.button()
			.click(function() {
				$( "#dialog-form" ).dialog( "open" );
		});
		
		// ログアウト用関数
		$("#logout-dialog").dialog({
			autoOpen: false,
			height: 300,
			width: 350,
			modal: true,
			show: "explode",
			hide: "explode",
			buttons: {
					"ログアウト": function(){
					$.post("logout.php", {"logout":true}, function(){
						location.reload();
						$( this ).dialog( "close" ); // ダイアログを閉じる
					});
				},
				"キャンセル": function(){
					jQuery(this).dialog("close");
				}
			},
		});
		
		$("#logout").button().click(function(){
			$("#logout-dialog").dialog("open");
		});
	});
	</script>
</head>
<body>
<?php 
	if (isset($_SESSION["auth"])){
?>
		<div id="logout-dialog" title="ログアウト確認">
			<p>ログアウトしてもよろしいですか?</p>
		</div>
		<button id="logout">ログアウト</button>
		<p id="loginMessage">※ログイン中です</p>
	<?php }else{ ?>
		<div id="dialog-form" title="ログインフォーム">
			<p class="validateTips">パスワードを入力して下さい</p>

			<form>
			<fieldset>
				<label for="password">パスワード</label>
				<input type="password" name="password" id="password" value="" class="text ui-widget-content ui-corner-all" />
			</fieldset>
			</form>
		</div>
		<button id="login">ログイン</button>
		<p id="loginMessage">※ログアウト中です</p>
	<?php }	?>
</body>
</html>


この画面はログインする前にはログインボタン、ログイン後はログアウトボタンを表示するシンプルな画面です。
$.POSTでlogin.phpにPOSTを送信し、ログイン成功の場合はリロードをしています。
jQuery.postの使い方はこちらに書いてあります。

ログアウトに関しては、logout.phpにPOST送信をし、logout.php側でセッション破棄してログアウト処理を行っています。


ログイン処理のPHPファイルです。

login.php

<?php
	// POSTない場合はリダイレクト
	if (!isset($_POST["password"])){
		header("Location: ./sample.php");
	}
	
	$mysqli = new mysqli("localhost", "username", "password", "database");
	
	if (mysqli_connect_errno()){
		printf("Connect failed: %s\n", mysqli_connect_error());
		exit();
	}
	
	$mysqli->set_charset("utf-8");
	
	$pass = sha1($_POST["password"]);
	$query = "select * from index_login where password = ?;";
	
	if ($stmt = $mysqli->prepare($query)){
		$res = ""; // リターン用変数
		$stmt->bind_param('s', $pass);
		if ($stmt->execute()){
			$stmt->store_result();
			if ($stmt->num_rows > 0){
				$res = "OK";
				session_start();
				$_SESSION["auth"] = true;
			}else
				$res = "NG";
		}else{
			$res = "error";
		}
	}else
		$res = "error";
					
	$stmt->close();
	$mysqli->close();
	
	echo $res;
?>

こちらは特に難しいことはしていません。mysqliでハッシュ化したPOSTの値を使ってDBを参照し、num_rows()でヒット件数を確認しています。
ヒットした場合(パスワードが一致した場合)はSESSIONに値を代入し、OKという文字列をsample.php側に返しています。


次にログアウト処理です。

<?php
	// POSTない場合はリダイレクト
	if (!isset($_POST["logout"])){
		header("Location: ./sample.php");
	}
	session_start();
	
	$_SESSION = array();
	session_destroy();
?>

こちらはセッション破棄しているだけなので特に何もありませんね。

実行結果がこちらになります。

まずはログイン前

f:id:Furu222:20131009024156p:plain

ログイン後

f:id:Furu222:20131009024247p:plain



長くなってしまいましたが、以上です。

jQueryすごく便利だなと改めて実感しました。

それでは。

2013/10/11 追記

このダイアログを使って、OKボタンが押された時に別のダイアログを出そうとして以下のようなコードを書いたらエラーが出ました。

$( "#dialog" ).dialog({
   autoOpen: false,
   modal: true,
   buttons: {
      "OK": function(){
      $("#new-dialog").dialog("open");
      $(this).dialog( "close" );
      }
   }
});

エラー文

"Uncaught cannot call methods on dialog prior to initialization; attempted to call method 'close'"


これに関してはこちらの情報が参考になりました。

英語なのでよくわかりませんが、とりあえず何回も$(this).dialog("close")をやるのはよろしくないようで、thisではなく、ちゃんと名前で指定してあげる必要があるみたいです。

なので、以下のようにすると解決出来ます。

$( "#dialog" ).dialog({
   autoOpen: false,
   modal: true,
   buttons: {
      "OK": function(){
      $("#new-dialog").dialog("open");
      $("#dialog").dialog( "close" ); // 名前で指定
      }
   }
});

同じようなエラーが出た人は是非確認してみてください!