db2_prepare & db2_executeの怪
PHPでDB2のテーブルにSQLを投げる際に、代表的な関数が2つあります。
- もう1つは
「db2_exec」は1回のアクションで、結果を取るのに対して、「db2_prepra」はSQLを事前コンパイルし、DB2用に最適化後に、「db2_execute」でSQLを実際に投げるという最低2アクションがあります。(パラーメタArrayの代わりに、db2_bind_parmを使うことも出来ます。)
どちらかを使用用途に合った形で使えば良いのですが、「db2_prepra」方だけ、不思議な現象が起きるのです。
IBM i(AS/400)のDB2には文字列のデータ属性が幾つかあります。以下が代表的なモノです。
- A:SBCSのみ
- O:SBCS,DBCS混合
- J:DBCSのみ(先頭桁にx'0E'と最終桁にx'0F'が強制的に挿入される)
- G:DBCSのみ(x'0E'とx'0F'を扱わないDBCSフィールド)
この内”G”は、殆使う機会もないので、試してないのですが、”J”に関して言うと、「db2_prepra」だと、正しいSQLの結果が得られないのです。「db2_exec」だと問題なく結果が得られるのに...。:-(
そういう仕様なのか?不具合なのか?は、不明ですが、”J”フィールドを使われている方は、困るかもしれませんね。
自分は、強制的に入る、シフトイン・シフトアウトがどうも好きになれないので、あまり使う機会がないのですが。
AMFPHPを使ってdb2_connectなどのエラーハンドル
「AMFPHPを使って、db2_connect(phpのDB2用関数)などのエラーハンドルが、AMFPHPのメッセージになってしまうけど、どうしてる?」という質問を受けたので、こんな感じにしてますというのを載せておきます。
■[db2_connect()]
$db=db2_connect($dbname,$dbuser,$dbpwd,$option); // 接続エラー if(!$db){ $message = "db2_connectでエラー -> <". date('Y/m/d H:i:s') .">" .db2_conn_errormsg() . "\n"; error_log($message, 3, '/var/tmp/AS400ConnectionError.log'); return $message; }
■[db2_exec()]
$sql="select * from {$dbfile} fetch first 15 rows only "; // SQL処理はAMFPHPでエラーをthrowしてくる try { $result = db2_exec($db,$sql); } catch (Exception $e) { // SQLエラー if(!$result){ $message = "db2_execでエラー -> <". date('Y/m/d H:i:s') .">\n" .db2_stmt_errormsg() . "\n" .$e->__toString() . "\n"; error_log($message, 3, '/var/tmp/AS400SQLStatementError.log'); db2_close($db); return $message; } }
■[Flex側]
private function onResult(etc:*):void { if (typeof etc == 'object') { dataList = new ArrayCollection(etc); } else { Alert.show(etc.toString()); //エラー } }
”db2_connect”も”db2_exec”も関数でエラーが起きても”false”が返されるだけとなっているが、実際エラーを起こしてみると、”db2_connect”は”flase”に対する処理だけで問題ないのですが、SQLに関わるエラー(db2_prepareも同じ)は、AMFPHPがExceptionをスローしてきます。その為、”try〜catch”が必要になってくるようです。
結局エラーハンドルといっても、PHPの処理はFlexからすると、ただのサービスのなので、「仮に結果がエラーだとしても、メッセージとして受けるしかないのかな?」と思い、正常時の戻り値がObjectという前提で、"String"=エラー内と容半ば強引にしていますが、何かもっとスマートな良い方法が無いものだろうか?
■[Flexでエラーを受けた場合]
Zedo Core i5 で、PHPとFlex連携(その3)
前回の続きで、今度はFlexでAMFPHP上のサービスを呼出します。今回はグラフをやってみたかったので、リンク付きであればフリーで使える「amCharts」という、swfベースのコンポーネントを使ってみました。しかも丁度Flex版があり、SWCのライブラリとして使えるので、ラッキーでした。
amCharts for Flexの入手
サイトの右側の「amCharts Flex components」からFlex版のページへいき、Downloadから入手します。現時点で”1.3.2.0 beta”です。
SWCコンポーネントをFlex Builderに設定
ダウンロードした「SWC」をローカルPCの任意のディレクトリに配置します。(例「C:\lib\flex\amchart\1.3.2.0_beta\build」)
Flex Builderで適当なFlexプロジェクトを作成します。作成したプロジェクトを右クリックして[プロパティ]を開きます。左のメニューから[Flexビルドパス]を選び、[ライブラリパス]タブを選びます。
[SWCの追加]ボタンを押し、先程ダウンロードした、バージョンが3のSWCファイルを選びます。
AMFPHPサービスの呼出
ActionScriptでは次のようにして、AMFPHP上の関数を呼びだす事ができます。
AMFPHPでサービスを呼びだす為に「flash.net.NetConnection ,ObjectEncoding ,Responder」クラスを使います。
ここで前々回作成した「amfGateway.php」の配置先を”NetConnection”接続先のURLとします。
「NetConnection」クラスのインスタンスで”AMFゲートウェイ”への接続を試みます。「Responder」クラスで接続成功時と失敗時に実行するメッソドを渡した、インスタンスを作成します。接続したコネクションの”call”メソッドの引数に「PHPクラス名.関数名の文字列とResponderのインスタンス」をとり、サービスを呼び出します。呼出しに成功したら、Flex上のコンポーネントにデータをバインドすれば、PHPとFlexの連携の完了です。
■「Chart.mxmlの抜粋」
import flash.net.NetConnection; import flash.net.ObjectEncoding; import flash.net.Responder; import mx.core.Application; import mx.utils.URLUtil; [Bindable] private var dataChart: ArrayCollection ; /** * コネクション取得 */ private function callAMFPHP():void { var time:Number = (new Date()).getTime(); var con:NetConnection = new NetConnection(); //ゲートウェイへのパス var GATEWAY_URL:String = '/etc/amfGateway.php'; // ドメイン&ポート var appURL :String = Application.application.url; var DOMAIN_URL:String = URLUtil.getProtocol(appURL) + "://" + URLUtil.getServerNameWithPort(appURL); con.connect(DOMAIN_URL + GATEWAY_URL + '?time=' + time); con.objectEncoding = ObjectEncoding.AMF3; // Responder(呼出に成功した時のメソッド,失敗した時のメソッド) var responder:Responder = new Responder(onResult, onFault); // param1=画面の開始月,param2=画面の終了月 // NetConnection.call(クラス名.関数名 ,レスポンダー ,引数...) con.call('Uriage.getList', responder,param1,param2); } /** * 成功 */ private function onResult(etc:*):void { if (typeof etc == 'object') { dataChart = new ArrayCollection(etc); } else { Alert.show('オブジェクトではありません'); } } /** * 失敗 */ private function onFault(etc:*):void { Alert.show('通信に失敗しました'); }
こんな感じのチャートが出来ました。
Zedo Core i5 で、PHPとFlex連携(その2)
前回の続きで、今度はPHPのサービスプログラムを作成します。
サービスプログラムの作成
今回は適当な”売上データ”を連想配列で返す、サービスを作成します。
- 引数
- 開始年月:YYYYMM(文字 6Byte)
- 終了年月:YYYYMM(文字 6Byte)
- 戻り値
- 売上データリスト:連想配列
ソースは以下のような感じです。
■「Uriage.php」
<?php /** * Uriage * * 売上データ取得サービス * * @package * @access public * @author Yoshiki Ushida <CSC> * @create 2009/12/23 * @version v 1.0.0 */ class Uriage { /** * 指定月の売上データをリストで返します * @access public * @param string $fromMonth 開始月 * @param string $toMonth 終了月 * @return array 売上リスト */ public function getList($fromMonth,$toMonth){ $ret = array(); // カラム名小文字の設定 $option["DB2_ATTR_CASE"] = DB2_CASE_LOWER; // デフォルトライブラリーの設定(i5_lib) $option["i5_lib"] = "PHPDEMO"; $db=db2_connect("*LOCAL","foo","*****",$option); if(!$db){ $message = "Error->getConnection:<". date('Y/m/d H:i:s') .">" .db2_conn_errormsg() . "\n"; error_log($message, 3, '/var/tmp/AS400ConnectionError.log'); return $ret; } // SQL文 $sql="select * from uriage where month >= ?" ." and month <= ?"; // SQLプリペア $result = db2_prepare($db,$sql); // パラメータのバインド db2_bind_param($result ,1 ,"fromMonth",DB2_PARAM_IN); db2_bind_param($result ,2 ,"toMonth" ,DB2_PARAM_IN); // SQLの実行 (db2_execute($result)) or die("$sql に失敗しました。"); while ( ($row=db2_fetch_assoc($result)) != false) { $ret[]=$row; } db2_close($db); return $ret; } }
■「URIAGE」ファイルのDDS
A***************************************************************** A* URIAGE 売上データ 09/12/24 CSC)Y.U * A***************************************************************** A R URIAGER TEXT('売上データ') A MONTH 6S 0 COLHDG('売上年月') A* A AREAC 4S 0 COLHDG('区域コード') A AREA1 16O COLHDG('管轄') A AREA2 16O COLHDG('区域') A EMPLOYEE 16O COLHDG('営業名') A CUSTC 6S 0 COLHDG('得意先コード') A TYPE 1A COLHDG('販売形態コード') A TYPEN 16O COLHDG('販売形態名') A SALES 9S 0 COLHDG('売上金額') A MARGIN 9S 0 COLHDG('粗利金額') A*KEY A K MONTH A K CUSTC A K TYPE
作成した「Uriage.php」は、IFS上の”/www/zendcore/htdocs/amfphp/services”(※/www/zendcore/htdocs/は適宜変えて下さい)に配置します。
次に”http://ホスト名/amfphp/browser/”にアクセスすると、PHP単体の動作を確認する事が出来ます。定義した「getList関数」が正常に動作すれば、PHP側は完了です。
Zedo Core i5 で、PHPとFlex連携(その1)
IBMi(AS/400)で”Zend Core”が、メーカーサポートということもあり、PHPネタをやったので、メモしておきます。
ちなみに”Zend Core i5”とは、AS/400上で動作するPHPのエンジンです。
Flexが有ったから
会社でゴソゴソと物色していると、「若者たちのスキル向上にと、”Flex Builder 3”」がありました。
Flexは全く触れた事も無いのですが、せっかくならと、PHPとFlexで連携して、すこしRIAな感じのモノが、出来ないかと、探してみたら、Flex連携用のライブラリがすぐ見つかりました。
AMFPHPの導入
- AMFPHP入手先
上記のリンク”Download”から、"AMFPHP"を入手します。現時点では「amfphp 1.9 beta2 」でした。AMFは、”ActionScript Message Format”の略で、” BlazeDS”が使っている、通信と同じものの様です。
- 導入手順
■「amfGateway.php」
<?php $_AMFPHP_DIR = '/www/zendcore/htdocs/amfphp'; // AMFPHPディレクトリへのパス include $_AMFPHP_DIR . '/core/amf/app/Gateway.php'; $gateway = new Gateway(); $gateway->disableDebug(); $gateway->setClassPath($_AMFPHP_DIR . '/services/'); // サービスクラスの場所 $gateway->enableGzipCompression(25 * 1024); $gateway->service();
”http://ドメイン/etc/amfGateway.php”にアクセスして、次の画面が表示されれば、導入は完了です。
IBM i 5250での ftp client
IBM i(AS/400)の5250をclientとして、別のAS/400へftpする時に、デフォルトのファイルフォーマットが、「ライブラリ/ファイル.メンバー形式」だったりします。PCクライアントなどを使っている時は、勝手にやってくれるので意識しないのですが、ふと5250でやった時に毎回調べているので、メモを残しておきます。
- 相手のファイル形式を帰るときに実行するコマンド
- quote site namefmt 0(ライブラリ形式)
- quote site namefmt 1(IFS形式)
- 自分のファイル形式を帰るときときに実行するコマンド
- namefmt 0(ライブラリ形式)
- namefmt 1(IFS形式)
これで、”5250 対 AS/400”でも、「cd /home/xxxuser」や「lcd /home/myuser」が普通に使えて、
「get /home/xxxuser/hoge.file /home/user/hoge.file」が出来る様になります。
Zend Studio for Eclipse i5/OS 版をインストール
”Zend Studio for Eclipse i5/OS 版”は、i(AS/400)のユーザーならば、無償で使えるという記事(しかも、1年保守<ウェブ・ベースのサポート、保守、パッチ、修正>が付いている様です。)を見たので、早速インストールしました。
自分の勘違いで、最初は日本のZend社を探していましたが、Eclipseのi5をサポートしているのは、本家イスラエルの様です。(Zendジャパンのかたに、Q&Aで教えて頂きました。※ただ現状は、i5版はメモリ消費が大きくなる為、日本での販売を見合わせているとの事でした。)
- Zend Studio for Eclipse i5/OS 版入手
- zend.comのダウンロードより”i5版”が入手可能です。現時点の最新はバージョン7でした。
- ダウンロードが始まる前に、Zendアカウントの登録が必要です。
- インストール
- exe形式のインストーラを実行すると勝手にインストールしてくれます。
- Eclipseを開始後、[Help]→[Get a License]を選択すると、AS/400のシリアルナンバーを入力するサイトにジャンプします。
- 5250を使い「DSPSYSVAL QSRLNBR」コマンドでシリアル確認して登録します。
- Zendサイトに、前述で登録したアカウントで、サインインします。
- 右上の”My Account”に進むと、右側”Products”の”Licenses”タブの”Get license”より、オーダー№とライセンスキーを取得できるので、Eclipseの[Help]→[Register]に登録して、再起動したら完了です。
WDScもEclipseベースと有ってこちらの方が、幾分か使い慣れている感があります。他にEclipseのプラグインが使えるところが大きそうです。