前回からパスワード再設定機能を実装しています。
パスワード再設定機能
パスワード再設定機能は以下の9ステップで進めています。
前編でステップ5まで実装したので、後編ではステップ6から進めていきます。
1 ニックネーム登録プログラムをメールアドレス登録プログラムに書き換え(DB構造も修正)
2 ローカル環境でメールを送信する設定
3 リセットディレクトリとファイルの作成
4 ログイン画面に再設定リンク設置
5 リセットリクエストを記録するDBテーブルを作成
6 認証とメール送信ページ実装
7 送信完了ページ実装
8 パスワード再設定ページ実装
9 パスワード再設定完了ページ実装
認証とメール送信ページ実装
まずは前回作成したpassword-resetディレクトリのindex.phpを実装していきます。
このページではユーザーにパスワードを再設定したいユーザー名とメールアドレスを入力してもらい、送信ボタン押下で、入力されたユーザー名とメールアドレスの存在チェックを行いメールを送信するという機能を実装します。
<?php
require_once('../dbconnect.php');
include_once('../functions.php');
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../css/style.min.css">
<script src="../js/footer-fixed.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&family=Zen+Maru+Gothic:wght@400;500;700;900&display=swap" rel="stylesheet">
<link rel="icon" href="../favicon.ico">
<title>家計簿アプリ|パスワード再設定</title>
</head>
<body class="body" id="body">
<header class="l-header--join">
<h1 class="l-header__title l-header__title--join">パスワード再設定</h1>
</header>
<main class="l-main">
<section class="p-section p-section__password-reset">
<form action="" method="post" class="p-form p-form--password-reset">
<div class="p-form__vertical-input">
<p>ユーザー名<span>※半角英数字6〜12文字</span></p>
<input type="text" id="username" name="username" autocomplete="off" minlength="6" maxlength="12" pattern="[0-9a-zA-Z]+$" onkeyup="usernameChange();inputCheck('resetAuth');" required>
<p class="username-check" id="usernameCheck"></p>
</div>
<div class="p-form__vertical-input">
<p>登録メールアドレス</p>
<input type="email" name="email" autocomplete="off" id="email" pattern="^[a-zA-Z0-9.!#$&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$" class="js-check" onkeyup="emailChange();inputCheck('resetAuth');" required>
<p class="email-check" id="emailCheck"></p>
</div>
<input id="submitButton" class="c-button c-button--bg-blue" type="submit" name="auth" value="認証してメール送信" disabled>
</form>
<a class="c-button c-button--bg-blue" href="../login.php">ログイン画面へ</a>
</section>
</main>
<footer id="footer" class="l-footer">
<p>家計簿アプリ|2022</p>
</footer>
<script src="../js/input-check.js"></script>
</body>
</html>
CSSが当てられていないのですが、ログインフォームと同じものを使うので、以下のようにセレクタを追加し修正します。
.p-section{
//省略
//ログイン、パスワード再設定認証フォームセクション
&__login,
&__password-reset { //セレクタ追加
//省略
}
//省略
}
.p-form{
//省略
//ログイン、パスワード再設定認証フォーム
&--login,
&--password-reset { //セレクタ追加
//省略
input[type="text"],
input[type="password"],
input[type="email"] { //セレクタ追加
//省略
}
}
//省略
}
そしてメールアドレスチェックの関数をjs/input-check.jsに追加します。
//passwordConfirmClear = 0, の下に追記
emailClear = 0,
//const passwordConfirm の下に追記
const email = document.getElementById("email");
//const passCheck の下に追記
const emailCheck = document.getElementById("emailCheck");
//メールアドレス正規表現チェック(パスワード強度チェックの下に追記)
const checkEmail = (checkVal, checkElement) => {
//正規表現を格納
const pattern =
/^[a-zA-Z0-9_+-]+(\.[a-zA-Z0-9_+-]+)*@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$/;
//正規表現に一致しているかの結果を格納
const result = pattern.test(checkVal.value);
if (!result) {
//正しくない形式のメールアドレスが入力されている場合
checkElement.classList.add("incorrect"); //メッセージ要素にincorrectクラス追加
return ["正しいメールアドレスを入力してください", result]; //メッセージ本文と正規表現の結果を返す
} else {
//正しい形式のメールアドレスが入力されている場合
checkElement.classList.remove("incorrect"); //メッセージ要素からincorrectクラスを削除
return ["", result]; //メッセージ本文(空文字)と正規表現の結果を返す
}
};
//const passConfirmChangeの下に追記
const emailChange = () => {
//正規表現チェック関数を実行
const checkResult = checkEmail(email, emailCheck);
//正規表現チェック関数から返されたメッセージ本文をメッセージ要素に挿入
emailCheck.innerHTML = checkResult[0];
//正規表現チェック関数クリアならメールアドレスチェッククリア
if (checkResult[1]) emailClear = 1;
//正規表現チェック関数を通っていない場合はメールアドレスチェックを0にする(未クリア状態)
else emailClear = 0;
};
//1つ目の条件文の末尾に条件追加
const inputCheck = (page) => {
if (page === "join") {
clearSum =
nicknameClear + usernameClear + passwordClear + passwordConfirmClear;
clearVal = 4;
} else if (page === "login") {
clearSum = usernameClear + passwordClear;
clearVal = 2;
}
//★追加★
else if (page === "resetAuth") {
//パスワード再設定認証ページの場合
clearSum = usernameClear + emailClear; //入力クリア合計計算し格納
clearVal = 2; //入力クリア値の2を格納
}
//★追加★
if (clearSum === clearVal) submitButton.disabled = false;
else submitButton.disabled = true;
};
以上でスタイリングと入力チェック処理の実装が終わり、正しい情報を入力すれば送信ボタンを押せるようになります。
続いて送信ボタンが押されたときの処理を実装します。
以下を共通ファイル読み込みプログラムの下に追記します。
//認証してメール送信が押されたら
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['auth'])) :
//値受け取り
$post_username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_SPECIAL_CHARS);
$post_email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
//受け取った値と一致するデータがあるかSQLデータ抽出
$sql = 'SELECT username, email FROM user WHERE username=? AND email=? LIMIT 1';
$stmt = $db->prepare($sql);
$stmt->bind_param('ss', $post_username, $post_email);
sql_check($stmt, $db);
$stmt->store_result();
$count = $stmt->num_rows();
$stmt->bind_result($username, $email);
$stmt->fetch();
if ($count === 0 ) :
echo '登録されていないデータ';
//userテーブルに登録されていない情報で送信が行われている場合の処理
else :
echo 'メール送信';
//認証完了でデータベースにリクエストログ記録とメール送信する処理
endif;
endif;
値を受け取った後、SQLで送られてきた値と一致するデータがあるかを抽出し、データがない場合とある場合で条件分岐を行っています。
一致するデータがあるとき(左上にメール送信と表示される)
一致するデータがないとき(左上に登録されていないデータと表示される)
データが有るときとないときの条件分岐が正しく処理されていることが確認できたので、実際の処理に変更します。
まずはデータがないときです。
if ($count === 0) :
header('Location: ./request-success.php');
exit();
ユーザー名が正しくないのか、メールアドレスが正しくないのか、両方なのかと細かく分岐することもできますが、第三者に情報が漏洩することを考え、正しくない情報の送信でも送信完了ページへ遷移させています。
続いて一致するデータが存在した場合の処理です。
else : //認証完了でデータベースにリクエストログ記録とメール送信
//トークン作成
$reset_token = bin2hex(random_bytes(32));
//リセットリクエストテーブルに記録
$sql = 'INSERT INTO reset_request(username, email, token, time) VALUES (?, ?, ?, ?)';
$stmt = $db->prepare($sql);
$post_time = date('Y-m-d H:i:s');
$stmt->bind_param('ssss', $post_username, $post_email, $post_time, $reset_token);
sql_check($stmt, $db);
//メール作成初期設定
mb_language("Japanese");
mb_internal_encoding("UTF-8");
//送信先
$to = $post_email;
//本文に載せるリセットURL(URLは各環境にあわせてください、以下のURLは架空のものです)
$url = 'https://kakeibo.com/password-reset/password-reset.php?token=' . $reset_token;
//メールタイトル
$subject = '【家計簿アプリ】パスワードリセット用URLのご案内';
//メール本文("\r\n"で改行)
$body = '24時間以内に下記URLへアクセスし、パスワードの変更を完了してください。' . "\r\n\r\n" . $url . "\r\n\r\n" . 'このメールは送信用です。';
//メールヘッダー(各環境に合わせてください。以下は架空のものです。)
// 送信元
$from = "家計簿アプリ事務局 <noreply@https://kakeibo.com>";
// 送信元メールアドレス
$from_mail = "noreply@https://kakeibo.com";
// 送信者名
$from_name = "家計簿アプリ事務局";
// 送信者情報の設定
$header = '';
$header .= "Content-Type: text/plain \r\n";
$header .= "Return-Path: " . $from_mail . " \r\n";
$header .= "From: " . $from . " \r\n";
$header .= "Sender: " . $from . " \r\n";
$header .= "Reply-To: " . $from_mail . " \r\n";
$header .= "Organization: " . $from_name . " \r\n";
$header .= "X-Sender: " . $from_mail . " \r\n";
$header .= "X-Priority: 3 \r\n";
//メール送信処理と送信完了ページへ遷移
mb_send_mail($to, $subject, $body, $header);
header('Location: ./request-success.php');
exit();
プログラムの流れとしては、まずreset-requestテーブルのtokenカラムと、メールアドレスのURLパラメータにつけるトークンを作成します。
bin2hex – 公式ドキュメント
トークン発行後、SQLでreset-requestテーブルに再設定のリクエストがあったことを記録します。
テーブルへの記録が終わったら、メールを送信するために必要な送信先や本文、タイトルを設定し、mb_send_mail関数で送信します。
mb_send_mail – 公式ドキュメント
メールのヘッダー設定は以下の記事を参考にさせていただきました。
送信したら送信完了ページへ遷移させています。
一度テスト送信をしてみましょう。実際に受け取ることのできる自分のメールアドレスを登録したあとログアウトし、パスワード再設定ページからユーザー名とメールアドレスを入力して送信してみます。
前編で紹介したMAMPローカル環境でメールを送信する設定が正しく行われていれば、以下のようにメールが届きます。
そしてreset-requestテーブルにもレコードが登録されています。
以上で認証とメール送信ページの実装は完了です。
送信完了ページ実装
続いて送信完了ページを実装します。
このページは先程テスト送信をした最後に表示された真っ白のページです。
以下をpassword-reset/request-success.phpに記述します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../css/style.min.css">
<script src="../js/footer-fixed.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&family=Zen+Maru+Gothic:wght@400;500;700;900&display=swap" rel="stylesheet">
<link rel="icon" href="../favicon.ico">
<title>家計簿アプリ|パスワード再設定URLメール送信完了
</title>
</head>
<body class="body" id="body">
<header class="l-header--join">
<h1 class="l-header__title l-header__title--join">家計簿アプリ</h1>
</header>
<main class="l-main">
<section class="p-section p-section__request-success">
<p>パスワード再設定URLメール送信完了</p>
<p class="caution">第三者への情報漏えい防止のため、正しくない情報の場合も本画面が表示されます。<br>受信フォルダをご確認の上、メールが届かない場合はお手数ですが、再度<a href="./index.php" class="c-link">こちら</a>からお試しください。</p>
<a href="../login.php" class="c-button c-button--bg-blue">ログイン画面に戻る</a>
</section>
</main>
<footer id="footer" class="l-footer">
<p>家計簿アプリ|2022</p>
</footer>
</body>
</html>
CSSはすでに設定済みなので、以上を追記すると以下のような送信完了画面が表示されます。
このページでは特にPHPのプログラムを記述する箇所はないので、以上で完了です。
パスワード再設定ページ実装
続いてメールに添付したURLの飛ばし先である新しいパスワードを入力し再設定するページを実装します。
まずは以下の静的コーディングと共通ファイルの読み込みプログラムを記述します。
<?php
require_once('../dbconnect.php');
include_once('../functions.php');
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../css/style.min.css">
<script src="../js/footer-fixed.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&family=Zen+Maru+Gothic:wght@400;500;700;900&display=swap" rel="stylesheet">
<link rel="icon" href="../favicon.ico">
<title>家計簿アプリ|パスワード再設定</title>
</head>
<body class="body" id="body">
<header class="l-header--join">
<h1 class="l-header__title l-header__title--join">パスワード再設定</h1>
</header>
<main class="l-main">
<section class="p-section p-section__password-reset">
<form action="" method="POST" class="p-form p-form--password-reset">
<input type="hidden" name="post_username" value="<?php echo $username; ?>">
<input type="hidden" name="post_token" value="<?php echo $token; ?>">
<div class="p-form__vertical-input">
<p>パスワード<span>※半角英数字6〜12文字</span></p>
<input type="password" id="password" name="password" autocomplete="off" minlength="6" maxlength="12" pattern="[0-9a-zA-Z]+$" onkeyup="passChange('reset');inputCheck('reset');" required>
<p class="pass-check" id="passCheck"></p>
</div>
<input id="submitButton" class="c-button c-button--bg-blue" type="submit" name="reset" value="パスワード再設定" disabled>
</form>
</section>
</main>
<footer id="footer" class="l-footer">
<p>家計簿アプリ|2022</p>
</footer>
<script src="../js/input-check.js"></script>
</body>
</html>
そしてこのページは以下の条件に当てはまるときだけ表示します。
・tokenパラメータが存在する
・tokenパラメータの値がリクエスト時に記録した値と一致する
・リクエストが記録されてから24時間以内のアクセスである
まずは以上の条件があったときに表示、条件に当てはまらないときは、ログインページや再設定リクエストページ(password-request/index.php)にエラーパラメータ付きで戻すプログラムを追記します。
以下を冒頭のPHPプログラムの下に追記します。
//メール添付URLからの遷移が正しいかチェック
if (!isset($_GET['token'])) :
//tokenパラメータがない場合はlogin.phpに戻す
header('Location: ../login.php?dataOperation=error');
exit();
//tokenがある場合はリクエスト記録テーブルと照会
else :
//パラメータについているtokenを変数に格納
$token = $_GET['token'];
//パラメータtokenが一致するレコードを抽出
$sql = 'SELECT username, email, time FROM reset_request WHERE token = ? LIMIT 1';
$stmt = $db->prepare($sql);
$stmt->bind_param('s', $token);
sql_check($stmt, $db);
$stmt->store_result();
$count = $stmt->num_rows();
$stmt->bind_result($username, $email, $time);
$stmt->fetch();
//一致するtokenを持つデータがない場合はlogin.phpに戻す
if ($count === 0) :
header('Location: ../login.php?dataOperation=expired');
exit();
//有効期限切れの場合はレコードを削除してからindex.phpに戻す
elseif (date("Y-m-d H:i:s", strtotime("-24 hour")) > $time) :
$stmt = $db->prepare('DELETE FROM reset_request WHERE token=?');
$stmt->bind_param('s', $token_param);
sql_check($stmt, $db);
header('Location: ./index.php?dataOperation=expired');
exit();
endif;
$stmt->close();
endif;
条件判定は以下のようなフローで行っています。
パスワード再設定ボタンが押下されたプログラムの実装の前に、tokenパラメータエラーでログイン画面やリクエスト画面に戻したときのモーダルを実装します。
このモーダルは過去に更新や削除プログラムなどの操作をした際に実装した、メッセージモーダルと同じ処理を使います。
メッセージモーダルのプログラムをログイン画面ファイルと再設定リクエストファイルの<main>の下に追記します。
<main class="l-main">
<!-- 以下追加 操作完了コンテンツ -->
<?php if ($_GET['dataOperation'] && $_GET['dataOperation'] === 'error') : ?> <section class="p-section p-section__full-screen" id="doneOperateBox">
<div class="p-message-box line-red">
<p id="doneText"> 無効なURLです </p>
<button class="c-button c-button--bg-darkred" onclick="onClickOkButton('');">OK</button>
</div>
</section>
<?php endif; ?>
<!---footerの閉じタグ下に追加-->
<script src="./js/import.js"></script>
<script src="./js/functions.js"></script>
<main class="l-main">
<!-- 以下追加 操作完了コンテンツ -->
<?php if ($_GET['dataOperation'] && $_GET['dataOperation'] === 'expired') : ?> <section class="p-section p-section__full-screen" id="doneOperateBox">
<div class="p-message-box line-red">
<p id="doneText"> 有効期限切れのURLです </p>
<button class="c-button c-button--bg-darkred" onclick="onClickOkButton('');">OK</button>
</div>
</section>
<?php endif; ?>
<!---footerの閉じタグ下に追加-->
<script src="../js/import.js"></script>
<script src="../js/functions.js"></script>
パラメータ付きで遷移されたときの処理を実装したので、パスワード再設定ファイルに戻り、再設定で送信されたときのプログラムを実装します。
以下をtokenパラメータチェック処理の下に追記します。
//再設定ボタンが送信されたら
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['reset'])) :
$post_username = filter_input(INPUT_POST, 'post_username', FILTER_SANITIZE_SPECIAL_CHARS);
$post_token = filter_input(INPUT_POST, 'post_token', FILTER_SANITIZE_SPECIAL_CHARS);
$post_password = filter_input(INPUT_POST, 'password', FILTER_SANITIZE_SPECIAL_CHARS);
//送信されたユーザー名とtokenと一致するデータの存在チェック
$sql = 'SELECT username, token FROM reset_request WHERE username=? AND token=? LIMIT 1';
$stmt = $db->prepare($sql);
$stmt->bind_param('ss', $post_username, $post_token);
sql_check($stmt, $db);
$stmt->store_result();
$count = $stmt->num_rows();
$stmt->fetch();
//一致するデータが存在する場合
if ($count === 1) :
//UPDATE構文で該当ユーザーのパスワードをアップデート(暗号化を忘れない)
$stmt = $db->prepare('UPDATE user SET password = ? WHERE username=?');
$hash_password = password_hash($post_password, PASSWORD_DEFAULT);
$stmt->bind_param('ss', $hash_password, $post_username);
$success = $stmt->execute();
if ($success) :
//パスワード再設定完了で該当tokenを持つレコード削除
$stmt = $db->prepare('DELETE FROM reset_request WHERE token=?');
$stmt->bind_param('s', $post_token);
sql_check($stmt, $db);
header('Location: ./reset-complete.php');
exit();
else :
//SQLが実行できなかった場合はログイン画面へパラメータ付きで遷移
header('Location: ../login.php?dataOperation=unexpected-error');
exit();
endif;
//一致するデータが存在しない場合
else :
header('Location: ../login.php?dataOperation=unexpected-error');
exit();
endif;
endif;
再設定ボタンが押されると、入力した新しいパスワードの他に隠しinputにセットしているユーザー名とtokenも送信されます。
まずはそれらのデータを受け取ったあと、もう一度該当するリクエストレコードがあるかチェックします。
有効期限切れのレコードは1つ前のチェックでテーブルから削除しているので、ここではレコードの件数が1であれば、パスワード再設定のプログラムへ移します。
一致するデータがない場合や、故意に隠しinputが操作されるなど不正な遷移が送信が行われた場合は、ログイン画面にエラーパラメータ付きで戻します。
このときのパラメータは先程のエラーパラメータと区別するために別の文字列にしています。
最後に不正遷移のエラーパラメータ処理をlogin.phpに追加します。
<main class="l-main">
<!-- 操作完了コンテンツ 条件文修正とpタグ文字列を三項演算子に修正-->
<?php if ($_GET['dataOperation'] && ($_GET['dataOperation'] === 'error' || $_GET['dataOperation'] === 'unexpected-error')) : ?> <section class="p-section p-section__full-screen" id="doneOperateBox">
<div class="p-message-box line-red">
<p id="doneText">
<?php echo $_GET['dataOperation'] === 'error' ? '無効なURLです' : '不正な遷移が行われました'; ?>
</p>
<button class="c-button c-button--bg-darkred" onclick="onClickOkButton('');">OK</button>
</div>
</section>
<?php endif; ?>
以上でパスワード再設定ページの実装は完了です。
正しくパスワードが更新されると真っ白のページに遷移します。
パスワード再設定完了ページ実装
最後にパスワードの再設定が正しく更新されたあとに遷移するページの実装をします。
このページはPHPのプログラム実装はないので静的ページになります。
以下をreset-complete.phpに記述します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="../css/style.min.css" />
<script src="../js/footer-fixed.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&family=Zen+Maru+Gothic:wght@400;500;700;900&display=swap" rel="stylesheet" />
<link rel="icon" href="../favicon.ico" />
<title>家計簿アプリ|パスワード再設定完了</title>
</head>
<body>
<header class="l-header--join">
<h1 class="l-header__title l-header__title--join">パスワード再設定</h1>
</header>
<main class="l-main">
<section class="p-section p-section__reset-complete">
<div class="p-message-box p-message-box--desc">
<p>パスワードの再設定が完了しました</p>
<a class="c-button c-button--bg-blue" href="../login.php">ログイン画面へ</a>
</div>
</section>
</main>
<footer id="footer" class="l-footer">
<p>家計簿アプリ|2022</p>
</footer>
</body>
</html>
CSSはすでに設定済みです。
以上でパスワード再設定機能全てが完了です。
ヘッダーの共通化
パスワード再設定機能は完成しましたが、最後にヘッダー部分を共通ファイルにまとめて各ファイルに読み込む形式に修正します。
password-resetディレクトリ直下に「header.php」を新規作成し以下を記述します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="../css/style.min.css" />
<script src="../js/footer-fixed.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;300;400;500;700;900&family=Zen+Maru+Gothic:wght@400;500;700;900&display=swap" rel="stylesheet" />
<link rel="icon" href="../favicon.ico" />
<title>家計簿アプリ|<?php echo $page_title; ?></title>
</head>
<body>
<header class="l-header--join">
<h1 class="l-header__title l-header__title--join"><?php echo $page_headertitle; ?></h1>
</header>
そしてpassword-resetディレクトリ内各ファイルの<!DOCTYPE html>から</header>までを削除し以下を冒頭のPHPプログラム内一番下に追記します。
$page_title = '各ページタイトル';
$page_headertitle = '各ページヘッダータイトル';
include_once('./header.php');
以上でヘッダーの共通化は完了です。
最後に
前編後編と2回に分けましたが、今回でパスワード再設定機能が完成しました。
次回はデータ一覧を月ごとで表示するだけでなく、カテゴリーや選択項目で絞り込んで表示する機能を実装します。
最後までお読みいただきありがとうございました。
コメント