1 <?xml version="1.0" encoding="UTF-8"?>
3 <!-- EN-Revision: 21741 -->
4 <sect1 id="zend.amf.server">
5 <title>Zend_Amf_Server</title>
8 <classname>Zend_Amf_Server</classname> は <acronym>RPC</acronym> スタイルのサーバで、
9 Adobe Flash Player からの <acronym>AMF</acronym> プロトコルによるリクエストを処理します。
10 他の Zend Framework のサーバクラス群と同様に SoapServer <acronym>API</acronym> にしたがっており、
11 サーバを作成するための習得しやすいインターフェイスを提供します。
14 <example id="zend.amf.server.basic">
15 <title>基本的な AMF サーバ</title>
18 さまざまな public メソッドを持つクラス <classname>Foo</classname>
19 を作ったものとしましょう。<acronym>AMF</acronym> サーバを作成するためのコードは次のようになります。
22 <programlisting language="php"><![CDATA[
23 $server = new Zend_Amf_Server();
24 $server->setClass('Foo');
25 $response = $server->handle();
30 もうひとつの方法として、単純な関数をコールバックとしてアタッチすることもできます。
33 <programlisting language="php"><![CDATA[
34 $server = new Zend_Amf_Server();
35 $server->addFunction('myUberCoolFunction');
36 $response = $server->handle();
41 複数のクラスや関数を混ぜて使用することもできます。
42 その場合は、それぞれに名前空間を指定してメソッド名の衝突を回避させることをおすすめします。
43 名前空間を指定するには、<methodname>addFunction()</methodname> あるいは
44 <methodname>setClass()</methodname> の 2 番目の引数に文字列を指定します。
47 <programlisting language="php"><![CDATA[
48 $server = new Zend_Amf_Server();
49 $server->addFunction('myUberCoolFunction', 'my')
50 ->setClass('Foo', 'foo')
51 ->setClass('Bar', 'bar');
52 $response = $server->handle();
57 <classname>Zend Amf Server</classname> は、
58 指定したディレクトリパスから動的にサービスに読み込ませることもできます。
59 好きなだけのディレクトリをサーバに指定することが可能です。
60 サーバに後から追加したディレクトリから順に (<acronym>LIFO</acronym>: 後入れ先出し)
61 検索を行い、クラスにマッチするディレクトリを探します。
62 ディレクトリの追加は <methodname>addDirectory()</methodname> メソッドで行います。
65 <programlisting language="php"><![CDATA[
66 $server->addDirectory(dirname(__FILE__) .'/../services/');
67 $server->addDirectory(dirname(__FILE__) .'/../package/');
71 リモートサービスをコールする際には、アンダースコア ("_") およびドット
72 (".") をディレクトリ区切り文字として使用します。
73 アンダースコアを使用すると、<acronym>PEAR</acronym> や
74 Zend Framework のクラス命名規約に従った形式となります。
75 つまり、サービス com_Foo_Bar をコールした場合は、
77 <filename>com/Foo/Bar.php</filename> を探します。ドット記法を使用してリモートサービスを
78 <filename>com.Foo.Bar</filename> のように指定すると、
79 インクルードされたパスの最後に <filename>com/Foo/Bar.php</filename>
80 を追加して <filename>Bar.php</filename> を自動的に読み込みます。
84 スクリプトに送られたすべての <acronym>AMF</acronym> リクエストがサーバで処理され、
85 その結果の <acronym>AMF</acronym> レスポンスが返されます。
90 <title>アタッチされるすべてのメソッドや関数には docblock が必要</title>
93 Zend Framework の他のサーバコンポーネント群と同様、クラスのメソッドには
94 <acronym>PHP</acronym> docblock 形式のドキュメントが必要です。
95 少なくとも必須引数と返り値についてのアノテーションが必要となります。
99 <programlisting language="php"><![CDATA[
103 * @param string $name
104 * @param string $greeting
107 function helloWorld($name, $greeting = 'Hello')
109 return $greeting . ', ' . $name;
113 <programlisting language="php"><![CDATA[
119 * @param string $name
120 * @param string $greeting
123 public function hello($name, $greeting = 'Hello')
125 return $greeting . ', ' . $name;
131 その他のアノテーションを使用することもできますが、無視されます。
135 <sect2 id="zend.amf.server.flex">
136 <title>サーバへの Flex からの接続</title>
139 <classname>Zend_Amf_Server</classname> に Flex プロジェクトから接続するのはきわめて簡単です。
140 エンドポイントの <acronym>URI</acronym> を
141 <classname>Zend_Amf_Server</classname> スクリプトに指定するだけでよいのです。
145 たとえば、作成したサーバをアプリケーションルートに
146 <filename>server.php</filename> という名前で配置したとしましょう。<acronym>URI</acronym> は
147 <filename>http://example.com/server.php</filename> となります。
148 この場合は、services-config.xml ファイルを編集して、
149 チャンネルのエンドポイント URI 属性をこの値に変更します。
153 まだ <filename>service-config.xml</filename> ファイルを作っていない場合は、
154 まずナビゲータウィンドウでプロジェクトを開きます。
155 そしてプロジェクト名のところを右クリックして 'プロパティ' を選択します。
156 プロジェクトのプロパティダイアログで 'Flex ビルドパス' を選択し、
157 'ライブラリパス' タブで '<filename>rpc.swc</filename>'
158 ファイルがプロジェクトに追加されていることを確認したら、
163 また、リモートオブジェクトのエンドポイントを探す際に <filename>service-config.xml</filename>
164 を使用することをコンパイラに指定する必要もあります。
165 ナビゲータのプロジェクトフォルダを右クリックしてプロパティを選択し、
166 もういちどプロジェクトのプロパティパネルを開きます。
167 そこで 'Flex コンパイラ' を選択して、
168 <command>-services "services-config.xml"</command> を追加します。
169 適用、そして OK を押してオプションを更新します。
170 これで結局何をやったのかというと、実行時の変数を
171 <filename>services-config.xml</filename> から読み込んで RemotingObject クラスで使うよう
172 Flex コンパイラに指示したということです。
176 それから、リモートメソッドへの接続の際に使用するサービス設定ファイルを
177 Flex に教えてやる必要があります。そこで、Flex プロジェクトの src フォルダに
178 '<filename>services-config.xml</filename>' ファイルを新たに作成します。
179 プロジェクトフォルダで右クリックして '新規作成' 'ファイル'
180 を選択すると新しいウィンドウが開きます。プロジェクトフォルダを選択し、
181 ファイル名を '<filename>services-config.xml</filename>' と指定して終了を押します。
185 Flex は新しい <filename>services-config.xml</filename> ファイルを作成し、それを開きます。
186 次の例のとおりに <filename>services-config.xml</filename> ファイルを作成してください。
187 エンドポイントの部分はあなたが使用するサーバに書き換えます。
188 そしてファイルを保存することを忘れないようにしましょう。
191 <programlisting language="xml"><![CDATA[
192 <?xml version="1.0" encoding="UTF-8"?>
195 <service id="zend-service"
196 class="flex.messaging.services.RemotingService"
197 messageTypes="flex.messaging.messages.RemotingMessage">
198 <destination id="zend">
200 <channel ref="zend-endpoint"/>
209 <channel-definition id="zend-endpoint"
210 class="mx.messaging.channels.AMFChannel">
211 <endpoint uri="http://example.com/server.php"
212 class="flex.messaging.endpoints.AMFEndpoint"/>
213 </channel-definition>
220 <acronym>AMF</acronym> チャネルを作成し、そしてエンドポイントの <acronym>URL</acronym> を
221 <classname>Zend_Amf_Server</classname> に指定します。
224 <programlisting language="xml"><![CDATA[
225 <channel-definition id="zend-endpoint"
226 <endpoint uri="http://example.com/server.php"
227 class="flex.messaging.endpoints.AMFEndpoint"/>
228 </channel-definition>
232 このチャネルの ID として "zend-endpoint" を指定したことに注意しましょう。
233 この例では、このチャネルを指すサービスを作成して、その ID を指定しました。
234 この場合の ID は "zend" となります。
238 Flex の <acronym>MXML</acronym> ファイルで、
239 RemoteObject をサービスにバインドしなければなりません。
240 <acronym>MXML</acronym> で次のように記述します。
243 <programlisting language="xml"><![CDATA[
244 <mx:RemoteObject id="myservice"
245 fault="faultHandler(event)"
246 showBusyCursor="true"
251 ここでは、新しいリモートオブジェクトに "myservice" という名前をつけ、
252 さきほど <filename>services-config.xml</filename> で定義した "zend"
253 にそれをバインドしています。ActionScript からメソッドをコールするには、
254 "myservice.<method>" とするだけです。例を示します。
257 <programlisting language="ActionScript"><![CDATA[
258 myservice.hello("Wade");
263 "myservice.<namespace>.<method>" のようにします。
266 <programlisting language="ActionScript"><![CDATA[
267 myservice.world.hello("Wade");
271 Flex RemoteObject の実行についてのより詳細な情報は <ulink
272 url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html">
273 Adobe Flex 3 のヘルプサイト</ulink> をごらんください。
277 <sect2 id="zend.amf.server.errors">
281 デフォルトでは、アタッチしたクラスや関数からスローされた例外はすべて捕捉され、
282 <acronym>AMF</acronym> ErrorMessage として返されます。しかし、この ErrorMessage
283 オブジェクトの中身は、サーバが "production" モード (デフォルトの状態)
288 production モードの場合は、例外コードのみが返されます。
289 production モードを無効にする (これはテスト時にしか行ってはいけません)
290 と、例外についての詳細が返されるようになり、
291 例外メッセージや行番号、バックトレースがすべて返されます。
295 production モードを無効にするには、次のようにします。
298 <programlisting language="php"><![CDATA[
299 $server->setProduction(false);
303 再度有効にするには、<constant>TRUE</constant> を渡します。
306 <programlisting language="php"><![CDATA[
307 $server->setProduction(true);
311 <title>production モードの無効化は慎重に!</title>
314 production モードを無効にするのは、開発時のみにすることを推奨します。
315 例外メッセージやバックトレースにはシステムに関する重大な情報が含まれる可能性があり、
316 外部からアクセスされることは好ましくありません。
317 <acronym>AMF</acronym> はバイナリ形式ではありますが、その仕様は公開されています。
318 つまり、誰でもメッセージを解読できる可能性があるということです。
323 もうひとつ、特に注意を要するのが <acronym>PHP</acronym> のエラーです。
324 <acronym>INI</acronym> 設定 <emphasis>display_errors</emphasis> が有効になっていると、
325 エラー報告レベルに応じてあらゆる <acronym>PHP</acronym> のエラーが直接出力されてしまいます。
326 これは、<acronym>AMF</acronym> のレスポンスを壊してしまう可能性があります。
327 運用時には <emphasis>display_errors</emphasis> を無効にし、
332 <sect2 id="zend.amf.server.response">
333 <title>AMF レスポンス</title>
336 レスポンスオブジェクトを操作したくなることもあるかもしれません。
337 メッセージヘッダを追加したい場合などが考えられます。サーバの
338 <methodname>handle()</methodname> メソッドはレスポンスオブジェクトを返すので、これが利用できます。
341 <example id="zend.amf.server.response.messageHeaderExample">
342 <title>AMF レスポンスへのメッセージヘッダの追加</title>
345 この例では、'foo' という MessageHeader に値
346 'bar' を設定したものをレスポンスに追加してからそれを返します。
349 <programlisting language="php"><![CDATA[
350 $response = $server->handle();
351 $response->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
357 <sect2 id="zend.amf.server.typedobjects">
358 <title>型付きオブジェクト</title>
361 <acronym>SOAP</acronym> と同様、
362 <acronym>AMF</acronym> でもクライアントとサーバの間でオブジェクトをやりとりできます。
363 これにより、クライアントとサーバの間での柔軟性と一貫性を確保できます。
367 <classname>Zend_Amf</classname> には、
368 ActionScript と <acronym>PHP</acronym> オブジェクトを関連付けるための 3 つのメソッドが用意されています。
374 まず、サーバ側で明示的なバインドを行うには
375 <methodname>setClassMap()</methodname> メソッドを使用します。
376 最初の引数は ActionScript クラス名で、2 番目の引数は関連付ける
377 <acronym>PHP</acronym> クラス名となります。
380 <programlisting language="php"><![CDATA[
381 // ActionScript クラス 'ContactVO' と PHP クラス 'Contact' を関連付けます
382 $server->setClassMap('ContactVO', 'Contact');
388 次に、<acronym>PHP</acronym> クラス内で public プロパティ
389 <varname>$_explicitType</varname> を設定する方法があります。
390 ここには、関連付けたい ActionScript クラス名を指定します。
393 <programlisting language="php"><![CDATA[
396 public $_explicitType = 'ContactVO';
403 3 番目の方法として、PHP クラスの public メソッド
404 <methodname>getASClassName()</methodname> を使用することもできます。
405 このメソッドは、適切な ActionScript クラスを返すようにしなければなりません。
408 <programlisting language="php"><![CDATA[
411 public function getASClassName()
421 サーバ側で ContactVO を作成したら、
422 サーバオブジェクトに対応するクラスを <acronym>AS3</acronym> で書かなければなりません。
426 Flex プロジェクトの src フォルダを右クリックし、新規作成 ->
427 ActionScript ファイルを選択します。ファイルに ContactVO
428 という名前をつけて終了を押すと、新しいファイルがあらわれます。
429 次のコードをコピーして、クラスを作成しましょう。
432 <programlisting language="as"><![CDATA[
436 [RemoteClass(alias="ContactVO")]
437 public class ContactVO
440 public var firstname:String;
441 public var lastname:String;
442 public var email:String;
443 public var mobile:String;
444 public function ProductVO():void {
451 このクラスは、同名の <acronym>PHP</acronym> のクラスと構文的に同等となります。
452 変数名はまったく同じで、大文字小文字もあわせておかなければ正しく動作しません。
453 このクラスでは、<acronym>AS3</acronym> 独特のメタタグが 2 つ用いられています。
454 最初のタグは bindable で、これは更新時に change イベントを発火させます。
455 2 番目のタグは RemoteClass で、このクラスがリモートオブジェクトを保持できること、
456 そのエイリアス名が (ここでは) <emphasis>ContactVO</emphasis> であることを定義します。
457 このタグに設定される値は、<acronym>PHP</acronym> のクラスと正確に一致していなければなりません。
460 <programlisting language="as"><![CDATA[
462 private var myContact:ContactVO;
464 private function getContactHandler(event:ResultEvent):void {
465 myContact = ContactVO(event.result);
470 サービスコールの後の result イベントは即時に Flex の ContactVO にキャストされます。
471 myContact にバインドされているすべての内容は、返された
472 ContactVO データで更新されます。
476 <sect2 id="zend.amf.server.resources">
480 <classname>Zend_Amf</classname> には、サービスクラスが返すリソース型を
481 ActionScript で使用可能な形式のデータにマッピングするツールが用意されています。
485 リソース型を扱うには、そのリソース名に対応する名前のプラグインクラスを作成する必要があります。
486 クラス名は、リソース名の単語の先頭を大文字化してスペースを除去したものとなり
487 (つまり、リソース型 "mysql result" の場合は MysqlResult となります)、
488 それに何らかのプレフィックスをつけてたとえば <classname>My_MysqlResult</classname>
489 のようになります。このクラスは <methodname>parse()</methodname>
491 このメソッドはリソースを引数として受け取り、ActionScript に送信する値を返します。
492 このクラスを記述するファイル名は、クラス名の最後の部分と同じ名前にしなければなりません。
493 たとえば先ほどの例の場合は <filename>MysqlResult.php</filename> となります。
497 リソース用のプラグインを含むディレクトリは、
498 <classname>Zend_Amf</classname> 型ローダーで登録しなければなりません。
501 <programlisting language="php"><![CDATA[
502 Zend_Amf_Parse_TypeLoader::addResourceDirectory(
504 "application/library/resources/My"
510 <link linkend="zend.loader.pluginloader">プラグインローダー</link> を参照ください。
514 <classname>Zend_Amf</classname> リソース用のデフォルトディレクトリは自動的に登録されており、
515 現在ここには "mysql result" リソースおよび "stream" リソースのプラグインが格納されています。
518 <programlisting language="php"><![CDATA[
519 // Example class implementing handling resources of type mysql result
520 class Zend_Amf_Parse_Resource_MysqlResult
523 * Parse resource into array
525 * @param resource $resource
528 public function parse($resource) {
530 while($row = mysql_fetch_assoc($resource)) {
539 未知のリソース型 (つまり、処理用プラグインが存在しない型)
545 <sect2 id="zend.amf.server.flash">
546 <title>サーバへの Flash からの接続</title>
549 <classname>Zend_Amf_Server</classname> に Flash プロジェクトから接続する方法は、
550 Flex からの場合とは多少異なります。しかし、いったん接続してしまえば
551 <classname>Zend_Amf_Server</classname> は flex の場合と同じように動作します。
552 次の例は Flex <acronym>AS3</acronym> ファイルからでも使用できます。
553 同じ <classname>Zend_Amf_Server</classname> 設定ファイルを用い、
558 Flash CS を開き、新規 Flash ファイル (ActionScript 3) を作成します。
559 そのドキュメントに <filename>ZendExample.fla</filename> という名前をつけ、
560 このサンプルを使用するフォルダに保存します。
561 次に、同じディレクトリに新規 <acronym>AS3</acronym> ファイルを作成し、
562 <filename>Main.as</filename> という名前をつけます。
563 そして両方のファイルをエディタで開きます。
564 これから、ドキュメントクラスを通じてふたつのファイルをつないできます。
565 ZendExample を選択し、ステージ上でクリックします。
566 ステージのプロパティパネルで、ドキュメントクラスを Main に変更します。
567 これで、ActionScript ファイル <filename>Main.as</filename> が
568 <filename>ZendExample.fla</filename> のユーザインターフェイスとつながります。
569 Flash ファイル ZendExample を実行すると、
570 <filename>Main.as</filename> クラスが実行されるようになるのです。
571 次に、<acronym>AMF</acronym> をコールする ActionScript を追加します。
575 それでは、Main クラスを作成していきましょう。
576 これを用いてデータをサーバに送信し、結果を表示します。
577 次のコードを <filename>Main.as</filename> にコピーしましょう。これから、
578 このコードの中身を追いかけながら何をやっているのかを説明していきます。
581 <programlisting language="as"><![CDATA[
583 import flash.display.MovieClip;
584 import flash.events.*;
585 import flash.net.NetConnection;
586 import flash.net.Responder;
588 public class Main extends MovieClip {
589 private var gateway:String = "http://example.com/server.php";
590 private var connection:NetConnection;
591 private var responder:Responder;
593 public function Main() {
594 responder = new Responder(onResult, onFault);
595 connection = new NetConnection;
596 connection.connect(gateway);
599 public function onComplete( e:Event ):void{
600 var params = "Sent to Server";
601 connection.call("World.hello", responder, params);
604 private function onResult(result:Object):void {
605 // Display the returned data
606 trace(String(result));
608 private function onFault(fault:Object):void {
609 trace(String(fault.description));
616 まず、さまざまな作業をするための ActionScript ライブラリをインポートする必要があります。
617 ひとつめが NetConnection で、これはクライアントとサーバの間でパイプのような働きをします。
618 もうひとつは Responder オブジェクトで、
619 これはコールが成功したかどうかなどのサーバからの返り値を処理します。
622 <programlisting language="as"><![CDATA[
623 import flash.net.NetConnection;
624 import flash.net.Responder;
628 クラスの中で 3 つの変数を用意します。これらがそれぞれ NetConnection、Responder
629 そして <classname>Zend_Amf_Server</classname> へのゲートウェイ
630 <acronym>URL</acronym> をあらわします。
633 <programlisting language="as"><![CDATA[
634 private var gateway:String = "http://example.com/server.php";
635 private var connection:NetConnection;
636 private var responder:Responder;
640 Main のコンストラクタでレスポンダを作成し、また
641 <classname>Zend_Amf_Server</classname> エンドポイントへの新規接続も作成します。
642 レスポンダでは、サーバからのレスポンスを処理するメソッドが 2 つ定義されています。
643 わかりやすくするため、それぞれ onResult および onFault と名づけます。
646 <programlisting language="as"><![CDATA[
647 responder = new Responder(onResult, onFault);
648 connection = new NetConnection;
649 connection.connect(gateway);
653 onComplete 関数は、コンストラクタの処理が終わった直後に実行されます。
655 <classname>Zend_Amf_Server</classname> World->hello 関数をコールするコードを 1 行追加しています。
658 <programlisting language="as"><![CDATA[
659 connection.call("World.hello", responder, params);
663 responder を作成した際に、サーバからのレスポンスを処理する関数として
664 onResult と onFault を定義しました。サーバから正しい結果が返ってきたとき用の関数を追加します。
665 成功時のイベントハンドラは、サーバへの接続が正しく処理されるたびに毎回実行されます。
668 <programlisting language="as"><![CDATA[
669 private function onResult(result:Object):void {
670 // Display the returned data
671 trace(String(result));
676 onFault 関数は、サーバから無効な結果が返ってきたときにコールされます。
677 たとえば、サーバからエラーが返された場合、サーバへの <acronym>URL</acronym> が無効な場合、
678 リモート側にサービスやメソッドが存在しない場合など、
679 接続時に問題が発生した場合にコールされることになります。
682 <programlisting language="as"><![CDATA[
683 private function onFault(fault:Object):void {
684 trace(String(fault.description));
689 これで、ActionScript 内でのリモート接続処理は完成しました。
690 ZendExample を実行すると、 <classname>Zend_Amf</classname> へ接続されるようになります。
691 ここまでを振り返ってみましょう。まず最初にリモートサーバへの接続に必要な変数を追加し、
692 サーバからのレスポンスを受け取ったときに使用するメソッドを定義し、
693 そして最後に返された結果を <methodname>trace()</methodname> で出力しました。
698 <sect2 id="zend.amf.server.auth">
702 <classname>Zend_Amf_Server</classname> では、認証と認可のフックを指定して
703 サービスへのアクセスを制御できます。この仕組みは、
704 <link linkend="zend.auth"><classname>Zend_Auth</classname></link> および
705 <link linkend="zend.acl"><classname>Zend_Acl</classname></link>
706 コンポーネントが提供するものを使用しています。
711 <classname>Zend_Amf_Auth_Abstract</classname> を継承した認証アダプタを作成します。
713 <link linkend="zend.auth.introduction.adapters">認証アダプタ</link>
714 と同様に <methodname>authenticate()</methodname> メソッドを実装しなければなりません。
719 <classname>Zend_Amf_Auth_Abstract</classname> のプロパティ
720 <emphasis>_username</emphasis> および
721 <emphasis>_password</emphasis> を使用しなければなりません。
722 <acronym>AMF</acronym> リクエストヘッダに認証情報が含まれていれば、
723 <methodname>authenticate()</methodname> がコールされる前にサーバが
724 <methodname>setCredentials()</methodname> メソッドを用いてその情報を設定します。
728 アダプタが返す識別情報は、<emphasis>role</emphasis>
729 プロパティを含むオブジェクトでなければなりません。
730 これを用いて <acronym>ACL</acronym> アクセス制御が動作します。
734 認証に失敗した場合はそれ以降のリクエストの処理は行われず、
735 失敗したというメッセージとその理由を結果として返します。
739 アダプタとサーバを関連づけるには <methodname>setAuth()</methodname> メソッドを使用します。
742 <programlisting language="php"><![CDATA[
743 $server->setAuth(new My_Amf_Auth());
748 <methodname>setAcl()</methodname> メソッドで設定した
749 <classname>Zend_Acl</classname> オブジェクトを使用します。
752 <programlisting language="php"><![CDATA[
753 $acl = new Zend_Acl();
754 createPermissions($acl); // パーミッション情報を作成します
755 $server->setAcl($acl);
759 <acronym>ACL</acronym> オブジェクトが設定され、コールされるクラスで
760 <methodname>initAcl()</methodname> メソッドが定義されていれば、
761 <acronym>ACL</acronym> オブジェクトを引数としてこのメソッドがコールされます。
762 このクラスは追加の <acronym>ACL</acronym> ルールを作成して
763 <constant>TRUE</constant> を返すこともできますし、
765 <constant>FALSE</constant> を返すこともできます。
769 <acronym>ACL</acronym> の準備が終わると、
770 サーバ側で「指定されたロールで、指定されたクラス (関数コールの際は null)
771 のリソース、指定された関数の実行権限があるかどうか」を調べます。
773 <emphasis>anonymous</emphasis> ロールが定義されているかどうかを調べ、
774 定義されている場合はそれを使用します。定義されていない場合はアクセスを拒否します。
777 <programlisting language="php"><![CDATA[
778 if($this->_acl->isAllowed($role, $class, $function)) {
781 require_once 'Zend/Amf/Server/Exception.php';
782 throw new Zend_Amf_Server_Exception("Access not allowed");