フレームワークなしでPHPを用いてセッション認証機能を構築する(Ⅲ.開発<part1>)

本記事は、フレームワークなしでPHPを用いてセッション認証機能を構築する(II.開発環境の構築)の続きです。

Ⅲ.開発(前半)

  1. index.phpの作成
  2. フォーム画面の作成
  3. 共通部分のhtml<head>タグを切り出したphpファイル

1.index.phpの作成

ユーザーからのリクエストの起点となるphpファイルを作成します。

/index.php

<?php
// サインアップ画面へリダイレクト
 header('Location: /views/signin.php');

2.フォーム画面の作成

2-1.サインイン画面

/views/signin.php

<?php

/**
* サインイン画面の実装内容
* ①認証状態(セッションが残っている)でサインイン画面に遷移した場合はマイページへリダイレクトする
* ②サインイン画面で必要項目を入力し、postして処理をコントローラーに投げる
* ③認証に失敗したらサインイン画面に戻り、エラーを受け取って表示する
* ④csrfトークンを生成しフォームにセット。同トークンをサーバーのセッションファイルに書き込む
*/

/**
* session_startにより、セッションIDが発行され、ブラウザのクッキーにはPHPSESSIDという名称でセッションが、サーバーの/tmpにセッションファイルが生成
* (セッションを作成もしくはセッションIDに基づき現在のセッションを復帰)
* セッション情報はスーパーグローバル変数の $_SESSION に連想配列として格納されるので、プログラムからは$_SESSIONを操作することでセッションを扱うことができる
*/
session_start();

/**
* dirname(__FILE__)にはそのファイルの絶対パスとファイル名が入る
* requireやincludeは絶対パスで指定することが推奨(相対パスだと、読み込み先のファイルでもrequire等でファイルを読み込んでいる場合に、最初に読み込んでいるファイルを起点として相対パスを書く必要があり、ややこしい)
*/
require_once(dirname(__FILE__) . '/../classes/Auth.php');
require_once(dirname(__FILE__) . '/../functions.php');

/**
* ①認証状態(セッションが残っている)でサインイン画面に遷移した場合はマイページへリダイレクトする
* staticなメソッドは、インスタンスを生成しなくても使用することが可能
* if文でtrue(認証のセッションが残っている状態)の場合はマイページへリダイレクト
* exit()はreturnとは違い、ここで処理が即終了する(returnは、呼び出し元へ戻り値を返したい場合に使用)
*/
$isAuthenticated = Auth::checkIsAuthenticated();
if ($isAuthenticated) {
  header('Location: mypage.php');
exit();
}

// ③認証に失敗したらサインイン画面に戻り、エラーを受け取って表示する
$signin_error = [];

// セッションにサインインエラー内容が入っていればそれを$signin_errorへ入れる
isset($_SESSION['err']) ? $signin_error = $_SESSION['err'] : null;
unset($_SESSION['err']);

/**
* ④csrfトークンを生成しフォームにセット。同トークンをサーバーのセッションファイルに書き込む
* サインアウト直後 or セッション状態が切断された場合以外はセッションのcsrfトークンが存在するので、else節へ
* jsとphpのif文のスコープの違い
* */
if (empty($_SESSION['csrf_token'])) {
  $token = generateCsrfToken();
  $_SESSION['csrf_token'] = $token;
} else {
  $token = $_SESSION['csrf_token'];
}
?>

<!-- ②サインイン画面で必要項目を入力し、postして処理をコントローラーに投げる -->
<!DOCTYPE html>
<html lang="ja">

  <!-- includeで共通部分をhtmlで読み込み、titleタグを動的に渡す -->
  <?php $title = 'サインイン'; include(dirname(__FILE__) . '/../layouts/layout.php'); ?>

  <body>
    <section class="d-flex justify-content-center align-items-center vh-100">
      <div>
        <!-- bootstrapのクラス(margin-bottom) -->
        <h2 class="mb-5">サインイン</h2>
        <!-- isset関数は変数に値がなく、かつNULLでないときに、TRUEを返す(NULLが変数に入っていたとしてもFALSEの扱いになる) -->
        <!-- html上でのphpの書き方 -->
        <?php if (isset($signin_error['email_invalid'])) : ?>
          <!-- XSS対策(エスケープ処理) -->
          <!-- echoは1つ以上の文字列を出力する -->
          <p class="text-danger"><?php echo h($signin_error['email_invalid']); ?></p>
        <?php endif; ?>
        <!-- getとpost、action属性 -->
        <form action="../controllers/signin_controller.php" method="post">
          <div class="input-group mb-3">
            <label for="email">メールアドレス:</label>
            <!-- name属性 -->
            <input type="email" name="email" class="form-control">
       <?php if (isset($signin_error['email_blank'])) : ?>
       <p class="text-danger"><?php echo h($signin_error['email_blank']); ?></p>
         <?php endif; ?>
      </div>
      <div class="input-group mb-3">
       <label for="password">パスワード:</label>
       <input type="password" name="password" class="form-control">
       <?php if (isset($signin_error['password_blank'])) : ?>
       <p class="text-danger"><?php echo h($signin_error['password_blank']); ?></p>
       <?php endif; ?>
          </div>
          <div>
            <input type="hidden" name="csrf_token" value="<?php echo h($token); ?>">
            <input type="submit" value="サインインする" class="btn btn-success mb-3">
         </div>
        </form>
        <a href="signup.php">新規登録はこちら</a>
      </div>
    </section>
  </body>
</html>

2-2.サインアップ画面

/views/signup.php

<?php

/**
* サインアップ画面の実装内容
* ①認証状態(セッションが残っている状態)でサインアップ画面にアクセスした場合はマイページへリダイレクトする
* ②サインアップ画面で必要項目を入力し、postして処理をコントローラーに投げる
* ③認証に失敗したらサインアップ画面に戻り、エラーを受け取って表示する
* ④csrfトークンを生成しフォームにセット。同トークンをサーバーのセッションファイルに書き込む
*/

session_start();

require_once(dirname(__FILE__) . '/../classes/Auth.php');
require_once(dirname(__FILE__) . '/../functions.php');

// ①認証状態(セッションが残っている状態)でサインアップ画面にアクセスした場合はマイページへリダイレクトする
$isAuthenticated = Auth::checkIsAuthenticated();
if ($isAuthenticated) {
  header('Location: mypage.php');
exit();
}


// ③認証に失敗したらサインアップ画面に戻り、エラーを受け取って表示する
$signup_error = [];

isset($_SESSION['err']) ? $signup_error = $_SESSION['err'] : null;
unset($_SESSION['err']);

// ④csrfトークンを生成しフォームにセット。同トークンをサーバーのセッションファイルに書き込
if (empty($_SESSION['csrf_token'])) {
  $token = generateCsrfToken();
  $_SESSION['csrf_token'] = $token;
} else {
  $token = $_SESSION['csrf_token'];
}
?>

<!-- ②サインアップ画面で必要項目を入力し、postして処理をコントローラーに投げる -->
<!DOCTYPE html>
<html lang="ja">

  <?php $title = 'ユーザ登録画面'; include(dirname(__FILE__) . '/../layouts/layout.php'); ?>

  <body>
   <section class="d-flex justify-content-center align-items-center vh-100">
    <div>
     <h2 class="mb-5">ユーザ登録フォーム</h2>
     <?php if (isset($signup_error)) : ?>
     <!-- foreach(繰り返し) -->
     <?php foreach ($signup_error as $error) : ?>
     <p class="text-danger"><?php echo h($error); ?></p>
     <?php endforeach; ?>
     <?php endif; ?>
     <form action="../controllers/signup_controller.php" method="POST">
      <div class="input-group mb-3">
       <label for="username">ユーザ名:</label>
       <input type="text" name="username" class="form-control">
      </div>
      <div class="input-group mb-3">
       <label for="email">メールアドレス:</label>
       <input type="email" name="email" class="form-control">
      </div>
      <div class="input-group mb-3">
       <label for="password">パスワード:</label>
       <input type="password" name="password" class="form-control">
      </div>
      <div class="input-group mb-3">
       <label for="password_conf">パスワード確認:</label>
       <input type="password" name="password_conf" class="form-control">
      </div>
      <input type="hidden" name="csrf_token" value="<?php echo h($token); ?>">
      <div class="input-group mb-3">
       <input type="submit" value="新規登録" class="btn btn-success mb-3">
      </div>
     </form>
     <a href="./signin.php">アカウントをお持ちの方はこちら</a>
    </div>
   </section>
  </body>
</html>

2-3.マイページ

/views/mypage.php

<?php

/**
* マイページ画面の実装内容
* ①認証しているか判定し、していなかったらサインイン画面へ返す
*/

session_start();

require_once(dirname(__FILE__) . '/../classes/Auth.php');
require_once(dirname(__FILE__) . '/../functions.php');

// ①認証状態(セッションが残っている状態)を判定し、していなかったらサインイン画面へ返す
$isAuthenticated = Auth::checkIsAuthenticated();

if (!$isAuthenticated) {
  header('Location: signin.php');
  exit();
}

$signin_user = $_SESSION['signin_user'];

?>
<!DOCTYPE html>
<html lang="ja">
<?php $title = 'マイページ'; include(dirname(__FILE__) . '/../layouts/layout.php'); ?>

<body>
  <section class="d-flex justify-content-center align-items-center vh-100">
    <div>
      <h2 class="mb-5">マイページ</h2>
      <p>サインインユーザ:<?php echo h($signin_user['name']) ?></p>
      <p>メールアドレス:<?php echo h($signin_user['email']) ?></p>
      <form action="../controllers/signout_controller.php" method="POST">
        <input type="submit" name="signout" value="サインアウトする" class="btn btn-success mb-3">
      </form>
    </div>
  </section>
</body>
</html>

3.共通部分のhtml<head>タグを切り出したphpファイル

/layouts/layout.php

<?php
// headタグを共通部分として切り出したphpファイル

require_once ( dirname(__FILE__) . '/../functions.php');
?>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- bootstrapのCDN -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
    integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"
      integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous">
    </script>
  <!-- titleタグは動的に受け取って出力 -->
  <title><?php echo h($title);?></title>
</head>

ここまでで、ユーザーからのリクエストの起点となるindex.phpと各種フォーム画面、<head>タグの共通部分を切り出したphpファイルの作成が完了しましたので今回は以上になります。次回はⅢ.開発<part2>になります。

コメント

タイトルとURLをコピーしました