PDOを使用して新規登録とログインシステムを実装する

バックエンド

データベースの設定

ユーザーはグローバル権限のあるものか、今回作るベースに権限のあるものを使用します。 グローバル権限でももちろん問題はないですが、必要なデータベースにのみ権限があるユーザーを使用する方が好ましいです。

データベース名

testData ここは好きなものでOKです。

テーブル

user

idint(11)被り防止のためにAUTO_INCREMENTの設定、primary key設定
namevarchar(10)
passwordtextまたはvarchar登録時にハッシュ化を登録するため長めに設定

新規登録ページの作成

フォームで入力された値を受け取って、パスワードが一定桁数以上の時(今回は8桁でデモ)にデータベース登録。 パスワードはpassword_hash()を使用しハッシュ化を行ったあとに登録します。 登録完了後は、アラートで登録完了を表示し、メインページへ遷移するようになっています。

<?php
|s|    // セッション開始
|s|    session_start();
|s|    // 既にログインしている場合にはメインページに遷移
|s|    if (isset($_SESSION['USERID'])) {
|s|        header('Location: main.php');
|s|        exit;
|s|    }
|s|    $db['host'] = 'localhost';
|s|    $db['user'] = 'root';
|s|    $db['pass'] = 'root';
|s|    $db['dbname'] = 'testData';
|s|    $error = '';
|s|    // ログインボタンが押されたら
|s|    if (isset($_POST['signUp'])) {
|s|        if (empty($_POST['username'])) {
|s|            $error = 'ユーザーIDが未入力です。';   
|s|        }else if (empty($_POST['password'])) {
|s|            $error = 'パスワードが未入力です。'; 
|s|        }
|s|        if (!empty($_POST['username']) && !empty($_POST['password'])) {
|s|            $username = $_POST['username'];
|s|            $password = $_POST['password'];
|s|            $dsn = sprintf('mysql: host=%s; dbname=%s; charset=utf8', $db['host'], $db['dbname']);
|s|            $pdo = new PDO($dsn, $db['user'], $db['pass'], array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
|s|            // idの重複とパスワードの桁数チェック
|s|            function cheak($id,$count){
|s|                if($count > 0){
|s|                    throw new Exception('そのユーザーIDは既に使用されています。');
|s|                }
|s|                if ($id < 8) {
|s|                    throw new Exception('パスワードは8桁以上で入力してください。');    
|s|                }
|s|            }
|s|            try{
|s|                $sqlname = 'SELECT COUNT(*) FROM user WHERE `name` = '$username'';
|s|                $ss = $pdo->query($sqlname);
|s|                $count = $ss->fetchColumn();

|s|                $id = strlen($_POST['password']);
|s|                cheak($id,$count);

|s|                $stmt = $pdo->prepare('INSERT INTO `user`(`name`, `password`) VALUES (:username, :password)');
|s|                $pass = password_hash($password, PASSWORD_DEFAULT);
|s|                $stmt->bindParam(':username', $username, PDO::PARAM_STR);
|s|                $stmt->bindParam(':password', $pass, PDO::PARAM_STR);
|s|                $stmt->execute();
|s|              
|s|                $_SESSION['USERID'] = $username;
|s|                echo '<script>
|s|                        alert("登録が完了しました。");
|s|                        location.href="main.php";
|s|                      </script>';
|s|            } catch(Exception $e){
|s|                $error = $e->getMessage();
|s|            }
|s|        }  
|s|    }
?>

<!DOCTYPE html>
<html>
|s|    <head>
|s|        <title>新規登録</title>
|s|    </head>
|s|    <body>
|s|        <main>
|s|            <form id="loginForm" name="loginForm" action="" method="POST">
|s|                <p style="color:red;"><?php echo $error ?></p>
|s|                <label for="username">ユーザーID<br>
|s|                    <input type="text" id="username" name="username" placeholder="ユーザー名を入力" value="<?php if (!empty($_POST["username"])) {echo htmlspecialchars($_POST["username"], ENT_QUOTES);} ?>">
|s|                </label><br>
|s|                <label for="password">パスワード<br>
|s|                    <input type="password" id="password" name="password" value="" placeholder="パスワードを入力">※8桁以上
|s|                </label>
|s|                <input type="submit" id="signUp" name="signUp" value="新規登録" class="btn up">
|s|            </form>
|s|        </main>
|s|    </body>
</html>

ソースの内容について

if (isset($_SESSION['USERID'])) {
|s|        header('Location: main.php');
|s|        exit;
}

セッションに値が入っているとき=ログインを既にしているときには、このページを表示しないようにしています。

function cheak($id,$count){
|s|        if($count > 0){
|s|               throw new Exception('そのユーザーIDは既に使用されています。');
|s|        }
|s|        if ($id < 8) {
|s|               throw new Exception('パスワードは8桁以上で入力してください。');    
|s|        }
}

下のtryの中から引数を渡して、それぞれIDの重複とパスワードの桁数をチェックしています。 エラーの場合にはthrow new Exception()で例外が出たことを投げ、エラー文をあとのcatchで表示しています。

$stmt = $pdo->prepare('INSERT INTO `user`(`name`, `password`) VALUES (:username, :password)');
$pass = password_hash($password, PASSWORD_DEFAULT);
$stmt->bindParam(':username', $username, PDO::PARAM_STR);
$stmt->bindParam(':password', $pass, PDO::PARAM_STR);
$stmt->execute();

prepare()の値にはパラメータ(:任意の文字列)をおき、実行はパラメータに値が入るまで待機となります。 password_hash()を使用してパスワードハッシュを生成しています。 bindParamは指定した変数を文字列としてパラメータに入れるもので、また、PDO::PARAM_STRは変数の値を文字列として扱うことを宣言するものです。 今回は数値がないので使用してませんが、数値などを登録する場合にはbindValuePDO::PARAM_INTを使用します。

$_SESSION['USERID'] = $username;
echo '<script>
|s|           alert("登録が完了しました。");
|s|           location.href="main.php";
    </script>';

セッションに入力されたユーザー名を入れ(=ログイン)、その後アラートを表示し、メインページへ遷移をさせています。 PHPとJavaScriptでは処理するタイミングが違うため、アラート後のリダイレクトもJavaScriptで行う必要があります。

ログインページの作成

ハッシュ化したパスワードをユーザー名を照らし合わせてログインをします。 先ほど同様、ログインをすでにしている場合にはログインページには飛べないようになっています。

<?php
|s|    // セッション開始
|s|    session_start();
|s|    // 既にログインしている場合にはメインページに遷移
|s|    if (isset($_SESSION["USERID"])) {
|s|        header('Location: main.php');
|s|        exit;
|s|    }
|s|    $db['host'] = 'localhost';
|s|    $db['user'] = 'root';
|s|    $db['pass'] = 'root';
|s|    $db['dbname'] = 'testData';
|s|    $error = '';
|s|    // ログインボタンが押されたら
|s|    if (isset($_POST['login'])) {
|s|        if (empty($_POST['username'])) {
|s|            $error = 'ユーザーIDが未入力です。';
|s|        } else if (empty($_POST['password'])) {
|s|            $error = 'パスワードが未入力です。';
|s|        }
|s|        if (!empty($_POST['username']) && !empty($_POST['password'])) {

|s|            $username = $_POST['username'];

|s|            $dsn = sprintf('mysql: host=%s; dbname=%s; charset=utf8', $db['host'], $db['dbname']);
|s|            try {
|s|                $pdo = new PDO($dsn, $db['user'], $db['pass'], array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
|s|                $stmt = $pdo->prepare('SELECT * FROM user WHERE name = ?');
|s|                $stmt->execute(array($username));
|s|                $password = $_POST['password'];

|s|                $result = $stmt->fetch(PDO::FETCH_ASSOC);
|s|                if (password_verify($password, $result['password'])) {
|s|                    $_SESSION['USERID'] = $username;
|s|                    header('Location: main.php');
|s|                    exit();
|s|                } else {
|s|                    $error = 'ユーザーIDあるいはパスワードに誤りがあります。';
|s|                }

|s|            } catch (PDOException $e) {
|s|                echo $e->getMessage();
|s|            }
|s|        }
|s|    }
?>

<!DOCTYPE html>
<html>
|s|    <head>
|s|        <title>ログイン</title>
|s|    </head>
|s|    <body>
|s|    <main>
|s|        <form id="loginForm" name="loginForm" action="" method="POST">
|s|            <p style="color:red;"><?php echo $error ?></p>
|s|            <br>
|s|            <label for="username">ユーザーID<br>
|s|                <input type="text" id="username" name="username" placeholder="ユーザーIDを入力" value="<?php if (!empty($_POST["username"])) {echo htmlspecialchars($_POST["username"], ENT_QUOTES);} ?>">
|s|            </label><br>
|s|            <label for="password">パスワード<br>
|s|                <input type="password" id="password" name="password" value="" placeholder="パスワードを入力">
|s|            </label>
|s|            <input type="submit" id="login" name="login" value="ログイン">
|s|        </form>
|s|        <p><a href="signup.php">新規登録はこちら</a></p>
|s|    </main>
|s|    </body>
</html>

ソースの内容について

array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION)

エラーレポートについて例外をスローする設定にしています。 デフォルトはPDO::ERRMODE_SILENTでエラーコードのみが設定されるようになっています。

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

結果セットを1行ごとに連想配列形式で取り出し、返り値を $result に代入しています。 $result['name']などで値が表示できます。

password_verify($password, $result['password'])

入力されたパスワードがハッシュ化されたパスワードと一致するかどうかを判定しています。 $passwordの部分には入力されたパスワードが、$result['password']の部分にはハッシュ化パスワードが入ることで判定ができます。 返り値は「true」「false」が返ってきます。

ログイン後のメインページの作成

ログアウトへのリンクと、ログイン状態のチェックをします。

<?php
|s|    session_start();

|s|    // ログイン状態チェック
|s|    if (!isset($_SESSION["USERID"])) {
|s|        header("Location: login.php");
|s|        exit;
|s|    }
?>
<!DOCTYPE html>
<html>
|s|    <head>
|s|        <title>メインページ</title>
|s|    </head>
|s|    <body>
|s|        <main>
|s|            <p>メイン</p>
|s|            <a href="logout.php">ログアウト</a>
|s|        </main>
|s|    </body>
</html>

ソースの内容について

if (!isset($_SESSION["USERID"])) {
|s|        header("Location: login.php");
|s|        exit;
}

セッションに値がない場合にはログイン画面に遷移させています。

ログアウトページの作成

ログインページへのリンクと、セッションのクリアを行います。

<?php
|s|    session_start();
|s|    // セッションクリア
|s|    session_destroy(); 
|s|    $error = "ログアウトしました。";
?>

<!doctype html>
<html>
|s|    <head>
|s|        <title>ログアウト</title>
|s|    </head>
|s|    <body>
|s|        <div><?php echo $error; ?></div>
|s|        <ul>
|s|            <li><a href="login.php">ログインページへ</a></li>
|s|        </ul>
|s|    </body>
</html>

ソースの内容について

session_destroy(); 

上記の一文でセッションをクリアしています。

まとめ

ソースは下記からダウンロードできます。


ファイルを開く

PDOの使用&がっつりphp書いたのが初めてなので、間違いやここはこうじゃなくて....って部分があるかと思いますので、気づいた方はコメントまたはご連絡ください!


この記事の読んだ方におすすめ