※完成形のコードは最後に全て載せてあります。
今回使用するファイルは「login.php」と「style.css」の2つだけです。
作成するログインページは、
【2-1】7ステップでお問い合わせページを作成で使用したコードがほとんどそもまま使えるので、
レイアウトに関してはHTMLとCSSを再利用させていただきます。
ログイン画面を作成(HTMLとCSS)
再利用できると言ってもHTMLの方は多少異なるので、変更点を解説していきます。
ちなみに、今回はCRUDの機能を作ることの方が重要なので、見た目にこだわる必要は特にありません。
<!DOCTYPE html>
<html lang="en">
<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">
<title>ログインページ</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="title-area">
<h1>ログインページ</h1>
</div>
<form action="" method="POST">
<input type="text" class="input-area" name="name" placeholder="Your Name" required> <br>
<input type="password" class="input-area" name="password" placeholder="Your Password" required> <br>
<input type="submit" class="input-area submit" name="submit" value="Log in">
</form>
</body>
</html>
変更点1:method=”POST” の追加
今回は送信したデータをPOST通信で受け渡したいので、
「method=”POST”」と指定します。
変更点2:name属性の追加
それぞれのinputタグにname属性をつけてあります。
POST通信のデータの受け渡しとname属性については、
form送信の方法ということでこちらの記事でも解説してあります!
styel.cssの方は、「【2-1】7ステップでお問い合わせページを作成」で使用したコードがそもまま使えるのでこちらに載せておきます。
body {
margin: 0;
padding: 0;
text-align: center;
background-image: url(../img/top1.jpg);
background-size: cover;
background-position: center;
}
/* タイトル */
.title-area {
margin-top: 100px;
color: white;
}
.title-area h1 {
font-size: 45px;
line-height: 10px;
}
.title-area p {
font-size: 25px;
}
/* フォーム */
form {
margin-top: 50px;
}
.input-area {
width: 600px;
background: transparent;
border: none;
border-bottom: 1px solid rgb(247, 241, 241);
color: #fff;
font-size: 18px;
margin-bottom: 16px;
}
input {
height: 45px;
}
input::placeholder {
color: white;
}
textarea::placeholder {
color: white;
}
/* 送信ボタン */
form .submit {
height: 50px;
background: rgb(28, 109, 249);
opacity: 0.8;
border-color: transparent;
color: white;
font-size: 20px;
font-weight: bold;
letter-spacing: 2px;
margin-top: 20px;
}
form .submit:hover {
background: rgb(73, 140, 255);
cursor: pointer;
}
この時点で、このような画面が完成しているはずです。
この時点では「Log in」ボタンを押しても何も起きません。
これから、実際にこの「Log in」ボタンを押した時に、ちゃんとログインできる機能を作っていきましょう。
ログイン機能のロジック部分について(PHP)
使用するファイルは先ほどまで使っていた「login.php」です。
実際に作り始める前に、ログイン機能の仕組みについて紹介しておきます。
<ログイン機能の仕組み>
入力された名前とパスワードの組み合わせが、
正しいものであれば中に入ることができるというものですね。
プログラミングっぽく言うと「name」と「password」を条件にして
DBからSELECT文で取得することができれば、その組み合わせはDBに登録されている。
つまり、ログインすることができるという事になります。
SELECT文の取得結果が0件であれば、その組み合わせはDBには登録されていない。
つまり、ログインすることはできないという事になります。
そのため、ログイン機能に必要なことを一言で言うと、
SELECT文を使ってDBから結果を取得することができればログインできる
という処理を作ろうということになります。
form送信されたデータを受け取る処理
まず「Log in」ボタンが押された時にデータとして送信される分を全て受け取っておきましょう。
<?php
// フォーム送信された情報を受け取る
$name = $_POST['name'];
$password = $_POST['password'];
$submit = $_POST['submit'];
?>
// ※この下にHTMLが続いています。
「log in」ボタンが押された時だけ処理をしたい
実は、ログインボタンを押さなくても、URLを直接入力すればアクセスできてしまうのです。
それは困りますよね。
では、どのようにすると「log in」ボタンが押された時だけという条件をつけることができるのでしょうか?
こんな感じです。↓
if (!empty($submit)) {
}
「empty」を使うと「値が空だった場合」というのを指定することができます。
それを「!」を使って否定するので「値が空じゃなかった場合」を表現することができます。
<?php
// フォーム送信された情報を受け取る
$name = $_POST['name'];
$password = $_POST['password'];
$submit = $_POST['submit'];
// $submitが空ではない→ログインボタンが押されたと言うこと。
if (!empty($submit)) {
}
?>
// ※この下にHTMLが続いています。
DB接続をしてログイン(SELECT)してみる
さっそくDB接続をしたいのですが、
DB接続処理は前回「db_connect.php」というファイルに「db_connect」メソッドとして作成してあります。
しかし、別ファイルにあるメソッドなので
「require」というのを使って別ファイルを読み込んであげる必要があります。
// DB接続のファイルを読み込む(db_connectメソッドを使いたいから)
require('db_connect.php');
この処理は「login.php」の一番上に書いておきましょう。
こんな感じですね。
<?php
// DB接続のファイルを読み込む(db_connectメソッドを使いたいから)
require('db_connect.php');
// フォーム送信された情報を受け取る
$name = $_POST['name'];
$password = $_POST['password'];
$submit = $_POST['submit'];
// $submitが空ではない→ログインボタンが押されたと言うこと。
if (!empty($submit)) {
}
?>
// ※この下にHTMLが続いています。
すると、本来別ファイル(db_connect.php)にある
DB接続処理が書いてあるメソッド(db_connectメソッド)を使用することができます。
DB接続の処理だけ抜き出して書いておきます。
// $submitが空ではない→ログインボタンが押されたと言うこと。
if (!empty($submit)) {
$pdo = db_connect();
try {
$sql = "SELECT * FROM users WHERE name = :name AND password = :password";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':password', $password);
$stmt->execute();
} catch (PDOException $e) {
echo 'エラー:' . $e->getMessage();
die();
}
}
db_connectを代入している?
定義元のdb_connectメソッドを見てみると、
returnで呼び出し元に値を返す記述をしています。(↓db_connect.php)
function db_connect() {
try {
// PDOインスタンスの作成
$pdo = new PDO(DSN, DB_USERNAME, DB_PASSWORD);
// エラー処理方法の設定
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
} catch(PDOException $e) {
echo 'Error: ' . $e->getMessage();
die();
}
}
今回returnを使ったのは、
このDB接続処理を別ファイルから呼び出して使う必要があるためです。
WHERE句にある、:name AND password = :password”; について
SQLのWHERE句に見慣れない「:name」や「:password」という記述がありますね。
これは、
SQL文は作っておきたいけど、何が値として使用されるかは後で決まる。
という時に一旦仮で置いておく書き方です。
bindParamについて
見慣れない記述というともう一つ「bindParam」というものがあります。
実はこの「bindParam」で「:name」や「:password」の値を決定しています。
bindPramの考え方
bindParam(‘:name’, $name);
これを書くときの考え方は
突然出てきた「:name」という文字列は何かというと、中身は「$name」です。
という感じです。
ついに「ログインするかログインしないか」の処理
tryの中にある、実際にDBにSELECTでアクセスしている処理の流れを軽くおさらいしておきます。
- $sql = “SELECT * FROM users WHERE name = :name AND password = :password”;
nameとpasswordを条件にしたSQLを文字列として$sqlという文字列に代入している - $pdo->prepare($sql);
文字列のままだと効力を得ないので、PHPが認識できる状態にしている - bindParamで「:name」や「:password」の値を決定する
- executeでSQL実行
現在、$stmtという変数の中にSELECTした結果が入っています。
そのため「$stmt->fetch(PDO::FETCH_ASSOC)」を使うと、
$stmtの中から結果を取り出すことができるので
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
header("Location: main.php");
exit;
} else {
echo '<font color="red">パスワードか名前に間違いがあります。</font>';
}
このように書くと、
SELECTの結果として1件も取得できなかった場合はelseの処理に入ります。
if文がTUREだった場合は「header(“Location: main.php”);」という処理が実行されます。
これはリダイレクトと言って、
「Location:」の部分に指定した箇所に遷移させることができます。
つまり、SELECTを実行してデータが取得できたのであれば、
メインページに遷移するという流れになります。
動作確認
では、実際に動かしてみましょう。
ログインが成功したら「main.php」に遷移することになっています。
「main.php」は次回作成していくのですが、動作確認のために一旦仮のページを作成しておきます。
<!DOCTYPE html>
<html lang="en">
<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">
<title>メインページ</title>
</head>
<body>
メインページ
</body>
</html>
「login.php」で作った画面にアクセスするためには、
MAMP/XAMPPが起動している状態で以下のURLにアクセスします。
(※ソースコードを変更した際は、画面を更新しないと結果が反映されないのでお気をつけください。)
http://localhost/todo/login.php
フォルダ名が「todo」ではなかったり、ファイル名が「todo.php」ではない場合はURLが異なります。
今、DBには以下のユーザが一人登録されているはずなので、ログインしてみましょう。
- 名前:田中太郎
- パスワード:taro
「メインページ」と表示されれば成功です!
それから、ちゃんとエラーが出るかどうかの確認も必要です。
今回だと、DBに登録していない名前とパスワードの組み合わせを使うと、
「パスワードか名前に間違いがあります。」
という文字が表示されるはずです。
まとめ
「login.php」の完成形のソースコードを載せておきます。
<?php
// DB接続のファイルを読み込む(db_connectメソッドを使いたいから)
require('db_connect.php');
// フォーム送信された情報を受け取る
$name = $_POST['name'];
$password = $_POST['password'];
$submit = $_POST['submit'];
// $submitが空ではない→ログインボタンが押されたと言うこと。
if (!empty($submit)) {
$pdo = db_connect();
try {
$sql = "SELECT * FROM users WHERE name = :name AND password = :password";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':password', $password);
$stmt->execute();
} catch (PDOException $e) {
echo 'エラー:' . $e->getMessage();
die();
}
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
header("Location: main.php");
exit;
} else {
echo '<font color="red">パスワードか名前に間違いがあります。</font>';
}
}
?>
<!DOCTYPE html>
<html lang="en">
<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">
<title>ログインページ</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="title-area">
<h1>ログインページ</h1>
</div>
<form action="" method="POST">
<input type="text" class="input-area" name="name" placeholder="Your Name" required> <br>
<input type="password" class="input-area" name="password" placeholder="Your Password" required> <br>
<input type="submit" class="input-area submit" name="submit" value="Log in">
</form>
</body>
</html>
軽く処理の流れを示しておきます。
- 「name」と「password」に値を入力して「Log in」ボタンを押す
- name属性に指定した値がデータとして、actionに指定したページに飛ばされる
- 今回はactionは何も指定していないので、login.phpに戻ってくる
➡︎ login.phpを上から再度実行する - PHPの処理では、requireでDB接続用の関数が記述されているファイルを読み込む
- 「Log in」ボタンが押されたかどうかを「empty」を使ってチェック
- SELECT文を実行
- 何かしらの結果が取得できれば、main.phpにリダイレクトする
- HTMLとCSSはこちらの記事で使用したのとほとんど同じです
- ログイン画面のスタイルは今回は特に重要ではないので適当でも問題ないです
- ログイン機能は言い換えると「SELECT文で結果を取得できるどうか」と同じような意味
- bindParamを使うと、WHERE句の値を後から入れることができる
- header(Location: )を使うと別ファイルに遷移させることができる