気まぐれSE日記

地方でエンジニアしてます

Linux上のPHPからAccessのMDBを使うには

題名の件ですが調査を依頼されたのですが個人的に結構苦戦した部類だったのでメモしておきます。先日書いていたPHPコンパイルでおかしくなったのはこれをやろうとしてはまりました。

まずはLinuxからMDBを操作できるのか?

ググってみたところでは Microsoft のAccessDB(MDB)をLinuxから使おうと思ったらなかなか手段がないらしく、LinuxODBC経由で取れるらしいことが判明。ODBC経由でmdbにアクセスするには、MDB Toolsってのと brodbc(ODBC-ODBC Bridge)が使えるらしい。

MDB Tools

MDB Toolsは直接Linux側にmdbを置いて操作できそう!だったので、DLしてコンパイルして試してみた*1けどうまく動かない。どうもまだ開発中(ていうかストップしてる?)らしく、unixODBCのisqlコマンドでSQLを実行するとなぜかループ。当然日本語とかも全く未対応で使えないため使えないと判断。

brodbc (ODBC-ODBC bridge)

これは、開発止まっているようだけど日本で作成されたソフトで、ODBCをネットワーク経由して別のマシンからアクセスできるようにするODBCドライバ。本家見てみるとわかるけど、mdbLinux単体で直接扱えず、Windowsマシンが必要。

具体的には

  1. Windows側でコンパネ→ODBCマネージャから読み込ませたいMDBを指定する
  2. Windows側でbrodbcサーバを起動させ常駐させる(TCP22002番を使う)
  3. Linux側からbrodbcクライアントODBCドライバからWindowsのbrodbcにへアクセス
  4. Linux側からSQL実行

てな流れになる。


brodbcのコンパイル

開発が止まっているため、makeするのはなかうまくいかないです。こちらの場合は、unixODBCかiODBCおよび、libiconvの開発ライブラリが必要でした。あらかじめ、パッケージインストールかソースからをmakeしてインストールしておいてください。私の場合はlibiconvとiODBCをソースからインストールしましたのでライブラリは/usr/local配下にインストールされます。手順は省略します。そのあとで、brodbcのmake を行います。

1.ダウンロード・展開


wget http://www.amy.hi-ho.ne.jp/jbaba/brodbc/brodbc03.tgz
tar xfz brodbc03.tgz
cd brodbc03

2. ここで、client/makefile.uxを次のように修正


CC = gcc -c -DUNIX -DICONV

CC = gcc -fPIC -c -DUNIX -DICONV

〜中略〜

ODBCLIB = /usr/local/lib/libodbc.so

ODBCLIB = /usr/local/lib/libiodbcinst.so /usr/local/lib/libiconv.so
# ※iodbcとiconvを手動インストールしている場合です。unixodbcだとlibodbcinst.soとなります。

3.common/makefile.ux


CC = gcc -c -DUNIX

CC = gcc -fPIC -c -DUNIX

4.client/brodbc.c を書き換える

30c30
<     SQLSMALLINT FAR   *pcbConnStrOut,
---
>     SQLSMALLINT   *pcbConnStrOut,
236c236
<     SQLSMALLINT FAR   *pcbConnStrOut,
---
>     SQLSMALLINT   *pcbConnStrOut,
252c252
<     SQLSMALLINT FAR   *pcbConnStrOut)
---
>     SQLSMALLINT   *pcbConnStrOut)
282,285c282,285
<     SQLSMALLINT FAR   *pfSqlType,
<     SQLUINTEGER FAR   *pcbParamDef,
<     SQLSMALLINT FAR   *pibScale,
<     SQLSMALLINT FAR   *pfNullable)
---
>     SQLSMALLINT   *pfSqlType,
>     SQLULEN   *pcbParamDef,
>     SQLSMALLINT   *pibScale,
>     SQLSMALLINT   *pfNullable)
311,312c311,312
<     SQLINTEGER         irow,
<     SQLUINTEGER FAR   *pcrow,
---
>     SQLLEN         irow,
>     SQLULEN   *pcrow,
365c365
<     SQLCHAR FAR       *szSqlStrIn,
---
>     SQLCHAR       *szSqlStrIn,
367c367
<     SQLCHAR FAR       *szSqlStr,
---
>     SQLCHAR       *szSqlStr,
369c369
<     SQLINTEGER FAR    *pcbSqlStr)
---
>     SQLINTEGER    *pcbSqlStr)
377c377
<     SQLSMALLINT FAR   *pcpar)
---
>     SQLSMALLINT   *pcpar)
392,393c392,393
<     SQLUINTEGER        crow,
<     SQLUINTEGER FAR   *pirow)
---
>     SQLULEN        crow,
>     SQLULEN   *pirow)
504c504
<     SQLSMALLINT FAR   *pcbDriverDesc,
---
>     SQLSMALLINT   *pcbDriverDesc,
507c507
<     SQLSMALLINT FAR   *pcbDrvrAttr)
---
>     SQLSMALLINT   *pcbDrvrAttr)
519c519
<     SQLUINTEGER        cbColDef,
---
>     SQLULEN        cbColDef,
522,523c522,523
<     SQLINTEGER         cbValueMax,
<     SQLINTEGER FAR    *pcbValue)
---
>     SQLLEN         cbValueMax,
>     SQLLEN     *pcbValue)
705,706c705,706
<     SQLINTEGER         cbValueMax,
<     SQLINTEGER FAR    *pcbValue)
---
>     SQLLEN         cbValueMax,
>     SQLLEN FAR    *pcbValue)
783,784c783,784
<     SQLSMALLINT FAR   *pcbDesc,
<     SQLINTEGER FAR    *pfDesc)
---
>     SQLSMALLINT   *pcbDesc,
>     SQLLEN FAR    *pfDesc)
1011,1015c1011,1015
<     SQLSMALLINT FAR   *pcbColName,
<     SQLSMALLINT FAR   *pfSqlType,
<     SQLUINTEGER FAR   *pcbColDef,
<     SQLSMALLINT FAR   *pibScale,
<     SQLSMALLINT FAR   *pfNullable)
---
>     SQLSMALLINT   *pcbColName,
>     SQLSMALLINT   *pfSqlType,
>     SQLULEN   *pcbColDef,
>     SQLSMALLINT   *pibScale,
>     SQLSMALLINT   *pfNullable)
1104,1106c1104,1106
<     SQLCHAR FAR       *szSqlState,
<     SQLINTEGER FAR    *pfNativeError,
<     SQLCHAR FAR       *szErrorMsg,
---
>     SQLCHAR        *szSqlState,
>     SQLINTEGER    *pfNativeError,
>     SQLCHAR        *szErrorMsg,
1108c1108
<     SQLSMALLINT FAR   *pcbErrorMsg)
---
>     SQLSMALLINT   *pcbErrorMsg)
1178c1178
<     SQLCHAR FAR       *szSqlStr,
---
>     SQLCHAR        *szSqlStr,
1468c1468
<     SQLSMALLINT FAR   *pcbCursor)
---
>     SQLSMALLINT   *pcbCursor)
1482c1482
<     SQLSMALLINT FAR   *pccol)
---
>     SQLSMALLINT   *pccol)
1518c1518
<     SQLCHAR FAR       *szSqlStr,
---
>     SQLCHAR        *szSqlStr,
1555c1555
<     SQLINTEGER FAR    *pcrow)
---
>     SQLLEN FAR    *pcrow)
1626c1626
<     SQLUINTEGER        cbParamDef,
---
>     SQLULEN        cbParamDef,
1629c1629
<     SQLINTEGER FAR     *pcbValue)
---
>     SQLLEN      *pcbValue)
1731,1732c1731,1732
<     SQLINTEGER         cbValueMax,
<     SQLINTEGER FAR    *pcbValue)
---
>     SQLLEN         cbValueMax,
>     SQLLEN FAR    *pcbValue)
1802c1802
<     SQLSMALLINT FAR   *pcbInfoValue)
---
>     SQLSMALLINT   *pcbInfoValue)
1903c1903
<     SQLINTEGER         cbValue)
---
>     SQLLEN         cbValue)
1944c1944
<     SQLUINTEGER        vParam)
---
>     SQLULEN        vParam)
1974c1974
<     SQLUINTEGER        vParam)
---
>     SQLULEN        vParam)
2127c2127
<     SQLSMALLINT FAR   *pcbDSN,
---
>     SQLSMALLINT   *pcbDSN,
2130c2130
<     SQLSMALLINT FAR   *pcbDescription)
---
>     SQLSMALLINT   *pcbDescription)

書き換えないとmake に失敗します。

5.client/iconv.c も書き換えます

36c36
<     int  in_bytes, out_bytes;
---
>     size_t  in_bytes, out_bytes;

書き換えないとmake に失敗します。

6.make インストール


make
make install

unixODBC または iODBCの設定

/etc/odbcinst.iniの設定

例)

[brodbc03]
Description     = ODBC-ODBC bridge
Driver          = /usr/local/lib/brodbc.so
FileUsage       = 1
#UsageCount      = 1


/etc/odbc.ini ファイルにbrodbcを使用できるように記述

例)

[test]                       # ← Linux odbcでのDSN(DB名)
Driver = brodbc03
Server = windows側のIP
Port = 22002
DSN = test
Database = test
Username = 指定した場合記述
Password = 指定した場合記述
Servercharset = Shift_JIS
Charset = eucjp
Debug = 0

ODBCの動作確認

isql コマンド(unixODBC?)を実行してみて接続できればOK。


isql DSN ユーザ名(省略可能) パスワード(省略可能)

isqlコマンド実行例
isql test
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+

SQL> select * from テーブル名

+-----------+-----------+----------+
| ID | field1 | field2 |
+-----------+-----------+----------+
| 1 | 990112 | aaaaaa |
| 2 | 21213 | xccccc |
| 3 | 11111 | bbbbbb |
| 4 | 1254 | dddd |
| 5 | 888888888 | 日本語 |
+-----------+-----------+----------+
SQLRowCount returns -1
5 rows fetched

とか出てきてればおk


追記:brodbcドライバの動作に関してですが、TurboLinux 10 x64のisqlコマンドは正常動作しましたが、VineLinux 4.2ではisqlでは全く動作せずセグフォルトで落ちてしまいます。でもPHP経由ではなぜか正常動作しますので、この辺、何が悪いのかがよくわかりません...。

PHPコンパイル

PHPをソースからmakeしている場合は、ODBC関数を使えるように configure時に unixODBCiODBCのどちらかを指定する*2パッケージでインストールされていればそのままodbc関数が動作するかもしれせん。phpinfoを確認してodbcが表示されてればOKかと。

例)
./configure 〜省略〜 --with-unixODBC=/usr
make
make install

このあと、httpd を再起動するとODBC関数が利用できるようになる。

注:iODBCを使用する場合は configureで --with-iodbc=/usr/local などと指定します。

テストプログラム

DSN名がtest、ユーザ名・パスワード未設定。テーブル名testの場合のサンプルです。

<?php
        $con = odbc_connect("test", "", "");
        
        echo "ただいまODBC接続中......<br>";
        
        if(!$con) {
            die("エラー:ODBC接続に失敗しました!<br>");
        }
        
        $result = odbc_exec($con, "SELECT * FROM test");
        
        while(odbc_fetch_row($result)) {
            
                $id = odbc_result($result, 1);
                $f1 = odbc_result($result, 2);
                $f2 = odbc_result($result, 3);
                
                echo "$id  $f1  $f2<br>";
        }
        
        odbc_free_result($result);
        odbc_close($con);
?>

PHPからbrodbc経由でodbc関数を実行してみたが

私が試した環境(TurboLinux 10 64bit)ところでは、たまにsegfaultになるという不安定さが残ってしまってます..実用的な安定感がないのが困ったところ。

↓参考:落ちる
Re: Linux上のPHPからAccessを使うには?
「PHPからODBC経由でMS-Accessに接続できない」(1) Linux Square − @IT

まとめると

  1. MDB Toolsは使えない
  2. brodbcのmakeにはiODBCとlibiconvが必要
  3. brodbcの動作確認(isqlコマンド)にはunixODBCが必要
  4. PHPにはunixODBCが必要

ほんとややこしいです。

*1:unixODBCかiODBCの開発ライブラリが必要

*2:両方指定すると、後者が優先されるようです。unixODBCを指定した方が良いようです→iODBC指定だとodbc_fetch_rowが使えないため。