Przyjemna komunikacja php – flash czyli AMFPHP

Z pewnością każdy programista php, który w swoim projekcie musiał komunikować się z flash’em na własnej skórze doświadczył, że nie jest to zadanie ani przyjemne ani przyjazne w implementacji.

Aby przekazać dane flash’owi, skrypty muszą generować XML’e, które następnie zasysa flash i przetwarza Action Script’em. Bolączek tego rozwiązania jest wiele, poczynając od dodatkowego czasu potrzebnego na implementacje, wygenerowania XML i późniejszego jego zdekodowania a skończywszy na generowaniu sztucznego transferu, ograniczeniach w wielkości plików XML i trudności w debugowaniu.

Znamy zatem bolączki standardowej komunikacji php-flash, zatem trzeba zadać sobie pytanie czy możemy ich uniknąć? Oczywiście!

AMFPHP czyli przyjazna komunikacja na lini php – flash

AMFPHP to open source’owa implementacja Action Message Format (AMF). Bibliteka ta poprzez RPC (Remote Procedure Call) pośredniczy w komunikacji skryptów Action Script ze skryptami serwerowymi, przesyłane dane są serializowane do postaci binarnej. Wymiana danych następuje poprzez plik gateway.php. AMFPHP zachowuje typu danych: obiekt, tablica, wartości typu int, null, bool będą w tej samej postaci dostępne w Action Script w php.

Powyższy opis może nieco odstraszać egzotycznymi nazwami, to tylko teoria w praktyce nie ma się czego obawiać, zaraz na przykładzie pokaże, że instalacja jak i konfiguracja jest banalna.

1. Ściągamy najnowszą wersję AMFPHP, aktualnie jest to wersja 1.9 beta 2. Znaczkiem beta nie ma się co zanadto przejmować, gdyż wersja ta jest stabilna i dobrze przetestowana.
2. Rozpakowywujemy archiwum powyżej document_root gdyż katalog browser i plik gateway.php muszą być dostępne przez HTTP. Resztę plików można by schować poniżej document_root, jednak na potrzeby tej prezentacji nie będę się w takie szczgóły zagłębiać.
3. W katalogu services tworzymy usługi, które maja postac klas PHP. Kod przykładowej usługi:

<?php
require_once( '/my_application/library/core_classes/game.php' );

class FlashGame {

	private $game;
	
	public function __construct() {
		$this->game = new Game();
	}
	
	/**
	 * Metoda zwraca informacje o grze i uzytkowniku
	 *
	 * @param integer - id gry
	 * @param integer - id usera
	 * @return array
	 */
	public function getResults( $gameID, $userID ) {
		$response['info'] = $this->game->getGameInfo( $gameID );
		$response['user'] = $this->game->getUserInfo( $userID );

		return $response;
	}

	/**
	 * Metoda usua uzytkownika
	 *
	 * @param integer - id usera
	 * @return bool
	 */
	public function remove( $userID ) {
		return (bool)$this->game->remove( $userID );
	}
	
	/**
	 * Metoda zwraca obiekt gry
	 *
	 * @return Object
	 */
	public function getGameObject() {
		return $this->game->getGameObject();
	}
}
?>

Klasy usług powinny być maksymalnie proste i jedynie odwoływać się do klas logiki biznesowej aplikacji. Taka konstrukcja zapewnia jasny i przejrzysty kod aplikacji i jest zgodna z kanonami programowania.

Jeżeli poprawnie wykonaliśmy powyższe operacje to będziemy mogli odpalić browsera i z jego poziomu przetestować działanie. Odpalamy browsera (tutaj przykład), przy pierwszym odpaleniu pyta się nas o ścieżkę do gateway i prezentacje wyników, wybierzmy ‚tree view’, i klikamy OK.

Po lewej stronie widzimy dostępne usługi, po dwukrotnym kliknięciu na nazwę usługi pojawiają nam się dostępne metody. Domyślnie widoczne są wszystkie metody, można to zmienić pisząc znak podkreślenia na początku jej nazwy. Każda metoda opisana jest komentarzem wyciągniętym z klasy oraz zawiera pola na wprowadzenie testowych danych. Pola te odpowiadają parametrom przyjmowanym przez tą metodę.

Z poziomu browsera możemy przetestować działanie metod poprzez kliknięcie na przycisk call, wyniki prezentowane są w oknie poniżej. Prezentowany wynik jest identyczny z tym co dostaje Flash. Po publikacji aplikacji należy pamiętać o skasowaniu lub zabezpieczeniu hasłem dostępu katalog browsera.

Zatem podsumujmy co daje nam AMFPHP:

  • oszczędność w implementacji
  • łatwe testowanie i debugowanie aplikacji
  • mniejszy transfer serwera
  • większa szybkość działania aplikacji
  • przejrzystość i skalowalność
  • bezpieczeństwo (dane przesyłane binarnie a XML w postaci jawnej)
  • proste wdrożenie do aplikacji

Tutaj do ściągnięcia jest cała paczka AMFPHP wraz z przykładowymi serwisami.

Konwersja pliku wideo (mpg,mpeg,avi,3gp) do flv – ffmpeg

Aby odtwarzać plik wideo w playerze flash’owym osadzonym na stronie naszej aplikacji plik
musi być w formacie FLV (Flash Video). Konwersję można zrobić ‚ręcznie’ lub zautomatyzować używając do tego dziennika crontab’a i unix’owego programu ffmpeg.

Ffmpg jest naprawdę rewelacyjnym programem, obsługuje konwersję wielu formatów audio, video oraz graficznych.

Posiada on sporą liczbę opcji i umożliwia dokonywanie wielu operacji na przetwarzanych
plikach. Pełna lista opcji dostępna jest w dokumentacji. Zobacz także składnię ffmpeg.

ffmpeg -i plik_wejsciowy -s 352×288 -acodec mp3 -r 25 -ar 22050 -ac 2 -ab 48k -b 400k -f flv plik_wyjsciowy.flv

Powyższe polecenie dokona konwersji pliku wejściowego do formatu FLV. Użyte parametry oznaczają:

* -i plik wejściowy
* -s 352x288: ustalenie rozmiaru (szerokość x wysokość) pliku wyjściowego (wartości muszą być parzyste)
* -acodec mp3: wymuszenie użycia kodeku audio (mp3)
* -r 25: ustawienie framerate'u pliku wyjściowego na 25 klatek/sek
* -ar 22050: ustawienie częstotliwości próbkowania dźwięku w Hz (domyślnie 44100hz)
* -ac 2: ustawienie liczby kanałów audio (2 - stereo, 1 - mono)
* -ab 48k: ustawienie bitrate'u dźwięku pliku wyjściowego bits/s  (domyślnie 64kbps)
* -b 400k: ustawienie bitrate'u wyjściowego pliku wideo bits/s (domyślnie 2000kbps)
* -f flv: wymuszenie formatu pliku wyjściowego
* plik_wyjsciowy.flv - plik wyjściowy

Tak przekonwertowany plik wideo powinien zachować jakość bardzo zbliżoną do oryginału. W razie potrzeby można poeksperymentować z wielkością parametrów bitrate’u, framerate’u oraz z kodekami aby otrzymać pożądaną jakość widea wyjściowego.

Działanie response w FireBug

Co to jest Firebug nie będę wyjaśniał, każdy webdeveloper powinien wiedzieć o co chodzi. W dwóch słowach: jest to bardzo przydatny plugin do Firefoxa umożliwiający m.in wyświetlenie wszystkich request-ów wygenerowanych przez wygenerowaną stronę. Dotyczy to zarówno żądań wygenerowanych przez odwołania do obrazków, css-ów jak i żądań wygenerowanych przez skrypty javascript-owe i flash-owe. (inspect->net-all)

Przy każdym requescie można podglądnąć ‚response’ – czyli odpowiedź skryptu na wysłane żądanie. Jest to szczególnie przydatne w przypadku debugowania serwerowych skryptów aplikacji, które dostarczają dane skryptom działającym po stronie przeglądarki (np. javascript, flash).

Ale uwaga! Należy pamiętać, że w momencie gdy w Firebugu przy danym requescie klikniemy na response to prezentowany response niestety nie jest tym oryginalnym tylko skrypt, którego dotyczy jest wywoływany ponownie.

Wszystko byłoby fajnie gdyby nie to, że niektóre skrypty serwerowe wykonują operacje, które nie można powtórzyć (np. INSERTy, DELETy w bazie) i w takim przypadku kolejne wywołania zwrócą już błędne dane. W takim wypadku jedyna sensowną opcją debugowania pozostaje zapis do pliku. Nie jest to niestety zbyt przyjazna metoda, ale cóż…jedyna skuteczna.