はじめに
今回は、PHPとMySQLを使ってログイン機能を実装していきます。
※当ページは、【PHPでECサイト】で作られたものを前提にしています。
バージョン
PHP:7.4.5
phpMyAdmin:5.0.2
MySQL:5.7.30
今回作成するファイル
html
- login.php
- login_process.php
- signup.php
- signup_process.php
- logout.php
model
- users.php
view
- login_view.php
- signup_view.php
テーブルの作成
sample_users.sql
CREATE TABLE `sample_users` (
`user_id` int(11) NOT NULL,
`user_name` varchar(20) NOT NULL,
`password` varchar(20) NOT NULL,
`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `sample_users`
MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY (`user_id`);
定義
処理に使うものを追記
const.php
define('SIGNUP_URL', '/signup.php');
define('LOGIN_URL', '/login.php');
define('LOGOUT_URL', '/logout.php');
// 正規表現
define('REGEXP_ALPHANUMERIC', '/\A[0-9a-zA-Z]+\z/');
// 文字数制限
define('USER_NAME_LENGTH_MIN', 6);
define('USER_NAME_LENGTH_MAX', 20);
define('USER_PASSWORD_LENGTH_MIN', 6);
define('USER_PASSWORD_LENGTH_MAX', 20);
ユーザ登録
Modelの作成
users.phpを作成し、ユーザ登録・ログイン処理を記述
users.php
// ログイン
function get_user_by_name($db, $name){
$sql = "
SELECT
user_id,
user_name,
password
FROM
sample_users
WHERE
user_name = ?
";
return fetch_query($db, $sql, array($name));
}
function login_as($db, $name, $password){
$user = get_user_by_name($db, $name);
if($user === false || $user['password'] !== $password){
return false;
}
set_session('user_id', $user['user_id']);
return $user;
}
// ユーザ登録
function regist_user($db, $name, $password) {
if(is_valid_user($name, $password) === false){
return false;
}
return insert_user($db, $name, $password);
}
// バリデーション
function is_valid_user($name, $password){
// 短絡評価を避けるため一旦代入。
$is_valid_user_name = is_valid_user_name($name);
$is_valid_password = is_valid_password($password);
return $is_valid_user_name && $is_valid_password ;
}
function is_valid_user_name($name) {
$is_valid = true;
if(is_valid_length($name, USER_NAME_LENGTH_MIN, USER_NAME_LENGTH_MAX) === false){
set_error('ユーザー名は'. USER_NAME_LENGTH_MIN . '文字以上、' . USER_NAME_LENGTH_MAX . '文字以内にしてください。');
$is_valid = false;
}
if(is_alphanumeric($name) === false){
set_error('ユーザー名は半角英数字で入力してください。');
$is_valid = false;
}
return $is_valid;
}
function is_valid_password($password){
$is_valid = true;
if(is_valid_length($password, USER_PASSWORD_LENGTH_MIN, USER_PASSWORD_LENGTH_MAX) === false){
set_error('パスワードは'. USER_PASSWORD_LENGTH_MIN . '文字以上、' . USER_PASSWORD_LENGTH_MAX . '文字以内にしてください。');
$is_valid = false;
}
if(is_alphanumeric($password) === false){
set_error('パスワードは半角英数字で入力してください。');
$is_valid = false;
}
return $is_valid;
}
// ユーザデータの挿入
function insert_user($db, $name, $password){
$sql = "
INSERT INTO
sample_users(user_name, password)
VALUES (?,?);
";
return execute_query($db, $sql, array($name, $password));
}
functions.php
// ログイン処理
function is_logined(){
return get_session('user_id') !== '';
}
// バリデーション
function is_valid_length($string, $minimum_length, $maximum_length = PHP_INT_MAX){
$length = mb_strlen($string);
return ($minimum_length <= $length) && ($length <= $maximum_length);
}
function is_alphanumeric($string){
return is_valid_format($string, REGEXP_ALPHANUMERIC);
}
function is_valid_format($string, $format){
return preg_match($format, $string) === 1;
}
Viewの作成
※メッセージ表示のところは、繰り返し使用する為、別のファイルに記述し、それを読み込んでいます。
signup_view.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ユーザ登録</title>
</head>
<body>
<h1>ユーザ登録ページ</h1>
<!-- メッセージ・エラーメッセージ -->
<?php include VIEW_PATH. 'templates/messages.php'; ?>
<!-- ログインフォーム -->
<form method="post" action="signup_process.php">
<div>
<label>ユーザ名:</label>
<input type="text" name="name">
</div>
<div>
<label>パスワード:</label>
<input type="password" name="password">
</div>
<input type="submit" value="新規登録">
<input type="button" onclick="location.href='<?php print(LOGIN_URL); ?>'" value="ログインページへ">
</form>
</body>
</html>
Controllerの作成
signup.php
<?php
require_once '../conf/const.php';
require_once MODEL_PATH. 'functions.php';
session_start();
// ログインされていれば、商品管理ページへ遷移
if(is_logined() === true){
redirect_to(ADMIN_URL);
}
include_once VIEW_PATH. 'signup_view.php';
signup_process.php
<?php
require_once '../conf/const.php';
require_once MODEL_PATH. 'functions.php';
require_once MODEL_PATH. 'users.php';
session_start();
// ログインされていれば、商品管理ページへ遷移
if(is_logined() === true){
redirect_to(ADMIN_URL);
}
// Postされたものを定義
$name = get_post('name');
$password = get_post('password');
// データベース接続
$db = get_db_connect();
// ユーザ登録処理
try{
$result = regist_user($db, $name, $password);
if($result === false){
set_error('ユーザ登録に失敗しました。');
redirect_to(SIGNUP_URL);
}
}catch(PDOException $e){
set_error('ユーザ登録に失敗しました。');
redirect_to(SIGNUP_URL);
}
set_message('ユーザ登録が完了しました。');
// ユーザ登録完了後、そのままログインして商品管理ページへ遷移
login_as($db, $name, $password);
redirect_to(ADMIN_URL);
ログイン
Viewの作成
※メッセージ表示のところは、繰り返し使用する為、別のファイルに記述し、それを読み込んでいます。
login_view.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ログイン</title>
</head>
<body>
<h1>ログインページ</h1>
<!-- メッセージ・エラーメッセージ -->
<?php include VIEW_PATH. 'templates/messages.php'; ?>
<!-- ログインフォーム -->
<form method="post" action="login_process.php">
<div>
<label>ユーザ名</label>
<input type="text" name="name">
</div>
<div>
<label>パスワード</label>
<input type="password" name="password">
</div>
<input type="submit" value="ログイン">
<input type="button" onclick="location.href='<?php print(SIGNUP_URL); ?>'" value="ユーザ登録ページへ">
</form>
</body>
</html>
Controllerの作成
login.php
<?php
require_once '../conf/const.php';
require_once MODEL_PATH . 'functions.php';
session_start();
// ログインされていれば、商品管理ページへ遷移
if(is_logined() === true){
redirect_to(ADMIN_URL);
}
include_once VIEW_PATH . 'login_view.php';
login_process.php
<?php
require_once '../conf/const.php';
require_once MODEL_PATH. 'functions.php';
require_once MODEL_PATH. 'users.php';
session_start();
// ログインされていれば、商品管理ページへ遷移
if(is_logined() === true){
redirect_to(ADMIN_URL);
}
// Postされたものを定義
$name = get_post('name');
$password = get_post('password');
// データベース接続
$db = get_db_connect();
// ログイン処理
$user login_as($db, $name, $password);
if($user === false){
set_error('ログインに失敗しました。');
redirect_to(LOGIN_URL);
}
set_message('ログインしました。');
redirect_to(ADMIN_URL);
ログアウト
Modelの作成
users.php
// ログイン状況
function get_user($db, $user_id){
$sql = "
SELECT
user_id,
user_name,
password
FROM
sample_users
WHERE
user_id = ?
";
return fetch_query($db, $sql, array($user_id));
}
function get_login_user($db){
$login_user_id = get_session('user_id');
return get_user($db, $login_user_id);
}
Viewの作成
遷移先のページに、ログアウトできるよう追記
admin_view.php
<p>ようこそ、<?php print($user['user_name']); ?>さん。</p>
<a href="<?php print(LOGOUT_URL);?>">ログアウト</a>
Controllerの作成
logout.php
<?php
require_once '../conf/const.php';
require_once MODEL_PATH. 'functions.php';
session_start();
$_SESSION = array();
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"],
$params["domain"],
$params["secure"],
$params["httponly"]
);
session_destroy();
redirect_to(LOGIN_URL);
admin.php
require_once MODEL_PATH. 'users.php';
// ログインされてなければ、ログインページへ遷移
if(is_logined() === false){
redirect_to(LOGIN_URL);
}
$user = get_login_user($db);