ここまでで、管理画面用のHTMLをひととおり作成しました。
機能の実装をはじめる前に、管理画面のログイン認証機能を作成したいと思います。
ログイン認証の仕組み
セッションの仕組みを使って、以下のような設計でログイン状況を管理します。
なお、管理画面ユーザーのアカウント情報については、usersテーブルで管理します。
- 未ログイン状態で管理画面にアクセスされた場合、ログインフォームに転送
- ログインフォームにてログイン情報入力
- ログイン情報が正しかった場合、sessionにログイン情報を保存
- 以降、全ページでログイン状況をチェック
セッションについて詳しくは、以下を参考にしてください。
テーブルの用意
以下のデータベーステーブルを作成します。
usersテーブルの設計
phpMyAdminから、管理画面用のアカウントを管理するusersテーブルを作成します。
phpMyAdminを開いたら、データベースのトップ画面へ移動します。
「テーブルを作成」ブロックで、「名前:users」「カラム数:5」を指定して、「実行」をクリックしてください。
テーブルの内容は以下となります。
名前 | データ型 | 長さ/値 | インデックス | A_I | コメント |
---|---|---|---|---|---|
user_id | INT | PRIMARY | ON | 通しID | |
user_loginid | VARCHAR | 20 | ログインID | ||
user_password | VARCHAR | 100 | パスワード | ||
user_updated | TIMESTAMP | 更新日時 | |||
user_created | TIMESTAMP | 作成日時 |
SQLは以下となります。
CREATE TABLE `users` ( `user_id` int(11) NOT NULL COMMENT '通しID', `user_loginid` varchar(20) NOT NULL COMMENT 'ログインID', `user_password` varchar(100) NOT NULL COMMENT 'パスワード', `user_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時', `user_created` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '作成日時' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='管理画面ユーザー'; ALTER TABLE `users` ADD PRIMARY KEY (`user_id`); ALTER TABLE `users` MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '通しID', AUTO_INCREMENT=1;
アカウントの追加
管理画面用アカウントについては、phpMyAdminから直接作成することにします。
さっそくusersテーブルを開いた画面で、タブの「挿入」をクリックしてください。
レコードを作成する画面が表示されます。
ここでは、以下のように入力します。
user_id: 空欄のままとします。(オートインクリメントなので)
user_loginid: 今回は「admin」とします。
user_password: 今回は「admin_password」とします。また、関数に「SHA1」を指定します。
user_update: 「CURRENT_TIMESTAMP」のままとします。
user_created: 任意の値を入力します。
※phpMyAdminでは、レコード挿入時に関数を指定できます。今回user_passwordについては、セキュリティのため、生のパスワードではなく、SHA1アルゴリズムでハッシュ化したパスワードを保存するようにします。ハッシュ化をしておくことで、万一user_passwordのデータが漏洩しても、被害を最小限にできます。
上記のレコード作成については、以下のSQLを実行することでも実施できます。
INSERT INTO `users` (`user_id`, `user_loginid`, `user_password`, `user_updated`, `user_created`) VALUES (1, 'admin', SHA1('admin_password'), '2017-01-01 00:00:00', '2017-01-01 00:00:00');
プログラムの修正
ログインフォームの実装のために、以下の修正を行います。
管理画面用の共通処理プログラム
system/common_admin.phpを以下のように修正します。
<?php
// 関連ファイルをロード
require_once "common.php";
// セッションの開始
session_start();
// ログイン状態のチェック
$logined_flag = false; // ログイン状態フラグ
if (!isset($ignore_login)) {
// 認証用変数をsessionから取得
if (isset($_SESSION["user_id"])) {
$session_user_id = $_SESSION["user_id"];
try {
$stmt = $db->prepare("SELECT * FROM users WHERE user_id = ? LIMIT 1");
$stmt->execute(array($session_user_id)); // クエリの実行
$row_user = $stmt->fetch(PDO::FETCH_ASSOC); // SELECT結果を配列に格納
if ($row_user) {
// 該当のuserレコードがあったらログイン状態にする
$logined_flag = true;
}
} catch (PDOException $e) {
// エラー発生時
exit("ログイン状態のチェックに失敗しました");
}
}
// ログイン状態でなかったら、ログインページへジャンプ
if (!$logined_flag) {
header("location: login.php");
exit;
}
}
以下でブロックごとに解説します。
// セッションの開始 session_start();
セッションを有効化します。
Webアプリケーションではセッションを利用することで、ページをまたいだ状態の保持を行うことができます。
// ログイン状態のチェック $logined_flag = false; // ログイン状態フラグ if (!isset($ignore_login)) {
$logined_flagをfalseで初期化しています。
また、$ignore_loginがfalseの際にログイン状態のチェックを行うように切り分けています。
(login.phpのみ、未ログイン状態でも表示できるようにしています)
// 認証用変数をsessionから取得 if (isset($_SESSION["user_id"])) { $session_user_id = $_SESSION["user_id"];
スーパーグローバル変数(プログラム上で自動的に初期化される変数)である$_SESSIONから、user_idを取得しています。(login.phpにて、ログイン成功時にuser_idをセットしています)
try {
try構文を使って、例外(エラー)をcatchできるようにしています。
$stmt = $db->prepare("SELECT * FROM users WHERE user_id = ? LIMIT 1"); $stmt->execute(array($session_user_id)); // クエリの実行 $row_user = $stmt->fetch(PDO::FETCH_ASSOC); // SELECT結果を配列に格納
SQL内のWHERE句にプレースホルダー文字列(?)を記入し、execute時にセッションから取得したlogin_idを指定しています。
その後、該当行をfetchで取得しています。
if ($row_user) { // 該当のuserレコードがあったらログイン状態にする $logined_flag = true; }
ログイン状態だと判断できたら、ログイン状態を表すフラグにtrueを代入します。
// ログイン状態でなかったら、ログインページへジャンプ if (!$logined_flag) { header("Location: login.php"); exit; }
未ログインと判断された場合、強制的にlogin.phpを表示します。
header関数について詳しくは、以下をご覧ください。
フォーム認証プログラム
admin/login.phpを以下のように修正します。
<?php $ignore_login = true;?> <?php require_once "../system/common_admin.php";?> <?php // ホワイトリスト変数の作成 $whitelist = array("send", "user_loginid", "user_password"); $request = whitelist($whitelist); $page_message = ""; // ページに表示するメッセージ $page_error = ""; // エラーメッセージ // エラーチェック if (isset($request["send"])) { if ($request["user_loginid"] == "") { $page_error .= "ログインIDを入力してください\n"; } if ($request["user_password"] == "") { $page_error .= "パスワードを入力してください\n"; } } // ログイン実行 if (isset($request["send"]) && $page_error == "") { try { // まずはログインIDでSELECTする $stmt = $db->prepare("SELECT * FROM users WHERE user_loginid = ? LIMIT 1"); $stmt->execute(array($request["user_loginid"])); // クエリの実行 $row_user = $stmt->fetch(PDO::FETCH_ASSOC); // SELECT結果を配列に格納 if ($row_user) { // 該当のuserレコードがあったら、パスワードを照合する if (sha1($request["user_password"]) == $row_user["user_password"]) { $_SESSION["user_id"] = $row_user["user_id"]; header("Location: index.php"); exit; } } $page_error .= "入力内容をご確認ください\n"; } catch (PDOException $e) { // エラー発生時 exit("ログイン処理に失敗しました"); } } ?> <?php $page_title = "ログイン";?> <?php require "header.php";?> <p class="attention"> <?php echo nl2br(he($page_error)); ?> </p> <form action="login.php" method="post"> <div> ログインID<br> <input type="text" name="user_loginid" size="30" value=""> </div> <div> パスワード<br> <input type="password" name="user_password" size="30" value=""> </div> <div> <input type="submit" name="send" value="ログインする"> </div> </form> <?php require "footer.php";?>
以下でブロックごとに解説します。
<?php $ignore_login = true;?>
ログインページのみ、認証チェックを無効化するフラグ変数にtrueを代入します。
// ホワイトリスト変数の作成 $whitelist = array("send", "user_loginid", "user_password"); $request = whitelist($whitelist);
このプログラムで使用する変数を指定し、$requestに代入します。
// エラーチェック if (isset($request["send"])) { if ($request["user_loginid"] == "") { $page_error .= "ログインIDを入力してください\n"; } if ($request["user_password"] == "") { $page_error .= "パスワードを入力してください\n"; } }
必須入力チェックをします。
// まずはログインIDでSELECTする $stmt = $db->prepare("SELECT * FROM users WHERE user_loginid = ? LIMIT 1"); $stmt->execute(array($request["user_loginid"])); // クエリの実行 $row_user = $stmt->fetch(PDO::FETCH_ASSOC); // SELECT結果を配列に格納
入力されたログインIDを使用して、アカウントデータを取得します。
if ($row_user) { // 該当のuserレコードがあったら、パスワードを照合する if (sha1($request["user_password"]) == $row_user["user_password"]) { $_SESSION["user_id"] = $row_user["user_id"]; header("Location: index.php"); exit; } }
パスワードをsha1関数を使って評価します。
正しいパスワードだった場合は、$_SESSION[“user_id”]に値をセットして、管理画面トップページにリダイレクトします。
以上で管理画面のフォーム認証が実装できました。
今回のコンテンツについては以下よりダウンロードできます。