20200807のMySQLに関する記事は4件です。

【PHP入門】ログイン機能

はじめに

今回は、PHPとMySQLを使ってログイン機能を実装していきます。
※当ページは、【PHP入門】CRUD機能で作られたものを前提にしています。

バージョン

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

テーブルの作成

bbs_user.sql
CREATE TABLE `bbs_users` (
  `user_id` int(11) NOT NULL,
  `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 `bbs_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,
        name,
        password
      FROM
        bbs_users
      WHERE
        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
        bbs_users(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(BBS_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(BBS_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(BBS_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(BBS_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(BBS_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(BBS_URL);

ログアウト

Modelの作成

users.php
// ログイン状況
function get_user($db, $user_id){
    $sql = "
      SELECT
        user_id, 
        name,
        password
      FROM
        bbs_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の作成

bbs_view.php
<p>ようこそ、<?php print($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);
bbs.php
require_once MODEL_PATH. 'users.php';

// ログインされてなければ、ログインページへ遷移
if(is_logined() === false){
    redirect_to(LOGIN_URL);
}  

$user = get_login_user($db);

参考

session_get_cookie_params

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FuelPHPでSQLの最新のレコードを取得する

SQLにあるレコードの、created_atが最も新しいものを取得したいといったとき、
SELECTにMAX(created_at)とするだけでやってくれます。

FuelPHPの場合は

example.php
$query = \DB::select('id', \DB::expr('MAX(created_at)'))
->from('table_name')
->execute();

とするだけでできます。
これに加えて
group_by('id')
などを使うときにすごく役立ちます。

配列で取得したあとに頑張って新しい配列に入れるみたいなことをせずに済みます。(自戒)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでユーザーの生年月日をちゃんと表示する

ユーザーの生年月日をdate型でデータベースに保存するようにします

そのまま表示しようとすると

1998-09-25

みたいな表示になるので

format関数を使って○月○日みたいな表示を可能にさせます

モデルの変更

対象となるモデルに記述(ここではUser.php)

User.php
protected [
  'birthday'
]

## 表示させたいカラムを指定

はいこれだけ、
これでformat関数が使えます


あとは指定すれば

<p>{{ $user->birthday->format(Y年m月d年) }}</p>

こう表示される

1998年09月25日

モデルに設定を記述しないとエラーが出る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQLでBOOLEAN型のカラムに'true'をINSERTするとfalseになる

MySQLでBOOLEAN型のカラムに'true'をINSERTすると、その値はfalseになります。

問題

次のような構造のテーブルがあり、レコードは空の状態だとします。

CREATE TABLE `users` (
  `id` INT NOT NULL,
  `name` TEXT NOT NULL,
  `status` TEXT NOT NULL,
  `active` BOOLEAN NOT NULL,
  PRIMARY KEY (`id`)
);

このテーブルに対して、レコードを追加してみましょう。

INSERT INTO `users` (`id`, `name`, `status`, `active`)
  VALUES (1, 'Alice', 'true', 'true');

その後、次のようなSQL文を実行するとどうなるでしょうか。

SELECT count(*) FROM users WHERE active = true;

結果は、次のようになります。

count(*)
0

それでは、次のようなSQL文を実行するとどうなるでしょうか。

SELECT count(*) FROM users WHERE active = false;

結果は、次のようになります。

count(*)
1

これはいったい、なぜしょうか。

原因

レコードを追加したあとのテーブルは、次のような状態になっています。

id name status active
1 Alice true 0

MySQLのBOOLEAN型は実際にはTINYINT(1)型のシノニムで、0がfalse、0以外がtrueを表しています。1
trueという文字列はTINYINT(1)型としては無効な値なので、デフォルト値である0になってしまったというわけです。

解決策

BOOLEAN型のカラムでは、文字列ではなくboolean リテラルで値を書きましょう。2

INSERT INTO `users` (`id`, `name`, `status`, `active`)
  VALUES (1, 'Alice', 'true', true);
INSERT INTO `users` (`id`, `name`, `status`, `active`)
  VALUES (2, 'Bob', 'true', false);

あるいは、対応する数値を使ってもいいでしょう。

INSERT INTO `users` (`id`, `name`, `status`, `active`)
  VALUES (1, 'Alice', 'true', 1);
INSERT INTO `users` (`id`, `name`, `status`, `active`)
  VALUES (2, 'Bob', 'true', 0);

CSVファイルをインポートする場合

LOAD DATA INFILE構文を用いて次のようなCSVファイルをインポートする場合も、同様の問題が発生します。

"id","name","status","active"
"1","Alice","true","true"
"2","Bob","true","false"

この問題を解決するには、インポート時にBOOLEAN型のカラムの値をboolean リテラルに変換します。

LOAD DATA LOCAL INFILE 'users.csv'
  REPLACE
  INTO TABLE users
  FIELDS
    TERMINATED BY ','
    OPTIONALLY ENCLOSED BY '"'
  IGNORE 1 LINES
  (id, name, status, @active)
  SET active = IF(@active='true', true, false);

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む