「新規会員登録機能を作成する」で作成した会員データ(memberテーブル)を利用したログイン機能を作成します。
スポンサーリンク
memberテーブルは以下のような構造になっています。
1 2 3 4 5 6 7 |
CREATE TABLE member ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, account VARCHAR(50) NOT NULL, mail VARCHAR(50) NOT NULL, password VARCHAR(128) NOT NULL, flag TINYINT(1) NOT NULL DEFAULT 1 )ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; |
新規会員機能を作成しなくてもログイン機能だけで試せるように、memberテーブルにはあらかじめ以下のデータを入力して下さい。アカウントは「ウェブの葉」、パスワードは「samplepass」でログインできるようになります。
1 |
INSERT INTO member(account,mail,password) VALUES ( 'ウェブの葉', 'sample@webnoha.co.jp', '$2y$10$V.Jg7kZNzX5vM.SBM4dwfewHmsrSJaeOFa9JOp7jHyXw15nuqZdv2'); |
上記SQL文を実行した結果。
passwordカラムに入力される$2y$10$V〜は「samplepass」をpassword_hash()関数でハッシュ化した値です。
password_hash()関数については関連ページをご参照下さい。
ハッシュ関数について/password_hash()を利用する
login_form.php(ログインフォーム画面)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?php session_start(); header("Content-type: text/html; charset=utf-8"); //クロスサイトリクエストフォージェリ(CSRF)対策 $_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(32)); $token = $_SESSION['token']; //クリックジャッキング対策 header('X-FRAME-OPTIONS: SAMEORIGIN'); ?> <!DOCTYPE html> <html> <head> <title>ログイン画面</title> <meta charset="utf-8"> </head> <body> <h1>ログイン画面</h1> <form action="login_check.php" method="post"> <p>アカウント:<input type="text" name="account" size="50"></p> <p>パスワード:<input type="text" name="password" size="50"></p> <input type="hidden" name="token" value="<?=$token?>"> <input type="submit" value="ログインする"> </form> </body> </html> |
7・8行目
クロスサイトリクエストフォージェリ(CSRF)については以下の関連ページをご参照下さい。
11行目
クリックジャッキング対策については以下の関連ページをご参照下さい。
login_check.php
(アカウント・パスワード確認。認証が通ればlogin_admin.phpへ遷移する。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
<?php session_start(); header("Content-type: text/html; charset=utf-8"); //クロスサイトリクエストフォージェリ(CSRF)対策のトークン判定 if ($_POST['token'] != $_SESSION['token']){ echo "不正アクセスの可能性あり"; exit(); } //クリックジャッキング対策 header('X-FRAME-OPTIONS: SAMEORIGIN'); //データベース接続 require_once("db.php"); $dbh = db_connect(); //前後にある半角全角スペースを削除する関数 function spaceTrim ($str) { // 行頭 $str = preg_replace('/^[ ]+/u', '', $str); // 末尾 $str = preg_replace('/[ ]+$/u', '', $str); return $str; } //エラーメッセージの初期化 $errors = array(); if(empty($_POST)) { header("Location: login_form.php"); exit(); }else{ //POSTされたデータを各変数に入れる $account = isset($_POST['account']) ? $_POST['account'] : NULL; $password = isset($_POST['password']) ? $_POST['password'] : NULL; //前後にある半角全角スペースを削除 $account = spaceTrim($account); $password = spaceTrim($password); //アカウント入力判定 if ($account == ''): $errors['account'] = "アカウントが入力されていません。"; elseif(mb_strlen($account)>10): $errors['account_length'] = "アカウントは10文字以内で入力して下さい。"; endif; //パスワード入力判定 if ($password == ''): $errors['password'] = "パスワードが入力されていません。"; elseif(!preg_match('/^[0-9a-zA-Z]{5,30}$/', $_POST["password"])): $errors['password_length'] = "パスワードは半角英数字の5文字以上30文字以下で入力して下さい。"; else: $password_hide = str_repeat('*', strlen($password)); endif; } //エラーが無ければ実行する if(count($errors) === 0){ try{ //例外処理を投げる(スロー)ようにする $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //アカウントで検索 $statement = $dbh->prepare("SELECT * FROM member WHERE account=(:account) AND flag =1"); $statement->bindValue(':account', $account, PDO::PARAM_STR); $statement->execute(); //アカウントが一致 if($row = $statement->fetch()){ $password_hash = $row[password]; //パスワードが一致 if (password_verify($password, $password_hash)) { //セッションハイジャック対策 session_regenerate_id(true); $_SESSION['account'] = $account; header("Location: login_admin.php"); exit(); }else{ $errors['password'] = "アカウント及びパスワードが一致しません。"; } }else{ $errors['account'] = "アカウント及びパスワードが一致しません。"; } //データベース接続切断 $dbh = null; }catch (PDOException $e){ print('Error:'.$e->getMessage()); die(); } } ?> <!DOCTYPE html> <html> <head> <title>ログイン確認画面</title> <meta charset="utf-8"> </head> <body> <h1>ログイン確認画面</h1> <?php if(count($errors) > 0): ?> <?php foreach($errors as $value){ echo "<p>".$value."</p>"; } ?> <input type="button" value="戻る" onClick="history.back()"> <?php endif; ?> </body> </html> |
16・17行目
データベースの接続を行っています。db.phpは本ページの下記に記載しています。
68行目
まずアカウントでmemberテーブルを検索しています。またflagが1(デフォルトで1の設定)の条件を付けています。
73行目〜
一致するアカウントがあれば、次にパスワードが一致するかを調べていきます。(※「新規会員登録機能を作成する」では、同じアカウント名で登録されているかをチェックしていません。)
78行目
入力されたパスワードとpassword_hash()関数でハッシュ化された値を検証しています。password_verify()関数については、以下の関連ページをご参照下さい。
ハッシュ関数について/password_hash()を利用する
81行目
ログインする前に、新しいセッションIDを生成しています。以下の関連ページをご参照下さい。
84行目
アカウント・パスワードが一致すればlogin_admin.phpへ遷移します。
login_admin.php(ログイン状態)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php session_start(); header("Content-type: text/html; charset=utf-8"); // ログイン状態のチェック if (!isset($_SESSION["account"])) { header("Location: login_form.php"); exit(); } $account = $_SESSION['account']; echo "<p>".htmlspecialchars($account,ENT_QUOTES)."さん、こんにちは!</p>"; echo "<a href='logout.php'>ログアウトする</a>"; |
logout.php(ログアウト)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php session_start(); header("Content-type: text/html; charset=utf-8"); // ログイン状態のチェック if (!isset($_SESSION["account"])) { header("Location: login_form.php"); exit(); } //セッション変数を全て解除 $_SESSION = array(); //セッションクッキーの削除 if (isset($_COOKIE["PHPSESSID"])) { setcookie("PHPSESSID", '', time() - 1800, '/'); } //セッションを破棄する session_destroy(); echo "<p>ログアウトしました。</p>"; echo "<a href='login_form.php'>ログイン画面へ</a>"; |
db.php(データベース接続)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php function db_connect(){ $dsn = 'mysql:host=◯◯◯;dbname=◯◯◯;charset=utf8'; $user = '◯◯◯'; $password = '◯◯◯'; try{ $dbh = new PDO($dsn, $user, $password); return $dbh; }catch (PDOException $e){ print('Error:'.$e->getMessage()); die(); } } |
4〜6行目
環境に合わせて適当な値を設定して下さい。