📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の18版が非表示)
133行目: 133行目:


== データベースの接続 ==
== データベースの接続 ==
==== 接続文字列 ====
PDOクラスのインスタンスを作成することにより、接続が確立される。<br>
PDOクラスのインスタンスを作成することにより、接続が確立される。<br>
コンストラクタには、データソース(DSN)、ユーザ名、パスワードを指定する。<br>
コンストラクタには、データソース(DSN)、ユーザ名、パスワードを指定する。<br>
156行目: 157行目:
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  $<PDOクラスのインスタンス名> = new PDO(<データソース名>, <データベースユーザ名>, <パスワード>, <ドライバオプション>);
  $<PDOクラスのインスタンス名> = new PDO(<データソース名>, <データベースユーザ名>, <パスワード>, <ドライバオプション>);
PDO PDO::__construct ( string dsn
                        [, string username
                        [, string password
                        [, array driver_options]]] )
指定されたデータベースへの接続を表すPDOインスタンスを生成します。
引数:
  dsn
    データソース名(Data Source Name)またはDSN。データベースに接続するために必要な情報が含まれる。
  username
    DSN文字列のユーザ名。このパラメータは、いくつかのPDOドライバではオプションである。
  password
    パスワード。
    DSN文字列で必要とされる場合に指定。
  driver_options
    ドライバ固有の接続オプションを指定するキー=> 値の配列
戻り値:
  成功時にPDOオブジェクトを返す。
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
196行目: 221行目:
*: 値は予め用意されている定数以外に、論理値や文字列等の一般的な値でもよい。
*: 値は予め用意されている定数以外に、論理値や文字列等の一般的な値でもよい。
<br>
<br>
以下に、よく使用されるドライバオプションとその値を示す。<br>
==== ドライバオプション ====
ドライバオプションとその値を以下に示す。<br>
<br>
<syntaxhighlight lang="php">
// ドライバオプションの使用例
$options = [
    // エラー発生時に例外をスロー
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    // フェッチモードをデフォルトで連想配列に設定
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    // プリペアドステートメントを有効化
    PDO::ATTR_EMULATE_PREPARES => false,
    // 持続的な接続を無効化
    PDO::ATTR_PERSISTENT => false,
    // カラム名を小文字に変換
    PDO::ATTR_CASE => PDO::CASE_LOWER
];
$db = new PDO(
    'mysql:host=localhost;dbname=sampledb;charset=utf8mb4',
    'root',
    'root',
    $options
);
</syntaxhighlight>
<br>
* PDO::ATTR_ERRMODE
* PDO::ATTR_ERRMODE
*: クエリの実行でエラーが起こった場合、どのように処理をするかを指定する。
*: エラーレポートの方法を設定するための属性である。
*: クエリの実行でエラーが起きた場合、どのように処理をするかを指定する。
*: 初期値は、<code>PDO::ERRMODE_SILENT</code>である。
*: 初期値は、<code>PDO::ERRMODE_SILENT</code>である。
** PDO::ERRMODE_EXCEPTION
** PDO::ERRMODE_EXCEPTION
**: 例外をスローする。
**: エラーが発生した時に例外 (PDOException例外クラス) をスローする。
**: エラーを例外としてキャッチできるようになり、デバッグが容易になる。
** PDO::ERRMODE_WARNING
** PDO::ERRMODE_WARNING
**: クエリの実行Lで発生したエラーをPHPのWarningとして報告する。
**: クエリの実行Lで発生したエラーをPHPのWarningとして報告する。
210行目: 267行目:
*: <br>
*: <br>
* PDO::ATTR_DEFAULT_FETCH_MODE
* PDO::ATTR_DEFAULT_FETCH_MODE
*: <code>PDOStatement::fetch</code>メソッドや<code>PDOStatement::fetchAll</code>メソッドで引数が省略された場合、または、
*: SELECT結果を連想配列で取得できる。
*: ステートメントが<code>foreach</code>文に直接かけられた場合のフェッチスタイルを設定する。
*: キーがカラム名になるため、データアクセスが直観的になる。
*: <br>
*: <code>PDOStatement::fetch</code>メソッドや<code>PDOStatement::fetchAll</code>メソッドで引数が省略された場合、
*: または、ステートメントが<code>foreach</code>文に直接かけられた場合のフェッチスタイルを設定する。
*: 初期値は、<code>PDO::FETCH_BOTH</code>である。
*: 初期値は、<code>PDO::FETCH_BOTH</code>である。
** PDO::FETCH_BOTH
** PDO::FETCH_BOTH
225行目: 285行目:
*: データベース側が持つプリペアドステートメント機能のエミュレーションをPDO側で行うかどうかを設定する。
*: データベース側が持つプリペアドステートメント機能のエミュレーションをPDO側で行うかどうかを設定する。
*: PHP 5.2以降の初期値は<code>true</code>である。
*: PHP 5.2以降の初期値は<code>true</code>である。
*: <br>
*: <code>false</code>の場合、ネイティブのプリペアドステートメントを使用する。
*: これは、SQLインジェクション対策として有効であり、また、クエリのパフォーマンスが向上する。
*: <br>
*: この設定は、いくつかPDOの挙動に違いが現れる。
*: この設定は、いくつかPDOの挙動に違いが現れる。
** プリペアドステートメントのためにデータベースと通信する必要が無くなるため、エミュレーションを行う方がパフォーマンスは向上する。
*: エミュレーションを行う場合、プリペアドステートメントのためにデータベースと通信する必要が無くなるため、パフォーマンスは向上する。
** 存在しないテーブル名やカラム名をクエリに持つプリペアドステートメントを発行する場合、<br>エミュレーションを行わない場合はすぐにエラーが発生するが、エミュレーションを行う場合はクエリを実行するまでエラーが発生するかどうかわからない。
*: 存在しないテーブル名 / カラム名をクエリに持つプリペアドステートメントを発行する場合、
*: エミュレーションを行わない場合は即エラーが発生するが、エミュレーションを行う場合はクエリを実行するまでエラーが発生するかどうかわからない。
** エミュレーションを行う場合のみ、<code>;</code>(セミコロン)区切りで複数のクエリを1つのクエリで実行することができる。
** エミュレーションを行う場合のみ、<code>;</code>(セミコロン)区切りで複数のクエリを1つのクエリで実行することができる。
*: <br>
*: <br>
* PDO::ATTR_PERSISTENT(コンストラクタでの指定のみ)
* PDO::ATTR_PERSISTENT (コンストラクタでの指定のみ)
*: <code>true</code>の場合、PHPスクリプトが終了してもデータベースへの接続を維持して、次回に再利用する。
*: <code>true</code>の場合、PHPスクリプトが終了してもデータベースへの接続を維持して、次回に再利用する。
*: 特に、大規模システムでは恩恵が大きい。
*: 特に、大規模システムでは恩恵が大きい。
*: <br>
*: <code>false</code>の場合は、持続的な接続を無効化する。
*: メモリ管理の観点から、通常は無効にすることを推奨する。
*: <br>
*: <br>
* PDO::MYSQL_ATTR_USE_BUFFERED_QUERY(MySQL専用)
* PDO::MYSQL_ATTR_USE_BUFFERED_QUERY(MySQL専用)
247行目: 315行目:
* PDO::MYSQL_ATTR_INIT_COMMAND(MySQL専用、コンストラクタでの指定のみ)
* PDO::MYSQL_ATTR_INIT_COMMAND(MySQL専用、コンストラクタでの指定のみ)
*: データベースに接続した直後に実行されるクエリをここに記述する。
*: データベースに接続した直後に実行されるクエリをここに記述する。
*: <br>
* PDO::ATTR_CASE
*: <code>PDO::CASE_LOWER</code>を指定する場合、カラム名を小文字に統一する。
*: そのため、一貫性のあるコーディングが可能になる。
<br>
<br>
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
257行目: 329行目:
                         PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                         PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                         PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                         PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                        PDO::ATTR_EMULATE_PREPARES => false,
                       ]);
                       ]);
   
   
264行目: 337行目:
       //                  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
       //                  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
       //                  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
       //                  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
      //                  PDO::ATTR_EMULATE_PREPARES => false,
       //              ]);
       //              ]);
       //$dbh->exec("SET NAMES utf8mb4");
       //$dbh->exec("SET NAMES utf8mb4");
276行目: 350行目:
     {
     {
       // エラーが発生した場合、"500 Internal Server Error"を表示して終了する
       // エラーが発生した場合、"500 Internal Server Error"を表示して終了する
       // もし、エラー画面を表示する場合、HTMLの表示を継続する
       // もし、任意のエラー画面を表示する場合、HTMLの表示を継続する
       // ここではエラー内容を表示しているが、実際の商用環境ではログファイルに記録してWebブラウザには表示しない方が望ましい
       // ここではエラー内容を表示しているが、実際の商用環境ではログファイルに記録してWebブラウザには表示しない方が望ましい
       header('Content-Type: text/plain; charset=UTF-8', true, 500);
       header('Content-Type: text/plain; charset=UTF-8', true, 500);
304行目: 378行目:
<u>データベースに接続できない場合等は、Warningが発生する。</u><br>
<u>データベースに接続できない場合等は、Warningが発生する。</u><br>
<u>もし、データベースを動的に指定する場合、<code>set_error_handler</code>関数を使用して<code>ErrorException</code>に変換した後、例外処理を行う。</u><br>
<u>もし、データベースを動的に指定する場合、<code>set_error_handler</code>関数を使用して<code>ErrorException</code>に変換した後、例外処理を行う。</u><br>
<br>
==== 文字コードの設定 ====
<u>PDOでMySQLに接続する場合は、文字コードの設定 (例: charset=utf8mb4) を指定することを強く推奨する。</u><br>
<br>
もし、明示的に指定しない場合、MySQLのデフォルト設定に依存することになり、環境によって動作が異なる可能性がある。<br>
そのため、確実な文字エンコーディングの制御のために、charsetを明示的に指定することを推奨する。<br>
<br>
* 絵文字や特殊文字のサポート
*: utf8mb4は絵文字やその他の4バイト文字を完全にサポートする。
*: 通常のutf8では絵文字などが正しく保存できない可能性がある。
*: <br>
* 文字化け防止
*: 日本語を含む多言語対応において、文字化けを防ぐことができる。
*: データベースとアプリケーション間で一貫した文字エンコーディングを保証する。
*: <br>
* 将来の互換性
*: 現代のWebアプリケーションでは、utf8mb4が事実上の標準となっている。
*: 後々データベースに絵文字等を格納する可能性を考慮すると、最初から設定しておくのが無難である。
<br>
<syntaxhighlight lang="php">
// 使用例
$db = new PDO('mysql:host=<IPアドレスまたはホスト名>;dbname=<データベース名>;charset=utf8mb4', '<ユーザ名>', '<パスワード>');
</syntaxhighlight>
<br><br>
<br><br>


333行目: 432行目:
データベースの接続は、PHPスクリプトが終了しても閉じられずにキャッシュされ、他のPHPスクリプトが同じ内容の接続を要求する時に再利用される。<br>
データベースの接続は、PHPスクリプトが終了しても閉じられずにキャッシュされ、他のPHPスクリプトが同じ内容の接続を要求する時に再利用される。<br>
このキャッシュにより、新しい接続を確立するオーバーヘッドを避けることができるため、Webアプリケーションを高速化できるようになる。<br>
このキャッシュにより、新しい接続を確立するオーバーヘッドを避けることができるため、Webアプリケーションを高速化できるようになる。<br>
<br>
もし、明示的に閉じる場合、作成したPDOクラスのオブジェクトにNULLを代入する。<br>
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  <?php
     $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass,
     try
                  [
                      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
                  ]);
   
    foreach($dbh->query('SELECT * from FOO') as $row)
     {
     {
       print_r($row);
       $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass,
     }  
                      [
                        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
                      ]);
      foreach($dbh->query('SELECT * from FOO') as $row)
      {
          print_r($row);
      }   
    }
    catch (PDOException $e)
    {
      print('Connection failed:'.$e->getMessage());
      die();
     }
   
   
     // データベースの切断
     // データベースの切断
    $sth = null;
     $dbh = null;
     $dbh = null;
  ?>
  ?>
370行目: 478行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
==== PDO::executeメソッド ====
==== PDO::executeメソッド(3ステップ) ====
<code>PDO::prepare</code>メソッド → <code>PDOStatement::bindValue</code>メソッド → <code>PDOStatement::execute</code>メソッドの3ステップでクエリを実行する。<br>
<code>PDO::prepare</code>メソッド → <code>PDOStatement::bindValue</code>メソッド → <code>PDOStatement::execute</code>メソッドの3ステップでクエリを実行する。<br>
ユーザ入力からクエリを動的に作成する場合、プリペアドステートメントとプレースホルダを使用する。<br>
ユーザ入力からクエリを動的に作成する場合、プリペアドステートメントとプレースホルダを使用する。<br>
427行目: 535行目:
<code>PDOStatement::bindParam</code>メソッドを使用する必要はない。<br>
<code>PDOStatement::bindParam</code>メソッドを使用する必要はない。<br>
エミュレーションが有効の場合、実行後にバインドした変数が文字列型に変換する仕様もあるので、注意すること。<br>
エミュレーションが有効の場合、実行後にバインドした変数が文字列型に変換する仕様もあるので、注意すること。<br>
<br>
==== PDO::executeメソッド(2ステップ) ====
<code>PDO::prepare</code>メソッド → <code>PDOStatement::execute</code>メソッドの2ステップでクエリを実行する。<br>
<code>PDOStatement::execute</code>メソッドの引数に配列を渡す場合、それらを全てバインドした後そのままクエリが実行される。<br>
<br>
ただし、以下の条件に注意すること。<br>
<u>NULL値以外は全て<code>PDO::PARAM_STR</code>扱いになる。</u><br>
もし、間違った型でバインドする場合はMySQL / SQLiteはデータベース側で自動的にキャストし直すが、<br>
パフォーマンスの低下やバグの原因になるため、可能な限り避けること。(PostgreSQLの場合はエラーになる)<br>
<br>
また、既に<code>PDOStatement::bindValue</code>メソッドで値がバインドされている場合でも、それらは全て無視される。<br>
これを用いる場合、全てのバインドをこの引数で行わなければならない。<br>
<br>
* 疑問符プレースホルダ
*: <code>PDOStatement::bindValue</code>メソッドとは異なり、<code>?</code>のインデックスは0から始まる。
<syntaxhighlight lang="php">
$stmt = $pdo->prepare('SELECT * FROM users WHERE city = ? AND gender = ?');
$stmt->execute([$city, $gender]);
// キーを設定して順番を変えて指定することもできる
$stmt->execute([1 => $gender, 0 => $city]);
</syntaxhighlight>
<br>
* 名前付きプレースホルダ
<syntaxhighlight lang="php">
$stmt = $pdo->prepare('SELECT * FROM users WHERE city = :city AND gender = :gender');
$stmt->execute([':city' => $city, ':gender' => $gender]);
// 先頭のコロンは省略できる
$stmt->execute(['city' => $city, 'gender' => $gender]);
// compact関数を使用する場合
$stmt->execute(compact('city', 'gender'));
</syntaxhighlight>
<br><br>
<br><br>


462行目: 606行目:
       $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
       $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   
   
      // トランザクション開始
       $dbh->beginTransaction();
       $dbh->beginTransaction();
      // SQLクエリの実行
       $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
       $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
       $dbh->exec("insert into salarychange (id, amount, changedate) values (23, 50000, NOW())");
       $dbh->exec("insert into salarychange (id, amount, changedate) values (23, 50000, NOW())");
      // 正常に実行できた場合はコミット
       $dbh->commit();
       $dbh->commit();
     }
     }
     catch(Exception $e)
     catch(Exception $e)
     {
     {
       $dbh->rollBack();
       // エラーが発生した場合はロールバック
      if ($dbh->inTransaction()) {
          $dbh->rollBack();
      }
       echo "失敗しました。" . $e->getMessage();
       echo "失敗しました。" . $e->getMessage();
     }
     }
484行目: 636行目:
<br><br>
<br><br>


== プリペアドステートメントおよびストアドプロシージャ ==
== プリペアドステートメント ==
プリペアドステートメントとは、実行するSQLをコンパイルしたテンプレートのようなものである。<br>
プリペアドステートメントとは、実行するSQLをコンパイルしたテンプレートのようなものである。<br>
パラメータ変数を使用することで、SQLをカスタマイズすることができる。<br>
パラメータ変数を使用することで、SQLをカスタマイズすることができる。<br>
493行目: 645行目:
<br>
<br>
プリペアドステートメントは、データベースの種類や機能に関わらず同じ仕組みで データベースへのアクセスができる。<br>
プリペアドステートメントは、データベースの種類や機能に関わらず同じ仕組みで データベースへのアクセスができる。<br>
<br><br>
== プリペアドステートメントの種類 ==
==== bindValueメソッド (値渡し) ====
* メリット
*: バインドした後に元の変数が変更されても影響を受けない。
*: 直接リテラル値をバインドできる。
*: メモリ効率が良い。 (参照を保持しない)
* デメリット
*: ループ内で変数を変更して再実行する場合は、その都度、bindValueメソッドが必要となる。
<br>
<br>
==== Insert (1)====
<syntaxhighlight lang="php">
以下の例では、nameおよびvalueを名前付きプレースホルダで置き換えて、INSERT句を実行する。<br>
$value = 100;
$stmt->bindValue(1, $value, PDO::PARAM_INT);
$value = 200;      // この変更はSQLに影響しない
$stmt->execute();  // 100 が使用される
</syntaxhighlight>
<br>
==== bindParamメソッド (参照渡し) ====
* メリット
*: 変数の参照を保持するので、値を変更して再実行が容易
*: ストアドプロシージャのOUTパラメータで使用可能
* デメリット
*: リテラル値を直接バインドできない。
*: メモリを若干多く使用する。 (参照を保持するため)
<br>
<syntaxhighlight lang="php">
$value = 100;
$stmt->bindParam(1, $value, PDO::PARAM_INT);
$value = 200;      // この変更がSQLに反映される
$stmt->execute();  // 200 が使用される
</syntaxhighlight>
<br>
==== executeメソッドで直接記述 ====
* メリット
*: コードが簡潔
*: 1回のみ使用する場合は効率的
*: <br>
* デメリット
*: 変数の値を後から変更して再実行する場合は、その都度配列を作る必要がある。
*: 参照渡しができない。
<br>
<syntaxhighlight lang="php">
$stmt = $pdo->prepare("UPDATE student SET id = ?, name = ?, grade = ? WHERE id = ?");
$stmt->execute([$id, $name, $grade, $old_id]);  // シンプル!
## 1回限りのクエリの場合、executeメソッド
$stmt->execute([$id, $name, $grade]);
</syntaxhighlight>
<br>
==== 使い分け ====
<syntaxhighlight lang="php">
# 使い分け
## 一般的なケースでは、bindValueメソッドを使用
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bindValue(1, $id, PDO::PARAM_INT);
$stmt->execute();
## 以下に示す場合は、bindParamメソッドを使用
## ループ内で値を変更しながら実行する場合
## ループ内で変数を変更しながら再実行する場合
## ストアドプロシージャのOUTパラメータを使用する場合
## 特別な理由で参照渡しが必要な場合
$stmt = $pdo->prepare("INSERT INTO logs (user_id, action) VALUES (?, ?)");
$stmt->bindParam(1, $user_id, PDO::PARAM_INT);
$stmt->bindParam(2, $action, PDO::PARAM_STR);
foreach($actions as $action) {
    $stmt->execute();  // $actionの値が自動的に使用される
}
</syntaxhighlight>
<br>
<u>セキュリティが重要な場合は、型を明示的に指定できるbindValueメソッド、または、bindParamメソッドを使用する。</u><br>
<br>
<u>※注意</u><br>
<u>ただし、実務では一貫性を保つため、特別な理由がない限りどちらか一方に統一することが推奨される。</u><br>
<br><br>
 
== レコードの取得(プリペアドステートメント) ==
<center>
{| class="wikitable" style="background-color:#fefefe;"
|-
! style="background-color:#00ffff;" | MySQL
! style="background-color:#00ffff;" | PHPのデータ型<br>(エミュレーション無しmysqlnd)
! style="background-color:#00ffff;" | PHPのデータ型(libmysqlclient)<br>(エミュレーション有りmysqlnd)
|-
| NULL || NULL || NULL
|-
| 文字列 || String || String
|-
| 日付 || String || String
|-
| タイムスタンプ || Integer || String
|-
| 論理値 || Integer || String
|-
| PHPで扱える値の整数 || Integer || String
|-
| PHPで扱えない値の整数 || String || String
|-
| 浮動小数点 || String || String
|}
</center>
<u>※注意</u><br>
<u>エミュレーションに関するオプションは、PDO::ATTR_EMULATE_PREPARESという命名ではあるが、</u><br>
<u>プリペアドステートメントを使用しない場合にも影響が及ぶことに注意すること。</u><br>
<br>
下表に、<code>PDO::setAttribute</code>で取得するデータ型を変更できるものを示す。<br>
<code>PDO::ATTR_ORACLE_NULLS</code>オプションは、Oracle以外のデータベースでも使用できる。<br>
<center>
{| class="wikitable" style="background-color:#fefefe;"
|-
! style="background-color:#00ffff;" | データベース
! style="background-color:#00ffff;" | PDO::NULL_EMPTY_STRING
! style="background-color:#00ffff;" | PDO::NULL_TO_STRING
|-
| NULL || NULL || ""
|-
| "" || NULL || ""
|}
</center>
<br>
また、PDO::ATTR_STRINGIFY_FETCHESオプションをtrueに指定する時、エミュレーションが無効の場合は数値が文字列に変換される。<br>
エミュレーションが有効の場合、設定に関わらず常に数値が文字列に変換される。<br>
<br>
==== PDOStatement::fetchメソッド ====
カーソルを移動して、指定したフェッチモードで1行ずつ取得する。<br>
* 引数を省略する場合、デフォルトフェッチモードが使用される。
* 全てのレコードを取得した場合、falseを返す。
<br>
以下の例では、フェッチモードを<code>PDO::FETCH_ASSOC</code>に設定している。<br>
<syntaxhighlight lang="php">
// 基本的な構文
while($row = $stmt->fetch())
{
    printf("%s lives in %s<br />\n", $row['name'], $row['city']);
}
// vprintf関数を使用する場合
while($row = $stmt->fetch())
{
    vprintf("%s lives in %s<br />\n", $row);
}
</syntaxhighlight>
<br>
デフォルトフェッチモードの場合、<code>PDOStatement</code>クラスは<code>Traversable</code>インターフェースを実装しているため、foreach文で記述することができる。<br>
ただし、HTMLのための変数を用意する場合、配列として持つ方が都合が良いため、<code>PDOStatement::fetchAll</code>メソッドの使用することを推奨する。<br>
<syntaxhighlight lang="php">
foreach($stmt as $row)
{
    printf("%s lives in %s<br />\n", $row['name'], $row['city']);
}
// 0から始まるオフセットを取得することもできる
foreach($stmt as $i => $row)
{
    printf("[%d] %s lives in %s<br />\n", $i, $row['name'], $row['city']);
}
</syntaxhighlight>
<br>
==== PDOStatement::fetchObjectメソッド ====
連想配列の代わりにクラスオブジェクトを取得する。<br>
これは、<code>PDO::FETCH_OBJ</code>を指定して<code>PDOStatement::fetch</code>メソッドを使用する場合と同じであるが、こちらの方が簡潔に記述できる。<br>
<syntaxhighlight lang="php">
while($row = $stmt->fetchObject())
{
    printf("%s lives in %s<br />\n", $row->name, $row->city);
}
</syntaxhighlight>
<br>
==== PDOStatement::fetchColumnメソッド ====
特定の1カラムのみを文字列として取得する。<br>
これは、<code>PDO::FETCH_COLUMN</code>を指定して<code>PDOStatement::fetch</code>メソッドを使用する場合と同じでるが、こちらの方が簡潔に記述できる。<br>
<br>
先頭から数えてそのカラムが何番目(0オリジン)にあるかを第1引数として渡す。(省略する場合、0を指定したとみなされる)<br>
カラムの値に0が含まれる可能性がある場合は、<code>false !==</code>の判定をしなければならない。<br>
<syntaxhighlight lang="php">
while(false !== $value = $stmt->fetchColumn())
{
    echo "{$value}<br />\n";
}
</syntaxhighlight>
<br>
==== PDOStatement::fetchAllメソッド ====
全てのレコードを取得して2次元配列とする。<br>
* 引数を省略する場合、デフォルトフェッチモードが使用される。
* 特定のカラムのみ全てのレコードを取得して1次元配列とする場合、<br>第1引数に<code>PDO::FETCH_COLUMN</code>を指定して、第2引数に先頭から数えてそのカラムが何番目(0オリジン)にあるかを渡す。(省略する場合、0を指定したとみなされる)
<syntaxhighlight lang="php">
$rows = $stmt->fetchAll();
var_dump($rows);
$values = $stmt->fetchAll(PDO::FETCH_COLUMN);
var_dump($values);
</syntaxhighlight>
<br>
==== PDOStatement::setFetchModeメソッド ====
上記のセクションでは、<code>PDO</code>クラス自身にデフォルトフェッチモードを指定する方法を記載したが、<br>
<code>PDOStatement::setFetchMode</code>メソッドを使用する場合、個別に発行された<code>PDOStatement</code>クラスに対して、後からフェッチモードを指定できる。<br>
また、モードにより引数の渡し方が異なるため、詳細はPHPのマニュアルを参照すること。<br>
<br>
以下の例では、0番目のカラムをforeach文で取得している。<br>
<syntaxhighlight lang="php">
$stmt->setFetchMode(PDO::FETCH_COLUMN, 0);
foreach($stmt as $i => $name)
{
    // ...処理
}
</syntaxhighlight>
<br>
また、<code>PDO::query</code>メソッドも同様の形式でフェッチモードを指定することができる。<br>
以下の例では、上記の例と同様、0番目のカラムをforeach文で取得している。<br>
<syntaxhighlight lang="php">
foreach($pdo->query($sql, PDO::FETCH_COLUMN, 0) as $i => $name)
{
    // ...処理
}
</syntaxhighlight>
<br>
==== SQLインジェクション攻撃の対策 ====
以下の例では、フォームで入力したキーの値に応じたデータを取得している。<br>
ユーザの入力内容は自動的に引用符で括られるため、SQLインジェクション攻撃の恐れは無い。<br>
<syntaxhighlight lang="php">
<?php
    $stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
    if($stmt->execute(array($_GET['name'])))
    {
      while($row = $stmt->fetch())
      {
          print_r($row);
      }
    }
?>
</syntaxhighlight>
<br><br>
 
== レコードの追加(プリペアドステートメント) ==
以下の例では、nameおよびvalueを<u>名前付きプレースホルダ</u>で置き換えて、INSERT文を実行している。<br>
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  <?php
514行目: 902行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
==== Insert (2) ====
以下の例では、nameおよびvalueを<u>プレースホルダ<code>?</code></u>で置き換えて、INSERT文を実行している。<br>
以下の例では、nameおよびvalueをプレースホルダ<code>?</code>で置き換えて、INSERT句を実行する。<br>
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  <?php
530行目: 917行目:
     $name = 'two';
     $name = 'two';
     $value = 2;
     $value = 2;
    $stmt->execute();
?>
</syntaxhighlight>
<br><br>
== レコードの更新(プリペアドステートメント) ==
以下の例では、name、value、idを<u>名前付きプレースホルダ</u>で置き換えて、UPDATE文を実行している。<br>
<syntaxhighlight lang="php">
<?php
    $stmt = $dbh->prepare("UPDATE REGISTRY SET name = :name value = :value WHERE id = :id");
    $stmt->bindParam(':name', $name);
    $stmt->bindParam(':value', $value);
    $stmt->bindParam(':id', $id);
    // レコード目の更新
    $name = 'one';
    $value = 1;
     $stmt->execute();
     $stmt->execute();
  ?>
  ?>
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
==== SELECT ====
以下の例では、name、value、idを<u>プレースホルダ<code>?</code></u>で置き換えて、UPDATE文を実行している。<br>
以下の例では、フォームで入力したキーの値に応じたデータを取得している。<br>
ユーザの入力内容は自動的に引用符で括られるため、SQLインジェクション攻撃の恐れは無い。<br>
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  <?php
     $stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
     $stmt = $dbh->prepare("UPDATE REGISTRY SET name = ? value = ? WHERE id = ?");
     if($stmt->execute(array($_GET['name'])))
     $stmt->bindParam(1, $name);
     {
     $stmt->bindParam(2, $value);
      while($row = $stmt->fetch())
    $stmt->bindParam(3, $id);
      {
          print_r($row);
    // レコードの更新
      }
    $name = 'one';
     }
    $value = 1;
     $stmt->execute();
  ?>
  ?>
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br><br>
<center>
{| class="wikitable" style="background-color:#fefefe;"
|-
! style="background-color:#00ffff;" | MySQL
! style="background-color:#00ffff;" | PHPのデータ型<br>(エミュレーション無しmysqlnd)
! style="background-color:#00ffff;" | PHPのデータ型(libmysqlclient)<br>(エミュレーション有りmysqlnd)
|-
| NULL || NULL || NULL
|-
| 文字列 || String || String
|-
| 日付 || String || String
|-
| タイムスタンプ || Integer || String
|-
| 論理値 || Integer || String
|-
| PHPで扱える値の整数 || Integer || String
|-
| PHPで扱えない値の整数 || String || String
|-
| 浮動小数点 || String || String
|}
</center>
<u>※注意</u><br>
<u>エミュレーションに関するオプションは、PDO::ATTR_EMULATE_PREPARESという命名ではあるが、</u><br>
<u>プリペアドステートメントを使用しない場合にも影響が及ぶことに注意すること。</u><br>
<br>


== ストアドプロシージャ ==
==== ストアドプロシージャの呼び出し : 出力パラメータの指定 ====
==== ストアドプロシージャの呼び出し : 出力パラメータの指定 ====
データベースドライバがサポートしている時、入力パラメータだけでなく、出力パラメータもバインドすることが可能である。<br>
データベースドライバがサポートしている時、入力パラメータだけでなく、出力パラメータもバインドすることが可能である。<br>
615行目: 991行目:
  ?>
  ?>
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br><br>
==== プレースホルダの間違った使用例 ====
 
== プレースホルダの間違った使用例 ==
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  <?php
628行目: 1,005行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:Web]]
[[カテゴリ:Web]][[カテゴリ:MySQL]]