flashとのAMF通信用CakePHPコンポーネント
こんにちは、中川です。
以前、「AMFPHPを試してみました」でphpとFlashの通信を試してみましたが、
今回はCakePHPを使ったFlashとAMFでのやり取りする方法を考えてみました。
CakePHPでAMF通信ができるものを探してみたところ、
「CakeAMFPHP」、
「CakeAMF」、
「CakeSWXPHP」
など、いろいろ見つかりました。
一通り試してみましたが、設置が面倒であったりうまく動かなかったり
(私のやり方が悪いと思いますが、)どうもしっくりきませんでした。
もっとCakePHPから使いやすそうなものがないか探してみたところ、
「SabreAMF」というライブラリを見つけました。
これを通常の使用方法で試したところ、非常に簡単にやり取りができましたので、
CakePHPからも使いやすいようにCakePHP用のコンポーネントを作ってみました。
※動作イメージ

構成は以下のようになります。
まず、SabreAMFの最新ライブラリ(今回はSabreAMF-1.1.187)を http://code.google.com/p/sabreamf/downloads/list から
ダウンロードして、解凍しSabreAMFに改名して、
そして、パス設定用のファイル
これで準備完了です。
AMFを使用したいControllerで、
以下、簡単な、文字列と、配列のやり取りのサンプル用Controllerです。
あとは、このコントローラにFlashからリクエストのサンプルです。
■RemoteTest.mxml(RemoteTest.swf)
上記サンプルでは、RemoteObjectを使用していますが、
NetConnectionを使った場合は以下のような感じで通信できると思います。
(以前のAMFPHPの記事も参照)
※しっかりした、動作確認はできておりません。
使用される場合は自己責任でご自由にお使いください。
-----------------------------------------------
最近CakePHPの人気はすごいですねー。今週水曜CakePHPの勉強会ですが、
申し込みに間に合わず、満員で参加できませんでしたorz
いきたかったなぁ~。。。
以前、「AMFPHPを試してみました」でphpとFlashの通信を試してみましたが、
今回はCakePHPを使ったFlashとAMFでのやり取りする方法を考えてみました。
CakePHPでAMF通信ができるものを探してみたところ、
「CakeAMFPHP」、
「CakeAMF」、
「CakeSWXPHP」
など、いろいろ見つかりました。
一通り試してみましたが、設置が面倒であったりうまく動かなかったり
(私のやり方が悪いと思いますが、)どうもしっくりきませんでした。
もっとCakePHPから使いやすそうなものがないか探してみたところ、
「SabreAMF」というライブラリを見つけました。
これを通常の使用方法で試したところ、非常に簡単にやり取りができましたので、
CakePHPからも使いやすいようにCakePHP用のコンポーネントを作ってみました。
※動作イメージ
構成は以下のようになります。
- `--
myproject `-- app |-- controllers | |-- amfs_controller.php(サンプルファイル) | `-- components | `-- sabre_amf.php(コンポーネント) `-- vendors |-- SabreAMF(解凍した中身を配置) `-- sabreamf_ini.php(PATH設定用ファイル)
まず、SabreAMFの最新ライブラリ(今回はSabreAMF-1.1.187)を http://code.google.com/p/sabreamf/downloads/list から
ダウンロードして、解凍しSabreAMFに改名して、
- /PROJECT_DIR/app/vendors/SabreAMF
そして、パス設定用のファイル
- /PROJECT_DIR/app/vendors/sabreamf_ini.php
- //sabreamf_ini.php
- define('SABREAMF_PATH',
dirname(__FILE__)); - set_include_path(SABREAMF_PATH
. PATH_SEPARATOR . get_include_path());
- /PROJECT_DIR/app/controllers/components/sabre_amf.php
- //sabre_amf.php
- vendor("sabreamf_ini");
- vendor('SabreAMF/CallbackServer');
- $_cakeController
= null; - function
amfCallBack($service, $method, $data) { global $_cakeController; $res = null; if ($_cakeController) { if (strpos($method, "_") !== 0) { // _(アンダーバー)で始まるmethodはエラー。 $_cakeController->amfData = $data; if (method_exists($_cakeController, $method)) { $res = $_cakeController->{$method}(); } else { $res = "not found action."; } } else { $res = "invalid method name."; } } else { $res = "not found controller."; } return $res; - }
- class
SabreAmfComponent extends Object { function initialize(&$controller) { global $_cakeController; $_cakeController = $controller; $controller->isAmf = true; // default true } function startup(&$controller) { if ($controller->isAmf) { Configure::write('debug', 0); $controller->autoRender = false; $server = new SabreAMF_CallbackServer(); $server->onInvokeService = 'amfCallBack'; $server->exec(); exit; //ここでexitしてるので、amf の 場合はほかのactionは呼べないはず。。。 } } function beforeRender(&$controller) { if ($controller->isAmf) { exit; // 念のため } } - }
これで準備完了です。
AMFを使用したいControllerで、
- var
$components = array("SabreAmf");
以下、簡単な、文字列と、配列のやり取りのサンプル用Controllerです。
- class
AmfsController extends AppController { var $name = 'Amfs'; var $uses = array(); var $components = array("SabreAmf"); function beforeFilter() { // ここでamf出力ではないactionを設定できる。 // 全部amf出力の場合は何も設定いらない。 // この場合は「normal」のみ通常アクセスできる。 // ほかのactionは、URLからは実行されないはず。。。 if ($this->action == "normal") { $this->isAmf = false; Configure::write('debug', 2); $this->autoRender = true; } } // indexアクションは通常出力に使わないほうがいい。 // beforeFilterで除外すると、初期アクセスがamfから指定ない場合、 // リモートで呼び出されたときにエラーでちゃう function index() { return "index"; } //これは通常表示できるアクション function normal() { $this->set("hoge", date("Y-m-d H:i:s")); } //文字列返却 function getstr() { $testname = $this->amfData[0]; // flashから送られてきた値はamfDataにある。しかし、キーが消えてるよ。。。 return date("Y-m-d H:i:s") . " こんにちは " . $testname; //各action で return した値が flashに返る。 } //配列返却 function getarr() { $res_list = array(); for($i = 0; $i < 10; $i++) { $res = array( "col1" => $i, "col2" => rand(1, 1000), ); $res_list[] = $res; } $this->log(print_R($res_list, true), LOG_ERROR); return $res_list; } - }
あとは、このコントローラにFlashからリクエストのサンプルです。
■RemoteTest.mxml(RemoteTest.swf)
- <?xml
version="1.0" encoding="utf-8"?> - <mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"> <mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.controls.Alert; import mx.utils.ArrayUtil; [Bindable] private var myDataItem:Array = []; private function resultHandler(evt:ResultEvent):void { myDataItem = ArrayUtil.toArray(evt.result); } private function faultHandler(evt:FaultEvent):void { Alert.show("Fault: " + evt.fault + " Msg: " + evt.message); } ]]> </mx:Script> <!-- remoting-config.xmlをちゃんと設定したほうがいいのかな? このサンプルでは、xmlを用意しないで、endpoint指定でやってます。 endpoint="{'http://{server.name}:{server.port}/amfs/'}" と書けば、 flash設置サーバの/amfs/と通信します。 以下のようにendpoint(cakeのcontroller呼び出し用URL)さえ指定しておけば source は今回の場合は適当でいいです。というのも、sevice名として サーバで受け取りますが、endpointのcakeのcontrollerの メソッドしか呼べないようにしているので送信しているが使っていない。 また、destinationも適当でいいですが指定しないとエラーでます。 --> <!-- 文字列読み込み例 --> <mx:RemoteObject id="ro" endpoint="{'http://{server.name}:{server.port}/amfs/'}" destination="MyAmfs" source="Amfs" result="myLabel.text = event.result.toString()" fault="faultHandler(event)"> <mx:method name="getstr"> <mx:arguments> <testname>hoge</testname> </mx:arguments> </mx:method> </mx:RemoteObject> <mx:Label text="string_sample" id="myLabel" /> <mx:Button label="string load test" click="ro.getstr.send()" x="24" y="42"/> <!-- ro.●●.send() でcake側のアクションを呼べる --> <mx:Spacer height="2" width="200"/> <!-- 配列読み込み例 --> <mx:RemoteObject id="ro2" endpoint="{'http://{server.name}:{server.port}/amfs/'}" destination="MyAmfs" source="Amfs" result="resultHandler(event)" fault="faultHandler(event)"> </mx:RemoteObject> <mx:Button label="array load test" click="ro2.getarr.send()" x="24" y="42"/> <mx:DataGrid id="myData" dataProvider="{myDataItem}"> <mx:columns> <mx:DataGridColumn headerText="列 1" dataField="col1"/> <mx:DataGridColumn headerText="列 2" dataField="col2"/> </mx:columns> </mx:DataGrid> - </mx:Application>
上記サンプルでは、RemoteObjectを使用していますが、
NetConnectionを使った場合は以下のような感じで通信できると思います。
(以前のAMFPHPの記事も参照)
- var
con:NetConnection = new NetConnection(); - con.connect(GATEWAY_URL);
- con.objectEncoding
= ObjectEncoding.AMF3; - con.call("Amfs.getstr",
new Responder(resultHandler, faultHandler));
※しっかりした、動作確認はできておりません。
使用される場合は自己責任でご自由にお使いください。
-----------------------------------------------
最近CakePHPの人気はすごいですねー。今週水曜CakePHPの勉強会ですが、
申し込みに間に合わず、満員で参加できませんでしたorz
いきたかったなぁ~。。。
コメント
コメントフォーム
トラックバック
-
- [CakePHP] AIRからSabreAMFを利用してCakePHPに通信する from 私的WEBサイト制作日誌
- AirのSWFファイルからPHPが動いているサーバーに接続する為には、AMFと...
2008年11月24日 20:31
最近の記事
- <Symfony Componentsシリーズ(2)> Symfony 2の秘密兵器: Request Handler [2010年03月11日 : 小川雄大]
- <Symfony Componentsシリーズ(1)> オブジェクトをつなぐEvent Dispatcher [2010年03月11日 : 小川雄大]
- Symfony 2のアプリケーション構成を読む [2010年03月04日 : 小川雄大]
- サーバサイドJavaScriptの「node.js」を試してみました [2010年03月03日 : 中川善樹]
- お初の山梨旅行 [2010年02月26日 : 阿部恵]
- OpenVPNで拠点間VPN [2010年02月25日 : 門脇優児]
- OracleでのLIMITの記述あれこれ [2010年02月24日 : 松田惇]
- symfony DoctrineのTIPS その2 [2010年02月18日 : 牧野克俊]
- KeyRemap4MacBookで自分好みにキーをリマッピング [2010年02月15日 : 熊谷裕志]
- 株式会社アシックス社向け、ランナーのためのゲイトアナリシス・ソフトウェアの共同開発 [2010年02月12日 : 小林有佳]



このコード公開してくれればありがたいのに・・・。
このページコードを参考にsabreAMFとCakePHPでやってみましたがうまくいきませんでした。
以下環境です。
━━━━━━━━━━━━━━
SabreAMF-1.2.203.tgz
CakePHP1.2 RC3
Flex Buider 3
AIR 1.5
━━━━━━━━━━━━━━
SWFはデータ送信時、内部的に初回だけ2回POSTするらしく、
sableAMFのCallbackServer.phpのexecメソッドで
振り分け処理を行っているようです。
1回目:CommandMessage(PING)
2回目:RemotingMessage(データ)
1回目のCommandMessageは受け取ってデータを返すところまで、
PHP側にログを出力させて確認できました。
ただ、apacheのログを見ても、2回目のPOSTが走らないようです。
1回目のPINGでの返信データがおかしいんですかね??
何か情報をお持ちでしたら教えて下さいm(_ _)m
なんだかんだ手こずったのですが、ソースコードをコピペする際に、phpタグの前にスペースが混入してしまっていたため、失敗してました。
気づくまでに丸2日かかりました。。情けない。。
ご存知のとおり、CakePHP1.2の場合は、vendorタグをApp::importに書き換えるとうまくいきました。
How to deal with authentication?