3
7

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 3 years have passed since last update.

PHPでログイン機能作ってみた

Last updated at Posted at 2021-04-01

作った動機

機能

ログインログアウト。
アカウント新規作成・更新・削除。

環境

PHP7
MariaDB10

コード

PHPのお作法がわからないので、Javaっぽい書き方になっています。

Model

account.php
<?php
class Account {
  private $id;
  private $name;
  private $password;

  public function idGet():int {
    return $this->id;
  }

  public function idSet(int $id) {
    $this->id = $id;
  }

  public function nameGet():string {
    return $this->name;
  }

  public function nameSet(string $name) {
    $this->name = $name;
  }

  public function passwordGet(): string {
    return $this->password;
  }

  public function passwordSet(string $password) {
    $this->password = $password;
  }
}
sessionDestroy.php
<?php
session_start();

//ログアウト処理。
//セッション変数を空にする。
$_SESSION = [];

// セッションクッキーが存在する場合には破棄
if(isset($_COOKIE[session_name()])) {
  $cparam = session_get_cookie_params();
  setcookie(session_name(), '', time() - 3600,
            $cparam['path'], $cparam['domain'],
            $cparam['secure'], $cparam['httponly']);
}
//セッションを破棄。
session_destroy();

// ログイン画面へ
header("Location: login.html");
encode.php
<?php
/**
 * クロスサイトスクリプティング(XSS)防止用。
 * ユーザー入力値をHTML表示する時に呼び出す。
 * $str:エンコード対象の文字列
 * #charset:エンコードタイプ
 * ENT_QUOTES | ENT_HTML5:シングル/ダブルクォートを双方エスケープし、HTML5文書として処理。原則はこれらしい。
 */ 
function e(string $str, string $charset = "UTF-8"): string {
  return htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, $charset);
}

DAO

connectDB.php
<?php
function getDb() { 
  $dsn = 'mysql:dbname=selfphp; host=127.0.0.1; charset=utf8'; 
  $usr = 'root'; 
  $password = 'password'; 
  
  //DB接続
  $db = new PDO($dsn, $usr, $password); 

  // 例外処理を有効化
  $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  return $db;
  }
accountSearch.php
<?php
require_once("./account.php");
require_once("./connectDB.php");

function getAccount(string $name, string $password)
{
  $account = new Account();
  try {
    //上記DB接続のgetDbメソッドでDB接続 
    $db = getDb();


    // 検索SQLプレースホルダで準備 
    $stt = $db->prepare("SELECT * FROM account WHERE name = ?");
    $stt->bindValue(1, $name);
    // SELECT命令を実行
    $stt->execute();

    //アカウントの有無判定フラグ
    $flag = 0;
    //検索結果の取得 PDO::FETCH_ASSOCは連想配列で取得
    while ($row = $stt->fetch(PDO::FETCH_ASSOC)) {
      $hash = $row['password'];
      //ハッシュ値とパスワードの照合
      if(password_verify($password, $hash)){
        $account->idSet($row['id']);
        $account->nameSet($row['name']);
        $account->passwordSet($row['password']);
        $flag = 1;
      }
    }
    // 例外が発生したら、エラー表示 
  } catch (PDOException $e) {
    print "エラーメッセージ:{$e->getMessage()}";
  } finally {
    $stt = null;
    $db = null;
  }
  if($flag === 0) {
    //アカウントが見つからなければnullを返す
    return null;
  }else{
    //アカウントが見つかればアカウント情報を返す
    return $account;
  }
}
accountInsert.php
<?php
require_once("./connectDB.php");


function insertAccount($name, $password)
{
  try {
    //上記DB接続のgetDbメソッドでDB接続 
    $db = getDb();
    // ドランザクションを開始 
    $db->beginTransaction();
    // パスワードハッシュを生成
    $hash = password_hash($password, PASSWORD_DEFAULT);
    // 更新SQLプレースホルダで準備 
    $stt = $db->prepare('INSERT INTO account(name, password) VALUES(:name, :password)');
    $stt->bindValue(':name', $name);
    $stt->bindValue(':password', $hash);
    // insert命令を実行 
    $stt->execute();
    // 全ての処理が完了したらトランザクションをコミット 
    $db->commit();
    // 例外発生したら、エラー表示&トランザクションをロールバック 
  } catch (PDOException $e) {
    $db->rollBack();
    print "エラーメッセージ:{$e->getMessage()}";
  } finally {
    $stt = null;
    $db = null;
  }
}
accountUpdate.php
<?php
require_once("./connectDB.php");

function updateAccount(int $id, string $name, string $password)
{
  try {
    //上記DB接続のgetDbメソッドでDB接続 
    $db = getDb();
    // ドランザクションを開始 
    $db->beginTransaction();
    // パスワードハッシュを生成
    $hash = password_hash($password, PASSWORD_DEFAULT);
    // 更新SQLプレースホルダで準備 
    $stt = $db->prepare('UPDATE account SET name=:name, password=:password WHERE id = :id');
    $stt->bindValue(':id', $id);
    $stt->bindValue(':name', $name);
    $stt->bindValue(':password', $hash);
    $stt->execute();
    // 全ての処理が完了したらトランザクションをコミット 
    $db->commit();
    // 例外発生したら、エラー表示&トランザクションをロールバック 
  } catch (PDOException $e) {
    $db->rollBack();
    print "エラーメッセージ:{$e->getMessage()}";
  } finally {
    $stt = null;
    $db = null;
  }
}
accountDelete.php
<?php
require_once("./connectDB.php");

function deleteAccount(int $id)
{
  try {
    $db = getDb();
    // ドランザクションを開始 
    $db->beginTransaction();
    $stt = $db->prepare('DELETE FROM account WHERE id = :id');
    $stt->bindValue(':id', $id);
    $stt->execute();
    // 全ての処理が完了したらトランザクションをコミット 
    $db->commit();
    // 例外発生したら、エラー表示&トランザクションをロールバック 
  } catch (PDOException $e) {
    $db->rollBack();
    print "エラーメッセージ:{$e->getMessage()}";
  } finally {
    $stt = null;
    $db = null;
  }
}

Controller

searchController.php
<?php
require_once("./accountSearch.php");
session_start();

$account = getAccount($_GET['name'], $_GET['password']);

if ($account === null) {
  // ログイン失敗
  header("Location: loginError.html");
} else {
  // ログイン成功
  //セッションにアカウント情報をセット
  $_SESSION["account"] = $account;
  header("Location: loginSuccess.php");
}
registerController.php
<?php
require_once("./accountInsert.php");
require_once("./accountSearch.php");
session_start();


insertAccount($_POST['name'], $_POST['password']);
$account = getAccount($_POST['name'], $_POST['password']);
//セッションにアカウント情報をセット
$_SESSION["account"] = $account; 

if($account === null) {
  header("Location: loginError.html");
}else{
  header("Location: loginSuccess.php");
}

updateController.php
<?php
require_once("./account.php");
require_once("./accountUpdate.php");
require_once("./accountSearch.php");
session_start();

$id = $_SESSION["account"]->idGet();
$name = $_POST["name"];
$password = $_POST["password"];
updateAccount($id, $name, $password);

$account = getAccount($name, $password);
//セッションにアカウント情報をセット
$_SESSION["account"] = $account; 

if($account === null) {
  header("Location: loginError.html");
}else{
  header("Location: loginSuccess.php");
}
deleteController.php
<?php
require_once("./accountDelete.php");
require_once("./account.php");
session_start();

$id = $_SESSION["account"]->idGet();
deleteAccount($id);
header("Location: delete.html");
?>

View

loginSuccess.php
<?php
require_once("./account.php");
session_start();

// セッションID盗聴対策
// ログイン後に新しいセッションIDを生成。セッション情報は保持される。
session_regenerate_id();

print "id:".$_SESSION["account"]->idGet();
print "<br>";
print "氏名:".$_SESSION["account"]->nameGet();
print "<br>";
print "password:".$_SESSION["account"]->passwordGet();
print "<br>";
print "<form method=\"POST\" action=\"login.html\">
        <input type=\"submit\" value=\"ログイン画面へ\">
       </form>";
print "<form method=\"POST\" action=\"sessionDestroy.php\">
       <input type=\"submit\" value=\"ログアウト\">
      </form>";
print "<form method=\"POST\" action=\"update.html\">
        <input type=\"submit\" value=\"アカウント情報変更\">
       </form>";
print "<form method=\"POST\" action=\"deleteController.php\">
       <input type=\"submit\" value=\"アカウント削除\">
      </form>";
login.html
<!DOCTYPE html>
<html lang="ja">
<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>
  <form method="GET" action="searchController.php">
    <p>氏名   <input type="text" name="name"></p>
    <p>パスワード<input type="text" name="password"></p>
    <p><input type="submit" value="ログイン"></p>
  </form>
  <p><a href="register.html">新規登録はこちら</a></p>
</body>
</html>
loginError.html
<!DOCTYPE html>
<html lang="ja">
<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>
  ログインできませんでした。
  <p><a href="login.html">ログイン画面へ</a></p>
  <p><a href="register.html">新規登録はこちら</a></p>
</body>
</html>
register.html
<!DOCTYPE html>
<html lang="ja">
<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>Document</title>
</head>
<body>
  <form method="POST" action="registerController.php">
    <p>氏名   <input type="text" name="name"></p>
    <p>パスワード<input type="text" name="password"></p>
    <p><input type="submit" value="新規登録"></p>
  </form>
</body>
</html>
update.html
<!DOCTYPE html>
<html lang="ja">
<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>
  <form method="POST" action="updateController.php">
    <p>氏名   <input type="text" name="name"></p>
    <p>パスワード<input type="text" name="password"></p>
    <p><input type="submit" value="アカウント情報変更"></p>
  </form>
</body>
</html>

DB構成

image.png

3
7
2

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
3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?