「PHPとデータベース - PDO」の版間の差分

520行目: 520行目:
<br><br>
<br><br>


== プリペアドステートメントおよびストアドプロシージャ ==
== プリペアドステートメント ==
プリペアドステートメントとは、実行するSQLをコンパイルしたテンプレートのようなものである。<br>
プリペアドステートメントとは、実行するSQLをコンパイルしたテンプレートのようなものである。<br>
パラメータ変数を使用することで、SQLをカスタマイズすることができる。<br>
パラメータ変数を使用することで、SQLをカスタマイズすることができる。<br>
529行目: 529行目:
<br>
<br>
プリペアドステートメントは、データベースの種類や機能に関わらず同じ仕組みで データベースへのアクセスができる。<br>
プリペアドステートメントは、データベースの種類や機能に関わらず同じ仕組みで データベースへのアクセスができる。<br>
<br><br>
== レコードの取得(プリペアドステートメント) ==
==== PDOStatement::fetchメソッド ====
カーソルを移動して、指定したフェッチモードで1行ずつ取得する。<br>
* 引数を省略する場合、デフォルトフェッチモードが使用される。
* 全てのレコードを取得した場合、falseを返す。
<br>
<br>
==== Insert (1)====
以下の例では、フェッチモードを<code>PDO::FETCH_ASSOC</code>に設定している。<br>
以下の例では、nameおよびvalueを名前付きプレースホルダで置き換えて、INSERT句を実行する。<br>
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  // 基本的な構文
    $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
while($row = $stmt->fetch())
     $stmt->bindParam(':name', $name);
{
    $stmt->bindParam(':value', $value);
     printf("%s lives in %s<br />\n", $row['name'], $row['city']);
}
   
   
    // 1レコード目の挿入
// vprintf関数を使用する場合
    $name = 'one';
while($row = $stmt->fetch())
     $value = 1;
{
    $stmt->execute();
     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']);
}
   
   
    // パラメータを変更して、2レコード目の挿入
// 0から始まるオフセットを取得することもできる
     $name = 'two';
foreach($stmt as $i => $row)
     $value = 2;
{
    $stmt->execute();
     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>
  </syntaxhighlight>
<br>
<br>
==== Insert (2) ====
==== PDOStatement::fetchAllメソッド ====
以下の例では、nameおよびvalueをプレースホルダ<code>?</code>で置き換えて、INSERT句を実行する。<br>
全てのレコードを取得して2次元配列とする。<br>
* 引数を省略する場合、デフォルトフェッチモードが使用される。
* 特定のカラムのみ全てのレコードを取得して1次元配列とする場合、<br>第1引数に<code>PDO::FETCH_COLUMN</code>を指定して、第2引数に先頭から数えてそのカラムが何番目(0オリジン)にあるかを渡す。(省略する場合、0を指定したとみなされる)
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  $rows = $stmt->fetchAll();
    $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
var_dump($rows);
    $stmt->bindParam(1, $name);
    $stmt->bindParam(2, $value);
   
   
    // 1レコード目の挿入
$values = $stmt->fetchAll(PDO::FETCH_COLUMN);
    $name = 'one';
  var_dump($values);
    $value = 1;
    $stmt->execute();
   
    // パラメータを変更して、2レコード目の挿入
    $name = 'two';
    $value = 2;
    $stmt->execute();
?>
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
==== SELECT ====
以下の例では、フォームで入力したキーの値に応じたデータを取得している。<br>
以下の例では、フォームで入力したキーの値に応じたデータを取得している。<br>
ユーザの入力内容は自動的に引用符で括られるため、SQLインジェクション攻撃の恐れは無い。<br>
ユーザの入力内容は自動的に引用符で括られるため、SQLインジェクション攻撃の恐れは無い。<br>
631行目: 662行目:
また、PDO::ATTR_STRINGIFY_FETCHESオプションをtrueに指定する時、エミュレーションが無効の場合は数値が文字列に変換される。<br>
また、PDO::ATTR_STRINGIFY_FETCHESオプションをtrueに指定する時、エミュレーションが無効の場合は数値が文字列に変換される。<br>
エミュレーションが有効の場合、設定に関わらず常に数値が文字列に変換される。<br>
エミュレーションが有効の場合、設定に関わらず常に数値が文字列に変換される。<br>
<br><br>
== レコードの追加(プリペアドステートメント) ==
以下の例では、nameおよびvalueを<u>名前付きプレースホルダ</u>で置き換えて、INSERT文を実行している。<br>
<syntaxhighlight lang="php">
<?php
    $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
    $stmt->bindParam(':name', $name);
    $stmt->bindParam(':value', $value);
    // 1レコード目の挿入
    $name = 'one';
    $value = 1;
    $stmt->execute();
    // パラメータを変更して、2レコード目の挿入
    $name = 'two';
    $value = 2;
    $stmt->execute();
?>
</syntaxhighlight>
<br>
<br>
以下の例では、nameおよびvalueを<u>プレースホルダ<code>?</code></u>で置き換えて、INSERT文を実行している。<br>
<syntaxhighlight lang="php">
<?php
    $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
    $stmt->bindParam(1, $name);
    $stmt->bindParam(2, $value);
    // 1レコード目の挿入
    $name = 'one';
    $value = 1;
    $stmt->execute();
    // パラメータを変更して、2レコード目の挿入
    $name = 'two';
    $value = 2;
    $stmt->execute();
?>
</syntaxhighlight>
<br><br>


== ストアドプロシージャ ==
==== ストアドプロシージャの呼び出し : 出力パラメータの指定 ====
==== ストアドプロシージャの呼び出し : 出力パラメータの指定 ====
データベースドライバがサポートしている時、入力パラメータだけでなく、出力パラメータもバインドすることが可能である。<br>
データベースドライバがサポートしている時、入力パラメータだけでなく、出力パラメータもバインドすることが可能である。<br>
669行目: 741行目:
  ?>
  ?>
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br><br>
==== プレースホルダの間違った使用例 ====
 
== プレースホルダの間違った使用例 ==
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  <?php