ushidayの日記

主に「IBMi」のメモに・・・

PASEのtarって...

ZendFrameWorkを入れようと、IBM i(AS/400)上で、”〜tar.gz”をungzipして、tarしたら...
「警告うんぬん」言われて、"@LongLink"ファイルが、解凍先に出来ているではありませんか。



どうやら、”PASE標準(AIX標準?)”って、100文字縛りがあるらしい。
というか、GNU tarでの100文字以上のファイルに付けられる”@LongLink”を理解してくれないみたい。
「まいったな。」という事で、今後の事も考えて、”GNU tar”を入れておきました。以前、"gcc"でお世話になったサイトに、AIXバイナリが有りましたので、有り難く使わせて頂きました。
そして、tarコマンドの既存の場所を検索すると、二つ出てきました。

PASE環境のtarシンボリックリンクGNU tarに置き換えて実行すると、今度は”libintl.so.2がねぇぞ!”と言われました。依存関係に有る「GNU gettext」が、PASEに無いので、これまた先程のありがたい場所から(バイナリあるとホント助かります。本来は別の所のお仕事な...)同じく取得して解凍すれば、その後は無事tarコマンドが動きました。めでたし×2。

db2_prepare & db2_executeの怪

PHPDB2のテーブルにSQLを投げる際に、代表的な関数が2つあります。

  • もう1つは
    1. db2結果 = db2_prepare(db2接続,SQL文字列)こちらは、SQL文に「?」でパラメータマーカを指定出来ます。次に...
    2. db2_execute(db2結果,[パラメータArray])

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_connectphpDB2用関数)などのエラーハンドルが、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"=エラー内と容半ば強引にしていますが、何かもっとスマートな良い方法が無いものだろうか?

■[AMFPHPがthorwするException]

■[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上のコンポーネントにデータをバインドすれば、PHPFlexの連携の完了です。

■「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は全く触れた事も無いのですが、せっかくならと、PHPFlexで連携して、すこしRIAな感じのモノが、出来ないかと、探してみたら、Flex連携用のライブラリがすぐ見つかりました。

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”にアクセスして、次の画面が表示されれば、導入は完了です。

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プラグインが使えるところが大きそうです。