LoginSignup
12
12

More than 5 years have passed since last update.

LaravelでDB2/400のデータを使う方法(Windows環境)

Last updated at Posted at 2017-11-28

経緯

社内で使っている基幹システムがAS/400(IBM i)で稼働しています。
このデータを使った社内Webシステムを作りたい、というのがきっかけでした。

環境

  • Web/APサーバ(OS) → Windows Server 2012 R2
  • Webサーバ → Apache
  • Webフレームワーク → Laravel 5.5
  • DBサーバ → AS/400(V6R1)
  • DBMS → DB2/400

パッケージの選定

まずはこのサイトを「db2」というキーワードで検索しました。

最初に候補に挙がったのが、laravel-ibmiでした。
理由としては…データベースの操作以外にもTS::PgmCallという機能があり、既存のRPGプログラムを呼べることが魅力だったからです。(今回の要件にはなかったのですが、将来的な資産になりそうだったので…)

しかし! 結果としてこのパッケージは使えませんでした…
どうやら、下記の設定でエラー発生…

PDO::I5_ATTR_DBC_SYS_NAMING => false,

エラーコード

Undefined class constant 'I5_ATTR_DBC_SYS_NAMING'

調べてみるとpdo_ibmが必須なんだそうで…

それじゃあ、と張り切ってPDO_IBMを入手しにPECLを訪れてみるとWindows用のDLLは1.3.3までしかない。CHANGELOGを見ると、 PHP7のサポートは1.3.4からだって…orz
それでも、無理矢理に突っ込んでみると…案の定、失敗。

Unable to load dynamic library 'C:\\xampp\\php\\ext\\php_pdo_ibm.dll' - \xef\xbf\xbdw\xef\xbf\xbd\xe8\x82\xb3\xef\xbf\xbd\xea\x82\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbdW\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd[\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xc2\x82\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xdc\x82\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbdB\r\n in Unknown on line 0

ついに、ここで挫折:sob:


追記

この記事を書いた後に、ふと我に返って下記の設定を消したらlaravel-ibmiも問題なく動きました…
(自分のアホさにビックリ:anguished:)
でも、下記で書いた文字化けは解消せず…(sjisで文字を取得してしまう) うーん、何だろなー。

            PDO::I5_ATTR_DBC_SYS_NAMING => false,
            PDO::I5_ATTR_COMMIT => PDO::I5_TXN_NO_COMMIT,
            PDO::I5_ATTR_JOB_SORT => false,
            PDO::I5_ATTR_DBC_LIBL => '',
            PDO::I5_ATTR_DBC_CURLIB => '',

ならばと、laravel-iseriesに挑戦。
こちらのパッケージでは、導入は問題なく出来ました。:thumbsup:

laravel-iseriesの導入方法

導入の仕方としては上記のサイトに書いてある通りで、composer.json

"jacksonwebservices/laravel-iseries": "3.0.*"

を追加

composer update

を実行

app/config/app.php

'providers' => [
    JWS\Iseries\IseriesServiceProvider::class,
],

を追加して

config/database.phpに下記を追加します。

      'odbc' => [
            'driver'               => 'odbc',
            'driverName'           => '{iSeries Access ODBC Driver}',
             // General settings
            'host'                 => env('DB2_HOST'),
            'username'             => env('DB2_USER'),
            'password'             => env('DB2_PASSWORD'),
            //Server settings
            'database'             => env('DB2_NAME'),
            'prefix'               => '',
            'schema'               => env('DB2_DEFAULT_SCHEMA'),
            'signon'               => 3,
            'ssl'                  => 0,
            'commitMode'           => 2,
            'connectionType'       => 0,
            'defaultLibraries'     => '',
            'naming'               => 0,
            'unicodeSql'           => 1,
            // Format settings
            'dateFormat'           => 5,
            'dateSeperator'        => 0,
            'decimal'              => 0,
            'timeFormat'           => 0,
            'timeSeparator'        => 0,
            // Performances settings
            'blockFetch'           => 1,
            'blockSizeKB'          => 32,
            'allowDataCompression' => 1,
            'concurrency'          => 0,
            'lazyClose'            => 0,
            'maxFieldLength'       => 15360,
            'prefetch'             => 0,
            'queryTimeout'         => 1,
            // Modules settings
            'defaultPkgLibrary'    => 'HOGELIB',
            'defaultPackage'       => 'A/DEFAULT(IBM),2,0,1,0',
            'extendedDynamic'      => 1,
            // Diagnostic settings
            'QAQQINILibrary'       => '',
            'sqDiagCode'           => '',
            // Sort settings
            'languageId'           => 'JPN',
            'sortTable'            => '',
            'sortSequence'         => 0,
            'sortWeight'           => 0,
            'jobSort'              => 0,
            // Conversion settings
            'allowUnsupportedChar' => 0,
            'ccsid'                => 930,
            'graphic'              => 0,
            'forceTranslation'     => 1,
            // Other settings
            'allowProcCalls'       => 0,
            'DB2SqlStates'         => 0,
            'debug'                => 0,
            'trueAutoCommit'       => 0,
            'catalogOptions'       => 3,
            'libraryView'          => 0,
            'ODBCRemarks'          => 0,
            'searchPattern'        => 1,
            'translationDLL'       => '',
            'translationOption'    => 0,
            'maxTraceSize'         => 0,
            'multipleTraceFiles'   => 1,
            'trace'                => 0,
            'traceFilename'        => '',
            'extendedColInfo'      => 0,
            'options'  => [
                PDO::ATTR_CASE => PDO::CASE_LOWER,
                PDO::ATTR_EMULATE_PREPARES => false,
                PDO::ATTR_PERSISTENT => false
            ]

        ],

最後に、.env

DB_CONNECTION=odbc
DB2_host=AS/400のIP
DB2_user=接続用のUSER
DB2_PASSWORD=パスワード
DB2_NAME=dummy
DB2_DEFAULT_SCHEMA=初期スキーマライブラリ

を追加して完了。そこまで難しくはありませんでした。

未解決な事

ですが、さらに困難が待ち受けていました。なんと、日本語がShift-JISとしてデータ取得されてしまっています。
UTF-8で動かしたいのでこれは困る…
というわけで、optionのCCSIDに1208をしてみると…何と、何も変化しない。
何故!?というわけでソースを追うと、

<?php
namespace JWS\Iseries\Connectors;

use Illuminate\Database\Connectors\Connector;
use Illuminate\Database\Connectors\ConnectorInterface;

class ODBCConnector extends Connector implements ConnectorInterface
{

    public function connect(array $config)
    {
        $dsn = $this->getDsn($config);

        $options = $this->getOptions($config);

        $connection = $this->createConnection($dsn, $config, $options);

        if (isset($config['schema']))
        {
            $schema = $config['schema'];

          $connection->prepare("set schema $schema")->execute();
        }

        return $connection;
    }

    protected function getDsn(array $config) {
        extract($config);

        $dsn = "odbc:"
             // General settings
             . "Driver=$driverName;"
             . "System=$host;"
             . "UserID=$username;"
             . "Password=$password;"
             //Server settings
             . "Database=$database;"
             . "CommitMode=$commitMode;"
             . "ConnectionType=$connectionType;"
             . "DefaultLibraries=$defaultLibraries;"
             . "Naming=$naming;"
             . "AllowDataCompression=$allowDataCompression;"
             . "DefaultPkgLibrary=$defaultPkgLibrary;"
             . "DefaultPackage=$defaultPackage;"
             . "ExtendedDynamic=$extendedDynamic;"
             . "AllowUnsupportedChar=$allowUnsupportedChar;"
             . "ForceTranslation=$forceTranslation;"
             . "LibraryView=$libraryView;"
             . "Trace=$trace;"
             ;

        return $dsn;
    }

}

getDsnでCCSIDの指定してない!何のためのoptionなんだ:scream:
というわけで、手動でccsid=1208を追加してみたところ、とりあえずUTF-8になったものの半角カナ等が文字化けしたまま…
もはや、良く分からん:cry:

というわけで最終的な苦肉の策として、SJISをUTF-8に変換するFacadeを作ってView側で変換するという作りに…

<?php
namespace App\Services;
/**
 * 文字列操作用のファサード
 */
class ManipulateString{
    /**
     * DB2より日本語データを取得した時、SJIS+後ろスペース詰めと
     * なってしまうのでこれを整形するメソッド
     * @param string DB2/400より取得したSJISの文字列
     * @return string UTF8に変換後にトリムした文字列
     */
    public function convertToUtf8(string $string){
        return trim(mb_convert_encoding($string, 'utf-8','sjis-win'));
    }
}

解決策をご存知の方、コメントなど頂けると助かります。
まぁ、最終的には作りたいものは作れたのですがちょっと、課題の多いアウトプットとなってしまいました。

とはいうものの、これでLaravelとAS/400の接続が出来るようになりました。
AS/400が古い汎用機だから、と諦めずに使ってみるのも良いのではないでしょうか。

12
12
16

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12