経緯
社内で使っている基幹システムが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
ついに、ここで挫折
追記
この記事を書いた後に、ふと我に返って下記の設定を消したらlaravel-ibmiも問題なく動きました…
(自分のアホさにビックリ)
でも、下記で書いた文字化けは解消せず…(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に挑戦。
こちらのパッケージでは、導入は問題なく出来ました。
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なんだ
というわけで、手動でccsid=1208
を追加してみたところ、とりあえずUTF-8になったものの半角カナ等が文字化けしたまま…
もはや、良く分からん
というわけで最終的な苦肉の策として、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が古い汎用機だから、と諦めずに使ってみるのも良いのではないでしょうか。