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は永続設定の意味

Open Source Web Architecture Top

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