【初学者向けチュートリアル】PHPでログイン機能を実装する

PHP

今回はPHPでセッションを使用してログイン機能を実装していきます。

セッションに関する解説は下記の記事を参照ください。

0.実装の概要

画面と機能は下記の通りになります。

 1.ホーム画面

 2.新規登録画面

 3.ログイン画面

 4.マイページ画面

 5.パスワード編集画面

 6.名前変更画面

 7.ログアウト機能

1.ホーム画面は誰でもアクセスできますが、ログインしているかしていないかによって画面に表示するメニューを変更します。

2.新規登録画面および3.ログイン画面は、ログインしていない人のみがアクセスでき、

4.マイページ画面、5.パスワード編集画面、6.名前変更画面、7.ログアウト機能についてはログインしている人のみがアクセス可能なページ、機能になります。

URLの直接入力した際にログイン有無によるアクセス制限を行う画面や機能にアクセスした場合は、ホーム画面へ強制的に遷移するようにします。

それでは実装してみましょう。

1.事前準備

事前準備ではプロジェクトフォルダの準備とデータベースの作成を行います。

今回はMAMPを使用して開発を進めていきます。

MAMPの設定準備ができていない方は下記の記事を参考にMAMPをインストールしてください。

次にMAMP\htdocs配下にプロジェクトフォルダを「loginPhp」という名前で作成します。

また、localhost:8888/phpMyAdminにアクセスして、データベースの準備を行います。

インポートタブをクリックして下記のSQLを実行してください。

CREATE DATABASE IF NOT EXISTS `login_tutorial` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `login_tutorial`;

CREATE TABLE `m_user` (
  `userId` int(30) NOT NULL,
  `userEmail` varchar(255) NOT NULL,
  `userName` varchar(30) NOT NULL,
  `password` varchar(500) NOT NULL,
  `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


ALTER TABLE `m_user`
  ADD PRIMARY KEY (`userId`),
  ADD UNIQUE KEY `email` (`userEmail`);


ALTER TABLE `m_user`
  MODIFY `userId` int(30) NOT NULL AUTO_INCREMENT;

今回はlogin_tutorialというデータベースを作成し、m_userというテーブルを使用していきたいと思います。

m_userはauto_incrementによって自動で割り当てられるuserIdとEmailアドレスを格納するuserEmail、ユーザー名を格納するuserName、パスワードを格納するpassword、作成された日時を自動で挿入するcreatedAtによって構成されます。

また、Emailアドレスは複数のアドレスで登録されたら大量にIDを作成できてしまうため、UNIQUEで重複を認めない設定とします。

2.ホーム画面の実装

ホーム画面の仕様

ホーム画面の実装では、ログインがあるかないかで、表示されるメニュー項目を変更させるような仕様にしたいのですが、そのような機能は実際にログインされていないと実装できないので、一旦、単純なホーム画面を作成していきます。

実装

プロジェクトフォルダ直下にindex.phpを作成して、下記のプログラムを記述します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <div id="title">
            <a href=""><h1>Login Tutorial</h1></a>
        </div>
        <div id="menu">
            <ul>
                <li><a href="registerForm.php">新規登録</a></li>
                <li><a href="loginForm.php">ログイン</a></li>
                <li><a href="#">お問い合わせ</a></li>
                <li><a href="#">このサイトについて</a></li>
            </ul>
        </div>
    </header>
</body>
</html>

ヘッダーメニューの新規登録ボタンから新規のユーザー登録を行う画面への遷移、ログインボタンからログイン画面への遷移を行います。

お問い合わせとこのサイトについてはメニューが寂しいので形式上表示していますが、特に意味はありません。

ついでにCSSも簡単にコーディングしていきます。

a{
    text-decoration: none;
}

header {
    display: flex;
    justify-content: space-between;
}

header div#menu{
    justify-content: space-around;
}

header div#menu ul{
    list-style: none;
    display: flex;
}

header div#menu ul li{
    margin-right : 15px;
}

これでホーム画面の作成は完了です。

3.ユーザーの新規登録機能

続いてユーザーの新規登録機能の実装になります。

仕様

ホーム画面から、新規登録ボタンをクリック後遷移する画面で新規登録の必要事項を入力し、入力後確認画面へ遷移、確認が完了したら、登録し、登録後は確認画面へ遷移するような仕様にしていきたいと思います。

新規登録での必須項目は下記になります。

・ユーザー名

・メールアドレス

・パスワード

・確認用パスワード

また、確認画面へ遷移する際、パスワードと確認用パスワードが一致していない場合は、エラーメッセージを表示して入力画面へ戻します。

メールアドレスについては、重複の登録は認めず、一メールアドレス一アカウントを作成できるようにします。

データベースでもUNIQUE設定をしているので重複して登録できないようにはしているのですが、それではただデータベースに登録する際にエラーが返ってくるだけになってしまうので、事前に、重複がないように判別するようにもします。

また、パスワードデータベースへ保存するときはデータが盗まれても、パスワードが分からないように暗号化します。

実装

registerForm.phpの実装

まずは、プロジェクトフォルダにregisterForm.phpファイルを作成し、下のプログラムを記述します。

<?php 
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <div id="title">
            <a href=""><h1>Login Tutorial</h1></a>
        </div>
    </header>
    <main>
        <div id="mainTitle">
            <h2>新規登録</h2>
            <p>下記の登録情報を入力してください。</p>
        </div>

        <div id="mainForm">
            <form action="registerConfirm.php" method='POST'>
                <div>
                    <label>メールアドレス</label><br>
                    <input type="email" name="userEmail" required>
                </div>
                <div>
                    <label>ユーザー名</label><br>
                    <input type="text" name="userName" required>
                </div>
                <div>
                    <label>パスワード</label><br>
                    <input type="password" name="password" required>
                </div>
                <div>
                    <label>確認用パスワード</label><br>
                    <input type="password" name="confirmPassword" required>
                <div>
                <input type="submit" value='確認'>
            </form>
        </div>
    </main>
</body>
</html>

ざっくりと新規登録に必要な入力フォームを用意しています。

アクションはPOSTでPOSTする先はregisterConfirm.phpになります。

メールアドレスの欄はtypeをemailとすることによって、メールアドレスではない(っぽくない)値の入力値を未然に防いでくれます。

また、パスワードと確認用パスワードについては、typeをpasswordとすることで入力した値を「⚫︎」で表示して、表示内容を隠してくれます。

registerConfirm.phpの実装

次にregisterForm.phpから、ポストされた先のregisterConfrim.phpの実装を行います。

registerConfirm.phpをプロジェクトフォルダ直下に作成してください。

<?php
    // ①
    session_start();
    session_regenerate_id(true);
    
    $_SESSION['registerErrorMessage'] = null;

    // ②
    $userEmail = $_POST['userEmail'];
    $userName = $_POST['userName'];
    $password = $_POST['password'];
    $confirmPassword = $_POST['confirmPassword'];
    
    // ③
    if($password !== $confirmPassword){
        $_SESSION['registerErrorMessage'] = 'パスワードが一致しません。';
        header("Location:registerForm.php");
        exit();
    }

?>
// ④
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <main>
    <div>
        <h1>登録情報内容確認</h1>
        <p>下記の登録情報を登録します。</p>
    </div>
    <div>
        <h3>メールアドレス:<?php echo $userEmail; ?></h3>
        <h3>ユーザー名:<?php echo $userName; ?></h3>
        <form action="registerComplete.php" method="POST">
            <input type="hidden" name="userEmail" value='<?php echo $userEmail; ?>' required>
            <input type="hidden" name="userName" value='<?php echo $userName; ?>' required>
            <input type="hidden" name="password" value='<?php echo $password; ?>' required>
            <input type="submit" value="登録">
        </form>
        <button onclick="history.back()">戻る</button>
    </div>
</main>
</body>
</html>

①ではセッションを開始して、セッションIDを再発行します。

次に、セッションのエラーメッセージを空にしておきます。

ただ、入力内容のエラーメッセージをセッションに格納すると、エラーメッセージの管理が面倒くさいので、JavaScriptで制御するのが楽かなと思いますが、PHPで作成すると言っているのでセッションで書いていこうかなと思います。

②POST内容を変数に格納します。

③ではパスワードと確認用パスワードが一致するかを確認します。

もし一致しない場合は、エラーメッセージをセッションに格納して、registerForm.phpに強制的に遷移し、処理を停止します。

④はHTML部分になりフォーム内容に問題がなければ、登録ボタンを押し、問題がある場合は戻るボタンで前の画面に遷移するようにします。

registerForm.phpに追加

ここで、パスワードと確認用パスワードが一致していない場合のエラーメッセージをregisterForm.phpで表示するようにしましょう。

<?php 
    //①追加ここから
    session_start();
    session_regenerate_id(true);
    //①追加ここまで
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <div id="title">
            <a href=""><h1>Login Tutorial</h1></a>
        </div>
    </header>
    <main>
        <div id="mainTitle">
            <h2>新規登録</h2>
            <p>下記の登録情報を入力してください。</p>
        </div>

        <div id="mainForm">
            <form action="registerConfirm.php" method='POST'>
                <!-- ②追加ここから -->
                <?php if(isset($_SESSION['registerErrorMessage'])){ ?>
                    <div class="errorMessage">
                        <p><?php echo $_SESSION['registerErrorMessage']; ?></p>
                    </div>
                <?php } ?>
                <!-- ②追加ここまで -->
                <div>
                    <label>メールアドレス</label><br>
                    <input type="email" name="userEmail" required>
                </div>
                <div>
                    <label>ユーザー名</label><br>
                    <input type="text" name="userName" required>
                </div>
                <div>
                    <label>パスワード</label><br>
                    <input type="password" name="password" required>
                </div>
                <div>
                    <label>確認用パスワード</label><br>
                    <input type="password" name="confirmPassword" required>
                <div>
                <input type="submit" value='確認'>
            </form>
        </div>
    </main>
</body>
</html>

<!-- ③追加ここから -->
<?php
    $_SESSION['errorMessage'] = null;
?>
<!-- ③追加ここまで -->

①の追加ではセッションをスタートさせ、セッションIDを再度割り当てましょう。

②ではエラーメッセージがあるようでしたら、エラーメッセージを表示するようにします。

エラーメッセージは一回きり表示できればいいので③でセッション変数を空にしてください。

こうしないと、エラーメッセージが一度セッション変数に入ってしまうと別のページへ遷移した後に再度この入力フォームに遷移してくると何のエラーもないはずなのに、エラーメッセージが表示されてしまうことになってしまいます。

registerComplete.phpの実装

2-3で実装したregisterConfirmのPOSTした先になるregisterComplete.phpを実装していきます。

プロジェクトフォルダ直下にregisterComplete.phpを作成し、下記のプログラムを記述します。

<?php 
    // ①
    session_start();
    session_regenerate_id(true);
  
    // ②
    $userEmail = $_POST['userEmail'];
    $userName = $_POST['userName'];
    $password = password_hash($_POST['password'],PASSWORD_DEFAULT);

    // ③-1
    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    // ④-1
    try{
        // ③-2
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);

     // ⑤
        $sql = 'LOCK TABLES m_user WRITE';
        $stmt = $dbh->prepare($sql);
        $stmt->execute();

        // ⑥-1
        $dbh->beginTransaction();

        // ⑦
        $sql = "SELECT * FROM m_user WHERE userEmail = :userEmail";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userEmail', $userEmail, PDO::PARAM_STR);
        $stmt->execute();
        $results = $stmt->fetchAll();
        
     // ⑧-1
     if(count($results) > 0)
        {

            // ⑧-2
            echo "<p>ご登録されようとしているEmailは既に登録されております。</p>";
            echo "<a href='index.php'>ホーム画面へ戻る</a>";

            $sql = 'UNLOCK TABLES';
            $stmt = $dbh->prepare($sql);
            $stmt->execute();
            $dbh = null;

            exit();
            
        }else{
            // ⑧-3
            $sql = "INSERT INTO m_user(userEmail, userName, password) VALUES(:userEmail,:userName,:password)";
            $stmt = $dbh->prepare($sql);
            $stmt->bindValue(':userEmail', $userEmail, PDO::PARAM_STR);
            $stmt->bindValue(':userName', $userName, PDO::PARAM_STR);
            $stmt->bindValue(':password', $password, PDO::PARAM_STR);
            $stmt->execute();
            // ⑥-2
            $dbh->commit();            


            $sql = 'UNLOCK TABLES';
            $stmt = $dbh->prepare($sql);
            $stmt->execute();
            $dbh = null;
        }
    // ④-2
    }catch(PDOException $e){
        // ⑥-3
        $dbh->rollback();
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }

?>
// ⑨
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p><?php echo $userName; ?>さんの登録が完了しました。</p>
    <a href="loginForm.php">ログイン画面へ</a>

</body>
</html>

①では、他のプログラムと同様セッションをスタートさせ、セッションIDを再度割り当てましょう。

②も他のプログラムと同様、POST内容を変数に格納します。

この時、POSTされたパスワードを暗号化します。

③-1では、ユーザー名、パスワード、データベース名といったデータベースの接続に必要な情報を変数に格納し、③-2では、それらの情報を使用してデータベースに接続します。

④では例外処理を行うためにtry catchで囲んでいます。

try内での処理でネットワークの問題でデータベースに繋がらないなど、想定していないエラーが起きた場合は、catchでの処理が走ります。

⑤では他のセッションで他のプログラムからテーブル「m_user」への書き込みを禁止します。どういうことか。

A@test.comというメールアドレスを登録できるかBさんが検索した時点で、まだデータベースに登録されていないことを確認し、データを挿入しようとした瞬間、CさんがA@test.comをたまたまの時間差で登録してしまうというようなことがありえるかもしれません。

これを防ぐためにテーブルのロックを行います。

⑥-1ではトランザクションを開始します。トランザクションとは言葉の通り取引のことを指しますが、これは、データベースのひとまとまりの処理を指します。

このひとまとりまりの処理をしている最中に何らかのエラーが発生した場合、トランザクションが開始される前の状態に戻し(rollback)、全ての処理が終わった場合は処理の結果をデータベースに反映させます(commit)。

⑦では入力されたメールアドレスが登録されていないかをデータベースへ検索して、検索結果がある場合(=検索結果が0以上の場合)か否かを⑧のif文で判定します。

既に登録されている場合は、⑧-2でテーブルへのロックを解除し、⑧-3では登録処理を行います。

もし、処理内容に問題なく登録が完了されれば⑨で成功したHTMLを表示して完了となります。

4.ユーザーのログイン機能

仕様

ホーム画面から、ログインボタンをクリック後に遷移する画面でメールアドレスとパスワードを入力してログインします。

メールアドレスとパスワードを入力後はメールアドレスからデータベースを検索してユーザーIDを取得して、パスワードの照合を行います。

もし、パスワードの照合に成功した場合は、セッションにログイン情報を格納してログイン状態にします。

実装

ログインフォームの実装

<?php 
    // ①
    session_start();
    session_regenerate_id(true);
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <main>
        <div id="mainTitle">
            <h2>ログイン</h2>
            <p>メールアドレスとパスワードを入力してください</p>
        </div>

        <div id="mainForm">
            <form action="login.php" method='POST'>
                // ②
                <?php if(isset($_SESSION['loginErrorMessage'])){ ?>
                    <div class="errorMessage">
                        <p><?php echo $_SESSION['loginErrorMessage']; ?></p>
                    </div>
                <?php } ?>
                <div>
                    <label>メールアドレス</label><br>
                    <input type="email" name="userEmail" required>
                </div>
                <div>
                    <label>パスワード</label><br>
                    <input type="password" name="password" required>
                </div>
                <input type="submit" value='ログイン'>
            </form>
        </div>
    </main>
</body>
</html>

// ③
<?php
   $_SESSION['loginErrorMessage'] = null;
?>

ここではログインに必要なメールアドレスとパスワードを入力するためのインプットタグを用意し、login.phpにポストするようにします。

また、ログインする際にエラーがあった場合はエラーメッセージを表示できるよう、①でセッションの開始、②でエラーメッセージがある場合の表示、③で表示したエラーメッセージの初期化を行いましょう。

ログインロジックの実装

<?php
    // ①
    session_start();
    session_regenerate_id(true);
  
    // ②    
    $userEmail = $_POST['userEmail'];
    $password = $_POST['password'];

    // ③-1
    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    // ④-1
    try{
        // ③-2
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);

        // ⑤
        $sql = "select * from m_user where userEmail = :userEmail";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userEmail', $userEmail, PDO::PARAM_STR);
        $stmt->execute();
        $result = $stmt->fetch();
        $dbh = null;
    
    // ④-2
    }catch(PDOException $e){
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="http://localhost:8888/PHPToDo/index.php">前画面へ戻る</a>';
        exit();
    }

    
    $isLoginError = false;
    // ⑥-1
    if(count($result) === 0){
        $isLoginError = true;
    }
    // ⑥-2
    if(!password_verify($password , $result['password'])){
        $isLoginError = true;
    }
    // ⑥-3
    if($isLoginError === true){
        $_SESSION['loginErrorMessage'] = "メールアドレスもしくはパスワードが間違っています。";
        header("Location:loginForm.php");
    }else{
        $_SESSION['isLogin'] = true;
        $_SESSION['loginId'] = $result['userId'];
        $_SESSION['loginName'] = $result['userName'];
        header("Location:index.php");
    }
    exit();
?>

①でセッションを開始します。

②ではポストされた情報を変数に格納します。

③-1ではデータベース接続に必要なユーザー名、パスワード、データベース名を定義して変数に格納し、③-2でデータベースに接続します。

④-1、④-2ではデータベースへの接続および操作の際に想定外のエラーが出た時のために前回同様例外処理を行います。try内で想定外のエラーが出た際にはcatch内の処理が実行されます。

⑤では、入力されたメールアドレスを元に、データベースを検索しています。

⑥-1では、検索したメールアドレスで登録されているアドレスが存在するか、⑥-2では、パスワードが合っているか、⑥-3では、⑥-1および⑥-2で問題がないかを判定しています。

データベースに格納されているパスワードは暗号化されているため、単純な比較演算子で入力されたパスワードと比較することはできません。そのため、password_verify()という関数を使用します。password_verify()については下記のURLを参考にしてください。

PHP: password_verify - Manual
PHP is a popular general-purpose scripting language that powers everything from your blog to the most popular websites in the world.

⑥-3でログインの入力項目に問題がないことを確認したら、セッションにログイン情報を格納します。

もし問題があった場合はエラーメッセージをセッションに格納して、ログイン画面に遷移します。

これで、ログイン機能の実装は完了です。

実際にはシステムによってどのように認証をするかというところは異なりますが、おおよそこのような仕組みでログイン機能は実装されます。

5.ユーザーのマイページ画面の実装

仕様

ログインしている状態でのホーム画面にマイページボタンをクリックするとマイページへ遷移します。

マイページでは、ユーザー名と登録しているメールアドレスを表示し、ユーザー名の変更やパスワードの変更画面へ遷移するボタンを配置します。

ユーザー名の変更では、変更前のユーザー名を表示して、変更後のユーザー名、パスワードを入力します。

入力したパスワードが一致していた場合、ユーザー名の変更が行われます。

パスワードの変更では、変更前のパスワードと変更後のパスワード、確認用に変更後のパスワードを再度入力し、変更前のパスワード認証を行った後、変更後のパスワードが確認用と一致していた場合、パスワードの変更を行います。

実装

ホーム画面のログイン判定の実装

まずは、現状のホーム画面では、ログインしているしていないに関わらず、ホーム画面では同じメニューが表示されてしまいます。

使用ではログインしている場合は、マイページとログアウトボタンが表示され、ログインしていない場合は新規登録ボタンとログインボタンが表示されるようにしましょう。

<!-- 追加①ここから -->
<?php 
    session_start();
    session_regenerate_id(true);
?>
<!-- 追加①ここまで -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <div id="title">
            <a href=""><h1>Login Tutorial</h1></a>
        </div>
        <div id="menu">
            <ul>
                <!-- 追加②ここから -->
                <?php if(isset($_SESSION['isLogin'])){?>
                    <a href="myPage.php"><li>マイページ</li></a>
                    <a href="logout.php"><li>ログアウト</li></a>             
                <?php }else{?>
                    <a href="registerForm.php"><li>新規登録</li></a>
                    <a href="loginForm.php"><li>ログイン</li></a>
                <?php } ?>
                <!-- 追加②ここまで -->
                <a href="#"><li>お問い合わせ</li></a>
                <a href="#"><li>このサイトについて</li></a>
            </ul>
        </div>
    </header>
</body>
</html>

追加①ではセッションを開始します。

追加②はもし、ログインしてセッションのisLoginに値が入っている場合はマイページとログアウトボタンを表示し、ログインしていない場合は、新規登録とログインボタンを表示します。

マイページ画面の実装

次にマイページ画面の実装を行っていきます。

プロジェクト直下にmyPage.phpを作成し下記のプログラムを記述します。

<?php 
    // ①
    session_start();
    session_regenerate_id(true);
    
    // ②-1
    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';
    
    // ③-1
    try{
        // ②-2
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);
        // ④
        $sql = "select * from m_user where userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch();
        $dbh = null;
    // ③-2
    }catch(PDOException $e)
    {
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }
?>

<!-- ⑤ -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>ユーザー名:<?php echo $result['userName'];?></p>
    <p>登録アドレス:<?php echo $result['userEmail']; ?></p>
    <a href="changeUserNameForm.php">ユーザー名の変更</a>
    <a href="changePasswordForm.php">パスワードの変更</a>
</body>
</html>

①でセッションを開始します。

②-1でデータベースへの接続に必要なデータベース名、ユーザー名、パスワードを定義し、②-2で定義でのデータベースを接続します。

③-1および③-2でデータベースへの接続の際の例外処理を定義しておきます。

④ではセッションに格納されている、ログインユーザーの情報を元にユーザー情報をデータベースから取得します。

⑤では取得したユーザー情報とユーザー名の変更ボタンおよびパスワードの変更ボタンを表示します。

実際のところこれはどこまでセッションでログインユーザーの情報を持たせるかなども設計上の都合もありますので、データベースへの接続が不要になることも考えられるかと思います。

ユーザー名変更の実装

プロジェクト直下にchangeUserNameForm.phpを作成し下記のプログラムを入力してください。

<?php 
    session_start();
    session_regenerate_id(true);
    
    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);
        $sql = "select * from m_user where userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch();
        $dbh = null;
    }catch(PDOException $e)
    {
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="changeUserName.php" method="POST">
        <?php if(isset($_SESSION['userNameChangeError'])){ ?>
            <div class="errorMessage">
                <p><?php echo $_SESSION['userNameChangeError']; ?></p>
            </div>
        <?php } ?>
        <label for="">変更前ユーザー名:<?php echo $result['userName']; ?></label><br>
        <label for="">変更後ユーザー名:<input type="text" name="changeUserName"></label><br>
        <label for="">パスワードを入力してください<input type="password" name="password"></label><br>
        <input type="submit" value="変更する">
    </form>

</body>
</html>

<?php
    $_SESSION['userNameChangeError'] = null;
?>

変更前のユーザー名をデータベースから取得し表示し、変更後のユーザー名とパスワードをユーザーに入力してもらうようなページになります。

また、ポストした際にパスワードが誤っていた場合はエラーメッセージがセッションに入れるため、エラーメッセージが表示できるようにします。

続いてユーザー名の変更をポストした際の処理を書いていきます。

プロジェクトフォルダ直下にchangeUserName.phpを作成し、下記のプログラムを記述します。

<?php 
    session_start();
    session_regenerate_id(true);
    
    $userName = $_POST['changeUserName'];
    $password = $_POST['password'];

    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);
        $sql = "select * from m_user where userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch();

        if(!password_verify($password, $result['password'])){
            $dbh = null;
            $_SESSION['userNameChangeError'] = "パスワードが一致しません。";
            header('Location:changeUserNameForm.php');
            exit();
        }

        $isTransaction = $dbh->beginTransaction();
        $sql = "UPDATE m_user SET userName = :userName WHERE userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userName', $userName, PDO::PARAM_STR);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $dbh->commit();

    }catch(PDOException $e)
    {
        if($isTransaction)
        {
            $dbh->rollback();
        }
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>ユーザー名の変更が完了しました。</p>
    <a href="index.php">ホーム画面へ</a>
</body>
</html>

こちらもユーザーIDを元にデータベースを検索をかけてパスワードが一致しているかを確認します。

その後、問題ないようでしたら、ユーザー名の更新を行います。

これでユーザー名の変更プログラムの完成です。

パスワードの変更画面の作成

プロジェクトフォルダの直下にchangePasswordForm.phpを作成し、下記のプログラムを記述します。

<?php 
    session_start();
    session_regenerate_id(true);
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="changePassword.php" method="POST">
        <?php if(isset($_SESSION['passwordChangeError'])){ ?>
            <div class="errorMessage">
                <p><?php echo $_SESSION['passwordChangeError']; ?></p>
            </div>
        <?php } ?>
        <label for="">変更前パスワード:<input type="password" name="beforeChangePassword"></label><br>
        <label for="">変更後パスワード:<input type="password" name="changedPassword"></label><br>
        <label for="">変更後パスワード(確認用)<input type="password" name="changedPasswordConfirm"></label><br>
        <input type="submit" value="変更する">
    </form>

</body>
</html>

<?php
    $_SESSION['passwordChangeError'] = null;
?>

変更前のパスワード、変更後パスワードおよび確認用の変更後のパスワードをユーザーに入力してもらうような画面にします。

また、パスワードにエラーがあった場合はエラーメッセージを表示します。

次にパスワードを変更する際の処理を作成していきます。

プロジェクトフォルダ直下にchangePassword.phpを作成し、下記のプログラムを記述します。

<?php 
    session_start();
    session_regenerate_id(true);
    if(isset($_SESSION['isLogin']) === false){
        header("Location:index.php");
        exit();
    }

    $beforeChangePassword = $_POST['beforeChangePassword'];
    $changedPassword = $_POST['changedPassword'];
    $changedPasswordConfirm = $_POST['changedPasswordConfirm'];

    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);
        $sql = "select * from m_user where userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch();
        
        if(!password_verify($beforeChangePassword, $result['password']) || $changedPassword !== $changedPasswordConfirm){
            $_SESSION['passwordChangeError'] = 'パスワードが一致しません';
            $dbh = null;
            header('Location:changePasswordForm.php');
            exit();
        }

        $isTransaction = $dbh->beginTransaction();
        $sql = "UPDATE m_user SET password = :password WHERE userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userName', $changedPassword, PDO::PARAM_STR);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $dbh->commit();

        $dbh = null;
    }catch(PDOException $e)
    {
        if($isTransaction)
        {
            $dbh->rollback();
        }
        
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>パスワードの変更が完了しました。</p>
    <a href="index.php">ホーム画面へ</a>
</body>
</html>

セッションのログイン情報からデータベースに保存されているパスワードと入力された変更前のパスワードが一致しているか、入力された変更後のパスワードと確認用の変更後のパスワードが一致しているかを確認し、問題がなければ、パスワードの更新を実行します。

これで、パスワードの変更の処理の実装は完了です。

6.ログアウト機能を実装

仕様

今回はシンプルなログアウト機能になります。

ログアウトボタンをクリックしたら、セッション情報を削除してログアウト状態にする機能になります。

実装

プロジェクトフォルダの直下にlogout.phpを作成して、下記のプログラムを記述します。

<?php
    session_start();
    session_regenerate_id(true);

    $_SESSION['isLogin'] = null;
    $_SESSION['loginId'] = null;
    $_SESSION['loginName'] = null;

    session_destroy();

    header("Location:index.php");
    exit();
?>

まず、セッションをスタートします。

次にセッションに格納されているログイン情報をnullにします。

これで一応ログアウト状態にはなりますが、セッション情報を使用できないようsession_destroy()でセッション情報を全て削除します。

最後にホーム画面へ強制遷移させます。

これでログアウト機能の実装が完了になります。

7.ログイン状態の確認機能

仕様

マイページのようにログインしている状態でしか、表示できないページ、反対にログイン画面のようにログインしている状態では表示できないようなページや使用できない機能があります。

これは、基本的にリンクからの遷移を防ぐようにはしておりますが、URLから直接遷移された場合についても防ぐ必要があります。

ログインしている状態でのみアクセスできる画面、および機能としては、下記になります。

 ・マイページ画面

 ・パスワード編集画面

 ・名前変更画面

 ・ログアウト機能

これらのページではログインしていない場合は、ホーム画面へと強制的に遷移するようにします。

反対に、ログアウト状態でのみアクセスできるおよび機能としては、下記になります。

 ・新規登録画面

 ・ログイン画面

これらのページでは、ログインしている状態でアクセスを試みた場合、マイページ画面へと強制的に遷移するようにします。

実装

ログインしている状態でのみアクセスできる画面および機能

まずはマイページになります。

<?php 
    session_start();
    session_regenerate_id(true);
    
    // 追加ここから
    if(isset($_SESSION['isLogin']) === false){
        header("Location:index.php");
        exit();
    }
    // 追加ここまで

    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);
        $sql = "select * from m_user where userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch();
        $dbh = null;
    }catch(PDOException $e)
    {
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>ユーザー名:<?php echo $result['userName'];?></p>
    <p>登録アドレス:<?php echo $result['userEmail']; ?></p>
    <a href="changeUserNameForm.php">ユーザー名の変更</a>
    <a href="changePasswordForm.php">パスワードの変更</a>
</body>
</html>

追加部分ではログイン状態を保持するセッション変数を参照して、ログインしている状態であった場合、ホーム画面であるindex.phpへと遷移するようにします。

他の画面や機能についても同様の処理を追加します。

まずは、パスワード変更画面および変更機能についてです。

<?php 
    session_start();
    session_regenerate_id(true);
    
    // 追加ここから
    if(isset($_SESSION['isLogin']) === false){
        header("Location:index.php");
        exit();
    }
    // 追加ここまで
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="changePassword.php" method="POST">
        <?php if(isset($_SESSION['passwordChangeError'])){ ?>
            <div class="errorMessage">
                <p><?php echo $_SESSION['passwordChangeError']; ?></p>
            </div>
        <?php } ?>
        <label for="">変更前パスワード:<input type="password" name="beforeChangePassword"></label><br>
        <label for="">変更後パスワード:<input type="password" name="changedPassword"></label><br>
        <label for="">変更後パスワード(確認用)<input type="password" name="changedPasswordConfirm"></label><br>
        <input type="submit" value="変更する">
    </form>

</body>
</html>

<?php
    $_SESSION['passwordChangeError'] = null;
?>
<?php 
    session_start();
    session_regenerate_id(true);

    // 追加ここから
    if(isset($_SESSION['isLogin']) === false){
        header("Location:index.php");
        exit();
    }
    // 追加ここまで

    $beforeChangePassword = $_POST['beforeChangePassword'];
    $changedPassword = $_POST['changedPassword'];
    $changedPasswordConfirm = $_POST['changedPasswordConfirm'];

    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);
        $sql = "select * from m_user where userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch();
        
        if(!password_verify($beforeChangePassword, $result['password']) || $changedPassword !== $changedPasswordConfirm){
            $dbh = null;
            $_SESSION['passwordChangeError'] = 'パスワードが一致しません';
            header('Location:changePasswordForm.php');
            exit();
        }

        $isTransaction = $dbh->beginTransaction();
        $sql = "UPDATE m_user SET password = :password WHERE userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userName', $changedPassword, PDO::PARAM_STR);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $dbh->commit();

        $dbh = null;
    }catch(PDOException $e)
    {
        if($isTransaction)
        {
            $dbh->rollback();
        }
        
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>パスワードの変更が完了しました。</p>
    <a href="index.php">ホーム画面へ</a>
</body>
</html>

続いてユーザー名変更画面および変更機能です。

<?php 
    session_start();
    session_regenerate_id(true);

    // 追加ここから
    if(isset($_SESSION['isLogin']) === false){
        header("Location:index.php");
        exit();
    }
    // 追加ここまで
    
    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);
        $sql = "select * from m_user where userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch();
        $dbh = null;
    }catch(PDOException $e)
    {
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="changeUserName.php" method="POST">
        <?php if(isset($_SESSION['userNameChangeError'])){ ?>
            <div class="errorMessage">
                <p><?php echo $_SESSION['userNameChangeError']; ?></p>
            </div>
        <?php } ?>
        <label for="">変更前ユーザー名:<?php echo $result['userName']; ?></label><br>
        <label for="">変更後ユーザー名:<input type="text" name="changeUserName"></label><br>
        <label for="">パスワードを入力してください<input type="password" name="password"></label><br>
        <input type="submit" value="変更する">
    </form>

</body>
</html>

<?php
    $_SESSION['userNameChangeError'] = null;
?>
<?php 
    session_start();
    session_regenerate_id(true);
    
    // 追加ここから
    if(isset($_SESSION['isLogin']) === false){
        header("Location:index.php");
        exit();
    }
    // 追加ここまで
    
    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);
        $sql = "select * from m_user where userId = :userId";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userId', $_SESSION['loginId'], PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch();
        $dbh = null;
    }catch(PDOException $e)
    {
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="changeUserName.php" method="POST">
        <?php if(isset($_SESSION['userNameChangeError'])){ ?>
            <div class="errorMessage">
                <p><?php echo $_SESSION['userNameChangeError']; ?></p>
            </div>
        <?php } ?>
        <label for="">変更前ユーザー名:<?php echo $result['userName']; ?></label><br>
        <label for="">変更後ユーザー名:<input type="text" name="changeUserName"></label><br>
        <label for="">パスワードを入力してください<input type="password" name="password"></label><br>
        <input type="submit" value="変更する">
    </form>

</body>
</html>

<?php
    $_SESSION['userNameChangeError'] = null;
?>

最後にログアウト画面になります。

<?php
    session_start();
    session_regenerate_id(true);
    
    // 追加ここから
    if(isset($_SESSION['isLogin']) === false){
        header("Location:index.php");
        exit();
    }
    // 追加ここまで

    $_SESSION['isLogin'] = false;
    $_SESSION['loginId'] = null;
    $_SESSION['loginName'] = null;

    session_destroy();

    header("Location:index.php");
    exit();
?>

これでログイン状態でのみアクセス可能な画面と機能の制限の実装は完了です。

ログインしていない状態でのみアクセスできる画面および機能

続いてログアウトしていない状態でのみアクセスできる画面および機能の制限実装になります。

基本的には、2-1と反対の実装をすればOKです。

まずは、新規登録画面および、機能の制限についてです。

<?php 
    session_start();
    session_regenerate_id(true);
    
    // 追加ここから
    if(isset($_SESSION['isLogin']) === true){ 
        header("Location:myPage.php");
        exit();
    }
    // 追加ここまで

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <div id="title">
            <a href="index.php"><h1>Login Tutorial</h1></a>
        </div>
    </header>
    <main>
        <div id="mainTitle">
            <h2>新規登録</h2>
            <p>下記の登録情報を入力してください。</p>
        </div>

        <div id="mainForm">
            <form action="registerConfirm.php" method='POST'>
                <?php if(isset($_SESSION['registerErrorMessage'])){ ?>
                    <div class="errorMessage">
                        <p><?php echo $_SESSION['registerErrorMessage']; ?></p>
                    </div>
                <?php } ?>
                <div>
                    <label>メールアドレス</label><br>
                    <input type="email" name="userEmail" required>
                </div>
                <div>
                    <label>ユーザー名</label><br>
                    <input type="text" name="userName" required>
                </div>
                <div>
                    <label>パスワード</label><br>
                    <input type="password" name="password" required>
                </div>
                <div>
                    <label>確認用パスワード</label><br>
                    <input type="password" name="confirmPassword" required>
                <div>
                <input type="submit" value='確認'>
            </form>
        </div>
    </main>
</body>
</html>

<?php
    $_SESSION['errorMessage'] = null;
?>
<?php
    session_start();
    session_regenerate_id(true);

    // 追加ここから
    if(isset($_SESSION['isLogin']) === true){
        header("Location:myPage.php");
        exit();
    }
    // 追加ここまで

    $_SESSION['registerErrorMessage'] = null;

    $userEmail = $_POST['userEmail'];
    $userName = $_POST['userName'];
    $password = $_POST['password'];
    $confirmPassword = $_POST['confirmPassword'];

    if($password !== $confirmPassword){
        $_SESSION['registerErrorMessage'] = 'パスワードが一致しません。';
        header("Location:registerForm.php");
        exit();
    }

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <main>
    <div>
        <h1>登録情報内容確認</h1>
        <p>下記の登録情報を登録します。</p>
    </div>
    <div>
        <h3>メールアドレス:<?php echo $userEmail; ?></h3>
        <h3>ユーザー名:<?php echo $userName; ?></h3>
        <form action="registerComplete.php" method="POST">
            <input type="hidden" name="userEmail" value='<?php echo $userEmail; ?>' required>
            <input type="hidden" name="userName" value='<?php echo $userName; ?>' required>
            <input type="hidden" name="password" value='<?php echo $password; ?>' required>
            <input type="submit" value="登録">
        </form>
        <button onclick="history.back()">戻る</button>
    </div>
</main>
</body>
</html>
<?php 
    session_start();
    session_regenerate_id(true);

    // 追加ここから
    if(isset($_SESSION['isLogin']) === true){
        header("Location:myPage.php");
        exit();
    }
    // 追加ここまで

    $userEmail = $_POST['userEmail'];
    $userName = $_POST['userName'];
    $password = password_hash($_POST['password'],PASSWORD_DEFAULT);

    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);

        $sql = 'LOCK TABLES m_user WRITE';
        $stmt = $dbh->prepare($sql);
        $stmt->execute();

        $dbh->beginTransaction();

        $sql = "SELECT * FROM m_user WHERE userEmail = :userEmail";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userEmail', $userEmail, PDO::PARAM_STR);
        $stmt->execute();
        $results = $stmt->fetchAll();
        if(count($results) > 0)
        {
            echo "<p>ご登録されようとしているEmailは既に登録されております。</p>";
            echo "<a href='index.php'>ホーム画面へ戻る</a>";

            $sql = 'UNLOCK TABLES';
            $stmt = $dbh->prepare($sql);
            $stmt->execute();
            $dbh = null;

            exit();
            
        }else{

            $sql = "INSERT INTO m_user(userEmail, userName, password) VALUES(:userEmail,:userName,:password)";
            $stmt = $dbh->prepare($sql);
            $stmt->bindValue(':userEmail', $userEmail, PDO::PARAM_STR);
            $stmt->bindValue(':userName', $userName, PDO::PARAM_STR);
            $stmt->bindValue(':password', $password, PDO::PARAM_STR);
            $stmt->execute();
            $dbh->commit();            


            $sql = 'UNLOCK TABLES';
            $stmt = $dbh->prepare($sql);
            $stmt->execute();
            $dbh = null;
        }

    }catch(PDOException $e){
        $dbh->rollback();
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="index.php">前画面へ戻る</a>';
        exit();
    }

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p><?php echo $userName; ?>さんの登録が完了しました。</p>
    <a href="loginForm.php">ログイン画面へ</a>

</body>
</html>

これでログインしている状態でユーザー新規登録の画面や機能のプログラムが実行されるとマイページに遷移するようになります。

続いてログイン画面およびログイン機能の実装になります。

<?php 
    session_start();
    session_regenerate_id(true);

    // 追加ここから
    if(isset($_SESSION['isLogin']) === true){
        header("Location:imyPage.php");
        exit();
    }
    // 追加ここまで

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <main>
        <div id="mainTitle">
            <h2>ログイン</h2>
            <p>メールアドレスとパスワードを入力してください</p>
        </div>

        <div id="mainForm">
            <form action="login.php" method='POST'>
                <?php if(isset($_SESSION['loginErrorMessage'])){ ?>
                    <div class="errorMessage">
                        <p><?php echo $_SESSION['loginErrorMessage']; ?></p>
                    </div>
                <?php } ?>
                <div>
                    <label>メールアドレス</label><br>
                    <input type="email" name="userEmail" required>
                </div>
                <div>
                    <label>パスワード</label><br>
                    <input type="password" name="password" required>
                </div>
                <input type="submit" value='ログイン'>
            </form>
        </div>
    </main>
</body>
</html>

<?php
    $_SESSION['loginErrorMessage'] = null;
?>
<?php
    session_start();
    session_regenerate_id(true);

    // 追加ここから
    if(isset($_SESSION['isLogin']) === true){
        header("Location:myPage.php");
        exit();
    }
    // 追加ここまで

    $_SESSION['loginErrorMessage'] = null;
    $userEmail = $_POST['userEmail'];
    $password = $_POST['password'];

    $dsn = 'mysql:host=localhost;dbname=login_tutorial;charset=utf8';
    $username = 'root';
    $pass = 'root';

    try{
        $dbh = new \PDO($dsn, $username, $pass,[
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);


        $sql = "select * from m_user where userEmail = :userEmail";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':userEmail', $userEmail, PDO::PARAM_STR);
        $stmt->execute();
        $result = $stmt->fetch();
        $dbh = null;

    }catch(PDOException $e){
        echo 'ただいま障害により大変ご迷惑をおかけしております'.$e->getMessage();
        echo '<a href="http://localhost:8888/PHPToDo/index.php">前画面へ戻る</a>';
        exit();
    }

    $isLoginError = false;
    if(count($result) === 0){
        $isLoginError = true;
    }
    if(!password_verify($password , $result['password'])){
        $isLoginError = true;
    }
    if($isLoginError === true){
        $_SESSION['loginErrorMessage'] = "メールアドレスもしくはパスワードが間違っています。";
        header("Location:loginForm.php");
    }else{
        $_SESSION['isLogin'] = true;
        $_SESSION['loginId'] = $result['userId'];
        $_SESSION['loginName'] = $result['userName'];
        header("Location:index.php");
    }
    exit();
?>

これでログイン機能にアクセスした際にログイン状態であった場合、マイページへ遷移します。

これで一通りログイン機能の実装は完了になります。

~画像出展元~

Data illustrations by Storyset

コメント

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