There is another function which is not listed here.. for debugging
PDOStatement:::debugDumpParams() which will return a string with with the sql query and the bound param's.
PDO 関数
導入
PHP Data Objects (PDO) 拡張モジュールは、 PHP の中からデータベースにアクセスするための軽量で高性能な インターフェイスを定義します。 PDO インターフェイスを実装する各データベースドライバは、 正規表現関数のようなデータベース固有の機能を提供することができます。 PDO 拡張モジュールによりそのデータベースの全てのデータベース関数を 実行できるわけではないことに注意してください。 データベースサーバにアクセスするには、 データベース固有の PDO ドライバ を使用する必要があります。
PDO は、データアクセスの抽象化レイヤを提供します。 つまり、使用しているデータベースが何であるかにかかわらず、同じ 関数を使用してクエリの発行やデータの取得が行えるということです。 PDO は、データベースの抽象化を行うのでは ありません。つまり、SQL を書き直したり 存在しない機能をエミュレートしたりはしないということです。 もしそのような機能が必要なら、全体を網羅する (full-blown) 別の抽象化レイヤを使用すべきです。
PDO は PHP 5.1 以降にバンドルされており、PHP 5.0 では PECL 拡張モジュールとして使用可能です。PDO は PHP 5 の新機能である オブジェクト指向機能を使用しており、それより前のバージョンの PHP では動作しません。
インストール手順
-
PHP 5.1 を動作させているのならば、PDO および PDO_SQLITE はその配布物の中に含まれています。configure を実行した際に PDO は自動的に有効になります。 PDO は、共有モジュールとしてビルドすることを推奨します。 なぜなら、PECL からアップデート版を導入する際にそのほうが有利だからです。 PHP を PDO サポート込みでビルドする際の推奨設定は、 zlib サポートを有効にする (pecl インストーラを使用するため) ことです。 また、あなたが選択したデータベースについての PDO ドライバを有効にする必要もあります。 詳細についてはデータベース固有の PDO ドライバ を参照ください。PDO を共有モジュールとしてビルドした場合は、 PDO ドライバも共有モジュールとしてビルドする必要があることに注意しましょう。 SQLite 拡張モジュールは PDO に依存しています。そのため、PDO を共有モジュールとしてビルドした場合には SQLite も同じようにビルドしなければなりません。
./configure --with-zlib --enable-pdo=shared --with-pdo-sqlite=shared --with-sqlite=shared
-
PDO を共有モジュールとしてインストールした後は、PHP の実行時に PDO 拡張モジュールが自動的に読み込まれるよう、php.ini ファイルを編集する必要があります。 また同様に、データベース固有のドライバについてもここで有効にする必要があります。 この設定は pdo.so の行より後で記述するようにしましょう。なぜなら、 データベース固有のドライバが読み込まれるためには、それ以前に PDO が初期化されていなければならないからです。 PDO およびデータベース固有のドライバを静的にビルドしたのならば、 この設定は不要です。
extension=pdo.so
-
PDO を共有モジュールとしてビルドすると、新しいバージョンの PDO が公開された際に pecl upgrade pdo コマンドで更新することができるようになります。 その際に PHP 自体を再ビルドする必要はありません。注意すべき点として、 PDO をこの方法で更新した際はデータベース固有のドライバも同時に更新するようにしてください。
-
PDO は、 » http://pecl.php.net/package/pdo から PECL 拡張モジュールとして使用可能です。 pecl ツールを使用してインストールを行います。 このツールは、PHP の configure 時に自動的に使用可能になります。 pecl が圧縮されたパッケージを取り扱えるよう、 PHP が --with-zlib を含めて confiure されていることを 確認しておきましょう。
-
以下のコマンドにより、最新の安定版の PDO をダウンロードしてビルドを行い、そしてインストールします。
pecl install pdo
-
pecl コマンドは、PDO モジュールを自動的に PHP のエクステンションディレクトリにインストールします。 Linux や Unix 上で PDO を有効にするには、以下の行を php.ini に追加する必要があります。
extension=pdo.so
PECL パッケージのビルド方法についてのより詳細な情報は、マニュアルの PECL 拡張モジュールのインストール を参照ください。
-
PDO および主要データベースのドライバは、共有モジュールとして PHP に同梱されています。これを使用するには、単に php.ini ファイルを編集するだけです。
extension=php_pdo.dll
-
次に、その他のデータベース固有の DLL ファイルを選択します。 実行時に dl() によりロードするか、または、 php.ini の php_pdo.dll の下で有効にしてください。 例えば、以下のようになります。
extension=php_pdo.dll extension=php_pdo_firebird.dll extension=php_pdo_informix.dll extension=php_pdo_mssql.dll extension=php_pdo_mysql.dll extension=php_pdo_oci.dll extension=php_pdo_oci8.dll extension=php_pdo_odbc.dll extension=php_pdo_pgsql.dll extension=php_pdo_sqlite.dll
これらの DLL は、システムの extension_dir で指定した場所に存在する必要があります。 PDO_INFORMIX は PECL 拡張モジュールにのみ存在することに注意しましょう。
実行時設定
php.ini の設定により動作が変化します。
| 名前 | デフォルト | 変更の可否 | 変更履歴 |
|---|---|---|---|
| pdo.dsn.* | php.ini only |
以下に設定ディレクティブに関する 簡単な説明を示します。
- pdo.dsn.* string
-
DSN の別名を定義します。完全な説明については PDO->__construct() を参照ください。
PDO ドライバ
以下のドライバが現在 PDO インターフェイスを実装しています。
| ドライバ名 | サポートされるデータベース |
|---|---|
| PDO_DBLIB | FreeTDS / Microsoft SQL Server / Sybase |
| PDO_FIREBIRD | Firebird/Interbase 6 |
| PDO_IBM | IBM DB2 |
| PDO_INFORMIX | IBM Informix Dynamic Server |
| PDO_MYSQL | MySQL 3.x/4.x/5.x |
| PDO_OCI | Oracle Call Interface |
| PDO_ODBC | ODBC v3 (IBM DB2、unixODBC そして win32 ODBC) |
| PDO_PGSQL | PostgreSQL |
| PDO_SQLITE | SQLite 3 と SQLite 2 |
接続、および接続の管理
PDO 基底クラスのインスタンスを作成することにより、接続が確立されます。 どのドライバを使用するのかにかかわらず、常に PDO クラスを指定します。 コンストラクタに渡す引数により、データソース (いわゆる DSN) の指定や (もしあれば、オプションで) ユーザ名およびパスワードの指定を行います。
Example#1 MySQL への接続
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
?>
接続時になんらかのエラーが発生した場合、PDOException オブジェクトがスローされます。エラー処理を行いたい場合はこの例外を キャッチします。あるいはこれを無視して、 set_exception_handler() で設定した グローバル例外ハンドラに処理を任せることもできます。
Example#2 接続エラーの処理
<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
foreach ($dbh->query('SELECT * from FOO') as $row) {
print_r($row);
}
$dbh = null;
} catch (PDOException $e) {
print "エラー!: " . $e->getMessage() . "<br/>";
die();
}
?>
PDO コンストラクタからの例外をアプリケーション内でキャッチしない場合、 zend エンジンはスクリプトの実行を終了し、バックトレースを表示します。 このバックトレースを見れば、データベースへの接続の詳細がわかってしまいます。 その中にはユーザ名やパスワードも含まれます。 (catch 文を使用して) 明示的に例外をキャッチするか、 あるいは set_exception_handler() を使用して 暗黙的に例外をキャッチするようにしましょう。
データベースへの接続に成功すると、PDO クラスのインスタンスが スクリプトに返されます。この PDO オブジェクトが存在する間、 接続がアクティブであり続けます。接続を閉じるには、他から 参照されていないことを保障することでオブジェクトを破棄する 必要があります。それには、オブジェクトを保持している変数に対して NULL を代入します。 明示的にこれを行わなかった場合は、スクリプトの終了時に自動的に 接続が閉じられます。
Example#3 接続を閉じる
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
// ここで接続を使用します
// 使用を終了したので、閉じます
$dbh = null;
?>
データベースサーバへの持続的な接続による恩恵をこうむる web アプリケーションは多いでしょう。持続的な接続は、スクリプトが 終了しても閉じられずにキャッシュされ、他のスクリプトが同じ内容の 接続を要求してきた際にそれが再利用されます。持続的接続の キャッシュにより、スクリプトがデータベースを使用するたびに 新しい接続を確立するオーバーヘッドを避けることができます。 それにより、結果として web アプリケーションを高速化できるように なります。
Example#4 持続的な接続
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
PDO::ATTR_PERSISTENT => true
));
?>
注意: 持続的な接続を使用したい場合は、ドライバのオプションを表す配列に PDO::ATTR_PERSISTENT を設定して PDO のコンストラクタに渡す必要があります。この属性を PDO->setAttribute() を用いてインスタンス作成後に設定した場合は、 そのドライバは持続的な接続を使用しません。
注意: PDO ODBC ドライバを使用しており、ODBC ライブラリが ODBC 接続プーリングをサポートしている場合 (unixODBC および Windows はこれをサポートしています。他にもあるかもしれません) は、 PDO の持続的接続を使用せずに ODBC の接続プーリングに 接続キャッシュ処理を任せることを推奨します。 ODBC の接続プールは、プロセス内で他のモジュールと共有されています。 PDO が接続をキャッシュしてしまうと、その接続は ODBC の 接続プールに返されなくなり、他のモジュールによって新たな接続が 作成されてしまうようになります。
トランザクションおよび自動コミット
さあ、PDO を使用してデータベースに接続することができました。 クエリを発行する前に、PDO がトランザクションをどのように扱うのかを 理解しなければなりません。トランザクションについてよくわからない方の ために説明すると、これは以下の 4 つの機能、つまり 原子性 - Atomicity、一貫性 - Consistency、独立性 - Isolation および 永続性 - Durability (ACID) を提供するものです。 一般的な言葉で言うと、トランザクション内で実行された作業は たとえ段階的に行われたものであってもデータベースに安全に反映される ことが保証されています。トランザクションのコミット時に他の接続の 干渉を受けることはありません。また、トランザクション内での作業は (まだコミットされていなければ) いつでも自動的に取り消すことが できます。これにより、スクリプト内でのエラー処理がより楽になります。
トランザクションの一般的な実装は、変更内容を一時的に「蓄えて」おき、 それを一気に適用するようになっています。この実装には、更新処理の 性能を劇的に向上させるという効果もあります。つまり、 トランザクションによってあなたの書くスクリプトはより高速になり、 またより堅牢になるということです (これらの恩恵をうけるためには、トランザクションを正しく使用する 必要があります)。
残念ながら、すべてのデータベースがトランザクションをサポートしていると いうわけではありません。そのため、PDO で最初に接続をオープンした際には、 いわゆる「自動コミット」モードで動作します。自動コミットモードとは、 もしデータベースがトランザクションをサポートしていたら個々のクエリが 暗黙的なトランザクションのもとで実行され、サポートしていなかったら トランザクションを使用せずに実行されることを意味します。 トランザクションを使用する場合は、 PDO->beginTransaction() メソッドを使用して トランザクションを初期化する必要があります。使用しているドライバが トランザクションをサポートしていない場合は PDOException が スローされます (これは深刻な状態であるため、エラー処理の設定に かかわらず常にスローされます)。初期化した後でトランザクションを 終了させるには、トランザクション内でのコードが成功したか否かに応じて PDO->commit() あるいは PDO->rollBack() を使用します。
スクリプトが終了したり接続が閉じられようとした際に、もし処理が 完了していないトランザクションがあれば PDO が自動的に ロールバックします。これは、スクリプトが予期せぬ状態で終了した場合に データの不整合が発生するのを避けるための安全装置です。もし 明示的にコミットしていなければ、おそらく何かおかしなことが 起こったのだろうと推測されます。そのため、データを守るために ロールバックが行われるのです。
自動的にロールバックが行われるのは、トランザクションを PDO->beginTransaction() で開始した場合のみです。 トランザクションを開始するクエリを手動で発行した場合、 PDO はそれを知ることができません。そのため、何か問題が発生しても ロールバックすることはできないのです。
Example#5 トランザクション内で一括処理を行う
以下の例では、新しい従業員のデータを作成しているものとします。 この従業員には ID 番号 23 を割り当てます。この人物についての 基礎データを入力するだけでなく、その給与についても登録する 必要があります。以下では単純に 2 つの別々の更新を行っていますが、 それらは PDO->beginTransaction() および PDO->commit() のコールで囲まれています。 これにより、変更が完了するまでは他からは一切変更内容が 見えないことが保証されます。もし何か問題が発生すれば、 catch ブロック内でトランザクション開始以降のすべての変更が ロールバックされます。そしてエラーメッセージを表示します。
<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(PDO::ATTR_PERSISTENT => true));
echo "接続しました\n";
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();
$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->commit();
} catch (Exception $e) {
$dbh->rollBack();
echo "失敗しました。" . $e->getMessage();
}
?>
トランザクション内で行える処理は、更新には限りません。たとえば 何か複雑なクエリを発行してデータを抽出し、その情報をもとに データの更新をしたり別のクエリを実行したりすることも可能です。 トランザクションがアクティブな間は、作業中のデータについては 他から一切変更が加えられないことが保証されます。 実際のところこの説明は 100% 正確というわけではありませんが、 もしあなたがいままでトランザクションのことを知らなかったのであれば このように理解しておけば十分でしょう。
プリペアドステートメントおよびストアドプロシージャ
より成熟したデータベースの多くは、プリペアドステートメントという 概念をサポートしています。プリペアドステートメントとはいったい何の ことでしょう? これは、実行したい SQL をコンパイルした 一種のテンプレートのようなものです。パラメータ変数を使用することで SQL をカスタマイズすることが可能です。プリペアドステートメントには 2 つの大きな利点があります。
- クエリのパース (あるいは準備) が必要なのは最初の一回だけで、 同じパラメータ (あるいは別のパラメータ) を指定して何度でも クエリを実行することができます。クエリを実行するには、準備として クエリの解析やコンパイル、そして実行プランの最適化が行われます。 クエリが複雑になると、この処理には時間がかかるようになります。 同じクエリを異なったパラメータで何度も実行すると、アプリケーションの 動作は目に見えて遅くなるでしょう。 プリペアドステートメントを使用すると、この 解析/コンパイル/最適化 の繰り返しを避けることができます。 端的に言うと、プリペアドステートメントは使用するリソースが少なくいため 高速に動作するということです。
- プリペアドステートメントに渡すパラメータは、引用符で括る必要は ありません。それはドライバが自動的に行います。 アプリケーションで明示的にプリペアドステートメントを使用するように すれば、SQL インジェクションは決して発生しません (しかし、もし信頼できない入力をもとにクエリの他の部分を構築している のならば、その部分に対するリスクを負うことになります)。
プリペアドステートメントは非常に有用な機能なので、もしドライバが サポートしていなくても、例外的に PDO がこの機能をエミュレートします。 これにより、データベースの機能にかかわらず同じ仕組みで データベースへのアクセスができることが保証されます。
Example#6 プリペアドステートメントを使用して、繰り返し挿入処理を行う
この例は、name および value を名前つきプレースホルダで置き換えて INSERT クエリを実行します。
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// 行を挿入します
$name = 'one';
$value = 1;
$stmt->execute();
// パラメータを変更し、別の行を挿入します
$name = 'two';
$value = 2;
$stmt->execute();
?>
Example#7 プリペアドステートメントを使用して、繰り返し挿入処理を行う
この例は、name および value をプレースホルダ ? で置き換えて INSERT クエリを実行します。
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
// 行を挿入します
$name = 'one';
$value = 1;
$stmt->execute();
// パラメータを変更し、別の行を挿入します
$name = 'two';
$value = 2;
$stmt->execute();
?>
Example#8 プリペアドステートメントを使用してデータを取得する
この例では、フォームで入力したキーの値に応じたデータを取得します。 ユーザの入力内容は自動的に引用符で括られるので、SQL インジェクション攻撃の 恐れはありません。
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
?>
データベースドライバがサポートしていれば、入力パラメータだけでなく 出力パラメータもバインドすることが可能です。出力パラメータは、 一般にストアドプロシージャから値を受け取るために使用します。この場合、 返される値の大きさがどの程度になるのかをバインド時に知っておく必要が あります。指定した大きさよりも大きな値が返されると、エラーが発生します。
Example#9 出力パラメータを指定してストアドプロシージャをコールする
<?php
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// ストアドプロシージャをコールします
$stmt->execute();
print "プロシージャが返した値は $return_value です\n";
?>
入出力の両方に使用するパラメータを指定することもできます。 このパラメータの書式は、出力パラメータと同じです。 次の例では、ストアドプロシージャに文字列 'hello' を渡しています。 プロシージャの結果が返ってくると、 この文字列はプロシージャの返す値に置き換えられます。
Example#10 入出力パラメータを指定してストアドプロシージャをコールする
<?php
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// ストアドプロシージャをコールします
$stmt->execute();
print "プロシージャが返した値は $value です\n";
?>
Example#11 プレースホルダの間違った使用法
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));
// プレースホルダは、値全体に対して使用しなければなりません
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>
エラーおよびエラー処理
PDO が提供するエラー処理方法は 3 通り存在し、 アプリケーションの開発形態によって使い分けることができます。
-
PDO::ERRMODE_SILENT
デフォルトのモードです。ステートメントおよびデータベースオブジェクトの エラーについて、PDO は単にそのエラーコードのみを設定します。 これを取得するには PDO->errorCode() および PDO->errorInfo() メソッドを使用します。 ステートメントオブジェクトへのコールによってエラーが発生した場合は、 そのオブジェクトの PDOStatement->errorCode() あるいは PDO->errorInfo() メソッドを呼び出します。 データベースオブジェクトへのコールによってエラーが発生した場合は、 その代わりにデータベースオブジェクト上の同じメソッドを呼び出します。
-
PDO::ERRMODE_WARNING
エラーコードを設定することに加え、PDO は 伝統的な E_WARNING メッセージも出力します。この設定はデバッグ/テストの際に有用で、 アプリケーションの動作を妨げることなしに問題点を確認できるように なります。
-
PDO::ERRMODE_EXCEPTION
エラーコードを設定することに加え、PDO は PDOException をスローします。エラーコードや 関連情報が、クラスのプロパティとして設定されます。 この設定もまたデバッグ時に有用で、エラーが発生した時点で スクリプトの実行を停止させることによりコード内の問題点を 見つけやすくなります (例外によりスクリプトが終了した際には、トランザクションは自動的に ロールバックされることを覚えておきましょう)。
このモードが有用である理由のひとつとして、伝統的な PHP 形式の警告よりも より明確にエラー処理コードが書けることがあります。例外を発生させず、 データベースへのコールのたびに毎回明示的に返り値をチェックすることに 比べると、コードの量やネストを減らすことができます。
PHP の例外についての詳細な情報は、 例外 を参照ください。
PDO のエラーコードは、SQL-92 の SQLSTATE エラーコード文字列に 標準化されています。 ネイティブのコードを適切な SQLSTATE コードに変換するのは、個々の PDO ドライバの仕事となります。 PDO->errorCode() メソッドは SQLSTATE コードを返します。 エラーについての詳細な銃尾法が知りたい場合、PDO では PDO->errorInfo() メソッドも提供しており、 これは SQLSTATE コード、ドライバ固有のエラーコードおよびドライバ固有の エラーメッセージを含む配列を返します。
ラージオブジェクト (LOB)
アプリケーション内で、データベースに「大きな」データを格納する 必要を感じることがあるかもしれません。「大きな」とは、一般的には 「4kb 程度以上」を指しますが、データベースによっては 32kb くらいまでは 「大きい」と判断されずにすむこともあります。ラージオブジェクトは テキストあるいはバイナリの両方の形式をとり得ます。 PDO でこのラージデータ型を扱うには、 PDOStatement->bindParam() や PDOStatement->bindColumn() のコール時に 型コードとして PDO::PARAM_LOB を使用します。 PDO::PARAM_LOB を指定すると、PDO は データをストリームにマップします。これにより、 PHP ストリーム API を使用してデータを扱えるようになります。
Example#12 データベース内の画像を表示する
この例では $lob という名前の変数に LOB をバインドし、 fpassthru() を使用してそれをブラウザに送信します LOB はストリームで表されるので、 fgets()、fread() および stream_get_contents() といった関数を 使用することができます。
<?php
$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
$stmt = $db->prepare("select contenttype, imagedata from images where id=?");
$stmt->execute(array($_GET['id']));
$stmt->bindColumn(1, $type, PDO::PARAM_STR, 256);
$stmt->bindColumn(2, $lob, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);
header("Content-Type: $type");
fpassthru($lob);
?>
Example#13 画像をデータベースに挿入する
この例では、ファイルをオープンしてそのハンドルを PDO に渡し、 LOB としてデータベースに挿入します。PDO は、データベースに応じた もっとも適切な方法でデータを取得します。
<?php
$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
$stmt = $db->prepare("insert into images (id, contenttype, imagedata) values (?, ?, ?)");
$id = get_new_id(); // 新しい ID を割り当てるための何らかの関数
// フォームからファイルをアップロードしていると仮定します。
// 詳細な情報は PHP のドキュメントを参照ください。
$fp = fopen($_FILES['file']['tmp_name'], 'rb');
$stmt->bindParam(1, $id);
$stmt->bindParam(2, $_FILES['file']['type']);
$stmt->bindParam(3, $fp, PDO::PARAM_LOB);
$db->beginTransaction();
$stmt->execute();
$db->commit();
?>
Example#14 画像をデータベースに挿入する: Oracle
Oracle は、ファイルから LOB を挿入する方法が他とは少し違います。 また、必ずトランザクション内で挿入しなければなりません。 それ以外の場合、新しく挿入された LOB は長さゼロとなり、クエリの 実行時に暗黙的にコミットされます。
<?php
$db = new PDO('oci:', 'scott', 'tiger');
$stmt = $db->prepare("insert into images (id, contenttype, imagedata) " .
"VALUES (?, ?, EMPTY_BLOB()) RETURNING imagedata INTO ?");
$id = get_new_id(); // 新しい ID を割り当てるための何らかの関数
// フォームからファイルをアップロードしていると仮定します。
// 詳細な情報は PHP のドキュメントを参照ください。
$fp = fopen($_FILES['file']['tmp_name'], 'rb');
$stmt->bindParam(1, $id);
$stmt->bindParam(2, $_FILES['file']['type']);
$stmt->bindParam(3, $fp, PDO::PARAM_LOB);
$stmt->beginTransaction();
$stmt->execute();
$stmt->commit();
?>
定義済みクラス
PDO
PHP とデータベースサーバの間の接続を表します。
コンストラクタ
-
PDO - PDO オブジェクトのコンストラクタ
メソッド
-
beginTransaction - トランザクションを開始する
-
commit - トランザクションを コミットする
-
errorCode - エラーが発生した場合に、データベースからエラーコードを取得する
-
errorInfo - エラーが発生した場合に、データベースからエラー情報の配列を取得する
-
exec - SQL ステートメントを 発行し、作用された行の数を返す
-
getAttribute - データベース接続属性を取得する
-
lastInsertId - テーブルに挿入された直近の行の値を取得する
-
prepare - SQL ステートメントを実行するために準備する
-
rollBack - トランザクションをロールバックする
-
setAttribute - データベース接続属性を設定する
PDOStatement
プリペアドステートメントを表します。ステートメント実行後は関連する結果セットを 表します。
メソッド
-
bindColumn - PHP 変数を結果セットの出力カラムにバインドする
-
bindParam - プリペアドステートメントのパラメータに PHP 変数をバインドする
-
bindValue - プリペアドステートメントのパラメータに値をバインドする
-
closeCursor - カーソルを閉じてステートメントを再実行できるようにする
-
columnCount - 結果セットのカラム数を返す
-
errorCode - エラーが発生した場合、ステートメントからエラーコードを取得する
-
errorInfo - エラーが発生した場合、ステートメントからエラー情報の配列を取得する
-
execute - プリペアドステートメントを実行する
-
fetch - 結果セットから行を取得する
-
fetchAll - 結果セットからすべての行を含む配列を返す
-
fetchColumn 結果セットの単一カラムからデータを返す
-
getAttribute - PDOStatement 属性を取得する
-
getColumnMeta - 結果セットのカラムのメタデータを取得する
-
nextRowset - 次の行セット (結果セット) を取得する
-
rowCount - SQL ステートメントの実行により作用された行の数を返す
-
setAttribute - PDOStatement 属性を設定する
-
setFetchMode - PDOStatement の取得モードを設定する
PDOException
PDO が発するエラーを表します。あなた自身が書いたコードから PDOException をスローしてはいけません。 PHP の例外についての詳細な情報は、 例外 を参照ください。
Example#15 PDOException クラス
<?php
class PDOException extends Exception
{
public $errorInfo = null; // PDO::errorInfo()
// あるいは PDOStatement::errorInfo() に対応します。
protected $message; // テキストのエラーメッセージ。
// Exception::getMessage() を使用してアクセスします。
protected $code; // SQLSTATE エラーコード。
// Exception::getCode() を使用してアクセスします。
}
?>
定義済み定数
以下の定数が定義されています。 この関数の拡張モジュールが PHP 組み込みでコンパイルされているか、 実行時に動的にロードされている場合のみ使用可能です。
PHP 5.1 以降、PDO はクラス定数を使用します。 それ以前のリリースでは、PDO_PARAM_BOOL の形式のグローバル変数を使用します。
- PDO::PARAM_BOOL (integer)
- ブールデータ型を表します。
- PDO::PARAM_NULL (integer)
- SQL NULL データ型を表します。
- PDO::PARAM_INT (integer)
- SQL INTEGER データ型を表します。
- PDO::PARAM_STR (integer)
- SQL CHAR, VARCHAR, または他の文字列データ型を表します。
- PDO::PARAM_LOB (integer)
- SQL ラージオブジェクト型を表します。
- PDO::PARAM_STMT (integer)
- PDO::PARAM_INPUT_OUTPUT (integer)
- パラメータがストアドプロシージャ用の入力パラメータであることを指定します。 この値は、PDO::PARAM_* データ型とのビットORとして指定する必要があります。
- PDO::FETCH_LAZY (integer)
- 取得する方法として、 結果セットが返すカラム名と同じ名前の変数を有するオブジェクトとして各行を返す方法を 指定します。 PDO::FETCH_LAZY は、アクセスされたものと同じ名前のオブジェクト変数を作成します。
- PDO::FETCH_ASSOC (integer)
- 結果セットの対応するカラム名にふられているものと同じキーを付けた 連想配列として各行を返す取得方法を指定します。 もし結果セットが複数のカラムを同名で含む場合、 PDO::FETCH_ASSOC はカラム名毎に 1 つの値のみ返します。
- PDO::FETCH_NAMED (integer)
- 結果セットの対応するカラム名にふられているものと同じキーを付けた 連想配列として各行を返す取得方法を指定します。 もし結果セットが複数のカラムを同名で含む場合、 PDO::FETCH_NAMED はカラム名毎に値の配列を返します。
- PDO::FETCH_NUM (integer)
- 結果セットの対応するカラム番号にふられているものと同じ添字を付けた 配列として各行を返す取得方法を指定します。番号は0から始まります。
- PDO::FETCH_BOTH (integer)
- 結果セットと同じカラム名と0から始まるカラム番号を付けた配列として各行を返す 方法を指定します。
- PDO::FETCH_OBJ (integer)
- 結果セットが返すカラム名と同じ名前のプロパティを有する オブジェクトとして各行を返す方法を指定します。
- PDO::FETCH_BOUND (integer)
- 結果セットのカラムの値を PDOStatement::bindParam() または PDOStatement::bindColumn() メソッドでバインドされた PHP変数に代入し、TRUEを返すという取得方法を指定します。
- PDO::FETCH_COLUMN (integer)
- 結果セットの次の行から指定された一つのカラムのみを返す取得方法を指定します。
- PDO::FETCH_CLASS (integer)
- カラムをクラスのプロパティにマップしつつ、 指定されたクラスの新規インスタンスを返す取得方法を指定します。
- PDO::FETCH_INTO (integer)
- カラムをクラスのプロパティにマップしつつ、 指定されたクラスの既存のインスタンスを更新する取得方法を指定します。
- PDO::FETCH_FUNC (integer)
- PDO::FETCH_GROUP (integer)
- PDO::FETCH_UNIQUE (integer)
- PDO::FETCH_KEY_PAIR (integer)
- 最初のカラムの値をキー、それ以降のカラムの内容を値として持つ連想配列形式でデータを取得します。
- PDO::FETCH_CLASSTYPE (integer)
- PDO::FETCH_SERIALIZE (integer)
- PDO::FETCH_INTO と同様ですが、 シリアライズした文字列としてオブジェクトを提供します。 PHP 5.1.0 以降で使用可能です。
- PDO::FETCH_PROPS_LATE (integer)
- PHP 5.2.0 以降で使用可能です。
- PDO::ATTR_AUTOCOMMIT (integer)
- この値が FALSE の場合、PDO は接続がトランザクションを開始できるように オートコミットを無効にしようとします。
- PDO::ATTR_PREFETCH (integer)
- 独自アプリケーションにおけるメモリ使用量に対する速度のバランスを 調整するためのプリフェッチサイズを設定します。 全てのデータベースとドライバの組み合わせでプリフェッチサイズの設定を サポートしているわけではありません。
- PDO::ATTR_TIMEOUT (integer)
- データベースとの通信に対するタイムアウト値を秒で設定します。
- PDO::ATTR_ERRMODE (integer)
- PDO::ATTR_SERVER_VERSION (integer)
- PDO::ATTR_CLIENT_VERSION (integer)
- PDO::ATTR_SERVER_INFO (integer)
- PDO::ATTR_CONNECTION_STATUS (integer)
- PDO::ATTR_CASE (integer)
- PDO::CASE_* 定数で指定されたケースにカラム名を変更します。
- PDO::ATTR_CURSOR_NAME (integer)
- PDO::ATTR_CURSOR (integer)
- PDO::ATTR_DRIVER_NAME (string)
- ドライバ名を返します。
- PDO::ATTR_ORACLE_NULLS (integer)
- 空文字を SQL の NULL 値に変換します。
- PDO::ATTR_PERSISTENT (integer)
- 新規接続を生成するよりもむしろ持続的接続を要求します。
- PDO::ATTR_STATEMENT_CLASS (integer)
- PDO::ATTR_FETCH_CATALOG_NAMES (integer)
- 結果セット中の各カラム名にカタログ名を追加します。 カタログ名とカラム名は、小数点 (.) で区切られます。
- PDO::ATTR_FETCH_TABLE_NAMES (integer)
- 結果セット中の各カラム名にテーブル名を追加します。 テーブル名とカラム名は、小数点 (.) で区切られます。
- PDO::ATTR_STRINGIFY_FETCHES (integer)
- PDO::ATTR_MAX_COLUMN_LEN (integer)
- PDO::ATTR_DEFAULT_FETCH_MODE (integer)
- PHP 5.2.0 以降で使用可能です。
- PDO::ATTR_EMULATE_PREPARES (integer)
- PHP 5.1.3 以降で使用可能です。
- PDO::ERRMODE_SILENT (integer)
- エラー時にエラーもしくは例外を発生しません。 開発者の方は明示的にエラーをチェックするようにしてください。 これはデフォルトのモードです。
- PDO::ERRMODE_WARNING (integer)
- エラーが発生した場合、PHP の E_WARNING メッセージを発行します。
- PDO::ERRMODE_EXCEPTION (integer)
- エラーが発生した場合、PDOException を投げます。
- PDO::CASE_NATURAL (integer)
- カラム名をデータベースドライバにより返されたままにします。
- PDO::CASE_LOWER (integer)
- カラム名を小文字にします。
- PDO::CASE_UPPER (integer)
- カラム名を大文字にします。
- PDO::NULL_NATURAL (integer)
- PDO::NULL_EMPTY_STRING (integer)
- PDO::NULL_TO_STRING (integer)
- PDO::FETCH_ORI_NEXT (integer)
- 結果セットの次の行を取得します。スクローラブルなカーソルでのみ有効です。
- PDO::FETCH_ORI_PRIOR (integer)
- 結果セットの前の行を取得します。スクローラブルなカーソルでのみ有効です。
- PDO::FETCH_ORI_FIRST (integer)
- 結果セットの先頭の行を取得します。スクローラブルなカーソルでのみ有効です。
- PDO::FETCH_ORI_LAST (integer)
- 結果セットの最後の行を取得します。スクローラブルなカーソルでのみ有効です。
- PDO::FETCH_ORI_ABS (integer)
- 結果セットから行番号で指定した行を取得します。スクローラブルなカーソルでのみ有効です。
- PDO::FETCH_ORI_REL (integer)
- 結果セットのカーソルの現在の位置を基準とする相対位置により指定された行を 取得します。スクローラブルなカーソルでのみ有効です。
- PDO::CURSOR_FWDONLY (integer)
- 前進のみ可能なカーソルを有するPDOStatementオブジェクトを生成します。 これにより、アプリケーションの性能は改善しますが、 PDOStatementオブジェクトは前方にある結果セットから一度に一行を 取得するという制約を受けます。
- PDO::CURSOR_SCROLL (integer)
- スクローラブルカーソルを有するPDOStatementオブジェクトを作成しあす。 結果セットから取得した行を制御するためのPDO::FETCH_ORI_*定数を指定して ください。
- PDO::ERR_CANT_MAP (integer)
- PDO::ERR_SYNTAX (integer)
- PDO::ERR_CONSTRAINT (integer)
- PDO::ERR_NOT_FOUND (integer)
- PDO::ERR_ALREADY_EXISTS (integer)
- PDO::ERR_NOT_IMPLEMENTED (integer)
- PDO::ERR_MISMATCH (integer)
- PDO::ERR_TRUNCATED (integer)
- PDO::ERR_DISCONNECTED (integer)
- PDO::ERR_NO_PERM (integer)
- PDO::ERR_NONE (string)
- SQLSTATE '00000' は SQL ステートメントがエラーや警告がなく発行に成功したことを意味します。 この定数はエラーが発生したかどうかを判別するために PDO::errorCode() もしくは PDOStatement::errorCode() をチェックする際に 便利です。この場合、通常はエラー状態を発生したメソッドからの戻りコードを 検査することによって検知します。
- PDO::PARAM_EVT_ALLOC (integer)
- 割り当てられたときに発生するイベント。
- PDO::PARAM_EVT_FREE (integer)
- 割り当てが解除されたときに発生するイベント。
- PDO::PARAM_EVT_EXEC_PRE (integer)
- プリペアドステートメントの実行前に発生するイベント。
- PDO::PARAM_EVT_EXEC_POST (integer)
- プリペアドステートメントの実行後に発生するイベント。
- PDO::PARAM_EVT_FETCH_PRE (integer)
- 結果セットから結果を取得する前に発生するイベント。
- PDO::PARAM_EVT_FETCH_POST (integer)
- 結果セットから結果を取得した後に発生するイベント。
- PDO::PARAM_EVT_NORMALIZE (integer)
- バインドパラメータの登録時に発生するイベント。 これにより、ドライバがパラメータ名を正規化できるようになります。
目次
- PDO->beginTransaction() — トランザクションを開始する
- PDO->commit() — トランザクションをコミットする
- PDO->__construct() — データベースへの接続を表す PDO インスタンスを生成する
- PDO->errorCode() — データベースハンドラにおける直近の操作に関連する SQLSTATE を取得する
- PDO->errorInfo() — データベースハンドラにおける直近の操作に関連する拡張エラー情報を取得する
- PDO->exec() — SQL ステートメントを実行し、作用した行数を返す
- PDO->getAttribute() — データベース接続の属性を取得する
- PDO->getAvailableDrivers() — 利用可能な PDO ドライバの配列を返す
- PDO->lastInsertId() — 最後に挿入された行の ID あるいはシーケンスの値を返す
- PDO->prepare() — 文を実行する準備を行い、文オブジェクトを返す
- PDO->query() — SQL ステートメントを実行し、結果セットを PDOStatement オブジェクトとして返す
- PDO->quote() — クエリ用の文字列をクオートする
- PDO->rollBack() — トランザクションをロールバックする
- PDO->setAttribute() — 属性を設定する
- PDOStatement->bindColumn() — カラムを PHP 変数にバインドする
- PDOStatement->bindParam() — 指定された変数名にパラメータをバインドする
- PDOStatement->bindValue() — 値をパラメータにバインドする
- PDOStatement->closeCursor() — カーソルを閉じてステートメントを再実行できるようにする
- PDOStatement->columnCount() — 結果セット中のカラム数を返す
- PDOStatement->errorCode() — 文ハンドラにおける直近の操作に関連する SQLSTATE を取得する
- PDOStatement->errorInfo() — 文ハンドラにおける直近の操作に関連する拡張エラー情報を取得する
- PDOStatement->execute() — プリペアドステートメントを実行する
- PDOStatement->fetch() — 結果セットから次の行を取得する
- PDOStatement->fetchAll() — 全ての結果行を含む配列を返す
- PDOStatement->fetchColumn() — 結果セットの次行から単一カラムを返す
- PDOStatement->fetchObject() — 次の行を取得し、それをオブジェクトとして返す
- PDOStatement->getAttribute() — 文の属性を取得する
- PDOStatement->getColumnMeta() — 結果セットのカラムに対するメタデータを返す
- PDOStatement->nextRowset() — 複数の行セットを返す文ハンドラで次の行セットに移動する
- PDOStatement->rowCount() — 直近の SQL ステートメントによって作用した行数を返す
- PDOStatement->setAttribute() — 文の属性を設定する
- PDOStatement->setFetchMode() — この文に対するデフォルトのフェッチモードを設定する
PDO
29-Jan-2008 10:47
31-Dec-2007 05:57
Be careful with PDO extends : if you use the smileaf's example, PDO will close the connection only at the end of the script, because of the "array( $this )" parameter used with the setAttribute() method.
Instead, I use only this :
$this->setAttribute( PDO::ATTR_STATEMENT_CLASS, array( $this->statementClassName, array() ) );
And in prepare() and query() method you can populate the "dbh" if you really need it.
10-Dec-2007 09:29
If you will make a OBJ row from PDO you can use this eg.
$resKampange = $dbc->prepare( "SELECT * FROM Table LIMIT 1" );
$resKampange->execute();
$rowKampange = $resKampange->fetch( PDO::FETCH_OB );
echo $rowKampange->felt1;
Good lock :0)
03-Dec-2007 07:08
There is a book titled "Learning PHP Data Objects" written by Dennis Popel and published by Packt. There is a post with further links (ordering, reviews) at author's blog: http://www.onphp5.com/article/58
14-Nov-2007 09:24
When using persistent connections, pay attention not to leave the database connection in some kind of locked state. This can happen when you start a transaction by hand (i.e. not through the PDO->beginTransaction() method), possibly even acquire some locks (e.g. with "SELECT ... FOR UPDATE", "LOCK TABLES ..." or in SQLite with "BEGIN EXCLUSIVE TRANSACTION") and then your PHP script ends with a fatal error, unhandled exception or under other circumstances that lead to an unclean exit.
To use that database again, it may then be necessary to disable the persistence attribute to get a new database connection or restart the web server. (Persistent connections should not work with a PHP-CGI anyway.) It does not work (tested with PHP 5.2.3/WinXP and SQLite) to close a persistent database connection - it will not actually be closed but instead returned to PDO's connection pool.
The only thing you can do to resolve the lock as a regular user (I imagine) is to try and get all of your persistent connections in a single script and unlock the tables resp. end the transactions with the appropriate SQL statements ("UNLOCK TABLES" in MySQL, "ROLLBACK" for transactions). Should they fail, there is no problem, but one or some of them might succeed and thereby resolve your locking problem.
05-Nov-2007 08:52
I have seen a lot of user struggling with calling mysql procedures with in/out/inout parameters using bindParam. There seems to be a bug or missing feature within the mysql C api. This at least I could find out after reading a lot of posts at different places...
At the moment I workaround it like below. $con is a PDO object:
<?php
//in
$proc = $con->prepare( "call proc_in( @i_param )" );
$con->query( "set @i_param = 'myValue'" );
$proc->execute();
//out
$proc = $con->prepare( "call proc_out( @o_param )" );
$proc->execute();
$o_param = $con->query( "select @o_param" )->fetchColumn();
//inout
$proc = $con->prepare( "call proc_inout( @io_param )" );
$con->query( "set @io_param = 'myValue'" );
$proc->execute();
$io_param = $con->query( "select @io_param" )->fetchColumn();
?>
17-Oct-2007 12:34
Example 5:
<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(PDO::ATTR_PERSISTENT => true));
.......
} catch (Exception $e) {
$dbh->rollBack();
echo "Failed: " . $e->getMessage();
}
?>
We must change the last two lines to catch the error connecting to the database:
} catch (Exception $e) {
echo "Failed: " . $e->getMessage();
$dbh->rollBack();
}
?>
03-Sep-2007 04:12
Not all PDO drivers return a LOB as a file stream; mysql 5 is one example. Therefore when streaming a mime typed object from the database you cannot use fpassthru.
The following is a modified example that works with a mysql database. (Tested FreeBSD v 6.2 with mysql 5.0.45 and php 5.2.3)
<?php
ob_start();
$db = new PDO('mysql:host=localhost;dbname=<SOMEDB>', '<USERNAME>', 'PASSWORD');
$stmt = $db->prepare("select contenttype, imagedata from images where id=?");
$stmt->execute(array($_GET['id']));
$stmt->bindColumn(1, $type, PDO::PARAM_STR, 256);
$stmt->bindColumn(2, $lob, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);
ob_clean();
header("Content-Type: $type");
echo $lob; // fpassthru reports an error that $lob is not a stream so echo is used in place.
ob_end_flush();
?>
Please note the inclusion of buffer control. I only needed this when using 'include','include_once','require', or 'require_once' - my feeling is there is a subtle issue with those options as even an empty include file caused a buffer issue for me. === AND YES, I DID CHECK MY INCLUDE FILES DID NOT HAVE SPURIOUS WHITESPACE ETC OUTSIDE THE <?php ?> DELIMITERS! ===
25-May-2007 09:38
From Oracle example:
<?
$stmt->beginTransaction();
$stmt->execute();
$stmt->commit();
?>
PDOStatement has no beginTransaction(), nor commit(). Please fix documentation.
23-May-2007 11:57
It seems MySQL doesn't support scrollable cursors. So unfortunately PDO::CURSOR_SCROLL wont work.
17-Apr-2007 10:46
I just discovered that PDOStatement implements Traversable. That means you can use it in foreach loops to iterate over rows:
<?php
$pdo = new PDO('mysql:dbname=test');
$sth = $pdo->query('SELECT data FROM t1');
foreach($sth as $row) {
echo $row['data'], "\n";
}
?>
12-Mar-2007 10:04
Note this:
Won't work:
$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE ? < ?');
THIS WORKS!
$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < ?');
Parameters cannot be applied on column names!!
02-Mar-2007 03:57
If you intend on extending PDOStatement and your using
setAttribute(PDO::ATTR_STATEMENT_CLASS, ...)
you must override the __construct() of your PDOStatement class.
failure to do so will result in an error on any PDO::query() call.
Warning: PDO::query() [function.PDO-query]: SQLSTATE[HY000]: General error: user-supplied statement does not accept constructor arguments
Here is a minimum PDO and PDOStatement class
<?php
class Database extends PDO {
function __construct($dsn, $username="", $password="", $driver_options=array()) {
parent::__construct($dsn,$username,$password, $driver_options);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DBStatement', array($this)));
}
}
class DBStatement extends PDOStatement {
public $dbh;
protected function __construct($dbh) {
$this->dbh = $dbh;
}
}
?>
18-Feb-2007 04:52
Simple example to extends PDO
<?php
class connexion extends PDO
{
public $query = null;
public function prepare( $statement, $driver_options = array() )
{
$this->query = $statement;
return parent::prepare( $statement, $driver_options = array() );
}
public function last_query()
{
return $this->query;
}
}
class connexion_statement extends PDOStatement
{
protected $pdo;
protected function __construct($pdo)
{
$this->pdo = $pdo;
}
// return first column of first row
public function fetchFirst()
{
$row = $this->fetch( PDO::FETCH_NUM );
return $row[0];
}
// real cast number
public function fetch( $fetch_style = null, $cursor_orientation = null, $cursor_offset = null )
{
$row = parent::fetch( $fetch_style, $cursor_orientation, $cursor_offset );
if( is_array($row) )
foreach( $row as $key => $value )
if( strval(intval($value)) === $value )
$row[$key] = intval($value);
elseif( strval(floatval($value)) === $value )
$row[$key] = floatval($value);
return $row;
}
// permit $prepare->execute( $arg1, $arg2, ... );
public function execute( $args = null )
{
if( is_array( $args ) )
return parent::execute( $args );
else
{
$args = func_get_args();
return eval( 'return parent::execute( $args );' );
}
}
public function last_query()
{
return $this->pdo->last_query();
}
}
$pdo = new connexion( ... );
$pdo->setAttribute( PDO::ATTR_STATEMENT_CLASS, array( 'connexion_statement', array($pdo) ) );
?>
09-Jan-2007 05:38
It doesn't seem at this time that there's a practical solution (besides creating multiple PDO objects and therefore DB connections) to accessing and switching between multiple databases -- as with the mysql_select_db function.
28-Sep-2006 03:38
If you use $dbh = new PDO('pgsql:host=localhost;dbname=test_basic01', $user, $pass); and you get the following error:
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[08006] [7] could not connect to server: Connection refused\n\tIs the server running on host "localhost" and accepting\n\tTCP/IP connections on port 5432?'
then as pointed out under pg_connect at: http://www.php.net/manual/en/function.pg-connect.php#38291
******
you should try to leave the host= and port= parts out of the connection string. This sounds strange, but this is an "option" of Postgre. If you have not activated the TCP/IP port in postgresql.conf then postgresql doesn't accept any incoming requests from an TCP/IP port. If you use host= in your connection string you are going to connect to Postgre via TCP/IP, so that's not going to work. If you leave the host= part out of your connection string you connect to Postgre via the Unix domain sockets, which is faster and more secure, but you can't connect with the database via any other PC as the localhost.
******
Sincerely,
Aouie
31-Aug-2006 06:56
Please note this:
Won't work:
$sth = $dbh->prepare('SELECT name, colour, calories FROM ? WHERE calories < ?');
THIS WORKS!
$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < ?');
The parameter cannot be applied on table names!!
26-Jul-2006 12:42
If you need to get Output variable from MSSQL stored procedure, try this :
-- PROCEDURE
CREATE PROCEDURE spReturn_Int @err int OUTPUT
AS
SET @err = 11
GO
$sth = $dbh->prepare("EXECUTE spReturn_Int ?");
$sth->bindParam(1, $return_value, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT);
$sth->execute();
print "procedure returned $return_value\n";
13-Jul-2006 08:02
pdo doesn't care about charsets. if you want to have your connection in unicode / utf-8 or any other encoding, you'll have to tell your database, for example using $dbh->exec('SET CHARACTER SET utf8') (mysql).
22-May-2006 04:36
I use PDO with the ODBC driver to query stored procedures in a MS SQL Server 2005 Database under Windows XP Professional with IIS 5 and PHP 5.1.4. You may have the same problems with a different configuration.
I experienced 2 very time consuming errors:
1. The first one is when you return the result of a SELECT query, and you get the following clueless message:
>>> Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[24000]: Invalid cursor state: 0 [Microsoft][SQL Native Client]Invalid cursor state (SQLFetchScroll[0] at ext\pdo_odbc\odbc_stmt.c:372)' in (YOUR_TRACE_HERE) <<<
Your exact message may be different, the part to pay attention to is "Invalid cursor state".
-> I found that I had this error because I didn't include "SET NOCOUNT ON" in the *body* of the stored procedure. By default the server returns a special piece of information along with the results, indicating how many rows were affected by the stored procedure, and that's not handled by PDO.
2. The second error I had was:
>>> Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[22003]: Numeric value out of range: 0 [Microsoft][SQL Native Client]Numeric value out of range (SQLFetchScroll[0] at ext\pdo_odbc\odbc_stmt.c:372)' in (YOUR_TRACE_HERE) <<<
Another meaningless error "Numeric value out of range"...
-> I was actually returning a date datatype (datetime or smalldatetime) "as is", that is, without converting it to varchar before including it in the result set... I don't know if PDO is responsible for converting it to a PHP datatype, but it doesn't. Convert it before it reaches PHP.
24-Apr-2006 12:50
I wanted to extend PDO class to store statistics of DB usage, and I faced some problems. I wanted to count number of created statements and number of their executings. So PDOStatement should have link to PDO that created it and stores the statistical info. The problem was that I didn't knew how PDO creates PDOStatement (constructor parameters and so on), so I have created these two classes:
<?php
/**
* PHP Document Object plus
*
* PHP Document Object plus is library with functionality of PDO, entirely written
* in PHP, so that developer can easily extend it's classes with specific functionality,
* such as providing database usage statistics implemented in v1.0b
*
* @author Peter Pokojny
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/
class PDOp {
protected $PDO;
public $numExecutes;
public $numStatements;
public function __construct($dsn, $user=NULL, $pass=NULL, $driver_options=NULL) {
$this->PDO = new PDO($dsn, $user, $pass, $driver_options);
$this->numExecutes = 0;
$this->numStatements = 0;
}
public function __call($func, $args) {
return call_user_func_array(array(&$this->PDO, $func), $args);
}
public function prepare() {
$this->numStatements++;
$args = func_get_args();
$PDOS = call_user_func_array(array(&$this->PDO, 'prepare'), $args);
return new PDOpStatement($this, $PDOS);
}
public function query() {
$this->numExecutes++;
$this->numStatements++;
$args = func_get_args();
$PDOS = call_user_func_array(array(&$this->PDO, 'query'), $args);
return new PDOpStatement($this, $PDOS);
}
public function exec() {
$this->numExecutes++;
$args = func_get_args();
return call_user_func_array(array(&$this->PDO, 'exec'), $args);
}
}
class PDOpStatement implements IteratorAggregate {
protected $PDOS;
protected $PDOp;
public function __construct($PDOp, $PDOS) {
$this->PDOp = $PDOp;
$this->PDOS = $PDOS;
}
public function __call($func, $args) {
return call_user_func_array(array(&$this->PDOS, $func), $args);
}
public function bindColumn($column, &$param, $type=NULL) {
if ($type === NULL)
$this->PDOS->bindColumn($column, $param);
else
$this->PDOS->bindColumn($column, $param, $type);
}
public function bindParam($column, &$param, $type=NULL) {
if ($type === NULL)
$this->PDOS->bindParam($column, $param);
else
$this->PDOS->bindParam($column, $param, $type);
}
public function execute() {
$this->PDOp->numExecutes++;
$args = func_get_args();
return call_user_func_array(array(&$this->PDOS, 'execute'), $args);
}
public function __get($property) {
return $this->PDOS->$property;
}
public function getIterator() {
return $this->PDOS;
}
}
?>
Classes have properties with original PDO and PDOStatement objects, which are providing the functionality to PDOp and PDOpStatement.
From outside, PDOp and PDOpStatement look like PDO and PDOStatement, but also are providing wanted info.
10-Mar-2006 05:49
PDO doesn't return OUTPUT params from mssql stored procedures
/* Stored Procedure Create Code: */
/*
CREATE PROCEDURE p_sel_all_termlength @err INT OUTPUT AS
SET @err = 2627
*/
/* PHP Code: */
<?php
$Link = new PDO('mssql:host=sqlserver;dbname=database', 'username',
'password');
$ErrorCode = 0;
$Stmt = $Link->prepare('p_sel_all_termlength ?');
$Stmt->bindParam(1,$ErrorCode,PDO::PARAM_INT,4);
$Stmt->execute();
echo "Error = " . $ErrorCode . "\n";
?>
/* PHP Output:
Error = 0
*/
20-Feb-2006 03:16
Below is an example of extending PDO & PDOStatement classes:
<?php
class Database extends PDO
{
function __construct()
{
parent::__construct('mysql:dbname=test;host=localhost', 'root', '');
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DBStatement', array($this)));
}
}
class DBStatement extends PDOStatement
{
public $dbh;
protected function __construct($dbh)
{
$this->dbh = $dbh;
$this->setFetchMode(PDO::FETCH_OBJ);
}
public function foundRows()
{
$rows = $this->dbh->prepare('SELECT found_rows() AS rows', array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE));
$rows->execute();
$rowsCount = $rows->fetch(PDO::FETCH_OBJ)->rows;
$rows->closeCursor();
return $rowsCount;
}
}
?>
13-Feb-2006 03:50
I found a nice pdo modification written in php called Open Power Driver. It has identical API with the original, but allows you to cache query results: http://www.openpb.net/opd.php
08-Feb-2006 11:18
If your having problems re-compiling PHP with PDO as shared module try this.
--enable-pdo=shared
--with-pdo-mysql=shared,/usr/local/mysql
--with-sqlite=shared
--with-pdo-sqlite=shared
1. If PDO is built as a shared modules, all PDO drivers must also be
built as shared modules.
2. If ext/pdo_sqlite is built as a shared module, ext/sqlite must also
be built as a shared module.
3. In the extensions entries, if ext/pdo_sqlite is built as a shared
module, php.ini must specify pdo_sqlite first, followed by sqlite.
01-Jan-2006 09:09
Watch out for putting spaces in the DSN
mysql:host=localhost;dbname=test works
mysql: host = localhost; dbname=test works
mysql: host = localhost; dbname = test doesn't work...
04-Dec-2005 06:36
Hi there,
because of ZDE 5.0 and other PHP-IDEs do not seem to support PDO from PHP5.1 in code-completion-database yet, I wrote a code-completion alias for the PDO class.
NOTE: This Class has no functionality and should be only included to your IDE-Project but NOT(!) to your application.
<?php
/**
* This is a Code-Completion only file
* (For use with ZDE or other IDEs)
*
* Do NOT include() or require() this to your code
*
* @author Matthias Leuffen
*/
class PDO {
/**
* Error Constants
*
*/
const ERR_ALREADY_EXISTS = 0;
const ERR_CANT_MAP = 0;
const ERR_NOT_FOUND = 0;
const ERR_SYNTAX = 0;
const ERR_CONSTRAINT = 0;
const ERR_MISMATCH = 0;
const ERR_DISCONNECTED = 0;
const ERR_NONE = 0;
/**
* Attributes (to use in PDO::setAttribute() as 1st Parameter)
*
*/
const ATTR_ERRMODE = 0;
const ATTR_TIMEOUT = 0;
const ATTR_AUTOCOMMIT = 0;
const ATTR_PERSISTENT = 0;
// Values for ATTR_ERRMODE
const ERRMODE_EXCEPTION = 0;
const ERRMODE_WARNING = 0;
const FETCH_ASSOC = 0;
const FETCH_NUM = 0;
const FETCH_OBJ = 0;
public function __construct($uri, $user, $pass, $optsArr) {
}
/**
* Prepare Statement: Returns PDOStatement
*
* @param string $prepareString
* @return PDOStatement
*/
public function prepare ($prepareString) {
}
public function query ($queryString) {
}
public function quote ($input) {
}
public function exec ($statement) {
}
public function lastInsertId() {
}
public function beginTransaction () {
}
public function commit () {
}
public function rollBack () {
}
public function errorCode () {
}
public function errorInfo () {
}
}
class PDOStatement {
public function bindValue ($no, $value) {
}
public function fetch () {
}
public function nextRowset () {
}
public function execute() {
}
public function errorCode () {
}
public function errorInfo () {
}
public function rowCount () {
}
public function setFetchMode ($mode) {
}
public function columnCount () {
}
}
16-Mar-2005 03:53
Some useful links on PDO:
1. PDO Wiki ( http://wiki.cc/php/PDO )
2. Introducing PHP Data Objects ( http://netevil.org/downloads/Introducing-PDO.ppt ), [226 KB], Wez Furlong, 2004-09-24
3. The PHP 5 Data Object (PDO) Abstraction Layer and Oracle ( http://www.oracle.com/technology/pub/articles/php_experts/otn_pdo_oracle5.html ), [60.85 KB], Wez Furlong, 2004-07-28
4. PDO - Why it should not be part of core PHP! ( http://www.akbkhome.com/blog.php/View/55/ ), Critical review, [38.63 KB], Alan Knowles, 2004-10-22
HTH,
R. Rajesh Jeba Anbiah