Help us understand the problem. What is going on with this article?

【PHP】PDOでMS ACCESSに接続し、データを取得してみた

PHPにおけるデータベース接続において、ほとんどのDBMSに対応しているPDO。実はMS ACCESSのmdb、accdbファイルにも対応しており、データを取得することができます。

ただ、それにはこまごまと準備が必要です(特にLinux系の場合は色々と準備が必要になり、データの取得に対しても一工夫必要になります)。

※Linux(ここではRed Hat系のことを指す)の場合のデータ取得方法を追記しました。Linuxの場合、本当に困難を極めますが、以下の方法で取得可能です(centOS7にて取得テスト済)。なお、WSL(Ubuntu)なら、ここまで色々しなくても大丈夫なようです。

1 接続前の準備

xamppなどのWindowsの場合

php.iniファイルからpdo-odbcドライバを使用できるようにします。

php.ini
extension=pdo-odbc; //コメントを外す

その後はapache再起動で準備完了です。

Linuxの場合

必要なドライバのインストール

php-odbcドライバを使用するので、yumコマンドで開発用ドライバ、それからmdbodbcライブラリと一緒にインストールします(当然、php-pdoなどは事前に使えるようにしておく必要があります)。もし、依存関係などで一部のドライバがインストールできなかった場合、remiレポジトリでPHPのバージョンを合わせてインストールするとうまくいきます。例はPHP7.2-xを使用する場合)

参考(remiとか)
CentOS7にPHP7をyumでインストールする

# yum install --enablerepo=remi-php72 php-pdo php-odbc unixODBC unixODBC-devel libmdbodbc

libmdbodbc.so.1ライブラリのインストールと設定

上記のドライバに加え、libmdbodbc.so.1ライブラリが必要になりますが、標準ではインストールされていませんので、外部からインストールしてきます。その上で、odbcinst.iniを編集して、ドライバに読み込ませる必要があります。

このページが参考になりました
MDB Tools missing driver

# wget https://forensics.cert.org/cert-forensics-tools-release-el7.rpm //リポジトリのインストール
# rpm -Uvh cert-forensics-tools-release-el7.rpm //リポジトリの解凍
# yum --enablerepo=forensics install libmdbodbc1 //リポジトリを使って、yumコマンドでインストール
# find / -name *libmdbodbc* //インストールされた場所を探す
# cp -ap /usr/lib64/libmdbodbc.so.1 /usr/lib/ //インストール元から複製する(32bit機で動かす場合)

これで、ライブラリをセットできました。そして、次はこのライブラリを読み込むためにodbcinst.iniを編集します。

#vi /etc/odbcinst.ini

/*以下を追記して保存する。また、[***]内の名称(例ではMDBTools)が、LinuxでのPDO接続ドライバ名となる。*/
[MDBTools]
Description = ODBC for MDBTools
Driver64    = /usr/lib64/libmdbodbc.so.1
Setup64     = /usr/lib64/libmdbodbc.so.1
Driver      = /usr/lib/libmdbodbc.so.1
Setup       = /usr/lib/libmdbodbc.so.1
FileUsage   = 1
UsageCount  = 1

このようにパスを設定します。これでLinuxの準備は完了です。あとは

# systemctl restart httpd //centos7、Apacheの場合

でWEBサーバーを再起動します。

2 PDOでACCESSに接続する

ここからPDOを使って、ACCESSに接続するのですが、ここにも色々とトラップがあります。

このサイト(Github)のフォーラムがかなり参考になりました。
How to handle MS Access MDB files in Linux with PHP5 PDO and ODBC
Problems with MDBTools + unixODBC + php_odbc

このサイトの記述を使えば、OSがWindowsでもLinuxでも対応できます。
注意点は、WindowsとLinuxでドライバの記述が異なる点です。

ファイルパス記述の注意

  • ファイルパスは必ず/(スラッシュ)を使ってください(¥は無効となります)。
  • パスは必ず絶対パスで記述し、かつ書き方も癖があります(詳しくはサンプルで)
  • DbqパラメータはLinuxの場合、DBQと大文字で記述しないとデータベース名を取得できません。
PHP
/*ファイルパスの記述例*/
$dbName = "C:/xampp/htdocs/hogehoge.mdb"; //Xamppの場合はドライブの記述方法に注意。
$dbName = "/var/www/html/hogehoge.mdb"; //Linuxの場合は必ずサーバ内のパスで記述する
PHP
$uname = explode(" ",php_uname());
$os = $uname[0];
switch ($os){
  case 'Windows':
    $dbName = "D:/xampp/htdocs/hogehoge.mdb";
    $driver = '{Microsoft Access Driver (*.mdb, *.accdb)}';
    break;
  case 'Linux':
    $dbName = "/var/www/html/hogehoge.mdb";
    $driver = 'MDBTools'; //odbcinst.iniで追記したドライバ名
    break;
  default:
    exit("非対応のOSです");
}
$dbh = new PDO("odbc:Driver=$driver;DBQ=$dbName;");

これでCould not find Driver などのエラーが表示されなかったら、PDOへの接続は成功です。

3 データを取得する

Windowsの場合

データは普通にPDOオブジェクトを利用するだけで取得可能です。テーブル名が日本語などの場合でも"テーブル名"と、ダブルクォートで囲えば問題なく取得できます。

※現在、日本語カラムからデータを取得できないかテスト中です。成功次第、記事を追記したいと思います。

Linuxの場合

色々と注意点があり、各カラムをバインドしないとデータを取得できないようです(普通にFETCHしようとすると、カラムをBINDしてくださいと怒られて何も取得できません)

このページを参考にしました。
PDO Error when ODBC_Exec works correctly

カラムは逐一記述して、それぞれにPDO::bindColumn()メソッドでバインド処理を行っていきます。そして各行をfetchしていくのですが、unixODBCの仕様上PDO::FETCH_NUMPDO::FETCH_ASSOCなどが使用できないため(使用方法を探しましたが見つかりませんでした)、PDO::FETCH_BOUNDで、各行に対して判定結果をループさせ、個別の変数から直接値を取得するようにします。

また、SQLの記述もかなり厳格なルールがあり、それを守らないと正しくデータを取得してくれません。

  • カラム名はしっかりと書くこと。*(アスタリスク)を使った場合でも、取得する行番号をしっかりと付記しないと、正しいデータが取得できません。
  • SQL文の定型句(SELECT FROM WHEREなど)は英大文字で記述しないと、不正なSQL構文とエラー表示されます)
  • SQL文の末尾に;(コロン)を付けると、クエリを読み取ってくれません。
PHP
   //num,nameというカラムを持つテーブルtest
   $sql = "SELECT num,name FROM test"; //ルールは前述した通りです
   $sth = $dbh -> prepare($sql);
   $sth -> execute();
   //各カラムにバインドしていく
   $sth -> bindColumn(1,$num);
   $sth -> bindColumn(2,$name);

   //カラムに対してバインドをかけるため、$flgには判定結果しか帰ってこない
   $values = []; //値を代入する配列
   while( $flg = $sth -> fetch(PDO::FETCH_BOUND) ){
             $values[] = [$num,$name];
   }

※なお、例では変数名をカラムに合わせていますが、特に決まりはありません。数量が不確定の場合\$val[1],$val[2],…のような変数でも問題ありません。

注意

  • ACCESSでメモ型は使わないでください。データの値が取得できなくなるバグがあるようです(テキスト型に直すと取得できます)
  • カラム名でアンダーバー( _ )を使うと正しくデータを取得できないバグもあるようです。

4 最後に

どうしても実務に必要だったので、ACCESSデータをPHPで取得するという無茶振りをやってみたわけですが、もしこの研究、分析成果が、誰かのお役に立てればと思います。

なお、取得したデータをそのままCSVなどに吐き出すだけならここまで面倒なことをしなくても大丈夫なようです。
日々修行 LinuxのPHPでAccessファイルを読み込むには

BRSF
職業、PG・SE・DBエンジニア。オープン環境のwebプログラムをメインにシステム構築担当。使用言語はPHP(cakePHP、Laravel含)jQuery、JavaScript、ExcelVBA、Perl、Ruby、Python。現在Vue、React、Angular強化中。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした