LoginSignup
37
51

More than 1 year has passed since last update.

PDOを用いたPHPのデータベース接続・操作

Last updated at Posted at 2018-08-23

現在、PHPでデータベースに接続する際にはPDOを使う方法が主流だそうです(ドットインストールより)。そこで、PDOの基本的な使い方を確認していこうと思います。

データベースへの接続方法

基本的なフォーマットは次のようになります。

db_connect.php
<?php

define('DB_USERNAME', 'myname');
define('DB_PASSWORD', '12345678');
define('DSN', 'mysql:host=localhost; dbname=testdb; charset=utf8');

function db_connect(){
    $dbh = new PDO(DSN, DB_USERNAME, DB_PASSWORD);
    return $dbh;
}

?>
⚪︎⚪︎⚪︎.php
<?php

...

require_once('db_connect.php');

...

try {
    // データベースに接続
    $dbh = db_connect();

    //例外処理を投げるようにする(throw)
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // データベースから値を取ってきたり、 データを挿入したりする処理 
    $statement = $dbh->query('SELECT * FROM users');      // 例
  
    //データベース接続切断
    $statement = null;
    $dbh = null;

} catch (PDOException $e) {
    header('Content-Type: text/plain; charset=UTF-8', true, 500);
    // エラー内容は本番環境ではログファイルに記録して, Webブラウザには出さないほうが望ましい
    exit($e->getMessage()); 
}

...

?>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Title</title>
    </head>
    <body>
        <!-- DBに関する処理はここでは行わないこと -->
    </body>
</html>

db_connect.phpの
$dbh = new PDO(DSN, DB_USERNAME, DB_PASSWORD);
によりデータベースへの接続が行われます。

DSN

データベースに接続するために必要な情報になります。MySQLの基本的な書き方を例に挙げると、
mysql:dbname=test;host=localhost;charset=utf8mb4
というようになります。dbnameにはデータベース名を、hostにはホスト名またはIPアドレスを、charsetには文字セットを入力します。
: と ; の使い分けに注意しましょう。

DB_USERNAME

データベースのユーザー名です。

DB_PASSWORD

データベースに接続するためのパスワードです。

また、⚪︎⚪︎⚪︎.phpの
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
についてですが、このコードにより、SQL実行でエラーが起こった際に例外をスローしてくれるようになります。決まり文句だと思っても良さそうです。

SQLの実行方法(3パターン)

PDO::exec

結果を返す必要がなく、安全な(ユーザー入力を伴わない)SQLを実行する際に用います。

$dbh->exec('INSERT INTO users (name, age) values ('taguchi', 55)');

PDO::query

安全な(ユーザー入力を伴わない)SQLで、返り値としてPDOStatementオブジェクトが必要な場合に使います。

$statement = $dbh-> query('SELECT * FROM users');

PDO::preparePDOStatement::bindValuePDOStatement::execute

安全対策が必要な(ユーザー入力を伴う)SQLを実行する際に用いる方法です。返り値としてPDOStatementオブジェクトが得られます。

ユーザー入力を受け取ってSQL文を動的に生成する場合は、プリペアドステートメントプレースホルダを用いて、SQLインジェクションの対策を行う必要があります。この際、PDO::ATTR_EMULATE_PREPARESfalseにしておきましょう。

//ユーザが入力した値
$name = $_SESSION['name'];
$age = $_SESSION['age'];
$password_hash =  password_hash($_SESSION['password'], PASSWORD_DEFAULT);

//静的プレースホルダを用いるためにエミュレーションを無効化
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

// プレースホルダを用いたSQL文を生成(プリペアドステートメント)
$statement = $dbh->prepare("INSERT INTO users (name, age, password, date) VALUES (:name, :age, :password_hash, now())");
// プレースホルダへ実際の値を設定する
$statement->bindValue(':name', $name, PDO::PARAM_STR);
$statement->bindValue(':age', $age, PDO::PARAM_INT);
$statement->bindValue(':password_hash', $password_hash, PDO::PARAM_STR);
// プリペアドステートメントを実行
$statement->execute();

SELECT文による結果の取得

まず、以下のようなSELECT文を実行したとします。

$statement = $dbh-> query('SELECT * FROM users');

PDOStatement::fetch

結果セットから1行ずつ、次の行を取得してくれます。全ての取得が終わるとfalseを返します。

while ($user = $statement->fetch()) {
    printf("%s is %d years old.\n", $user['name'], $user['age']);
}

PDOStatement::fetchAll

結果セットを全件取得して、2次元配列にします。

$users = $statement->fetchAll();
for($i = 0; $i < count($users); $i++) {
    printf("%s is %d years old.\n", $user[$i]['name'], $user[$i]['age']);
}

行数の取得

##DELETE, INSERT, UPDATE文 ( [PDOStatement::rowCount] (http://www.php.net/manual/ja/pdostatement.rowcount.php) )

PDOStatement::rowCountを用いると、直近のSQLステートメント(DELETE, INSERT, UPDATE文)によって作用した行数を返してくれます。SELECT文で用いるのは推奨されていないようです。

// Usersテーブルから全ての行を削除する 
$statement = $dbh->query('DELETE FROM users');

// 削除された行数を返す 
$count = $statement->rowCount();
print("Deleted %d rows.\n", $count);

SELECT文

推奨されるのは以下の2通りです。

  • PDOStatement::fetchAll メソッドで結果全件を配列として取得し、それに対してPHPの count 関数を使う。
$statement = $dbh->query('SELECT * FROM users');
// 結果セットを全件取得
$users = $statement->fetchAll();

// 件数をカウント
$count = count($users);
  • SELECT COUNT(*) WHERE ... といったクエリを発行し、その結果を PDOStatement::fetchColumn メソッドで得る。
$statement = $dbh->query("SELECT COUNT(*) FROM users WHERE age > 20");
$count = $statement->fetchColumn();

トランザクション

ある一連の処理が必ず行われることを保証してくれるための仕組みです。基本的には以下のような形で使用します。

define('DB_USERNAME', 'myname');
define('DB_PASSWORD', '12345678');
define('DSN', 'mysql:host=localhost; dbname=testdb; charset=utf8');

try {
  // DB接続
  $db = new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD);
  // 例外処理をスロー
  $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // トランザクション開始
  $db->beginTransaction();
  // 一連で行いたい処理
  $db->exec("update users set score = score - 10 where name = 'taguchi'");
  $db->exec("update users set score = score + 10 where name = 'suzuki'");
  // トランザクションをコミット
  $db->commit();

} catch (PDOException $e) {
  // トランザクションをロールバック
  $db->rollback();
  echo $e->getMessage();
  exit;
}

トランザクション処理において用いるメソッドは、主に以下の3つです。

  • PDO::beginTransaction
    • トランザクションを開始する
  • PDO::commit
    • この時点(一連の処理が全てうまくいった時点)で、一連の処理を初めて結果に反映させる
  • PDO::rollBack
    • 一連の処理のどこかで失敗した場合に、データを元に戻してトランザクション開始前の状態にする

以上でこの記事を終了します。
間違い等ございましたら、コメントで教えていただけると幸いです。

37
51
0

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
37
51