PHP i Windows - Silverlight i PHP w jednym domu stały  Udostępnij na: Facebook

Autor: Maciej Wilgucki

Opublikowano: 2010-07-26

Silverlight jest technologią Microsoftu umożliwiającą tworzenie bogatych aplikacji działających w środowisku webowym. Niejednokrotnie przedstawiany jako konkurencja dla technologii Flash, zyskał uznanie programistów oraz użytkowników. Za co jest tak lubiany? Każdy udzieli innej odpowiedzi na to pytanie. Mnie, programistę PHP, przekonał do siebie prostotą komunikowania się z innymi technologiami, między innymi ze wspomnianym przed chwilą PHP. Sposobów komunikacji jest co najmniej kilka – najpopularniejsze opiszę w dzisiejszym artykule.

Najprostszy sposób pobierania danych

Najprostszym sposobem pobierania danych przez aplikację Silverlight ze skryptu PHP jest typowe żądanie GET:

WebClient wc = new WebClient();
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri("http://localhost/get.php?zmienna1=abc&zmienna2=123"));

Jedyne, co pozostało, to utworzyć metodę wc_DownloadStringCompleted, która odbierze i przetworzy dane. Adres, na jaki wysyłane jest żądanie GET, oraz dodatkowe parametry są dowolne i zależą od konkretnego projektu.

Bardzo ważne jest, aby na serwerze, do którego się łączymy, znajdował się plik crossdomain.xml, umożliwiający naszej aplikacji (a dokładniej rzecz ujmując, domenie, w której uruchamiana jest aplikacja Silverlight) dostęp do serwera. Wspomniany plik crossdomain.xml to ten sam plik, którego wymaga technologia Flash. Twórcy Silverlighta wyszli naprzeciw potrzebom programistów i korzystają z pliku stworzonego dla technologii Flash, dzięki czemu nie ma konieczności tworzenia dwóch różnych plików.

Po stronie PHP odebranie danych sprowadza się do pobrania danych z tablicy globalnej $_GET (ewentualnie $_REQUEST).

Wysyłanie formularza

Strona internetowa komunikuje się z użytkownikiem najczęściej za pomocą formularzy. Nie ma chyba dynamicznej strony, która nie zawierałaby przynajmniej jednego formularza, np. kontaktowego. Formularze najczęściej wysyłane są metodą POST. Silverlight, podobnie jak w przypadku żądań GET, ma możliwość wysyłania POST-ów do skryptu PHP.

WebClient wc = new WebClient();
            wc.UploadStringCompleted += new UploadStringCompletedEventHandler(wc_UploadStringCompleted);
            wc.Encoding = Encoding.UTF8;
            wc.Headers["Content-Type"] = "application/x-www-form-urlencoded";
string dane = "zmienna1=abc&zmienna2=123";
wc.UploadStringAsync(new Uri("http://localhost/post.php"), dane);

Podobnie jak poprzednim razem, musimy pamiętać o utworzeniu metody wc_UploadStringCompleted, która zajmie się odebraniem odpowiedzi z serwera. Nie można również zapomnieć o pliku crossdomain.xml.

Dane wysłane w ten sposób z aplikacji Silverlight znajdziemy w tablicy $_POST (lub $_REQUEST).

Serwery gniazd (socket server)

Opisane do tej pory sposoby komunikacji były jednostronne – żaden z nich nie umożliwia wysłania wiadomości z PHP do Silverlighta bez udziału drugiego „rozmówcy”. „Rozmowa” zawsze musiała być zainicjowana po stronie Silverlighta. Serwer gniazd umożliwia wysyłanie wiadomości do aplikacji Silverlight w dowolnym momencie.

W przypadku serwera gniazd sprawy nieco się komplikują, ponieważ skrypt po stronie serwera wymaga nieco więcej kodu niż sprawdzenie zawartości zmiennych $_GET lub $_POST. Przykładowy serwer może wyglądać następująco:

set_time_limit(0);

$address = '127.0.0.1';
$port = 9999;
// standardowe ustawienia socketa
$mainSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($mainSocket, $address, $port);
socket_listen($mainSocket);

// wyłączenie blokowania skryptu, podczas oczekiwania na nowe połączenia
// dzięki temu pętla działa cały czas i można sprawdzić
// czy na serwerze coś się zmieniło
socket_set_nonblock($mainSocket);

// lista podłączonych klientów
$clients = array();

while(true) {
 // utworzenie klientów, do których będą wysyłane wiadomości
$read = array();
 $read[0] = $mainSocket;
 foreach($clients as $client) {
  $read[] = $client;
 }

 foreach($read as $sock) {
  if($sock == $mainSocket) {
   if(($client = @socket_accept($sock)) !== false) {
$clients[] = $client;
   }
  }
 }

 // sprawdzenie, czy serwer stworzył plik informujący o zmianach
if(file_exists('./makechange.txt')) {
// wyślij do każdego klienta wiaomość
  foreach($clients as $client) {
   // treść wiadomości
   $message = "abc123\0";

   // jeśli nie udało wysłać się wiadomości, należy usunąć klienta
if(!@socket_write($client, $message)) {
    $indexClients = array_search($client, $clients);
    unset($clients[$indexClients]);
    $indexRead = array_search($client, $read);
    unset($read[$indexRead]);
    socket_close($client);
}
  }
  // usunięcie pliku z informacją o zmianach na serwerze
  unlink('./makechange.txt');
 }

 // dzięki tej funkcji skrypt nie zużyje wszystkich dostępnych zasobów serwera
 sleep(1);
}

Jest to serwer wysyłający wiadomość do wszystkich podłączonych klientów w momencie pojawienia się na serwerze jakieś informacji. „Jakaś” informacja w tym przypadku to utworzenie pliku.

Po stronie Silverlighta kod jest nieco prostszy:

IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999);
sock = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.UserToken = sock;
args.RemoteEndPoint = endPoint;
args.Completed += new EventHandler<socketasynceventargs>(ConectionCompleted);
args.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Http;

sock.ConnectAsync(args);

Jedyne, czego brakuje w powyższym kodzie, to obsługa przychodzących informacji, która powinna mieć miejsce w metodzie ConectionCompleted.

Podsumowanie

Poznaliśmy dzisiaj sposoby na skomunikowanie ze sobą Silverlighta oraz PHP. W ostatnim przypadku dowiedzieliśmy się, że niekoniecznie musi to być komunikacja jednostronna. Warto również wspomnieć, że Silverlight ma możliwość wywoływania funkcji JavaScript zdefiniowanych na stronie, na której jest osadzony. Otwiera to kolejne możliwości przed programistami.