AMFPHP i AS3 – szybki start.
AMFPHP to otwarta biblioteka napisana w PHP będąca w zasadzie implementacją AMF dla tego języka. AMF (Action Message Format) jest z kolei binarnym formatem serializacji danych pomiędzy Flash a innymi językami – w tym przypadku oczywiście z PHP chociaż nie jest to jedyna dostępna platforma. Co nam to wszystko daje? Otóż umożliwia bezpośrednią, bardzo wygodną wymianę danych pomiędzy AS3 a PHP oraz co więcej pewnego rodzaju wyjście AS3 poza stronę klienta z przeskokiem na stronę serwera. Klasy oraz metody napisane w PHP (którego chociaż podstawowe opanowanie jest banalne) mogą być teraz wywoływane bezpośrednio z poziomu AS3, wykonane po stronie serwera a ewentualne wyniki (nawet bardzo złożone) zwrócone wprost do As3.
Przed erą AMFPHP komunikacja Flash-serwer wyglądała mniej więcej w ten sposób: Flash wczytywał jakiś plik php – a właściwie to wczytywał wynik działania danego pliku *.php, ponieważ Flash to client-side a php to server-side, a więc zanim Flash dorwie się do pliku to ten zostanie najpierw wykonany przez serwer. Wyglądało to tak że AS3 ładowało te same dane które mógł zobaczyć w przeglądarce użytkownik wpisując adres danego pliku *.php. Jeśli jakiś programista zapragnął coś do PHP przesłać np. aby zapisać to w bazie danych mógł to zrobić poprzez metody GET/POST lecz dane nie były przekazywane do jakiejś konkretnej funkcji czy obiektu php lecz raczej do pliku który był wywoływany. Co więcej za pomocą GET/POST dane przekazywane są na zasadzie „zmienna”=”wartosc_zmienne” – co jest może i dobre ale przy przekazywaniu niewielkich ilości danych. Wróćmy na chwilę jeszcze do wczytywania danych, jak wspomniałem Flash wczytywał nie sam plik php lecz efekt jego działania – oczywiste jest to że Flash nie mógł wczytywać jakiejś witryny web tylko coś co był w stanie zrozumieć i zinterpretować. W efekcie pliki php najczęściej generowały po prostu kod XML który był wczytywany przez AS3 i dalej obrabiany. Mało wygodne, prawda? To spróbuj sobie wyobrazić jak wyglądała próba przesłania do php jakiejś tabeli – np. zawartości koszyka.
I tu wkracza AMFPHP – którego idea jest dość podobna do przedstawionej wyżej. Tak na prawdę obiekty (np. tabele) przesyłane przez AMF podlegają również „przerabiane” na coś co jest w stanie zrozumieć PHP i przesłane do niego. Nie jest to tym razem XML lecz dane przekształcane są do strumienia bajtów (co nazywamy serializacją chociaż tu bardziej by pasował marshalling) i jako takie przekazane do PHP który je deserializuje (proces w drugą stronę). Oczywiście cała realizacja tego zamysłu jest cholernie skomplikowana.
To teraz do dzieła bo okiełznanie tej bestii nie jest w cale takie trudne:) Po pierwsze ściagamy paczkę z AMFPHP – 2.0 stąd,
W rozpakowanym katalogu odnajdujemy folder „Amfphp” – i to jest w zasadzie wszystko co nam potrzeba, katalog ten należy skopiować na swój serwer php lub do odpowiedniego folderu serwera postawionego lokalnie.
Tak to powinno wyglądac jeśli wpiszemy adres naszego folderu „Amfphp”:
Teraz pora na kod PHP:
<?php class TestClass { public function sqr($no){ return $no*$no; } } ?>
Jak widać łatwo prosto i przyjemnie, jedna klasa o nazwie TestClass posiadająca jedną publiczną funkcję „sqr”, która przyjmuje jeden parametr – w naszym przypadku będzie to liczba. Funkcja oblicza kwadrat podanej liczby i zwraca wyliczoną wartość. Plik zapisujemy na serwerze w katalogu Amfphp/Services w folderze można tworzyć dalesze podfoldery zależnie od projektu. Wywołanie ponownie adresu amfphp pokaże na spisie nową klasę z jedną funkcją, klikając jej nazwę można w bardzo prosty sposób przetestować jej działanie (w pole „no” wpisujemy dowolną liczbę):
Strona Flasha – oto kod realizujący połączenie:
package { import flash.display.Sprite; import flash.events.Event; import flash.net.NetConnection; import flash.net.Responder; /** * ... * @author andrzej nowak */ public class Main extends Sprite { private const _address:String = "http://localhost/Amfphp/"; private var _nc:NetConnection; private var _res:Responder; public function Main():void { _nc = new NetConnection(); _nc.connect(_address); _res = new Responder(onResult, onStatus); _nc.call("Test.TestClass.sqr", _res, 2); } private function onResult($ob:Object):void { trace("Wynik: " + $ob.toString()); } private function onStatus($ob:Object):void { trace("Błąd"); } } }
a na outpucie:
Done(0)
[Starting debug session with FDB]
Wynik: 4
Do obsługi AMF potrzeba w sumie dwóch obiektów – klasy NetConnection oraz Responder.
_nc = new NetConnection(); _nc.connect(_address);
Za pomocą metody „connect” obiektu klasy NetConnection łączymy się z serwerem wskazując na folder – np. http://twoja_domena/Amfphp/
_res = new Responder(onResult, onStatus);
Konstruktor klasy Responder otrzymuje nazwy dwóch funkcji, pierwsza zostanie wywołana kiedy serwer zwórci prawidłową odpowiedz druga natomiast gdy nieprawidłową. Funkcję Respondera można więc porównać do sortownika danych i jak każdy sortownik tak i Responder przekazuje paczki dalej – tak więc każda z funkcji wywoływana przez obiekt respondera otrzymuje jeden argument typu Object.
I na koniec wywołanie funkcji po stronie serwera:
_nc.call("TestClass.sqr", _res, 2);
Służy do tego metoda „call” otrzymująca faktycznie 3 argumenty:
- 1 – w postaci String; nazwa klasy i po kropce nazwa funkcji jaką chcemy wywołać po stronie serwera, jesli klasa znajduje się w jakimś podfolderze wewnątrz /Amfphp/Services/ np. „Test” (/Amfphp/Services/Test/) należy nazwę tego folderu również uwzględnić – np. „Test.TestClass.sqr”
- 2 – to obiekt respondera który bedzie analizował odpowiedzi tego wywołania
- 3 – to właściwie tablica w której przekazujemy argumenty dla funkcji w PHP – w naszym przypadku jest to liczba „2”, jeśli funkcja oczekiwałaby większej ilości argumentów przekazujemy je po prostu dalej przedzielając przecinkiem – np: _nc.call(„TestClass.sqr”, _res, 2, 3, 6, „cos tam”)