PHP
db2
Bluemix
dashDB

PHP最新バージョン5.6系/7系からのDb2接続

この記事は、 PHP PDOで Db2 on Cloud data warehouse (愛称 dashDB) は繋がるか? 失敗ケース の続編で、PHPの本番システムで Db2を利用できる様に、PHP 5.6.31, PHP 7.1.7 から ODBCドライバ、PDOドライバからSSL接続でアクセスが可能なことを確認しました。  使用したドライバーのパッケージは Db2の IBM Data Server Driver Package v11.1 です。 ただし、Db2には、Db2 Warehouse on Cloud(旧 DashDB), Db2 Hosted, Db2 on Cloudが含まれます。また、この検証結果は、個人の見解であり、会社の見解を代表するものではありません。

今回の目指す環境

PHPからDb2シリースのDBaaSへ接続するもので、ローカルの開発環境からインターネット越しにDb2へ接続するため、暗号化通信接続を用います。

スクリーンショット 2017-08-02 0.03.29.png

ベース環境の起動

Macでビルド環境を作るのは、少々面倒であること、Cloud Foundry のビルドパックは、Ubuntu ベースであることから、Mac や Windows 上の Vagrant + Virtual Box の 仮想マシン上の Ubuntu 14.04 で検証を実施しました。 この仮想マシン環境を構築するために必要な Vagrantfile は、参考資料(1)にあります。 それから、MacOS や Windows 上に Vagrant の環境を未設定の場合は、参考資料(2),(3) を参照してください。 また、Gitのコマンドが入っていない場合は、Macの場合は、Xcode をインストールするか、または、参考資料(4)を参照してください。 Windows の場合も参考資料(4)に導入方法があります。

Vagrant + VritualBox の環境が出来ている方は、次のコマンドを使って、Vagrantfile をローカル環境へコピーします。

git clone https://github.com/takara9/bluemix-dev

ディレクトリを移って、仮想マシンを起動します。 このVagrantfileによって、必要なソフトウェア・モジュールを導入します。

cd bluemix-dev
vagrant up 

PHP 5.6.31 のビルド

前述の Vagrantfile で立ち上がる仮想マシンに導入された phpenv と php-build を利用して、PHP 5.6.31 をビルドします。 次のコマンドを実行することで、ソースコードをダウンロードして、ビルドが始まります。 PHPのビルドには、最大で約 800MBのメモリを利用しますから、VagrantfileにはRAMを1GB取得する様に設定しています。

phpenv install 5.6.31

このビルドのソースコードは、/tmp/php-buildの下の配置されています。 odbcドライバ、pdoドライバは、このphpenvで自動的にビルドされないため、個別に設定してビルドします。

ドライバ・パッケージの導入

Db2へ接続するために必要なドライバ・パッケージを導入します。 これは Bluemix のサービスの画面からダウンロードします。 少し解りにくい場所にあるので、ダウンロードのリンクまでのアクセス手順を示します。 Db2の管理画面から次の様に、Openのホットスポットをクリックします。
スクリーンショット 2017-08-02 0.13.40.png

次に、ドロップダウン・メニューの中から、"Connection Info"をクリックして、ダウンロードページへ移動します。
スクリーンショット 2017-08-02 0.13.53.png

次の画面には、接続関する情報とドライバ・パッケージをダウンロードするリンクがありますから、クリックしてダウンロードします。
スクリーンショット 2017-08-02 0.14.00.png

ダウンロードしたファイルは、ローカル環境の bluemix-dev へ移動します。 仮想マシンからは、/vagrant のディレクトリが、ホストマシンのファイル・システムになっています。 パッケージファイルを/opt/ibmの下に展開して、/opt/ibm/dsdriver のフォルダーへ移動します。 この中のインストーラーを起動して、インストールを完了させます。

vagrant@vagrant-ubuntu-trusty-64:/opt/ibm/dsdriver$ ./installDSDriver 

このあと、.bash_profile に、以下の行を追加します。

~/.bash_profile
# for clpplus
. /opt/ibm/dsdriver/db2profile

次のコマンドで、設定を有効にします。

exec $SHELL -l

clpplus でのログイン・テスト

clpplus が動作するためのセットアップを行います。 コマンドラインを利用する予定がなければ、このセクションは飛ばしても問題ありません。

サービス資格情報の取得

ログインするためのホスト名、ユーザーID、パスワードを取得するため、次のBluemix CLIで、ログインして、次のコマンドで、Db2のインスタンス名を取得します。

vagrant@vagrant-ubuntu-trusty-64:~$ bx cf services
Invoking 'cf services'...

Getting services in org takara9@gmail.com / space dev as takara9@gmail.com...
OK

name                      service   plan    bound apps   last operation
dashDB for Analytics-iq   dashDB    Entry                create succeeded

取得したインスタンス名に付与されているサービス資格情報の名前を取得します。

vagrant@vagrant-ubuntu-trusty-64:~$ bx cf sk "dashDB for Analytics-iq"
Invoking 'cf sk dashDB for Analytics-iq'...

Getting keys for service instance dashDB for Analytics-iq as takara9@gmail.com...

name
Credentials-1

次のコマンドで、Db2にログインするために必要な、すべての情報を入手出来ます。

bx cf service-key "dashDB for Analytics-iq" "Credentials-1"

clpplus (Db2コマンド・ライン・プロセッサ) のセットアップ

HOSTNAMEは、前述のサービス資格情報で得られたホストのドメイン名で置き換えて、実行します。

db2cli writecfg add -database BLUDB -host HOSTNAME -port 50001

次は、ラベルを設定します。 このラベルは、clpplus を実行する時に、ホスト名やポート番号と関連づけるために設定します。 dashとか短くて覚えやすいキーワードが良いと思います。

db2cli writecfg add -dsn LABEL -database BLUDB -host HOSTNAME -port 50001

さらに、SSLで接続することを指定するパラメータを追加します。

db2cli writecfg add -database BLUDB -host HOSTNAME -port 50001 -parameter "SecurityTransportMode=SSL"

これまで登録した情報を確認します。 LABELは前述で指定したもの、USERNAMEとPASSWORDは、サービス資格情報の該当項目に置き換えます。 このコマンドで、"[SUCCESS]"が表示されると、設定完了です。

db2cli validate -dsn LABEL -connect -user USERNAME -passwd 'PASSWORD'

Db2 へのログイン

以下のコマンで、ログインします。 USERNAME と LABEL は前述の db2cli validate と同じものを利用します。

clpplus -nw USERNAME@LABEL

CLPPlus: Version 1.6
Copyright (c) 2009, 2011, IBM CORPORATION.  All rights reserved.

Enter password: ************

Database Connection Information :
---------------------------------
Hostname = dashdb-entry-yp-dal09-08.services.dal.bluemix.net 
Database server = DB2/LINUXX8664  SQL11019 
SQL authorization ID = dash10598 
Local database alias = TKRDB 
Port = 50001 

SQL> 

テストデータ作成のSQL実行

のちにPHPのプログラムの動作を確認するために、確認用データを作っておきます。 次のSQL文をsetup.sql というファイル名で作成しておきます。

setup.sql
DROP TABLE animals;

CREATE TABLE animals (
     id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
     name VARCHAR(30) NOT NULL,
     PRIMARY KEY (id)
);

INSERT INTO animals (name) VALUES
    ('dog'),('cat'),('penguin'),
    ('lax'),('whale'),('ostrich');

COMMIT;

SELECT * FROM animals;

次のコマンドで、SQL文を実行して、テーブルを作成てデータをロードします。

SQL> start ./setup.sql  

これで、環境の準備が整いました。 今度は、PHPに組み込むドライバをビルドして、PHPの実行環境を設定します。

ODBCドライバのビルド

先ほど、phpenv install 5.6.31 を実行した際に、/tmp/php-build が作られ、tar形式のファイル、および、展開したフォルダーが存在しています。 このフォルダーは、/tmp の下に作られるので、再起動した後は消去されていますから、再起動後は、phpenv install 5.6.31 から再度実行しておきます。

odbc ドライバのソースコードは、/tmp/php-build/source/5.6.31/ext/odbc に展開されています。 このコードは、Db2以外のデータベースにも対応する様に書かれていますが、それ以外のコードを集めて全部入りODBCドライバーを作るのは大変なので、とりあえず、Db2専用のODBCドライバとするため、マクロ config.m4 を編集します。 編集内容は、Db2以外の部分を削除するだけなのですが、参考までに以下に添付しておきます。 それから、このマクロファイルに関して参考資料(5)にあります。

ext/odbc/config.m4
dnl
dnl $Id$
dnl

AC_DEFUN([PHP_ODBC_CHECK_HEADER],[
if ! test -f "$ODBC_INCDIR/$1"; then
  AC_MSG_ERROR([ODBC header file '$ODBC_INCDIR/$1' not found!])
fi
])


dnl
dnl configure options
dnl

PHP_ARG_WITH(odbcver,,
[  --with-odbcver[=HEX]      Force support for the passed ODBC version. A hex number is expected, default 0x0300.
                             Use the special value of 0 to prevent an explicit ODBCVER to be defined. ], 0x0300)

if test -z "$ODBC_TYPE"; then
PHP_ARG_WITH(ibm-db2,,
[  --with-ibm-db2[=DIR]      Include IBM DB2 support [/home/db2inst1/sqllib]])

  AC_MSG_CHECKING(for IBM DB2 support)
  if test "$PHP_IBM_DB2" != "no"; then
    if test "$PHP_IBM_DB2" = "yes"; then
      ODBC_INCDIR=/opt/ibm/dsdriver/include
      ODBC_LIBDIR=/opt/ibm/dsdriver/lib
    else
      ODBC_INCDIR=$PHP_IBM_DB2/include
      ODBC_LIBDIR=$PHP_IBM_DB2/$PHP_LIBDIR
    fi

    PHP_ODBC_CHECK_HEADER(sqlcli1.h)

    ODBC_INCLUDE=-I$ODBC_INCDIR
    ODBC_LFLAGS=-L$ODBC_LIBDIR
    ODBC_TYPE=ibm-db2
    ODBC_LIBS=-ldb2

    PHP_TEST_BUILD(SQLExecute, [
      AC_DEFINE(HAVE_IBMDB2,1,[ ])
      AC_MSG_RESULT([$ext_output])
    ], [
      AC_MSG_RESULT(no)
      AC_MSG_ERROR([
build test failed. Please check the config.log for details.
You need to source your DB2 environment before running PHP configure:
# . \$IBM_DB2/db2profile
])
    ], [
      $ODBC_LFLAGS $ODBC_LIBS
    ])
  else
    AC_MSG_RESULT(no)
  fi
fi


if test "no" != "$PHP_ODBCVER"; then
  if test "$PHP_ODBCVER" != "0"; then
    AC_DEFINE_UNQUOTED(ODBCVER, $PHP_ODBCVER, [ The highest supported ODBC version ])
  fi
else
  AC_DEFINE(ODBCVER, 0x0300, [ The highest supported ODBC version ])
fi


dnl
dnl Extension setup
dnl
if test -n "$ODBC_TYPE"; then
  if test "$ODBC_TYPE" != "dbmaker"; then
    PHP_EVAL_LIBLINE([$ODBC_LFLAGS $ODBC_LIBS], ODBC_SHARED_LIBADD)
    if test "$ODBC_TYPE" != "birdstep" && test "$ODBC_TYPE" != "solid"; then
      AC_DEFINE(HAVE_SQLDATASOURCES,1,[ ])
    fi
  fi

  AC_DEFINE(HAVE_UODBC,1,[ ])
  PHP_SUBST(ODBC_SHARED_LIBADD)
  PHP_SUBST(ODBC_INCDIR)
  PHP_SUBST(ODBC_LIBDIR)
  PHP_SUBST_OLD(ODBC_INCLUDE)
  PHP_SUBST_OLD(ODBC_LIBS)
  PHP_SUBST_OLD(ODBC_LFLAGS)
  PHP_SUBST_OLD(ODBC_TYPE)

  PHP_NEW_EXTENSION(odbc, php_odbc.c, $ext_shared,, $ODBC_INCLUDE)
else
  AC_MSG_CHECKING([for any ODBC driver support])
  AC_MSG_RESULT(no)
fi

これからODBCドライバをビルドしていく前に、phpのバージョンを指定しておきます。

phpenv global 5.6.31

config.m4 の準備ができたら、次のコマンドで、configureを生成します。

phpize

configureを実行して、Makefile を生成します。

./configure

次のコマンドで、odbcドライバーをコンパイルします。

make

最後に、phpの実行環境へインストールします。

make install

簡易の確認

次のコマンドで、参照している php.ini を編集できます。 このコマンドを実行して、ODBCドライバを追加します。

php configure 

次の様に行を追加します。

php.ini
 928 ; for on Linux 
 929 extension=odbc.so
 930 

モジュールが組み込まれるか確認するには、以下のコマンドです。 結果がodbcと表示されれば、PHP5系最新バージョンの Db2 ODBCドライバ のビルド成功です。

php -m |grep odbc

PDOドライバのビルド

次に、PDOドライバのビルドも実施します。 PDOドライバの説明は、参考資料(6)にあります。 PHPからDb2へPDOで接続するケースでは、PDOドライバは前章でビルドしたODBCドライバをラップして、PDOインタフェースを提供します。このため、Db2用のODBCドライバのビルドとインストールが前提となります。

PDO_IBMドライバは、参考資料(7)のリンクからダウンロードできます。

ダウンロードしたファイルは、Vagrant 仮想マシンとホストマシンの共用フォルダにおいて、仮想マシンの /vagrant からアクセスしてビルドします。

vagrant@vagrant-ubuntu-trusty-64:/vagrant$ pwd
/vagrant
vagrant@vagrant-ubuntu-trusty-64:/vagrant$ tar xzf PDO_IBM-1.3.4.tgz 
vagrant@vagrant-ubuntu-trusty-64:/vagrant$ cd PDO_IBM-1.3.4/

今回もM4マクロを編集して、コンパイルができる様にします。 編集箇所は、2箇所で、SEARCH_PATH に /opt/ibm/dsdriver を追加、ライブラリの配置で、lib32 に誤って引きづられるので、削除してしまいます。 参考までに、以下に編集後のconfig.m4 を添付しておきます。

config.m4
vagrant@vagrant-ubuntu-trusty-64:/vagrant/PDO_IBM-1.3.4$ cat config.m4
if test "$PHP_PDO" != "no"; then

PHP_ARG_WITH(pdo-ibm, for DB2 driver for PDO,
[  --with-pdo-ibm[=DIR] Include PDO DB2 support, DIR is the base
                            DB2 install directory, defaults to ${DB2DIR:-nothing}.
                            Set the PHP_PDO_IBM_LIB environment variable to set
                            the specific location of the DB2 libraries])

if test "$PHP_PDO_IBM" != "no"; then
  DSD_PATH=/opt/ibm/dsdriver  <---- 追加
  SEARCH_PATH="$DSD_PATH $PHP_PDO_IBM_LIB $PHP_PDO_IBM $DB2PATH $DB2DIR"   <--- 修正

  AC_MSG_CHECKING(Looking for DB2 CLI libraries)
  for i in $SEARCH_PATH ; do
<--- lib32,lib64 を削除 ---->
    AC_MSG_CHECKING([     in $i/lib])
    if test -r $i/lib/libdb2.so || test -r $i/lib/libdb2.a || test -r $i/lib/libdb400.a || test -r $i/lib/libdb2.dylib ; then
      LIB_DIR="$i/lib/"
      AC_MSG_RESULT(found)
      break
    else
      AC_MSG_RESULT()
    fi
  done

  AC_MSG_CHECKING([for DB2 CLI include files in default path])
  for i in $SEARCH_PATH ; do
    AC_MSG_CHECKING([in $i])
    if test -r "$i/include/sqlcli1.h" ; then
      PDO_IBM_DIR=$i
      AC_MSG_RESULT(found in $i)
      break
    fi
  done

  AC_MSG_CHECKING([for PDO includes])
  if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then
    pdo_inc_path=$abs_srcdir/ext
  elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then
    pdo_inc_path=$abs_srcdir/ext
  elif test -f $prefix/include/php/ext/pdo/php_pdo_driver.h; then
    pdo_inc_path=$prefix/include/php/ext
  else
    AC_MSG_ERROR([Cannot find php_pdo_driver.h.])
  fi
  AC_MSG_RESULT($pdo_inc_path)

  dnl Don't forget to add additional source files here
  php_pdo_ibm_sources_core="pdo_ibm.c ibm_driver.c ibm_statement.c"

  PHP_ADD_INCLUDE($PDO_IBM_DIR/include)
  PHP_ADD_LIBPATH($LIB_DIR, PDO_IBM_SHARED_LIBADD)
  PHP_ADD_LIBRARY(db2, 1, PDO_IBM_SHARED_LIBADD)

  case "$host_alias" in
    *aix*)
      CPPFLAGS="$CPPFLAGS -D__H_LOCALEDEF";;
  esac

  PHP_NEW_EXTENSION(pdo_ibm, $php_pdo_ibm_sources_core, $ext_shared,,-I$pdo_inc_path)

  ifdef([PHP_ADD_EXTENSION_DEP],
  [
    PHP_ADD_EXTENSION_DEP(pdo_ibm, pdo)
  ])

  PHP_SUBST(PDO_IBM_SHARED_LIBADD)

fi

fi

config.m4 の修正が完了したら、ビルドします。
phpize で configure を生成する。

vagrant@vagrant-ubuntu-trusty-64:/vagrant/PDO_IBM-1.3.4$ phpize
Configuring for:
PHP Api Version:         20160303
Zend Module Api No:      20160303
Zend Extension Api No:   320160303

configureを実行して Makefile 生成する。

vagrant@vagrant-ubuntu-trusty-64:/vagrant/PDO_IBM-1.3.4$ ./configure

コンパイルすることで、ソースから実行形式のコードを生成する。

vagrant@vagrant-ubuntu-trusty-64:/vagrant/PDO_IBM-1.3.4$ make

PHPの動的モジュールのディレクトリへコピーする。

vagrant@vagrant-ubuntu-trusty-64:/vagrant/PDO_IBM-1.3.4$ make install

こちらも、ODBCと同じ様に、phpenv configure で、 pdo_ibm.so を追加して、php -m で組み込みを確認してOKであれば終了です。

PHP ODBCでのアクセスのテスト

次のコードの ***** 部分を Bluemix から提供されるサービス資格情報で置き換えて、SSL接続でのテストができます。

     1  <?php
     2  
     3  $database = "BLUDB";
     4  $hostname = "****.bluemix.net";
     5  $user     = "*****";
     6  $password = "*****";
     7  $ssl_port = 50001;
     8  
     9  $driver  = "DRIVER={IBM DB2 ODBC DRIVER};";
    10  
    11  $ssl_dsn = "DATABASE=$database; " .
    12             "HOSTNAME=$hostname;" .
    13             "PORT=$ssl_port; " .
    14             "PROTOCOL=TCPIP; " .
    15             "SECURITY=SSL;";
    16  
    17  $conn_string = $driver . $ssl_dsn; # SSL
    18  
    19  #
    20  $conn = odbc_connect( $conn_string,$user,$password);
    21  if( $conn ){
    22      echo "Connection succeeded.\n";
    23  
    24      $sql = "SELECT id, name FROM animals";
    25      $resultset = odbc_exec($conn,$sql);
    26      while (odbc_fetch_row($resultset)) {
    27         $id = odbc_result($resultset,"id");
    28         $name = odbc_result($resultset,"name");
    29         print $id." ".$name."\n";
    30      }
    31      odbc_close($conn);
    32  
    33  } else {
    34    echo "Connection failed.\n";
    35    if (odbc_error()) {
    36      echo "I've found a problem: " . odbc_errormsg($conn);
    37    }
    38  }
    39 ?>

以下は実行結果です。 先に登録したデータがリストされているのが解ると思います。

php ./test2_odbc_ssl.php 
Connection succeeded.
1 dog
2 cat
3 penguin
4 lax
5 whale
6 ostrich

PHP PDOでのアクセスのテスト

前回、PHP PDOで Db2 on Cloud data warehouse (愛称 dashDB) は繋がるか? 失敗ケースで 最新バージョンのPHPからのPDO接続を断念したのですが、ここで、もう一度トライします。 PDOインタフェース用に書き直したコードが以下になります。もちろん、SSL接続です。

     1  <?php
     2  $host = "*****.bluemix.net";
     3  $port = 50001;
     4  $dbname = "BLUDB";
     5  $user = "*****";
     6  $pass = "*****";
     7  
     8  $dsn = "ibm:DRIVER={IBM DB2 ODBC DRIVER}".
     9         ";DATABASE=".$dbname.
    10         ";HOSTNAME=".$host.
    11         ";PORT=".$port.
    12         ";PROTOCOL=TCPIP".
    13         ";SECURITY=SSL;";
    14  
    15  $dbh = new PDO($dsn,$user,$pass);
    16  
    17  foreach($dbh->query('SELECT id, name FROM animals') as $row) {
    18      //print $row['id']."  ".$row['name']."\n";
    19      print $row[0]." ".$row[1]."\n";
    20  }
    21  $dbh = null;
    22  
    23  ?>

以下は実行結果です。

php test4_pdo_ssl.php 
1 dog
2 cat
3 penguin
4 lax
5 whale
6 ostrich

まとめ

PHPとPDOやODBC接続、また、SSL利用について、インターネットを検索してみたのですが、参考資料(8)〜(13)にある様な記事ばかりで、あまり参考にならない残念な記事ばかりで、相性が悪いと言った言葉で片付ける状況になっていることが解りました。 しかし、コンパイル環境を作るためのマクロを良く見直して適切なコンパイル環境を作ることで、PHPの5.6系、7系のバージョンで Db2とSSL接続するドライバをビルドできることが解りました。 次は CFコンテナにパッケージする方法を考えたいと思います。

参考資料

(1) Vagrantfile for The development environment of IBM Bluemix application https://github.com/takara9/bluemix-dev
(2) Qiita MacにVagrantとVirtualBoxを入れてみる http://qiita.com/you-me/items/3126e7f91ccdf4d8a873
(3) Qiita Windows上でVirtualBox+Vagrant+CentOSによる仮想環境構築 http://qiita.com/hiroyasu55/items/11a4c996b0c62450940f
(4) Git --distributed-is-the-new-centralized 1.5 使い始める - Gitのインストール https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-Git%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB
(5) PHPマニュアル UNIX 用のビルドシステム: config.m4 http://php.net/manual/ja/internals2.buildsys.configunix.php
(6) PHPマニュアル PDOドライバ http://php.net/manual/ja/pdo.drivers.php
(7) PECL PDO_IBM https://pecl.php.net/package/PDO_IBM
(8) 初めて PHP で ODBC を使ってみる https://www.ibm.com/developerworks/jp/opensource/library/os-php-odbc/index.html
(9) ODBC 64 ビット Windows および Linux に関する考慮事項 https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_61/rzaik/rzaikodbc64bitconsiderations.htm
(10) Linux または UNIX での IBM データ・サーバー製品のための PHP 環境のセットアップ https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_9.7.0/com.ibm.swg.im.dbclient.php.doc/doc/t0011926.html
(11) Configuring SSL for IBM Data Server Driver for ODBC and CLI https://www.ibm.com/developerworks/data/library/techarticle/dm-1512-ssl-data-server-driver-odbc-cli-trs/index.html
(12) GSKit 戻りコード https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_9.7.0/com.ibm.db2.luw.admin.sec.doc/doc/r0054271.html
(13) 初めて PHP で ODBC を使ってみる https://www.ibm.com/developerworks/jp/opensource/library/os-php-odbc/index.html