| |
PDOを使う
PHPのデータベースアクセス手段の一つ、PDOを使ったサンプルです。
まずOracleデータベース(OCI8)に接続する例です。
<?php
$sql = "SELECT * FROM SHITEN ORDER BY 1";
try {
$pdo = new PDO("oci:dbname=//falcon.nsnhnkmmkk.co.jp:1521/TESTDB", "testuser", "testpass");
$stmt = $pdo->query($sql);
print "<html><body>";
while($row = $stmt->fetch()){
print implode(", ", $row) . "<br>" . PHP_EOL;
}
print "</body></html>";
} catch(PDOException $e){
var_dump($e->getMessage());
}
$pdo = null;
|
上の例ではWebサーバにtnsnames.oraを配置せず、
プログラム中でOracle DBサーバのホスト名、ポート番号、データベース名(サービス名)を指定しています。
もしtnsnames.oraを定義しているなら、"oci:dbname=TESTDB" だけでOKです。
PDO::queryはプレースホルダー("?" とか、":name" のようなバインドパラメータ)を含まないSELECT文の発行時に使います。
プレースホルダーを含むSQLを実行する場合は、後述の PDO::prepare と PDO::executeを使う必要があります。
同様に、SQLite3に接続するサンプルです。
<?php
$sql = "SELECT * FROM SHITEN ORDER BY 1";
try {
$pdo = new PDO("sqlite:D:/usr/lang/php2018/test.db", null, null);
$stmt = $pdo->query($sql);
print "<html><body>";
while($row = $stmt->fetch()){
print implode(", ", $row) . "<br>" . PHP_EOL;
}
print "</body></html>";
} catch(PDOException $e){
var_dump($e->getMessage());
}
$pdo = null;
?>
|
SQLiteにはユーザーという概念がないので、
PDO()コンストラクタの2,3番目の引数=ユーザーとパスワードはいずれもnullでOKです。
もうひとつ、同様にMySQL/MariaDBに接続するサンプルです。
PDOの利点はまさにこの、RDBMS製品が異なっても同じ書き方ができることで、
上のOracleとSQLiteとMySQLの違いはPDOに渡す接続文字列(DSN)だけです。
<?php
$pdo = new PDO("mysql:host=falcon.nsnhnkmmkk.co.jp;port=3306;dbname=testdb;charset=utf8mb4", "testuser", "testpass");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = <<<SSQL
SELECT ITEM_ID, ITEM_NAME, CATEGORY_ID, SIZE_DESC, PRICE, MAKER_DESC
FROM ITEMS WHERE CATEGORY_ID = ?
SSQL;
$st = $pdo->prepare($sql);
$st->execute([ "8" ]);
while($rset = $st->fetch(PDO::FETCH_NUM)){
print(implode("\t", $rset) . "<br>" . PHP_EOL);
}
$st = null;
$pdo = null;
?>
|
PDOのエラー処理モードは、PHPマニュアルの
エラーおよびエラー処理
のページに解説されています。上の例のように、setAttribute()でモードを指定できます。
上の例ではプレースホルダー「?」を指定して、バインドパラメータをPDO::executeに配列で渡しています。
この方法の場合、PHPのデータ型とデータベースのデータ型は必要に応じて自動的に変換されます。
例えば上の例ではCATEGORY_ID列がデータベースでINTEGER型でも、
PHPからは "8" という文字列を渡していますが、自動的に整数に変換して実行されます。
(※変換は各DBMSのDriverで行われる場合もあれば、DBMS本体の機能として行われる場合もあります)
自動ではなく、各パラメータのデータ型を明示的に指定したい場合は、
PDO::bindValue または PDO::bindParam を使えばOKです。
両者の違いは、bindValueが値を渡すためDB側からOUT引数として値を受け取ることはできないのに対して、
bindParamは変数への参照を渡すためOUT引数がDBからPHP側へ受け取れる点です。
ではもう一つ。今度はFirebirdのデータベースに接続する例です。
<?php
$pdo = new PDO("firebird:dbname=localhost:/var/lib/firebird/data/mydb.fdb;charset=UTF8", "TESTUSER", "TestPass");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = <<<SSQL
SELECT ITEM_ID, ITEM_NAME, CATEGORY_ID, SIZE_DESC, PRICE, VENDOR_CODE
FROM ITEMS WHERE CATEGORY_ID = ?
SSQL;
$st = $pdo->prepare($sql);
$st->execute([ "7" ]);
while($rset = $st->fetch(PDO::FETCH_NUM)){
print(implode("\t", $rset) . "<br>" . PHP_EOL);
}
$st = null;
$pdo = null;
?>
|
OracleやMySQL/MariaDBの例とほとんど同じじゃないか!はい、毎度おなじみDSN部分が異なるだけで、
他の部分はデータベースが異なっても全く同じ書き方が可能です。
そのDSN部分も見たら分かる内容だと思いますが一点だけ、ポート番号がデフォルトの3050ではない場合、
公式の例の通り、
「dbname=localhost/4060:/var/lib...」という書き方になります。
スラッシュとコロンの使い分けが他の製品と少し異なりますが、覚えておけば混乱しない範囲でしょう。
最後に、SQLiteデータベースのデータ検索をPDOで行う例で、バインドパラメータの違う指定方法の例をもう一つ載せてみます。
$pdo = new PDO("sqlite:/the/path/of/wizdb", null, null);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = <<<SQL
SELECT SHITEN_CODE, SHITEN_NAME, AREA_CODE FROM SHITEN
WHERE AREA_CODE = :area_code ORDER BY SHITEN_CODE
SQL;
$s = $pdo->prepare($sql);
$r = $s->execute(array(":area_code" => "3"));
while($rset = $s->fetch(PDO::FETCH_NUM)){
print(implode("\t", $rset) . "\n");
}
$s = null;
$pdo = null;
|
この例では名前付きのパラメータ「:area_code」を使用しています。
同じSQL中に"?"と名前付きのパラメータを併用はできません。一つのSQLでは必ずどちらか片方だけを使うようにします。
バインド変数をパラメータと紐づけるには先述の通りPDO::bindValueも使えますが、
ここではPDO::executeの引数に配列を渡しています。
fetchや記号定数FETCH_NUMの使い方は先述のSQLite3モジュールとほぼ同じです。
最後に、StatementやConnectionの明示的なクローズ処理はありません。
それらの変数にnullを代入すると、自動的にクローズされます。
トラブルシューティング
PDO接続時に「SQLSTATE[HY000] [2002] Permission denied」が発生する
WebサーバからDBサーバへ、mysqlやpsqlなどのコマンドでは接続できるのに、PHPからはエラーになる場合、
また「Access denied」ではなくて「Permission denied」という文言の場合、
データベース側の原因ではなく、Webサーバ側のSELinuxの設定が原因と考えられます。
rootユーザーで /var/log/audit/audit.log を見てdeniedという文字が含まれているとSELinuxによって拒否されたことが分かります。
SELinuxにはhttpdから外部のデータベース、LDAP、メール送信などのネットワークアクセスを行うことを許可するフラグがあり、
初期設定はoffになっているためです。許可するには次のコマンドを実行します。
getsebool httpd_can_network_connect
httpd_can_network_connect --> off
# ↑off = 接続拒否の設定になっている
sudo setsebool -P httpd_can_network_connect_db 1
# -Pは永続設定の意味
|

(first uploaded 2013/03/10 last updated 2025/01/04, URANO398)
|