前回までは、入力フォーム表示・登録ロジック(registForm.php)と、入力データチェックロジック(registCheck.php)の2ファイルで、ユーザー情報の登録処理を行いました。
今回は、入力フォームに情報入力後、確認画面を経て、登録完了を行うようにロジックを分けたいと思います。
流れとしては、以下のようになるかと思います。
確認画面に入力データを渡す
入力フォームにデータを入力後、別画面の確認画面にデータを受け渡す方法はいくつかありますが
- POST、もしくはGETで渡った値をスーパーグローバル変数で取得し、再表示
- セッション変数に格納して、値を引き回す
の2つが一般的かと思います。
今回は、セッションを使い、POSTで渡された値をセッション変数から取得しなおすことにしました。
phpでは、session_start()関数を利用することで、セッションデータを取り扱うことができます。
まず、入力フォームの「registForm.php」で、セッションを開始。その後、registCheck.phpを経由してきたPOSTデータを、セッション変数に引き渡します。
セッション変数に値を登録することで、入力フォームに誤った入力をした場合、直前の入力内容を(パスワードを除き)再表示します。
入力データが問題なく、かつ正しくサブミットされた値であれば(submit時にhiddenで渡された値が期待通りであれば)、同ディレクトリにある確認用ロジック「registConfirm.php」へ移動します。
registForm.php
<?php session_start(); include "registCheck.php"; /* チェック用hidden値が正しく、かつエラーがない ($_regist_errorが空)の場合、 セッション情報にデータを登録して確認画面へ移動 */ if ($_POST['mode'] == "check" && empty($regist_error)) { header("Location: ./registConfirm.php"); break; } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>情報登録ページ</title> </head> <body> <h1>プロフィールの入力・更新</h1> <?php if (isset($regist_error)) { print ("<p><font color=\"red\">".$regist_error."</font></p>"); } ?> <form action="<? print($_SERVER['PHP_SELF']) ?>" method="post"> <input type="hidden" name="mode" value="check"> <table> <tr> <th>id:</th> <td><input type="text" name="username" size="20" value="<?php print(htmlspecialchars($_SESSION["username"])); ?>" ></td> </tr> <tr> <th>Email:</th> <td><input type="text" name="email" size="20" value="<?php print(htmlspecialchars($_SESSION["email"])); ?>" ></td> </tr> <tr> <th>パスワード:</th> <td><input type="password" name="password" size="20"></td> </tr> <tr> <th>パスワード(確認):</th> <td><input type="password" name="password2" size="20"></td> </tr> <tr> <th>表示名</th> <td><input type="text" name="uname" size="20" value="<?php print(htmlspecialchars($_SESSION["uname"])); ?>" ></td> </tr> </table> <input type="submit" value="登録する"> </form> </body> </html>
次に、registForm.phpから渡したデータを、確認画面として表示します。
そのまま表示した場合、悪意のあるスクリプトによるXSSがあり得るため、htmlspecialchars関数で、エスケープ処理を行ってから入力値を表示しました。
サブミットボタンは2つ準備し、「元に戻る」ボタンに対しては、nameをreturnとしました。
「登録する」 ボタンに対しては、nameをregistとして、次の登録ロジック「regisCompletephp」に渡します。同時に、hidden値でname要素modeに「registComplete」の文字列を渡します。
registConfirm.php
<?php session_start(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>登録情報の確認</title> </head> <body> <h1>マイページ</h1> <h2>プロフィールの入力確認</h2> <form action="registComplete.php" method="post"> <h3>入力内容はこれでよろしいですか?OKの場合は、「登録する」ボタンを押してください。</h3> <table> <tr> <th>id:</th> <td><?php print(htmlspecialchars($_SESSION["username"])); ?></td> </tr> <tr> <th>Email:</th> <td><?php print(htmlspecialchars($_SESSION["email"])); ?></td> </tr> <tr> <th>パスワード:</th> <td>セキュリティ対策のため表示しません</td> </tr> <tr> <th>表示名</th> <td><?php print(htmlspecialchars($_SESSION["uname"])); ?></td> </tr> </table> <input type="submit" name="return" value="元に戻る"> <input type="submit" name="regist" value="登録する"> <input type="hidden" name="mode" value="registComplete"> </form> </body> </html> </body> </html>
registConfirm.phpから値が正しく渡ってきたら、registComplete.phpで、データベース登録を行います。
registComplete.phpでは、
- hiddenで渡されたname要素、modeの値が、registCompleteかどうか
- submitされたname要素が、returnか、もしくはregistか
のチェックを行います。
modeのname値がregistCompleteで、かつ、submitのname要素registが真の場合、DBにデータを登録して、セッション情報を破棄します。セッション情報の扱い以外は、
「ユーザー情報をDBに登録する(PHP+PEARでウェブサービス勉強記録・3)」と同じロジックを使用しています。
逆に、submitのname要素returnが真の場合、セッション情報を保ったまま、入力フォームへ移動します。
いずれにも当てはまらない場合=registComplete.phpが不正に呼び出された場合、エラーメッセージを表示します。
registComplete.php
<?php session_start(); /* 確認画面からの遷移かどうかをチェック POSTで渡ったmodeの値が正しいかどうか、を確認 */ if($_POST['mode'] == "registComplete") { /* 入力値により処理を切り分け nameがreturnの場合、登録せずに入力画面へ強制遷移 nameがregistの場合、登録処理を実行 */ if($_POST['regist']){ /* name値 registが真の場合、 登録情報のエスケープ処理を行ってデータベースに登録 */ $conn = mysql_connect("localhost", "pear", "peartest"); mysql_select_db(auth); if (get_magic_quotes_gpc()) { $username = stripslashes($_SESSION["username"]); $email = stripslashes($_SESSION["email"]); $password = stripslashes($_SESSION["password"]); $uname = stripslashes($_SESSION["uname"]); } $username = mysql_real_escape_string($username); $email = mysql_real_escape_string($email); $passsword = mysql_real_escape_string($password); $uname = mysql_real_escape_string($uname); mysql_close($conn); require_once("Auth/Auth.php"); $params = array( "dsn" => "mysqli://pear:peartest@localhost/pear", "table" => "auth", "usernamecol" => "username", "passwordcol" => "password",); $myAuth = new Auth("DB",$params,""); $myAuth -> addUser("$username", "$password", array("email" => "$email", "uname" => "$uname") ); /* セッション情報を削除 */ session_destroy(); print("情報を登録しました。登録情報でログインできます。<br />"); } elseif ($_POST['return']) { /* submitボタンが「もとへ戻る」だった場合、登録フォームへ移動 */ header("Location: ./registForm.php"); } } else { /* hidden値が不正、もしくはsubmitボタンで渡されたname値が 不正な場合、エラーメッセージを表示して、セッション情報削除 */ print("不正なURLから呼び出された可能性があります。"); session_destroy(); } ?>
実行イメージ
入力データに間違ったデータを登録したとき。パスワード以外は直前の入力データを再表示
入力値を確認する画面
「元に戻る」ボタンを押したとき。入力値のID、Email、表示名はセッション情報から入力データを再表示する
確認画面から「登録する」ボタンを押したとき。
registComplete.phpを直接呼び出したとき
次回は、セキュリティ対策を考えてみる
現在の不正登録チェックは、hidden値のチェックのみにとどまっており、最低限のチェックのみになっています。このままでは非常に心もとないため、次回は、データ登録のセキュリティ対策を考えてみたいと思います。
usualoma
こんにちは、たびたび失礼します。
------------------------------------
header("Location: ./registConfirm.php");
------------------------------------
「Location:」の後ろは、仕様的には http:// から始まるURLと決められています。
いろんなところで上記のようなコードを見るので、気をきかせてくれるブラウザが多く問題はほとんど発生しないと思うのですが、確か、一部の携帯端末のブラウザではエラーになってしまったりした気がします。
--------------------
myAuth -> addUser
--------------------
addUser の内部でも mysql_real_escape_string 相当のことが行われるようなので、渡す前にエスケープしてしまうと、二重でエスケープされてしまいます。
にっく
天野さん
にっくです、連続でコメントありがとうございます。
こちらも、なるほどです。
前の記事と合わせて、PHPのマニュアル・参考書など見つつ、修正を行おうと思います。