iSeriesAccess for Linux の インストール
以前、Debian系にiSeriesAccess for Linuxをインストールした時に上手くいかず、投げ出したままだったので、CentOSで試した時のメモです。
IBMからは、rpmで提供されているので、環境としてはRHEL系を前提としている様です。
- 環境
- IBM i V5R4M0
- CentOS 5.5
- iSeriesAccess for Linuxのサイト
sudo rpm -hUv iSeriesAccess-5.4.0-1.6.i386.rpm libodbcinst.so.1 は iSeriesAccess-5.4.0-1.6.i386 に必要とされています libodbc.so.1 は iSeriesAccess-5.4.0-1.6.i386 に必要とされています libstdc++.so.5 は iSeriesAccess-5.4.0-1.6.i386 に必要とされています libstdc++.so.5(CXXABI_1.2) は iSeriesAccess-5.4.0-1.6.i386 に必要とされています libstdc++.so.5(GLIBCPP_3.2) は iSeriesAccess-5.4.0-1.6.i386 に必要とされています libstdc++.so.5(GLIBCPP_3.2.2) は iSeriesAccess-5.4.0-1.6.i386 に必要とされています libXm.so.3 は iSeriesAccess-5.4.0-1.6.i386 に必要とされています libXp.so.6 は iSeriesAccess-5.4.0-1.6.i386 に必要とされています
と足りないパッケージのオンパレードなので、
yum provides xxxxxxx.so.x
で結局たりないパッケージは以下の4つでした。
sudo yum install unixODBC-2.2.11-7.1.i386 compat-libstdc++-33-3.2.3-61.i386 openmotif22-2.2.3-18.i386 libXp-1.0.0-8.1.el5.i386 sudo rpm -hUv iSeriesAccess-5.4.0-1.6.i386.rpm
上記でインストールは完了しました。すんなり行きましたね。ibm5250というコマンドが/usr/binに出来ます。※ClientAccess(今は呼び方違うと思いますが)のライセンスが必要なようなのでご注意を。
5035の場合 : ibm5250 192.168.1.254 -LANG ja_JP -USE_CP5035 5026の場合 : ibm5250 192.168.1.254 -LANG ja_JP
コードページの設定は「-USE_CP5035」オプションで行えるようです。
暗黙スキーマの挙動の違い
PCからお手軽に、既存のIBM i(AS/400)のプログラムを呼び出す方法に、SQLのCALLを投げる方法があります。こんな感じで
■PC系の文法
CALL スキーマ名.プログラム名 ('引数','引数2')
CALL スキーマ名/プログラム名 ('引数','引数2')
通常自分は、ユーザーによって実行ライブラリが異なる可能性があるので、ライブラリ名(スキーマ名)を指定しません。スキーマ名を変数にしても良いのですが、AS/400の伝統的に暗黙のオープンというのがあります。暗黙オープンの方法としては...
- ユーザージョブの”ライブラリーリスト”に入れる。
- ”set schema ライブラリ名”をする。
が、考えられます。前者は、本番運用向きとは思いますが、開発の場合は環境毎にユーザーが変わるので、自分は後者の「set schema」を使っています。
この”暗黙のスキーマ”なのですが、PHPのDB2関数で、微妙にAS/400とPCで挙動の違いが有ったので、メモをしておきます。
AS/400(Zend Core for i5 2.6.1)の場合は、”set schema”でスキーマを指定すれば、暗黙でプログラムをcall出来ます。しかし開発用PC(Zend Server CE 4.0)から発行されたSQLの場合には、次の様なメッセージが返されました。
call hoge ('fuga') SQL0204N "ユーザ名.hoge" は未定義の名前です。 SQLSTATE=42704
PHPのDB2関数かDB2 Connectなのか分かりませんが、暗黙のスキーマが見つからない場合は、自動でユーザー名を明示的スキーマに置き換えます。(間違って存在していて勝手にプログラムが動かれても困りますが...。)
今回は対応方法として、AS/400のプログラムをストアドプロシージャ定義する事にしました。方法は以下の通りです。
-
- OPMプログラムならばILE化する。(OPMだとストアド情報の保管・復元が出来ないため)
- ”create procedure”で、プログラムをストアド定義する。
■ストアド定義SQLの例(※CLプログラムで5バイト文字列の引数を1つ取る場合)
CREATE PROCEDURE スキーマ名/プロシージャ名(IN 引数名 CHAR (5 )) LANGUAGE CL NOT DETERMINISTIC CONTAINS SQL EXTERNAL NAME ライブラリ名/プログラム名 PARAMETER STYLE GENERAL
-
- 実行時に”set path スキーマ名”で関数パスを指定して、プロシージャ名をcallで呼びだす。
OPMをILE化するのは、SAVLIBやRSTLIBでストアド定義の情報が反映されないからです。検証してわかったのですが、プログラムのリネームや削除、ライブラリのリネームをしてもストアド情報と同期はされません。プログラムをSAVOBJ,RSTOBJしても同様に、ストアド情報は同期されませんでした。但し、ライブラリを削除した時だけは、ストアド情報も消えるようです。ライブラリを保管→ライブラリ削除→ライブラリ復元だと、ストアド情報も同期された状態で、復元しました。この事から、ILEオブジェクトの何処かに、ストアドに関するメタ情報を持っていると思うのですが、何処にあるか見つける事が出来ませんでした。(DSPPGMなどには無かった)
※追記:その後、DMPOBJコマンドでメタ情報を確認出来ました。SQL文が丸ごと残ってます。
ちなみに、OPMでストアド定義すると、プロシージャは作成されますが、その旨の警告メッセージが出力されました。
■注意書き(※DB2 Universal Database for iSeries SQL 解説書より)
*PGM オブジェクトが保管された後、このシステムや別のシステムに復元すると、カタログはそれらの属性を使用して自動的に更新されます。 外部プロシージャーの場合は、次の制約の範囲内で属性を保管することができます。 ・ 外部プログラム・ライブラリーは、QSYS であってはなりません。 ・ 外部プログラムは、CREATE PROCEDURE ステートメントの発行時に存在していなければなりません。 ・ 外部プログラムは、ILE *PGM オブジェクトか*SRVPGM オブジェクトにする必要があります。 オブジェクトを更新できない場合でも、それにかかわらず、プロシージャーは作成されます。
これでプロシージャ名を呼び出せば、AS/400でもPCでも暗黙的にプログラムを呼び出す事が出来ます。
但しこの場合は、プログラム名の呼出と違って、AS/400でも”set path”で関数パスを指定する必要があります。ちなみに、ジョブのライブラリーリストに入っていれば、”set path”は不要です。本番運用ならばライブラリーリストでやるのが、一番楽チンかもしれませんネ。
ストアドプロシージャ定義の一覧を確認するには、次のSQLを投げると確認出来ます。
select * from sysroutines where specific_schema = 'スキーマ名'
トランザクション分離レベル・省略値の違い
以前は、IBM i(AS/400)上のZend Coreにデプロイしてテストやリモートデバッグをしていたのですが、最近は、Windowsのローカル環境に立てた、Zend Server for Windowsでテストやデバッグをしてから、AS/400にデプロイしています。一人チーム開発なので、人のソースとマージしたりする事もないですし、この程度の事でも、実はソースコードのバックアップの代わりにもなったりします。(※ちゃんと正規のバックアップはしていますよ。モチロン...。)
Zend Server for Windowsを使っていて、気づいた違いについてメモを残しておきます。(「今頃、遅いよ!」と言うツッコミは無しの方向で...(-_-;)ゞ)
普段AS/400をメインで使っていると、STRSQLやSQLRPGも省略のトランザクション分離レベルが「*NC(即時コミット)」です。Zend Core for i5を使っていても省略は即時コミットです。たまーに、VBやらでODBC使うときは、「*CS(コミットされていない読取)」と言うことを思い出して、ODBCドライバの設定を「*NC」にするか、ジャーナル処理を「STRJRNPF」で開始しておきます。そうしないと、追加更新時に、”ジャーナル処理されてないお。”エラーで怒られます。ちなみにADOだと意識しなくても追加更新できるので省略が「*NC」と言うことになってるのだと思います。
■ODBCの省略
本題ですが、Zend Core i5からZend Server for Windowsに移しただけで、特に動作なども問題のないアプリだったので、何も考えずテストしていたら、エントリー系のレコード追加更新で何処かで見たようなメッセージで怒られました。こんな感じのメセージです。
[IBM][CLI Driver][AS] SQL7008N REXX 変数 "TABLE NAME " に矛盾したデータが入っています。 SQLSTATE=55019 SQLCODE=-7008
「ジャーナル処理されてないよ。」というストレートなメッセージにして欲しいのですが、どうやらこのメッセージが”ジャーナル処理されてないよ”という事みたいで、DB2 ConnectのCLI接続もODBCと同様に省略が「*NC」ではなく「*CS」の様です。
- トランザクション分離レベルの設定で考えられそうな対処方法
まず(1)の方法ですが、対処としはジャーナルを作る事も、それはそれでアリですが、通常それ程クリティカルな要件で無い場合に、ジャーナル処理はレシーバーのオモリやリソースの消費も含めて考えると、必要では無いケースもあります。方法としては「CRTJRNRCV」→「CRTJRN」→「STRJRNPF」でジャーナルを開始します。確かにジャーナルがあると、万が一の時に、ある時点に戻る事が出来るので、トラブル時には威力を発揮してくれる事は確かでしょうが...。
■STRJRNPF
次に(2)の「db2cli.ini」でオプションを追加して、データベースカタログ単位で、分離レベルの省略を設定する事が可能です。以下が設定例です。これが一番簡単で、i5とも同期が取れるので、今回はこれを採用しました。
■「db2cli.ini」
; TXNISOLATION=1|2|4|8|32(UR|CS|RS|RR|NC 省略はCS。32はDB2 for iの即時コミット。) [カタログ名] DBALIAS=カタログ別名 TXNISOLATION=32
テキストファイルを直接変えてもいいですし、DB2の構成アシスタントで、選択(S)メニューのCLI設定でも変更する事が出来そうです。(自分は調子悪くてDB2のGUI画面は砂時計のまま動きませんでした。)
(3)と(4)は直接SQLの発行で、指定する方法ですが、(3)に関しては上手くいくかと思いきや、駄目でした。AS/400のSTRSQL等では勿論実行できますし、i5版ですとそういった解説もあるので、もしかしたらWindows版のDB2 Connectを使っているなど、実行環境による差異が幾分ありそうです。ちなみに返されたメッセージは以下の通り、
[IBM][CLI Driver][AS] SQL0525N セクション = "1" パッケージ = "SYSSH200 " 整合性トークン = X"NULLID" のバインド時にエラーが発生したため、SQL ステートメントは実行できません。 SQLSTATE=51015 SQLCODE=-525
(4)は問題なく実行されました。ちなみに「php.ini」の”ibm_db2.i5_allow_commit ”は”0(no commit)”になっていますが、(※「i5_allow_commit」は、OS/400上のZend CoreやZend Serverにしか有効でない設定だからでした。)(2)も(4)でコミットもロールバックも出来ているので、DB2 ConnectのCLI設定が優先されている模様です。(トランザクション処理を使う場合は、autocommitオプションをOFFする必要があります。)
db2_connect()関数のオプションに”i5_commit=DB2_I5_TXN_NO_COMMIT”がありますが、これを指定してもジャーナルが開始されていないと、エラーが返されました。まだ色々と試す時間が無かったので、検証しきれていませんが、今後トライしてみて、さらに実態がつかめればと思います。
ZendServer CEの環境変数
ローカルになんちゃって、IBM i(AS/400)の環境を作りたくて(個人では買えないですから...)、DB2 for WindowsとZend Sever CE 5.0 for Windowsを入れました。
そもそも、イケない感じはしていたのですが、DB2の入れた順序が悪いらしく、
の順で入れたら、変な挙動をして、一旦アンインストールと思い実行したのですが、待てど暮らせど終了せず、途中で失敗してからは、それはもう最悪の状況になりました。仕方なくレジストリを、地道に修正して、ようやく復帰しました。
今度は、バージョンの古い順に入れたら、おかしな動きはなくなりました。
DB2 V9以降は、複数のDB2を入れても、DB2_COPYという状態で、複数のインストールが出来ます。
DB2には、デフォルトDB2コピーの切り替えが可能な”デフォルトDB2選択ウィザード”([プログラム]→[IBM DB2]→[セットアップ・ツール]→[デフォルトDB2選択ウィザード])が、付属していて、システム環境変数やレジストリを書き換えてくれるようです。
無事切り替えてから、ヤレヤレとホットしたのもつかの間、PHPのアプリケーションでやりたかった、ローカルのDB2 Winの参照が出来ず、DB2 iを参照してしまいます。再起動しても何をしても結果は変わらず、システム環境変数の”PATH”も”DB2INSTANCE”もDB2 Winに変わっているのに...。
”var_dump($_SERVER)”で、環境変数を調べてみると、”PATH”がDB2 iのモジュールに通っている。プロセスブラウザで”Apacheのプロセス(httpd.exe)”を見てももちろん同じ、他のプロセスを見ると、現在のシステム環境変数になっているのにと、そんな状況。
httpd.confに何かあるのか?SetEnvとかしなきゃ駄目?→何もない..。
zend.confに何かあるのか?→何もない..。
php.iniに何か有るのか?→何もない..。
ZendEnablerConf.xml?→Coreには、なかったUTF-8でBOMがエラーで、インストール時のデフォルトでコケたぐらいのファイル。自分が認識が甘かった...。orz
ここにモロに、環境変数が記述してあります。こんな感じで...。
<Environment> <Variable name="DB2INSTANCE" value="DB2" /> <Variable name="PHP_FCGI_MAX_REQUESTS" value="10000" /> <Variable name="TEMP" value="C:\DOCUME~1\ushida\LOCALS~1\Temp" /> <Variable name="PHPRC" value="C:\Program Files\Zend\ZendServer\etc" /> <Variable name="PATH" value="...;C:\Program Files\IBM\SQLLIB\BIN;..." /> </Environment>
”DB2INSTANCE”と”PATH”を変更したら、無事ローカルのDB2 WinとDB iの切り替えが出来ました。これで同じカタログのデータベースを作成すれば、ローカルだけで開発とデモが出来そうです。(X60が頑張りすぎで、ソロソロやばいかもしれません)
あとはデータをDB2 iからDB2 Winへ簡単にレプリケーション出来ないかなぁ?
手動でエクスポート&インポートって何だか原始的だし
Zend Server CE 4.0.6 for Winを入れてみた
Zend Server CE(Community Edition)4.0.6をWindows環境に入れて、IBM i(AS/400)のDB2とゴタゴタやったので、メモしておきます。
■動作環境
- IBM i V5R4M0
- Windows XP SP3
- Zend Server CE 4.0.6 (PHP 5.2.11) for Windows
- DB2 Connect Personal Edtion V9.1 for Windows
DB2 Connectのセットアップ
- DB2ランタイムで躓き...
これは、結果論で分かったのですが、Zend Server(以下ZS)には、DB2のランタイムがバンドルされていて、ZSインストール時に導入されます。しかしランタイム版は”Unix,Linux,Windows”のDB2を対象としている様で、”DB2 for i”は対象外の様です。以下のエラーが投げられました。
---- 接続文字列 ---- 「DRIVER={IBM DB2 ODBC DRIVER};DATABASE=カタログ名;HOSTNAME=ホストIP;PORT=446;PROTOCOL=TCPIP;UID=ユーザー名;PWD=パスワード;」は接続出きません。 ---- db2_conn_errormsg()の内容 ---- [IBM][CLI Driver] SQL8002N Connect processing failed; a valid product license was not found. SQLSTATE=42968 SQLCODE=-8002
AS/400と同時提供されている”DB2 Connect Personal Edtion”を入れる必要がありました。
IBMよりCDが提供され入るので、32bit Windwos版のインストールを行ないます。
インストール自体は、フルインストールにして、特に難しいところはありません。
- カタログの作成
[スタート]→[プログラム]のDB2から、[セット・アップツール]→[構成アシスタント]を選び、カタログを構成します。
構成を追加するか?訪ねられるので”はい”を選びます。ウィザードを以下スナップショットの手順で、進めます。
ちなみにデータベース名は「WRKRDBDIREコマンド」で確認して、”*LOCAL”になっている項目です。
以下の設定が終わると、[管理ツール]の[データソース]でシステムDSNに、カタログが作成されています。
- db2cli.lstのバインド
DB2のコマンドウィンドウでcliのバインド事前にしておく必要があります。しておかないと、DB2接続で以下のエラーが発生しました。
------------------------------------------- [IBM][CLI Driver][AS] SQL0805N パッケージ "NULLID .SYSSH200" が見つかりませんでした。 SQLSTATE=51002 -------------------------------------------
■cliのバインド
※参考(https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.qb.dbconn.doc/doc/c0005595.html)
C:\Program Files\IBM\SQLLIB\BIN> db2 connect to カタログ名 user ユーザ名 using パスワード C:\Program Files\IBM\SQLLIB\BIN> cd ../bnd ※DB2 LUWの場合は以下を実行 C:\Program Files\IBM\SQLLIB\bnd> db2 bind @db2cli.lst blocking all grant public C:\Program Files\IBM\SQLLIB\bnd> db2 bind @db2ubind.lst blocking all grant public ※IBMiの場合は以下を実行 db2 bind @ddcs400.lst blocking all grant public (実行後に”NULLID”の中にSYSオブジェクトが作成される)
DB2クライアントのエンコーディングが、ローカル環境がデフォルトになるようで、DB2関数で返される結果が、SJISになって文字化けしました。以下のコマンドをDB2のコマンドウィンドウで実行して、エンコーディングをUTF-8(CCSID 1208)にします。
db2set db2codepage=1208 ---- 確認 ---- db2set -all
Zend Server CEのセットアップ
Zend.comより「Zend Server CE 4.0.6」のWindowsインストーラより導入します。
フルインストールをしないと、IBM系のExtension(ibm_db2,pdo_ibm)はインストールされないので、フルインストールします。最後に前述で入れたDB2 Connectについて、「既知のDB2 Clientがあるよ」と言われます。
- ZendEnablerConf.xmlの修正
”C:\Program Files\Zend\ZendServer\etc\ZendEnablerConf.xml”の先頭に壊れたデータが入っています。この壊れたデータを除去します。この壊れたデータの影響で、http://localhost:89/ZendServer/ の表示が500 Internal Server Error になります。id:satoruyoshidaさんのこちらの日記で解決させて頂きました。助かりました。
新しい管理用UIは、設定変更時のリスタートもその場で出来るなど、使い易くて良い感じです。
php.iniやhttpd.confを適宜直して、実行すればWindwos Zend Serverの出来上がり?
DB2関数の接続は、カタログ接続の場合は、i5と全く同等です。「*LOCAL」を使わずカタログ名にしておけば、そのままソースを変更する事なく動作します。以下の様な感じです。
<?php /* // 非カタログ接続 $database = 'CSC2008'; $user = 'name'; $password = '****'; $hostname = '192.168.xxx.xxx'; $port = 446; // WRKRDBDIREで確認。デフォルトの*DRDAは「446」 $conn_string = "DRIVER={IBM DB2 ODBC DRIVER};DATABASE=$database;" . "HOSTNAME=$hostname;PORT=$port;PROTOCOL=TCPIP;UID=$user;PWD=$password;"; $db = db2_connect($conn_string, '', ''); */ // カタログ接続 $conn_string = "CSC2008"; //カタログ名 $db = db2_connect($conn_string, 'name', '****');
しかし、「ibm_db2.i5_dbcs_alloc=1」を設定してやっても、i5だと半角カナが切れないのに、Windowsだと半角カナが切れてしまいます。(UTF-8で3バイトで認識されて、フィールドのバイト数にあたる文字数になってしまう)これは未解決のままです。
一応ベンチマーク
以前i5でやったベンチマーク同じ条件でやったら、若干遅くなりました。
■DB2関数
time index | ex time | % | |
Start | 1266922322.48437600 | - | 0.00% |
DB2 Start select | 1266922322.48439700 | 0.000021 | 0.00% |
DB2 End select | 1266922323.98632900 | 1.501932 | 23.22% |
DB2 Start insert | 1266922323.98635800 | 0.000029 | 0.00% |
DB2 End insert | 1266922328.55809400 | 4.571736 | 70.68% |
DB2 Start update | 1266922328.55812600 | 0.000032 | 0.00% |
DB2 End update | 1266922328.95244900 | 0.394323 | 6.10% |
Stop | 1266922328.95247100 | 0.000022 | 0.00% |
total | - | 6.468095 | 100.00% |
■PDO
time index | ex time | % | |
Start | 1266922241.96875100 | - | 0.00% |
PDO Start select | 1266922241.96878100 | 0.000030 | 0.00% |
PDO End select | 1266922243.73359700 | 1.764816 | 26.03% |
PDO Start insert | 1266922243.73362300 | 0.000026 | 0.00% |
PDO End insert | 1266922248.34333000 | 4.609707 | 67.98% |
PDO Start update | 1266922248.34335400 | 0.000024 | 0.00% |
PDO End update | 1266922248.74953300 | 0.406179 | 5.99% |
Stop | 1266922248.74956500 | 0.000032 | 0.00% |
total | - | 6.780814 | 100.00% |
先日行って来た、OS協議会のお話ですと、これからAS/400にもZend Serverがプリインストールされるみたいです。
Zend Framework Controllerメモ
Zend_Controllerを使ってみた時のメモを残しておきます。
httpd.confの設定
Zend Framework(ZF)では、URL変換に”mod_rewrite”モジュールを使用しているので、「/usr/local/Zend/apache2/conf/httpd.conf」を以下の様に書き換えます。
#LoadModule rewrite_module modules/mod_rewrite.so ↓ LoadModule rewrite_module modules/mod_rewrite.so
ちなみに、”Zend Core 2.6.1”はデフォルトでモジュールが有効になってました。”.htaccess”を有効にする為に、”
# ルートの設定 <Directory /> Options FollowSymLinks AllowOverride None </Directory> # ドキュメントルートの設定 <Directory "/www/zendcore/htdocs"> Options Indexes FollowSymLinks # AllowOverride None ↓ AllowOverride All Order deny,allow Deny from all Allow from 127.0.0.1 </Directory>
.htaccessの設定
Zend StudioのZend Frameworkプロジェクトで作成すると以下の構造になり、コントローラ、ビューの雛形や.htaccessもデォルトで用意されますので、それを適宜変更します。
■デフォルトの.htaccess
RewriteEngine On RewriteCond %{REQUEST_FILENAME} -s [OR] RewriteCond %{REQUEST_FILENAME} -l [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^.*$ - [NC,L] RewriteRule ^.*$ index.php [NC,L]
Controllerを使う
-
- フロントコントローラの準備。(e.g. PROJECT_HOME/public/index.php)
- Zend_Controller_Actionのサブクラスのアクションコントローラを準備。(e.g. PROJECT_HOME/application/controllers/IndexController.php)
- 継承されるメソッド
- init : コントローラの初期化の実装をオーバーライド
- preDispatch : Actionメソッド実行前のフックの実装をオーバーライド。
- postDispatch : Actionメソッド実行後のフックの実装をオーバーライド。
- _forward(アクション, クラス=null, モジュール, 引数) : アクション実行後にフォワード。preDispatchで行った場合は、アクションがキャンセルされる。(e.g. $this->_forward("hogehoge","hoge")<=> "/hoge/hogehoge" )
- _redirect(URI) : URIへリダイレクトする。(e.g. $this->_redirect("/hoge/hogehoge"))
- Viewを準備。(e.g. PROJECT_HOME/application/views/scripts/index/index.phtml)
- 命名規則
- URIにコントローラとメソッドを指定しない場合のデフォルト
- アクションコントローラ : 「IndexController.php」(setDefaultControllerNameで変更可)
- アクションメソッド : 「indexAction」(setDefaultActionで変更可)
■フロントコントローラの例
<?php require_once 'Zend/Controller/Front.php'; /* Zend_Controller_Front::run("../application/controllers"); ↑は↓と同意 $front = Zend_Controller_Front::getInstance(); $front->setControllerDirectory("../application/controllers"); $front->dispatch(); */ $front = Zend_Controller_Front::getInstance(); $front->setControllerDirectory("../application/controllers"); // 独自のデフォルトコントローラとデフォルトメソッドを指定する場合 /* $front->setDefaultControllerName("hoge"); $front->setDefaultAction("hogehoge"); */ $front->dispatch();
■アクションコントローラの例
<?php require_once 'Zend/Controller/Action.php'; require_once 'Zend/Date.php'; class hogeController extends Zend_Controller_Action { public function init() { /* 初期化処理をここに記述する。コンストラクタの後に実行される */ $this->view->assign("message","初期化を行いました。"); $this->view->assign("message3","forwardするとコントローラの初期化で消える"); } public function preDispatch(){ /* アクションの呼出前に実行する処理 */ } public function postDispatch(){ /* アクションの呼出後に実行する処理 */ $this->view->assign("message4","アクションを実行しました。"); } public function indexAction() { $this->view->assign("actionname","indexアクションです。"); $this->view->assign("message3","forwardするとこのメッセージは消される。"); $date = new Zend_Date(); $this->view->assign("dt",$date->get(Zend_Date::TIMES)); if(($date->compare("09:00:00",Zend_Date::TIMES) < 0) || ($date->compare("17:00:00",Zend_Date::TIMES) > 0)){ $this->view->assign("message2","9〜17時以外は稼働時間外です"); // 条件によって、別のアクションにフォワードする例 // forward(アクション名,コントローラ名,モジュール名,パラメータ) $this->_forward("hogehoge"); }else{ $this->view->assign("message2","システム稼働中"); } } public function hogehogeAction() { $this->view->assign("actionname","hogehogeアクションです。"); } }
■ビューの例
<html> <head> <title>タイトル</title> </head> <body> アクション名:「<?php echo $this->escape($this->actionname);?>」<br/> 現在の時刻は「<?php echo $this->escape($this->dt);?>」です。<br/> <?php echo $this->escape($this->message);?><br/> <?php echo $this->escape($this->message2);?><br/> <?php echo $this->escape($this->message3);?><br/> <?php echo $this->escape($this->message4);?><br/> </body> </html>
Zend Core for i5で国際化&ローカライズ
IBM i(AS/400)の5250アプリで、多言語対応する場合は、”*MSGF”を使ったり、画面制約に縛られたりで、実装も保守も個人的には「面倒だ」というネガティブなイメージがあります。(中には画面やメニューだけ別言語で書き直して、OVRDSPFなんてのもあります。)
しかし、海外拠点を持つカスタマー(特にアチラコチラに散在しているケース)からは、「今後どこの国に進出するか判らないけど(現在は主に中国、東南アジアやヨーロッパだったり)、アプリケーションは多言語対応したい」との要望を寄せられるケースもあります。そこで、”Zend Core for i5”に、デフォでバンドルされている、”Zend Framework(ZF)”の機能の1つ、”Zend Translate”を使って国際化&ローカライズを試してみました。
■サーバー環境
-
- OS:IBM i V5R4M0
- Zend Core for i5 2.6.1
- Zend Framework 1.10.0
■クライアント環境
-
- OS:Windows XP SP3
- Zend Studio i5 Edtion 7.0.2
- Poedit-1.4.5
■参考サイト
最新Zend Frameworkの導入
Zend CoreにデフォでバンドルされているZFは、”1.6.0”だったので、最新の”1.10.0”にしました。"Zend Frameworkの公式サイト"から手に入れる事が出来ます。
アーカイブをダウンロードしたら、AS/400のIFS上の適当なディレクトリで解凍して、php.ini(/usr/local/Zend/Core/etc/php.ini)の”include_path”に、「/usr/local/Zend/ZendFramework-1.10.0/library」を追加します。これで、”require”などで「Zend/フレームワーク名」で使えるようになります。
PHPプログラムの準備
”Translate”の大まかな使い方は、以下のステップです。
-
- 「require_once 'Zend/Translate.php'」でインクルード。
- Zend_Translateのインスタンス(※以下”$tl”)を作成。この際にコンストラクタで、翻訳アダプタ、翻訳されたリソースのパス、ローケルを指定します。翻訳アダプタは様々なフォーマットが使える様に柔軟に出来ているようです。今回はgettextで試しました。
- Array
- CSV
- gettext(*.mo)
- ini
- TMXなどなど...
- 追加のローケルがあれば、$tl->addTranslationメソッドで、翻訳リソースとローケルを追加する
- ローケルを設定しなければ、デフォルトローケルが使われます。明示的に設定する場合は、$tl->setLocaleメソッドを呼び出します。
- $tl->_メソッドで言語を変換。
翻訳ファイルの準備
gettextのソースファイルpoを編集可能な”poEdit”を使います。導入はインストーラまかせで、特に何もありません。初回起動時に言語の選択等があります。
起動後、phpのソースファイルを元に、翻訳用のカタログを作成します。[ファイル]→[新規カタログ]を選びます。
[情報]タブで、必要な項目を以下の様に入力します。
[パス]タブでは、[ベースパス]に環境依存のパスを指定します。今回の場合はZend Studioのワークスペースまでのパスとします。[パス]には、翻訳対象となるソースが存在するパスを指定します。
[キーワード]タブは、翻訳対象となるメソッドを登録します。デフォルトで”_”が存在するので特にする事はありません。OKボタンを押して、保管先を指定すればpoファイルが作成されます。
あとは、対訳をえっちらおっちらと、入力します。デフォルトで、”poファイル”を保存すれば、同じディレクトリに”moファイル”が作成される設定になってます。
元のPHPソースに変更が合った場合は、[カタログ(A)]→[ソースから更新(U)]を行うか、ツールバーにある地球マークをクリックすれば、poファイルをマージします。
翻訳リソースのmoファイルを、Zend Studioに適宜配置します。(PROJECT_HOME/languages/jp/message_jp.moなど)
以下が今回のサンプルプログラムです。
■ ZendTranslate.php
<?php require_once 'Zend/Translate.php'; // Zend Transelate $translate = new Zend_Translate("gettext","./languages/en/messages_en.mo","en"); $translate->addTranslation("./languages/ja/messages_ja.mo","ja"); echo "これは英語\n"; $translate->setLocale("en"); print $translate->_("Example") . "\n"; print "=======\n"; print $translate->_("Here is line one"). "\n"; $format = $translate->_("Today is the %1\$s.%2\$s.%3\$s"); printf($format . "\n" , date("m"),date("d") ,date("Y")); print $translate->_("Here is line two") . "\n"; print "\n"; echo "ここから日本語\n"; $translate->setLocale("ja"); print $translate->_("Example") . "\n"; print "=======\n"; print $translate->_("Here is line one"). "\n"; $format = $translate->_("Today is the %1\$s.%2\$s.%3\$s"); printf($format . "\n" , date("m"),date("d") ,date("Y")); print $translate->_("Here is line two") . "\n";
番外編:gtedプラグイン
Eclipseのpluginの”gted”も試してみました。”http://gted.sourceforge.net/update”を、Zend Studioの[Help]→[install New Software]から導入します。
導入後に[Preferences]→[gted]→[gettext Tools]で、”poEdit”のインストールディレクトリにある”bin”ディレクトリを指定します。
プロジェクトを右クリックして[Properties]→[gted Settings]を適宜設定します。
プロジェクトを右クリックして[gted]→[Update PO Files]を行うと、プロジェクト内のソースからpoファイルが作成されます。ただ一見するとマージ機能等はなさそうなので(※自分が機能を探しきれてないだけかも知れませんが...)、poEditの方が使い勝手は良いような気がします。ただ参照と編集だけの用途ならば、十分にも思えます。po専用のエディタは縦横2タイプのGUIビューとコードエディタが選べます。
結局この後、[Preference]→[General]→[Editors]→[File Associations]で、”*po”と”*pot”のデフォルトエディタを、外部エディタで”poEdit”に変更しました。