PHPログイン機能

# PHPによる新規登録からログイン・ログアウトまで

大まかな流れとして
◆登録画面でユーザー登録
　→すでに存在しているユーザーではないか
◆ログイン処理
　→入力された情報がDBと一致すればログイン
◆ホーム画面表示
　→ログインか非ログインで表示の変更

##新規登録
フォームの用意

```php:signup.php
<h1>新規会員登録</h1>
<form action="register.php" method="post">//処理を行う宛先を指定
<div>
    <label>
        名前：
        <input type="text" name="name" required>
    </label>
</div>
<div>
    <label>
        メールアドレス：
        <input type="text" name="mail" required>
    </label>
</div>
<div>
    <label>
        パスワード：
        <input type="password" name="pass" required>
    </label>
</div>
<input type="submit" value="新規登録">
</form>
<p>すでに登録済みの方は<a href="login.php">こちら</a></p>
```

フォームによって送信された値から新規登録の処理を行う

```php:register.php
<?php
//フォームからの値をそれぞれ変数に代入
$name = $_POST['name'];
$mail = $_POST['mail'];
$pass = password_hash($_POST['pass'], PASSWORD_DEFAULT);
$dsn = "mysql:host=localhost; dbname=xxx; charset=utf8";
$username = "xxx";
$password = "xxx";
try {
    $dbh = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
    $msg = $e->getMessage();
}

//フォームに入力されたmailがすでに登録されていないかチェック
$sql = "SELECT * FROM users WHERE mail = :mail";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':mail', $mail);
$stmt->execute();
$member = $stmt->fetch();
if ($member['mail'] === $mail) {
    $msg = '同じメールアドレスが存在します。';
    $link = '<a href="signup.php">戻る</a>';
} else {
    //登録されていなければinsert 
    $sql = "INSERT INTO users(name, mail, pass) VALUES (:name, :mail, :pass)";
    $stmt = $dbh->prepare($sql);
    $stmt->bindValue(':name', $name);
    $stmt->bindValue(':mail', $mail);
    $stmt->bindValue(':pass', $pass);
    $stmt->execute();
    $msg = '会員登録が完了しました';
    $link = '<a href="login.php">ログインページ</a>';
}
?>

<h1><?php echo $msg; ?></h1><!--メッセージの出力-->
<?php echo $link; ?>
```

【1】フォームで送信された値を$_POSTで受けて、それぞれ変数に代入
【2】送信された値がすでにDBに登録されていないかのチェック
　　→メールアドレスをWHEREの条件にしてSQLのSELECTを実行する
　　　`$member = $stmt->fetch();`で実行結果のデータを取り出す
　　　`["name"]=> string(12) "田中太郎"`のような配列で取り出される
　　　$member['カラム名']でそのカラムの値を取り出すことができる
【3】登録されていなければINSERTでフォームで送信された値をDBに登録

##ログイン

フォームの用意

```php:login_form.php
<h1>ログインページ</h1>
<form action="login.php" method="post">
<div>
    <label>
        メールアドレス：
        <input type="text" name="mail" required>
    </label>
</div>
<div>
    <label>
        パスワード：
        <input type="password" name="pass" required>
    </label>
</div>
<input type="submit" value="ログイン">
</form>
```

送信されたフォームからDBと照合し、登録済みのユーザーであればログイン処理を行う

```php:login.php
<?php
session_start();
$mail = $_POST['mail'];
$dsn = "mysql:host=localhost; dbname=xxx; charset=utf8";
$username = "xxx";
$password = "xxx";
try {
    $dbh = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
    $msg = $e->getMessage();
}

$sql = "SELECT * FROM users WHERE mail = :mail";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':mail', $mail);
$stmt->execute();
$member = $stmt->fetch();
//指定したハッシュがパスワードにマッチしているかチェック
if (password_verify($_POST['pass'], $member['pass'])) {
    //DBのユーザー情報をセッションに保存
    $_SESSION['id'] = $member['id'];
    $_SESSION['name'] = $member['name'];
    $msg = 'ログインしました。';
    $link = '<a href="index.php">ホーム</a>';
} else {
    $msg = 'メールアドレスもしくはパスワードが間違っています。';
    $link = '<a href="login.php">戻る</a>';
}
?>

<h1><?php echo $msg; ?></h1>
<?php echo $link; ?>
```

【1】セッションを開始するために`session_start();`の宣言
【2】送信されたフォームから指定したハッシュがDB上のパスワードとマッチするかチェック
【3】すでに登録されているユーザーであれば、ホーム画面でログインしたユーザーの名前を表示するためにセッションにユーザー名を保存
【4】存在しなければエラーメッセージ

##ログアウト

```php:logout.php
<?php
session_start();
$_SESSION = array();//セッションの中身をすべて削除
session_destroy();//セッションを破壊
?>

<p>ログアウトしました。</p>
<a href="login.php">ログインへ</a>
```
【1】`$_SESSION = array();`によってセッションの中身を削除する
【2】`session_destroy();`によってセッションを破壊する

##ホーム画面

```php:index.php
<?php
session_start();
$username = $_SESSION['name'];
if (isset($_SESSION['id'])) {//ログインしているとき
    $msg = 'こんにちは' . htmlspecialchars($username, \ENT_QUOTES, 'UTF-8') . 'さん';
    $link = '<a href="logout.php">ログアウト</a>';
} else {//ログインしていない時
    $msg = 'ログインしていません';
    $link = '<a href="login.php">ログイン</a>';
}
?>
<h1><?php echo $msg; ?></h1>
<?php echo $link; ?>
```


##参考文献
・$stmt->fetch()はどういう意味？
https://blog.senseshare.jp/stmtfetch.html
・【PHP入門】徹底解説！PHPでセッションを使う方法～基本から応用まで
https://www.sejuku.net/blog/25276
・PHP、PDOの「bindValue」と「bindParam」の違い
http://piyopiyocs.blog115.fc2.com/blog-entry-656.html