入力フォームと確認画面、登録実行画面を分ける(PHP+PEARでウェブサービス勉強記録・6)

前回までは、入力フォーム表示・登録ロジック(registForm.php)と、入力データチェックロジック(registCheck.php)の2ファイルで、ユーザー情報の登録処理を行いました。

今回は、入力フォームに情報入力後、確認画面を経て、登録完了を行うようにロジックを分けたいと思います。

流れとしては、以下のようになるかと思います。

 

 flowchart-20110225-6

確認画面に入力データを渡す

入力フォームにデータを入力後、別画面の確認画面にデータを受け渡す方法はいくつかありますが

  • 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();

    }

?>

 

実行イメージ

入力データに間違ったデータを登録したとき。パスワード以外は直前の入力データを再表示

wrong_regist

入力値を確認する画面

regist_confirm

「元に戻る」ボタンを押したとき。入力値のID、Email、表示名はセッション情報から入力データを再表示する

regist_return

 

確認画面から「登録する」ボタンを押したとき。

regist_complete

registComplete.phpを直接呼び出したとき

wrong_call

次回は、セキュリティ対策を考えてみる

現在の不正登録チェックは、hidden値のチェックのみにとどまっており、最低限のチェックのみになっています。このままでは非常に心もとないため、次回は、データ登録のセキュリティ対策を考えてみたいと思います。