PHPとMySQLでECサイトをフルスクラッチ開発②スタッフログイン、ログアウト画面の作成
2021-07-21
今回は、「ログイン画面」を作成します。ログインについての仕組みが分かると思いますので、結構重要な部分になります。
☆が前回作成したページです。先頭の雲マークの「スタッフログイン」の部分を今回作成します。
ログインの流れとしては、
①ログイン情報入力
②ログイン情報チェック
③ログイン後の管理画面に遷移
となります。ついでに
④ログアウト
まで作成しようと思います。
ログイン情報入力画面
staff_login.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content= "width=device-width, initial-scale=1.0"> <title>ログイン入力</title> <link rel="stylesheet" href="../style.css"> </head> <body> スタッフログイン<br><br> <form action="staff_login_check.php" method="post"> スタッフコード<br> <input type="text" name="code"> <br><br> パスワード<br> <input type="password" name="pass"> <br><br> <input type="submit" value="OK"> </form> </body> </html>
まずログイン情報の入力画面になりますが、このページはPHPを使わないのでhtmlになっています。
htdocs配下にstaff_loginフォルダを作成し、その配下にstaff_login.htmlファイルを作成します。
formタグでスタッフコードとパスワードの入力画面を表示させています。
submitで、staff_login_check.phpへスタッフコードとパスワードがpost送信されます。
127.0.0.1/staff_login_staff_login.htmlにアクセスすれば、下図のような画面が表示されます。
ログイン情報チェック画面
staff_login_check.php
<?php try { require_once("../common/common.php"); $post = sanitize($_POST); $code = $post["code"]; $pass = $post["pass"]; $pass = md5($pass); $dsn = "mysql:host=localhost; dbname=shop;charset=utf8"; $user = "root"; $password = ""; $dbh = new PDO($dsn, $user, $password); $dbh -> setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $sql = "SELECT name FROM mst_staff WHERE code=? AND password=?"; $stmt = $dbh -> prepare($sql); $data[] = $code; $data[] = $pass; $stmt -> execute($data); $dbh = null; $rec = $stmt -> fetch(PDO::FETCH_ASSOC); if(empty($rec["name"]) === true) { print "入力が間違っています。<br><br>"; print "<a href='staff_login.html'> 戻る</a>"; exit(); } else { session_start(); $_SESSION["login"] = 1; $_SESSION["name"] = $rec["name"]; $_SESSION["code"] = $code; header("Location:staff_login_top.php"); exit(); } } catch(Exception $e) { print "只今障害が発生しております。<br><br>"; print "<a href='staff_login.html'> 戻る</a>"; } ?>
staff_loginフォルダ配下にstaff_login.check.phpファイルを作成します。
このページは、データベースを参照し前のページで入力したスタッフコードとパスワードが一致すれば、ログイン完了するページになります。
前回作成した関数のファイルをインクルードさせて、sanitizeでPOSTの値にクロスサイトスクリプティング対策を施し、codeとpassを受け取ります。
passはmd5で32桁の乱数に変換させていますが、これはデータベースに登録されているパスワードをmd5で暗号化させているからですね。
12~16行目は、おなじみのDB接続の記述です。
18~22行目がSQLの記述になりますが、18行目の
"SELECT name FROM mst_staff WHERE code=? AND password=?"; は、
SELECT name(カラムの選択)、FROM mst_staff(テーブルの選択)、WHERE code=? AND password=?(code=?とpassword=?が一致するレコード)、になります。
$data[] = $code; $data[] = $pass; で code=?とpassword=? に値が渡されるので、つまり、前回データベースに登録したスタッフがあるかと思いますので、そのスタッフコードとパスワードを入力すれば、そのレコードのnameカラムである名前が選択される訳です。
レコードの追加は「INSERT INTO テーブル名(カラム)VALUES(?)」でしたが、
レコードの参照は「SELECT カラム名 FROM テーブル名 WHERE 参照したいレコードの情報」になります。
$stmt -> execute($data); でSQLを実行します。DB切断後の
$rec = $stmt -> fetch(PDO::FETCH_ASSOC); は、SQLで選択した値を取り出しています。今回の場合は、nameになりますね。
その後のif文で、empty($rec["name]) つまり取り出した値が空かどうかを確かめています。
したがって、もし前のページで入力した情報がデータベースに該当する事が無ければ、「空」になるので、入力が異なる旨を伝えて前のページへ誘導します。
exit(); は、そこでプログラムが強制終了するので、それ以降のプログラムは実行されません。
取り出したnameに値が入っているなら、それはデータベースからnameがと取り出せているので、ログイン成功と見なせます。
したがって、elseの内容が実効されます。
sessionについて
sessionとは、アクセスしているユーザーに一意のsession IDを付与し(サーバー側に保存される)、そのIDを利用してその後のページ移動の際にユーザーのログイン情報や購入情報(カートに入れている商品の情報等)を保持させる事が可能になります。
例えば、ページ移動の際に、値を受け渡す場合はpost送信やget送信が必要ですが、sessionの内容は一度専用の変数に値を入れてしまえば、なにをせずともページを移動した際にその内容が消える事はありません。これが最大の特徴です。
session_start(); は、ユーザーに一意のsession IDを付与する事になります。
$_SESSION[] は、前途したページを移動しても消える事が無い変数の値になります。引数には任意の値を格納する事が出来、session_start();後に使えるようになります。
したがって、ログインが完了すれば、今回のように$_SESSION[login]に1を格納し、ログインが完了している証拠にすることができます。
後はログインしているスタッフ名等を格納し、他のページで使えるようにしておきます。
headerについて
最後にheaderについてですが、これは
header("Location:staff_login_top.php");
引数にあるLocation: の後のURLに自動的に飛ばせることが可能になります。
つまり、ログイン認証が取れれば、sessionを開始させた後に自動的にstaff_login_top.phpのページに飛ぶことになるので、このページは「表示されることはない」のです。
注意点は、必ずその後のプログラムは終了させるためにexit();で閉める事と、「htmlの中に記述しない」事になります。htmlの中に記述すれば、正常に機能しなくなるみたいです。
したがって、このページではhtmlを記述していません。
ログイン後の管理画面
staff_login_top.php
<?php session_start(); session_regenerate_id(true); if(isset($_SESSION["login"]) === false) { print "ログインしていません。<br><br>"; print "<a href='staff_login.html'> ログイン画面へ</a>"; exit(); } else { print $_SESSION["name"]."さんログイン中"; print "<br><br>"; } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content= "width=device-width, initial-scale=1.0"> <title>管理画面TOP</title> <link rel="stylesheet" href="../style.css"> </head> <body> 管理画面TOP<br><br> <a href="../staff/staff_list.php"> スタッフ管理</a> <br><br> <a href="../product/product_list.php"> 商品管理</a> <br><br> <a href="staff_logout.php"> ログアウト</a> </body> </html>
ここから先はログインしたスタッフしかアクセスできなくしたいので、先頭にif文でログインしているか否かの記述を加えます。
していなければ、ログインページへ誘導し、exit();で閉めます。
session_start();は、前途したように$_SESSIONを使うページでは必須です。
session idは、前のページで与えられたものになりますが、「セッションハイジャック」により、なりすましの危険性があるので、session_regenerate_id(true); でページ毎にsession idをランダムに変更させています。
ログインしていれば、名前を表示させています。
このページは、スタッフ、及び商品管理のトップページにしたいので、html部にはリンクを張る事にします。
ログアウトのリンクも張っておきます。
それでは、staff_login.htmlでスタッフ情報を入力し、ログインしてみて下さい。問題なければ下図のようになっているはずです。
※この段階でsessionが使えるようになったので、前回作成したstaff_addのファイルのコメントアウト部は、解除しておいてください。
ログアウト画面
staff_logout.php
<?php session_start(); $_SESSION = array(); if(isset($_COOKIE [session_name()]) === true) { setcookie(session_name(), "", time()-42000, "/"); } session_destroy(); ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content= "width=device-width, initial-scale=1.0"> <title>ログアウト</title> <link rel="stylesheet" href="../style.css"> </head> <body> ログアウトしました。<br><br> <a href="staff_login.html">ログイン画面へ</a> </body> </html>
最後に、ログアウトのページを作成します。
$_SESSION = array(); は、sessionの値を全て消去しています。
if文の記述がややこしいですが、簡単に言えば「cookieの消去」になります。
cookieはブラウザ側に保存されるsession的な情報になるので、これも消去しています。
session_destroy(); でsessionが完全に解除されるので、ここまでがワンセットになります。
htmlは、ログアウトした旨を伝え、login画面へ誘導しています。