49
64

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPログイン機能サンプル

Last updated at Posted at 2018-09-18

某QAサイトでよく見るログイン機能のコードはとあるQiitaの記事を参考にしているものが多いのですが、if のネストも深くて美しいコードじゃないし、SQLに変数を直接埋め込んでいたりと、決して参考にしてはいけないサンプルだったので、こちらを書いた。

詳しく仕組みを理解したいのであれば、「PHPでログイン機能を実装するチュートリアル #1」を読んで欲しいが、コピペで済ませるなら、せめてこのコードを使って欲しい。

サンプルデータは、ユーザー名:user、パスワード:password となっている。

<?php

/**
 * database.php
 * @since 2018/09/18
 */
function h($string)
{
	return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
}

function connect()
{
	$dsn = 'mysql:host=localhost;dbname=sample;charset=utf8mb4;';
	$username = 'root';
	$password = 'password';
	$options = [
		PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
		PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
	];
	$pdo = new PDO($dsn, $username, $password, $options);
	return $pdo;
}
<?php
/**
 * index.php
 * @since 2018/09/18
 */
ini_set('display_errors', true);
error_reporting(E_ALL);

session_start();

require 'database.php';

// エラーを格納する変数
$err = [];

// 「ログイン」ボタンが押されて、POST通信のとき
if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') === 'POST') {
	$user_name = filter_input(INPUT_POST, 'user_name');
	$password = filter_input(INPUT_POST, 'password');

	if ($user_name === '') {
		$err['user_name'] = 'ユーザー名は入力必須です。';
	}
	if ($password === '') {
		$err['password'] = 'パスワードは入力必須です。';
	}

	// エラーがないとき
	if (count($err) === 0) {

		// DB接続
		$pdo = connect();

		// ステートメント
		$stmt = $pdo->prepare('SELECT * FROM User WHERE user_name = ?');

		// パラメータ設定
		$params = [];
		$params[] = $user_name;

		// SQL実行
		$stmt->execute($params);

		// レコードセットを取得
		$rows = $stmt->fetchAll();

		// パスワード検証
		foreach ($rows as $row) {
			$password_hash = $row['password'];

			// パスワード一致
			if (password_verify($password, $password_hash)) {
				session_regenerate_id(true);
				$_SESSION['login_user'] = $row;
				header('Location:main.php');
				return;
			}
		}
		$err['login'] = 'ログインに失敗しました。';
	}
}
?>
<!DOCTYPE HTML>
<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<title>ログイン</title>
		<style type="text/css">
			.error {
				color: red;
			}
		</style>
	</head>
	<body>
		<div id="wrapper">
			<form action="" method="post">
				<?php if (isset($err['login'])) : ?>
					<p class="error"><?php echo h($err['login']); ?></p>
				<?php endif; ?>
				<p>
					<label for="user_name">ユーザー名</label>
					<input id="user_id" name="user_name" type="text" />
					<?php if (isset($err['user_name'])) : ?>
						<p class="error"><?php echo h($err['user_name']); ?></p>
					<?php endif; ?>
				</p>
				<p>
					<label for="">パスワード</label>
					<input id="password" name="password" type="password" />
					<?php if (isset($err['password'])) : ?>
						<p class="error"><?php echo h($err['password']); ?></p>
					<?php endif; ?>
				</p>
				<p>
					<button type="submit">ログイン</button>
				</p>
			</form>
		</div>
	</body>
</html>
<?php
/**
 * main.php
 *
 * @since 2018/09/18
 */
session_start();

require 'database.php';
$login_user = $_SESSION['login_user'];
?>
<!DOCTYPE HTML>
<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<?php foreach ($login_user as $key => $val) : ?>
			<p><?php echo h($key); ?> : <?php echo h($val); ?></p>
		<?php endforeach; ?>
	</body>
</html>
<?php
/**
 * adduser.php
 *
 * @since 2018/09/21
 */
ini_set('display_errors', true);
error_reporting(E_ALL);

session_start();

require 'database.php';

$err = [];

// 「ログイン」ボタンが押されて、POST通信のとき
if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') === 'POST') {
	$user_name = filter_input(INPUT_POST, 'user_name');
	$password = filter_input(INPUT_POST, 'password');
	$password_conf = filter_input(INPUT_POST, 'password_conf');

	if ($user_name === '') {
		$err['user_name'] = 'ユーザー名は入力必須です。';
	}
	if ($password === '') {
		$err['password'] = 'パスワードは入力必須です。';
	}
	if ($password !== $password_conf) {
		$err['password_conf'] = 'パスワードが一致しません。';
	}

	// エラーがないとき
	if (count($err) === 0) {

		// DB接続
		$pdo = connect();

		// ステートメント
		$stmt = $pdo->prepare('INSERT INTO `User` (`id`, `user_name`, `password`) VALUES (null, ?, ?)');

		// パラメータ設定
		$params = [];
		$params[] = $user_name;
		$params[] = password_hash($password, PASSWORD_DEFAULT);

		// SQL実行
		$success = $stmt->execute($params);
	}
}
?>
<!DOCTYPE HTML>
<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<title></title>
        <style type="text/css">
            .error {
                color: red;
            }
        </style>
	</head>
	<body>
		<?php if (count($err) > 0) : ?>
			<?php foreach ($err as $e): ?>
				<p class="error"><?php echo h($e); ?></p>
			<?php endforeach; ?>
		<?php endif; ?>

		<?php if (isset($success) && $success) : ?>
			<p>登録に成功しました。</p>
			<p><a href="index.php">こちらからログインしてください。</a></p>
		<?php else: ?>
			<form action="" method="post">
				<p>
					<label for="user_name">ユーザー名</label>
					<input id="user_id" name="user_name" type="text" />
				</p>
				<p>
					<label for="">パスワード</label>
					<input id="password" name="password" type="password" />
				</p>
				<p>
					<label for="">確認用パスワード</label>
					<input id="password_conf" name="password_conf" type="password" />
				</p>
				<p>
					<button type="submit">ログイン</button>
				</p>
				<p>
					<a href="adduser.php">新規ユーザー登録</a>
				</p>
			</form>
		<?php endif; ?>
	</body>
</html>
CREATE TABLE `User` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'AI',
  `user_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '氏名',
  `password` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'パスワード',
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_name` (`user_name`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4;

INSERT INTO `User` (`id`, `user_name`, `password`)
VALUES
	(1,'user','$2y$10$ecRmAWY4n/jLa0tTzIaG7.SMhb1TfdROy3nXeG5aVZorUX1n6/WHO');
49
64
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
64

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?