こんにちは、ねこふらいです。

コンビニに行く途中、元気な小学生たちとすれ違いました。上着が欠かせない今日この頃、短パンで駆け抜けて行く彼らの姿に「若さってすげえ」と感動。


さて、今回は前回に引き続き、『WordPressのようなコメント管理システムを作ってみよう』と思います!

対象者
  • PHPの基礎がわかる人
  • phpMyAdminの使い方がわかる人

前回は入力したコメントをデータベースに保存するプログラムを作りました。

今回は、投稿されたコメントの管理画面……ではなく、管理画面にアクセスするためのログイン機能を作っていきます!

これから作っていくもの

はい。改めまして、簡易コメント管理システム『ふらこめ(necofly comment system)』制作シリーズ第2回です!

WordPressのコメント管理機能をイメージしてくれるとありがたいです。

『ふらこめ』で実装する機能は以下の通り。

ふらこめで実装する機能
  • コメントの受付
  • 管理画面でのコメント管理
  • コメントの承認・削除・編集・返信機能
  • 管理画面へのログイン機能
  • 新規管理アカウント取得機能

ざっとこんな感じです!

コメント欄からコメントを受け付けられるのはもちろんのこと、コメントの管理画面も欲しいところですね。

ただ見る人全員が好き勝手管理できたら大変なので、ログイン機能も設置。ついでに新規管理アカウント取得(サインアップ)機能も作ってしまいましょう。

最終的には下記のようなファイル構造になります。

hura_come
├── admin
│   ├── dashboard.php
│   ├── delete.php
│   ├── display.php
│   ├── login.php
│   ├── logout.php
│   ├── reply.php
│   ├── signup.php
│   └── update.php
├── css
│   └── style.css
├── db_info
│   └── db_info.php
├── images
│   └── logo.jpg
└── save_comment.php

では早速作っていきましょう!

今回作るもの – 『ログイン機能』

ねこふらい
第2回目となる今回は、管理画面への『ログイン機能』を作っていくよ。
メダ太郎
ログイン機能って必要なの? 普通にそのまま管理画面に行ける方がいいのでは?
ねこふらい
ログイン機能がなかったら、誰でもコメントを管理できるようになってしまう。コメントが勝手に消されたり、編集されたら嫌だろう?
めだ吉
それは確かに嫌ですね。だから、コメントを管理する人を制限できるように、ログイン機能が必要なんですね。

管理画面にアクセスするときにログイン画面を挟まないと、第三者が勝手にコメントを管理できるようになってしまいます。いただいたコメントを勝手に消されたら嫌なので、ログイン機能を実装した方がいいでしょう。

ふらこめのログイン機能に必要なのは、メールアドレスパスワードです。

入力したメールアドレスとパスワードがデータベース上に存在したら、管理画面にアクセスできるプログラムを作成していきます。

今回用意するファイルは『login.php』『logout.php』『dashboard.php』の3つです。

下記を参考に3つのファイルを用意しましょう。

hura_come
├── admin
│   ├── dashboard.php
│   ├── login.php
│   └── logout.php
├── css
│   └── style.css
├── db_info
│   └── db_info.php
└── save_comment.php

ファイルが準備できたら、まずはユーザー情報を管理する『user_table』テーブルを作成しましょう。

user_tableテーブルの準備

ねこふらい
プログラムを制作し始める前に、まずはユーザー情報を管理するテーブルを用意しよう。

前回と同じ流れで、hurakomeデータベースにuser_tableテーブルを作成します。必要なカラムは3つ。下記の画像を参考に3つのカラムを作成してください。idにAUTO_INCREMENTの設定をするのをお忘れなく!

手動で作成する以外にも、下記のコードを『SQL』に貼り付けて作成することもできます!

CREATE TABLE IF NOT EXISTS `user_table` (
  `id` int(11) NOT NULL,
  `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(15) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

ALTER TABLE `user_table`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `user_table`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=2;

また、今回は最初からログインできるユーザーを設定しておきます。

下記のコードを『SQL』で実行してください。実行すると、メースアドレスがsample@aaa、パスワードが1111のユーザーが追加されます。

INSERT INTO `user_table`(`email`, `password`) VALUES ('sample@aaa' , '1111')
ねこふらい
phpMyAdminでの作業はこれで終了。これから実際にプログラムを書いていきましょう!
メダ太郎
ドキドキが加速するぜ!

dashboard.phpの作成

dashboard.phpは次回で詳細に作成していきます。今回はdashboard.phpだとわかるように、簡単なHTMLを作成しましょう。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ダッシュボード</title>
    <meta name="viewport" content="width=1000">
    <meta name="robots" content="noindex,nofollow">
    <link rel="stylesheet" type="text/css" href="../css/style.css">
</head>

    <body>

    <section class="wrap">

        <h1>ダッシュボード</h1>

    </section>

</body>

</html>

これを実際に出力すると、下図のようになります。

ねこふらい
ログインに成功したらこのファイルにリダイレクトするんだ。このページでコメントの参照・編集・削除・承認・返信ができるようにするんだけど、その話はまた次回。今回は簡単なページだけで大丈夫だよ。
めだ吉
次回が楽しみですね。

dashboard.phpの準備できたら、下記のようにadminフォルダを作成し、その中に配置してください。

hura_come
├── admin
│   └── dashboard.php
├── css
│   └── style.css
├── db_info
│   └── db_info.php
└── save_comment.php

では、本題のlogin.phpを作っていきましょう!

login.phpの作成

全体のコード

login.phpを、実際にブラウザで出力するとこのようになります。

メールアドレスとパスワードを入力してログインボタンを押すと、入力された値をuser_tableテーブルのユーザー情報と照らし合わせます。合致したらdashboard.phpへリダイレクトします。


ねこふらい
login.phpはdashboard.phpへログインするためのプログラムです。まずは全体のコードを見てみよう。
<?php

session_start();

require '../db_info/db_info.php';

if($_SERVER['REQUEST_METHOD'] === 'POST'){

    //メッセージの初期化
    $error = '';

    //入力値のチェック
    if(empty($_POST['email']) || empty($_POST['password'])){
        $error = '未入力の項目があります。';
    } elseif(strlen($_POST['email']) > 100 || strlen($_POST['password']) > 16){
        $error = 'メールアドレスは100文字以内、パスワードは15文字以内でご入力ください。';
    } else {
        $email = htmlspecialchars($_POST['email'],ENT_QUOTES, 'UTF-8');
        $password = htmlspecialchars($_POST['password'],ENT_QUOTES, 'UTF-8');

        try{

            //データベースへ接続
            $dbh = new PDO(
                'mysql:host=' . $host . '; dbname=' . $db_name .'; charset=utf8',
                $user,
                $pass,
                array(
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_EMULATE_PREPARES => false,
                )
            );

            //メールアドレスとパスワードからid番号を取得
            $sql = 'SELECT id FROM user_table WHERE email=? AND password=?';
            $data[] = $email;
            $data[] = $password;
            $stmt = $dbh->prepare($sql);
            $stmt->execute($data);

            $row = $stmt->fetch(PDO::FETCH_ASSOC);

            if($row == false){
                //メールアドレスとパスワードが合致したデータがない場合
                echo '<div class="server_error">メールアドレスまたはパスワードが間違っています。</div>';
            } else {
                //合致したデータが存在する場合
                $_SESSION['id']=$row['id'];
                $_SESSION['email']=$email;
                header('Location: dashboard.php');
                exit();
            }

            //接続解除
            $dbh = null;

        } catch(PDOException $e){
            echo '<div class="server_error">現在サーバーエラーが発生しています。</div>';
        }

    }

}

?>


<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ログインページ</title>
    <meta name="viewport" content="width=1000">
    <meta name="robots" content="noindex,nofollow">
    <link rel="stylesheet" type="text/css" href="../css/style.css">
</head>

<body>

    <section class="wrap login">

        <div class="login_wrap">
            <img src="../images/logo.jpg" class="ic logo">

            <?php

                if(isset($error)){
                    echo '<ul class="error"><li>' . $error . '</li></ul>';
                }

            ?>

            <form action="login.php" method="post" class="login_form">
                <label>メールアドレス</label>
                <input type="email" name="email">
                <label>パスワード</label>
                <input type="password" name="password">
                <input type="submit" name="submit" value="ログイン">
            </form>

            <center><a href="signup.php">アカウントをお持ちでない方はこちら</a></center>

        </div>

    </section>

</body>

</html>

login.phpは下記のように配置してください。

hura_come
├── admin
│   ├── dashboard.php
│   └── login.php
├── css
│   └── style.css
├── db_info
│   └── db_info.php
└── save_comment.php

ではコードを細分化して見ていきましょう。

HTMLの用意
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ログインページ</title>
    <meta name="viewport" content="width=1000">
    <meta name="robots" content="noindex,nofollow">
    <link rel="stylesheet" type="text/css" href="../css/style.css">
</head>

<body>

    <section class="wrap login">

        <div class="login_wrap">
            <img src="../images/logo.jpg" class="ic logo">

            <?php

                if(isset($error)){
                    echo '<ul class="error"><li>' . $error . '</li></ul>';
                }

            ?>

            <form action="login.php" method="post" class="login_form">
                <label>メールアドレス</label>
                <input type="email" name="email">
                <label>パスワード</label>
                <input type="password" name="password">
                <input type="submit" name="submit" value="ログイン">
            </form>

            <center><a href="signup.php">アカウントをお持ちでない方はこちら</a></center>

        </div>

    </section>

</body>

</html>

まずはHTML部分を見ていきましょう。

色々書いていますが、重要なのはform部分です。

<form action="login.php" method="post" class="login_form">
    <label>メールアドレス</label>
    <input type="email" name="email">
    <label>パスワード</label>
    <input type="password" name="password">
    <input type="submit" name="submit" value="ログイン">
</form>

同一ファイル内で処理を行うので、データの受け渡し先はlogin.phpです。method属性にはpostを指定しましょう。

メールアドレス入力欄にはemail、パスワード入力欄にはpasswordと、name属性を与えます。


また、前回のsave_comment.phpで見たPHPコードが埋め込まれているのがわかりますね。

<?php

    if(isset($error)){
        echo '<ul class="error"><li>' . $error . '</li></ul>';
    }

?>

login.phpでも入力値のチェックを行うので、入力ミスがあればここにエラーメッセージが表示されます。

セッションの開始

ここで1行目に戻ります。

session_start();

最初にセッションの開始を宣言します。

めだ吉
セッションって何ですか?
ねこふらい
セッションとは、サーバ側に一時的にデータを保存する仕組みのことだよ。Cookieと似たようなものなんだけど、Cookieがブラウザ側にデータを一時的に保存する仕組みに対し、セッションはサーバ側にデータを保存するんだ。ログイン機能を作るのなら必須の機能だよ。詳しくは後で説明するよ。
セッションって?
  • サーバ側に一時的にデータを保存する仕組み
  • ログイン情報などを扱う際に重要な役割を果たす
db_info.phpの呼び出しと入力値のチェック
require '../db_info/db_info.php';

if($_SERVER['REQUEST_METHOD'] === 'POST'){

    //メッセージの初期化
    $error = '';

    //入力値のチェック
    if(empty($_POST['email']) || empty($_POST['password'])){
        $error = '未入力の項目があります。';
    } elseif(strlen($_POST['email']) > 100 || strlen($_POST['password']) > 16){
        $error = 'メールアドレスは100文字以内、パスワードは15文字以内でご入力ください。';
    } else {
        $email = htmlspecialchars($_POST['email'],ENT_QUOTES, 'UTF-8');
        $password = htmlspecialchars($_POST['password'],ENT_QUOTES, 'UTF-8');
ねこふらい
この部分は前回のsave_comment.phpと共通する部分なので、簡単に説明させてもらうね。
このコードでやっていること
  • require文で、データベース情報を記載しているdb_info.phpを呼び出し
  • ログインボタンが押されたら処理を実行開始
  • エラーメッセージの初期化
  • 入力値に問題があればエラーメッセージを表示させる
  • 問題がなければ入力した値をエスケープ処理し、変数に格納
データベースへ接続
try{

    //データベースへ接続
    $dbh = new PDO(
        'mysql:host=' . $host . '; dbname=' . $db_name .'; charset=utf8',
        $user,
        $pass,
        array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_EMULATE_PREPARES => false,
        )
    );

    //中略

} catch(PDOException $e){
    echo '<div class="server_error">現在サーバーエラーが発生しています。</div>';
}

入力した値に問題がなければ、データベースに接続します。

データベースに接続する場合はtry~catch文を使って例外処理を書きましょう。

テーブルからデータを取得
$sql = 'SELECT id FROM user_table WHERE email=? AND password=?';
$data[] = $email;
$data[] = $password;
$stmt = $dbh->prepare($sql);
$stmt->execute($data);

入力したメールアドレスとパスワードを使って、id番号を取得します。

ねこふらい
SELECT文はテーブルのデータを受け取るための命令です。
メダ太郎
ここでは入力したメールアドレスとパスワードをデータとして持つidを取得しようとしているんだな。
ユーザー情報があればdashboard.phpへリダイレクト
$row = $stmt->fetch(PDO::FETCH_ASSOC);

if($row == false){
    //メールアドレスとパスワードが合致したデータがない場合
    echo '<div class="server_error">メールアドレスまたはパスワードが間違っています。</div>';
} else {
    //合致したデータが存在する場合
    $_SESSION['id']=$row['id'];
    $_SESSION['email']=$email;
    header('Location: dashboard.php');
    exit();
}

$stmt->fetch(PDO::FETCH_ASSOC)の部分で、SQL実行結果を連想配列として取得し、変数rowに格納します。


ねこふらい
次に、if文でユーザー情報がない時の処理、ユーザー情報があった時の処理を定義します。

実行結果がfalse、つまり入力したメールアドレス・パスワードを持つデータがない場合、「メールアドレスまたはパスワードが間違っています」とエラーを表示させます。

逆に入力したメールアドレス・パスワードを持つデータが存在した場合、そのデータのidとメールアドレスをセッションのスーパーグローバル変数に保存します。そしてdashboard.phpにリダイレクトし、処理を終了させます。


以上でlogin.phpの作成は完了です。

dashboard.phpの修正

なぜ修正する必要があるのか?

login.phpができたら、dashboard.phpを少し修正します。


メダ太郎
何か修正する必要があるのか?
ねこふらい
うん。今のままじゃ、直接URLを入力してアクセスされたら、ログイン画面を通さずdashboard.phpにアクセスできてしまうんだ。
ねこふらい
せっかくログイン画面を作っているのに、これじゃセキュリティが意味をなさない。そこで、ログイン認証されていないユーザーが、直接URLを指定してdashboard.phpにアクセスしようとしたら、エラーが発生するようにしないといけない。
めだ吉
そんなことできるんですか?
ねこふらい
もちろん。そのためのセッションだよ。

login.phpのこのコードを見てください。

$_SESSION['id']=$row['id'];
$_SESSION['email']=$email;

ログイン画面でログイン認証した場合だけ、セッションのスーパーグローバル変数が定義されています。つまり、無事にログインした場合に限り、そのユーザーのidとemailのデータがサーバーに保存されるのです。

dashboard.phpへの不正アクセスを防ぐために、$_SESSION['id']を持たないユーザーのアクセスを禁止してしまえばいいのです。

dashboard.phpにコードを追加
ねこふらい
では次のコードをdashboard.phpの1行目に追加してください。
<?php

    session_start();

    session_regenerate_id(true);

    //エラー処理
    if(!isset($_SESSION['id'])){
        header('Location:login.php');
        exit();
    } else {
        echo '<div class="top_bar"><p>こんにちは!&emsp;' . $_SESSION['email'] .'さん&emsp;<a href="logout.php" class="logout_button">ログアウト</a></p></div>';
    }

?>

このコードを追加することで、ログイン認証を介していないユーザーのアクセスを防ぐことができます。

では細かく見ていきましょう。

セッションの開始
session_start();

session_regenerate_id(true);

セッションを開始し、セッションIDを新しいものと置き換えます。

セッションIDって?
  • セッションIDとは、アクセスするユーザーを識別するための識別情報
  • セッションIDは、セッションが開始されると自動的に発行される
  • session_regenerate_id関数で、新しいセッションIDを発行して置き換えられる
  • セッションIDを新しいものに置き換えるのは、セッションIDの特定されにくくして、セッションハイジャック(なりすましなど)を防ぐため
  • セッションIDを新しくしても、定義したスーパーグローバル変数の値は変わらない
不正アクセスを弾く
if(!isset($_SESSION['id'])){
    header('Location:login.php');
    exit();
} else {
    echo '<div class="top_bar"><p>こんにちは!&emsp;' . $_SESSION['email'] .'さん&emsp;<a href="logout.php" class="logout_button">ログアウト</a></p></div>';
}

if文を使って、アクセスを許可するか否か判別します。

$_SESSION['id']に値が存在しない、つまりログイン画面を介していないユーザーにはlogin.phpに強制的にリダイレクトしてもらいます。

きちんとログイン認証してアクセスしてきたユーザーには「こんにちは! ○○さん」と表示して、アクセスを歓迎してあげましょう!

logout.phpの作成

全体のコード

これで不正アクセスを防ぐことができますが、ちゃんと機能しているかログアウトして確認してみましょう。

では、最後にログアウトするための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">
    <title>ログアウトしました</title>
    <meta name="viewport" content="width=1000">
    <meta name="robots" content="noindex,nofollow">
    <link rel="stylesheet" type="text/css" href="../css/style.css">
</head>

<body>

    <section class="wrap">

        <h1>ログアウトしました。</h1>
        <p><a href="login.php">ログインページに戻る</a></p>

    </section>

</body>

</html>

logout.phpを準備できたら、下記のように配置してください。

hura_come
├── admin
│   ├── dashboard.php
│   ├── login.php
│   └── logout.php
├── css
│   └── style.css
├── db_info
│   └── db_info.php
└── save_comment.php

ここで注目するのはPHPの部分だけです。では見ていきましょう。

ログアウトの仕組み

ログアウトするための方法は、セッションを削除することです。

<?php

    session_start();

    $_SESSION = array();

    if(isset($_COOKIE[session_name()]) == true){
        setcookie(session_name() , '' ,time()-42000,'/');
    }

    session_destroy();

?>
ねこふらい
セッションの削除はほぼ定型文のようなものです。上記の方法で完全にセッションを削除できます。
めだ吉
セッションを削除するということは、ログインに使っていた$_SESSION['id']といったスーパーグローバル変数も使えなくなる……。だからdashboard.phpにアクセスすることができなくなるんだね。

実際にログインしてみよう!

ねこふらい
作成したら、まずは挙動確認! 実際にログインできるか確かめてみよう。
メダ太郎
できたぜ!
めだ吉
まるで神になったかのようだね!

上手く動作しましたか?

上手くいかない場合はどこか間違っている箇所がないか、よく確認してみましょう。

まとめ

今回制作したのは、dashboard.phpとlogin.phpとlogout.phpです。

ここまで制作したら、下記のようなツリー構造になっていると思います。

hura_come
├── admin
│   ├── dashboard.php
│   ├── login.php
│   └── logout.php
├── css
│   └── style.css
├── db_info
│   └── db_info.php
└── save_comment.php
ねこふらい
次回は管理画面を作り込み、コメントを操作できるようにしていきます。第3回はこちら


HOME > ふらこめ > WordPressのようなコメント管理システムを作ってみよう – 第2回