前回は新規ユーザー登録機能を実装しました。
今回はログインとログアウト機能の実装を行います。
↓前回の記事はこちら
ログイン機能
まずは実装する流れを確認します。
- ログイン失敗時の処理
- ログイン成功時の処理
- セッションがない状態で家計簿ページにアクセスされた場合はログインページへ戻す
それではこの流れに沿って実装していきます。
ログイン失敗時の処理
現在画面には「ログイン」と「初期設定へ」の2種類のボタンがありますが、ここではまず「ログイン」のボタンの処理を実装します。
ログイン処理はlogin.phpに記述します。そのためまずはファイル冒頭にDB接続ファイルや関数定義ファイルの読み込みプログラムを記述します。
<?php
require_once('./dbconnect.php');
include_once('./functions.php');
共通ファイルの読み込みが記述できたらログインボタン押下時の処理を実装していきます。
まずはデータベースに存在しない情報でログインが試みられた場合の処理です。
//ログインボタン押下処理
if ($_SERVER['REQUEST_METHOD'] === 'POST') :
$post_username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_SPECIAL_CHARS);
$post_password = filter_input(INPUT_POST, 'password', FILTER_SANITIZE_SPECIAL_CHARS);
endif;
上記のプログラムは、POST送信がされたら、送信されたデータをフィルターにかけて変数にセットする処理です。
ログインボタンがtype=submitのinput要素なので押下するとPOST送信が行われます。
ここからデータベース内を検索して一致する情報があったとき、なかったときの条件を分けて実装していきます。
ここからのプログラムは上記で作成したif文の中に追記していきます。
//ログイン確認
$sql = 'SELECT * FROM user WHERE username = ? LIMIT 1';
$stmt = $db->prepare($sql);
$stmt->bind_param('s', $post_username);
sql_check($stmt, $db);
$stmt->bind_result($user_id, $nickname, $username, $hash_password, $initial_savings);
$stmt->fetch();
まずSELECT文で入力されたusernameと同じデータを抽出するSQLを作り変数に格納します。
そのSQLをセットし、エラーチェックを挟んだあとSQLの「?」の部分に入れるusernameに送られてきたデータをセットしエラーチェックをはさみます。
その後得られたデータをそれぞれ変数にセットしてfetchで取り出していきます。
データの取り出しが始まったら、一致するデータが存在するかの条件をつけてログイン成功と不成功の処理を記述していきます。
//パスワード一致確認処理
if (password_verify($post_password, $hash_password)) : //ログイン成功時
echo 'ログイン成功';
exit();
//ログイン失敗時
else :
$login = 'error';
endif;
ログインが成功したかエラーかは取り出してきたデータのパスワードを比べて判断します。
まずパスワードは前回登録する際に暗号化しているのでそのまま文字列比較をすることができません。
そこでpassword_verify関数を使って、入力されたパスワードとデータベースに登録されている暗号化されたパスワードを比較します。
ここではログイン成功時には「ログイン成功」の出力を仮の処理として記述しています。
反対にログインが成功しなかった場合は$login変数に’error’ をセットし処理を終えます。
それではこの$login = ‘error’ を使って現在画面に表示されているエラーメッセージをログインに失敗したときだけ表示するようにしましょう。
<main>の下に以下のエラーメッセージ要素を追加します。
<?php if ($login === 'error') : ?>
<section class="p-section p-section__message p-section__message--join">
<div class="p-message-box p-message-box--error">
<p>ユーザー名またはパスワードが間違えています。</p>
</div>
</section>
<?php endif; ?>
エラーメッセージの要素をif文の中に入れて、ログインに失敗したときだけ表示するようにしました。
ログイン成功時には「ログイン成功」の文字が表示されています。
この時、その他の要素が表示されなくなるのはechoの下でexit()をしているためです。
以上でログイン失敗時の処理は完了です。続いてログイン成功時の処理を実装していきます。
ログイン成功時の処理の実装
ログインが成功した際の処理は先程「echo ‘ログイン成功’;」とした場所を書き換えていきます。
//パスワード一致確認処理
if (password_verify($post_password, $hash_password)) :
//以下を追記
session_regenerate_id();
$_SESSION['user_id'] = $user_id;
$_SESSION['nickname'] = $nickname;
$_SESSION['username'] = $username;
$_SESSION['initial_savings'] = $initial_savings;
//追記ここまで
//echo 'ログイン成功';
exit();
else :
$login = 'error';
endif;
ログインが成功した場合はまずセキュリティ強化のためセッションIDを再生成した後、セッションにパスワード以外の情報を保存します。
まだセッションを使う宣言をしていないので、共通ファイルの読み込みプログラムの上にセッションを使う宣言を追記します。
<?php
session_start(); //追記
require_once('./dbconnect.php');
include_once('./functions.php');
これでログインに成功するとセッションにユーザー情報が保存されるようになりました。
続いてセッションを保存したあとにheader関数を使って別の画面へ遷移させます。ユーザー登録をしたあと初めてログインする場合は「初期設定画面」にそれ以外は「ホーム画面」に遷移させます。
この初めてのログインを記録しておく必要がありますが、この情報もセッションを使って実装していきます。
まずconfirm.phpで初めてのログインに今後なるという情報を記述します。
unset($_SESSION['nickname'], $_SESSION['username'], $_SESSION['password'], $_SESSION['initial_savings']);
//以下1行を追記
$_SESSION['login_times'] = 'first';
header('Location: thanks.php');
exit();
thanks.phpに移る際、セッションをすべて削除したあとで ‘login_times’ というキーネームで初めてのログインであるという情報をセットします。
そしてthanks.phpもセッションを使うことを宣言し、上記の情報を保持し他のページに渡せるように準備します。
<?php
session_start();
if (!isset($_SESSION['login_times']) || !$_SESSION['login_times'] === 'first') :
header('Location: ../login.php');
endif;
?>
セッションを使うことを宣言したあと、初めてのログインであるという情報がセットしてない場合は不正な遷移とみなし、ログインページに強制的に戻します。
以上で初回ログイン情報が、正常にユーザー登録されてからログイン画面に遷移した際だけ渡ってくるようになります。
それではこの情報を使って現在ログイン画面にある「ログイン」と「初期設定へ」のボタンの表示非表示を切り替えます。
まず以下を共通ファイルの読み込みの下に追記します。
//初回ログイン情報処理
if (isset($_SESSION['login_times']) && $_SESSION['login_times'] === "first") :
$login_times = 'first';
else :
$login_times = 'not_first';
endif;
渡ってきた初回ログイン情報があった場合とない場合に$login_times変数に各値をセットしています。
<!--書き換え前 88行目付近-->
<input class="c-button c-button--bg-blue" type="submit" name="to_login" value="ログイン">
<input class="c-button c-button--bg-blue" type="submit" name="to_setting" value="初期設定へ">
<!--書き換え後-->
<?php if ($login_times === 'not_first') : ?>
<input class="c-button c-button--bg-blue" type="submit" name="to_login" value="ログイン">
<?php endif; ?>
<?php if ($login_times === 'first') : ?>
<input class="c-button c-button--bg-blue" type="submit" name="to_setting" value="初期設定へ">
<?php endif; ?>
各ボタンをif文で囲み、$login_timesの値によって出力するorしないを切り替えます。
これによって初回ログインの際は「初期設定へ」が表示され、それ以外の際は「ログイン」が表示されるようになります。
加えて、初回ログイン時は新規ユーザー登録ボタンは表示させないようにします。
<!--書き換え前 90行目付近-->
<p>ユーザー登録がお済みでない方</p>
<a class="c-button c-button--bg-blue" href="./join/index.php">新規ユーザー登録</a>
<!--書き換え後-->
<?php if ($login_times === 'not_first') : ?>
<p>ユーザー登録がお済みでない方</p>
<a class="c-button c-button--bg-blue" href="./join/index.php">新規ユーザー登録</a>
<?php endif; ?>
最後にそれぞれのボタンの遷移先をセットします。
以下をパスワードの一致確認処理の下に追記します。
//パスワード一致確認処理
if (password_verify($post_password, $hash_password)) : //ログイン成功時
session_regenerate_id();
$_SESSION['user_id'] = $user_id;
$_SESSION['nickname'] = $nickname;
$_SESSION['username'] = $username;
$_SESSION['initial_savings'] = $initial_savings;
//ここから追加 初期ログインかそれ以外で処理を可変
if (isset($_POST['to_login'])) :
header('Location: ./index.php');
exit();
elseif (isset($_POST['to_setting'])) :
header('Location: ./item-edit.php?editItem=1');
exit();
endif;
//ここまで追加
exit();
それぞれのボタンにname属性をセットしているので、name属性の値によって遷移先をセットしています。ここでは初回ログイン時は支出カテゴリーの設定画面へ遷移させています。
以上でログイン成功時の処理は完了です。
セッションが保存されていない場合はログインページへ戻す
現在、URLを直接打つことでログインしなくても遷移することができます。
これではログインの意味がないので、ログインしたセッションがない場合はログインページに強制的に戻すようにします。
以下のプログラムを必要なページにいちいち記述するのは手間なので、DB接続や関数のように、共通ファイルとしてすべてのページに読み込ませていきます。
「session.php」というファイルを新たに作成し、以下を記述します。
<?php
session_start();
//ログインセッション処理
if (isset($_SESSION['user_id']) && isset($_SESSION['nickname']) && isset($_SESSION['initial_savings']) && isset($_SESSION['username'])) :
$user_id = $_SESSION['user_id'];
$username = $_SESSION['username'];
$nickname = $_SESSION['nickname'];
$initial_savings = $_SESSION['initial_savings'];
else :
header('Location: login.php');
exit();
endif;
それでは上記を必要なファイルに読み込ませます。
既にsession_start()やログインセッションの処理が記述されている場合はその部分を削除してからファイル読み込み処理を記述します。
読み込みが必要なファイル(joinディレクトリ直下は全て必要なし)
・account.php
・index.php
・item-edit.php
・record-edit.php
include_once('./session.php');
上記のファイル読み込みプログラムを共通ファイルの読み込みの1番上に記述します。
以上でログインをしていない状態で直接URL遷移を試みても、ログイン画面へ戻すという実装が完了です。
ログアウト機能
最後にログアウト機能を実装します。
各ページのヘッダー1番右のアイコンがログアウトボタンになります。
ここを押下することで確認画面を踏んだあと、ログアウトされログイン画面へ戻すという処理を実装します。
まずはログアウトボタンが押されたら「ログアウトしますか?」という確認ダイアログを表示するイベントを作成します。
//ログアウトボタン押下確認ダイアログイベント
const logoutConfirm = () => {
const logoutButton = document.getElementById('logoutButton');
const confirmText = confirm('ログアウトしますか?');
if (!confirmText) {
logoutButton.setAttribute('href', '');
}
}
プログラムの内容は過去にデータを削除するときに作成したイベントと同様です。
続いて上記イベントをそれぞれのページのログアウトボタンにセットします。その際にhref属性も一緒にセットしておきます。
ログアウトボタンがあるページ
・account.php
・index.php
・item-edit.php
・record-edit.php
<a href="./logout.php" id="logoutButton" onclick="logoutConfirm();">
それではログアウトのプログラムを記述していきます。まずは「logout.php」という名前でファイルを作成します。
そして以下を記述します。
<?php
session_start();
session_destroy();
header('Location: ./login.php');
exit();
?>
session_start()でセッションをスタートさせたあと、session_destroy()でセッションを削除します。
session_destroy関数 – 公式ドキュメント
以上でログアウト機能の実装は完了です。
最後に
今回はログインとログアウトの機能を実装しました。
次回は初期設定の画面と、各ページをユーザーの情報と連携する実装を行います。
最後までお読みいただきありがとうございました。
コメント