10. Serwery w PHP
Ponieważ programy PHP mogą być uruchamiane przez serwer WEB, taki program staje się programem serwerowym, który może obsługiwać wielu klientów. Z punktu widzenia klienta wywołanie usługi WEB sprowadza się do zażądania adresu URL tej usługi. Klient może być napisany w dowolnym języku, w szczególności w PHP. W tym ostatnim przypadku wykorzystuje się funkcje sieciowe, które właśnie omówiliśmy. Musimy ponadto umieć „komunikować się” z usługą WEB, czyli rozumieć protokół http służący do komunikacji między serwerem WWW a jego klientami. Taki jest cel poniższych programów.
Klient internetowy opisany w paragrafie 9.2 pozwolił nam poznać część protokołu HTTP.

W najprostszej wersji wymiana danych między klientem a serwerem przebiega następująco:
- klient nawiązuje połączenie z portem 80 serwera internetowego
- wysyła żądanie dotyczące dokumentu
- serwer wysyła żądany dokument i zamyka połączenie
- klient z kolei zamyka połączenie
Klient może mieć różną postać: tekst w formacie HTML, obraz, film... Może to być dokument istniejący (dokument statyczny) lub dokument generowany na bieżąco przez skrypt (dokument dynamiczny). W tym ostatnim przypadku mówimy o programowaniu internetowym. Skrypt do dynamicznego generowania dokumentów może być napisany w różnych językach: PHP, Python, Perl, Java, Ruby, C#, VB.net itp.
W tym przypadku używamy języka PHP do dynamicznego generowania dokumentów tekstowych.
![]() |
- w [1] klient nawiązuje połączenie z serwerem, żąda skryptu PHP, wysyła lub nie parametry do tego skryptu
- W przypadku [2] serwer WWW uruchamia skrypt PHP za pomocą interpretera PHP. Skrypt ten generuje dokument, który jest wysyłany do klienta [3]
- serwer zamyka połączenie. Klient robi to samo.
Serwer WWW może obsługiwać wielu klientów jednocześnie. W przypadku pakietu oprogramowania WampServer serwerem WWW jest serwer Apache, serwer typu open source opracowany przez Apache Foundation (http://www.apache.org/). W poniższych aplikacjach należy uruchomić WampServer. Spowoduje to uruchomienie trzech programów: serwera WWW Apache, SGBD oraz MySQL, a także interpretera PHP.
Skrypty uruchamiane przez serwer WWW będą pisane przy użyciu narzędzia NetBeans. Do tej pory napisaliśmy skrypty PHP uruchamiane w środowisku konsoli:
![]() |
Użytkownik korzysta z konsoli, aby zlecić wykonanie skryptu PHP i otrzymać jego wyniki.
W kolejnych aplikacjach typu klient-serwer
- skrypt kliencki jest uruchamiany w środowisku konsoli,
- skrypt serwera jest wykonywany w kontekście internetowym
![]() |
Skrypt serwerowy PHP nie może znajdować się w dowolnym miejscu w systemie plików. Serwer WWW przeszukuje bowiem w lokalizacjach określonych w konfiguracji, szukając żądanych dokumentów statycznych i dynamicznych. Domyślna konfiguracja WampServer powoduje, że dokumenty są wyszukiwane w folderze <WampServer>/www, gdzie <WampServer> to folder instalacyjny WampServer. W ten sposób, gdy klient sieciowy żąda dokumentu D z katalogu URL lub [http://localhost/D], serwer sieciowy dostarczy mu dokument D znajdujący się w ścieżce [<WampServer>/www/D].
W poniższych przykładach umieścimy skrypty serwerowe w folderze [www/exemples-web]. Jeśli skrypt serwerowy nosi nazwę S.php, zostanie on zażądany od serwera WWW za pomocą URL i [http://localhost/exemples-web/S.php]. Wówczas zostanie mu dostarczony dokument o nazwie [<WampServer>/www/exemples-web/S.php].
![]() |
Aby w programie utworzyć skrypt serwerowy za pomocą NetBeans, należy postępować w następujący sposób:
![]() |
- w [1] tworzymy nowy projekt
- w [2] wybieramy kategorię [PHP] oraz projekt [PHP Application]
![]() |
- w [3] nadajemy nazwę projektowi
- w [4] wybieramy folder dla projektu
- w [5] określamy, że skrypt ma być uruchamiany przez lokalny serwer WWW (adres skryptu będzie miał postać http://localhost/...). Lokalnym serwerem WWW będzie serwer Apache z WampServer.
- W polu [6] podajemy adres URL projektu. W tym miejscu ustalamy, że skrypt o identyfikatorze S.php z projektu zostanie wywołany wraz z identyfikatorami URL i [http://localhost/exemples-web/S.php]. Z powyższego wynika, że ścieżka do skryptu S.php w systemie plików będzie brzmiała [<WampServer>/www/exemples-web/S.php]. Tak właśnie jest wskazane w [7]. Prosimy tutaj, aby każdy skrypt S.php z projektu został skopiowany do drzewa katalogów serwera WWW Apache.
- w nowym projekcie o nazwie [8].
Napiszmy skrypt testowy:
![]() |
- o nazwie [1], w projekcie [exemples-web] tworzymy pierwszy skrypt o nazwie PHP
- w [2] nadajemy mu nazwę
- w [3], po utworzeniu nadajemy mu następującą treść
Następnie należy uruchomić skrypt WampServer.
![]() |
- w [4] uruchamiamy skrypt internetowy [exemple1.php]. NetBeans uruchomi wówczas domyślną przeglądarkę na komputerze i poprosi ją o wyświetlenie pliku URL, [http://localhost/exemples-web/exemple1.php] oraz [5]
- w formacie [6], a przeglądarka wyświetla to, co skrypt serwera wysłał do klienta.
W dalszej części spotkamy się z dwoma typami klientów internetowych:
- przeglądarkę taką jak powyżej. Napisaliśmy, że serwer WWW wysyła odpowiedź w postaci: nagłówki HTTP, pusty wiersz, tekst. Przeglądarka wyświetla tylko texte.
- skrypt PHP, który wyświetli mu całą odpowiedź: nagłówki HTTP, pusty wiersz, tekst.
W dalszej części
- skrypty serwerowe będą pisane tak jak powyższy [exemple1.php]
- skrypty klienckie będą zapisywane tak samo jak skrypty konsolowe, które pisaliśmy do tej pory.
10.1. Aplikacja klient-serwer do obsługi daty i godziny
10.1.1. Serwer (web_01)
<?php
// czas: liczba milisekund od 01.01.1970
// format wyświetlania daty i godziny
// d: dzień w formacie dwucyfrowym
// m: miesiąc (2 cyfry)
// y: rok (2 cyfry)
// H: godzina 0,23
// i: minuty
// s: sekundy
print date("d/m/y H:i:s",time());
Zasadniczo powyższy skrypt PHP wyświetla aktualny czas na ekranie. Jednak gdy jest on uruchamiany przez serwer WWW, strumień nr 1, który zazwyczaj jest powiązany z ekranem, jest przekierowywany do połączenia łączącego serwer z klientem. W związku z tym w środowisku internetowym powyższy skrypt wysyła aktualny czas w postaci tekstu do klienta.
Uruchommy ten skrypt w środowisku NetBeans:
![]() |
- w pliku [1] uruchamiamy skrypt. Następnie uruchamia się przeglądarka internetowa.
- W pliku [2] wywoływany jest plik URL, o który poprosiła przeglądarka internetowa
- w [3] – tekst wysłany przez skrypt serwera
Przeglądarka kliencka wykorzystuje protokół HTTP do komunikacji z serwerem WWW. Opisaliśmy już strukturę tego protokołu.
Klient wysyła wiersze tekstu, które można podzielić na trzy części: nagłówki HTTP, pusty wiersz oraz dokument. Dokument wysyłany do serwera internetowego jest najczęściej pusty lub stanowi zbiór parametrów parami=vali, gdzie vali to wartość wprowadzona przez użytkownika w formularzu HTML.
Odpowiedź serwera ma tę samą strukturę: nagłówki HTTP, pusty wiersz, dokument, gdzie document to tym razem dokument żądany przez przeglądarkę klienta. Jeśli klient przesłał parametry, dostarczony dokument zależy zazwyczaj od tych parametrów.
W przeglądarce Firefox można prześledzić rzeczywistą wymianę danych między klientem a serwerem internetowym. Istnieje wtyczka o nazwie Firebug, która pozwala na śledzenie tej wymiany. Firebug jest dostępny na stronie URL [https://addons.mozilla.org/fr/firefox/addon/firebug/]. Jeśli używamy przeglądarki Firefox do odwiedzenia tego adresu URL, możemy pobrać wtyczkę Firebug. W dalszej części zakładamy, że wtyczka Firebug została pobrana i zainstalowana. Jest ona dostępna poprzez opcję w menu przeglądarki Firefox:
![]() |
W oknie przeglądarki Firefox otwiera się okno Firebug. Okno to zawiera własne menu:
![]() |
Aby sprawdzić komunikację między klientem a serwerem podczas żądania HTTP, wysyłamy żądanie URL [http://localhost/exemples-web/web_01.php] za pomocą przeglądarki Firefox. Okno Firebug wypełnia się wówczas informacjami:
![]() |
Powyżej znajduje się podsumowanie komunikacji między klientem a serwerem:
- [1]: klient wysłał polecenie HTTP: GET /exemples-web/web_01.php HTTP/1.1 w celu zażądania dokumentu [web01.php]
- [2]: serwer wysłał odpowiedź: HTTP/1.1 200 OK, wskazując, że znalazł żądany dokument.
Firebug pozwala uzyskać pełną treść wymiany danych. Wystarczy „rozwinąć” URL:
![]() |
Powyżej widzimy nagłówki HTTP wymieniane między klientem (żądanie) a serwerem (odpowiedź). Możliwe jest uzyskanie kodu źródłowego tej wymiany, c.a.d, oraz rzeczywistych wierszy tekstu, które zostały wymienione, [1]. Otrzymujemy wówczas następujący kod źródłowy:
![]() |
Aby napisać skrypt kliencki dla serwera WWW, wystarczy odtworzyć zachowanie przeglądarki. Po nawiązaniu połączenia z serwerem skrypt kliencki mógłby wysłać 8 wierszy powyższego żądania. W rzeczywistości nie wszystko jest niezbędne i wyślemy tylko trzy następujące wiersze:
- wiersz 1: określa żądany dokument i używany protokół HTTP
- wiersz 2: podaje nazwę komputera, na którym znajduje się skrypt kliencki
- wiersz 3: wskazuje, że po zakończeniu wymiany danych klient zamknie połączenie z serwerem
Przyjrzyjmy się teraz odpowiedzi serwera. Wiemy, że została ona wygenerowana przez skrypt PHP [web_01.php]. Powyżej widzimy nagłówki odpowiedzi HTTP. Kod skryptu [web01.php] wskazuje, że to nie on je wygenerował. Przypomnijmy sobie konfigurację skryptu serwera:
![]() |
To serwer WWW wygenerował nagłówki odpowiedzi HTTP. Skrypt serwera może je generować samodzielnie. Przykład tego zobaczymy nieco dalej.
Wspomnieliśmy, że odpowiedź serwera internetowego miała następującą postać: nagłówki HTTP, pusty wiersz, dokument. Jeśli dokument jest dokumentem tekstowym, można go zobaczyć w zakładce [Réponse] w Firebug:
![]() |
Ta odpowiedź została wygenerowana przez skrypt [web_01.php].
10.1.2. Klient (client1_web_01)
Teraz piszemy skrypt kliencki dla powyższej usługi. Wiemy, że klient musi:
- nawiązać połączenie z serwerem WWW
- wysłać tekst: nagłówki HTTP, pusty wiersz
- odczytać całą odpowiedź serwera, aż ten zamknie połączenie z klientem
- zamknąć połączenie z serwerem
Skrypt kliencki jest uruchamiany w środowisku konsoli programu NetBeans:
![]() |
- w [1] skrypt kliencki [client1_web_01.php] jest dołączony do projektu NetBeans [exemples]
- w [2] właściwości projektu NetBeans [exemples]
- w [3] projekt NetBeans [exemples] działa w trybie „wiersza poleceń”, który nazwaliśmy również trybem „konsoli”.
Kod skryptu klienckiego wygląda następująco:
<?php
// dane
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_01.php";
// nawiązanie połączenia na porcie 80 serwera $HOTE
$connexion = fsockopen($HOTE, $PORT);
// błąd?
if (!$connexion) {
print "Erreur : $erreur\n";
exit;
}
// nagłówki (headers) protokołu HTTP muszą kończyć się pustym wierszem
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Połączenie
fputs($connexion,"Connection: close\n");
// pusty wiersz
fputs($connexion,"\n");
// serwer będzie teraz odpowiadał na kanale $connexion. Wyśle wszystkie
// swoje dane, a następnie zamknie kanał. Klient odczytuje zatem wszystko, co nadchodzi z $connexion
// aż do zamknięcia kanału
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
}//, podczas gdy
// klient z kolei zamknie połączenie
fclose($connexion);
// koniec
exit;
Komentarze
- wiersz 8: nawiązanie połączenia z serwerem
- wiersz 16: polecenie HTTP GET
- wiersz 18: polecenie HTTP Host
- wiersz 20: polecenie HTTP Połączenie
- wiersz 22: pusty wiersz
- wiersze 26–28: odczyt wszystkich wierszy tekstu wysłanych przez serwer, aż do momentu zamknięcia połączenia przez serwer.
- wiersz 30: klient z kolei zamyka połączenie
Wyniki
Wykonanie skryptu klienckiego daje następujące wyniki:
Komentarze
- wiersze 1–7: odpowiedź serwera WWW o treści HTTP.
- wiersz 8: pusty wiersz sygnalizujący koniec nagłówków HTTP
- wiersze od 9 wzwyż: dokument. W tym przypadku jest to prosty tekst przedstawiający aktualną datę i godzinę. Jest to tekst zapisany przez skrypt PHP na wyjściu nr 1.
- wiersz 1: serwer odpowiada, że znalazł żądany dokument.
- wiersz 2: aktualna data i godzina serwera
- wiersz 3: identyfikator serwera WWW
- wiersz 4: wskazuje, że następujący po nim dokument został wygenerowany przez skrypt PHP
- wiersz 5: liczba znaków w dokumencie
- wiersz 6: serwer informuje, że po wysłaniu dokumentu zamknie połączenie
- wiersz 7: wskazuje, że dokument wysłany przez serwer jest tekstem w formacie HTML. W tym przypadku jest to nieprawidłowe. Dokument jest tekstem bez określonego formatu. Gdy dokument nie jest tekstem w formacie HTML, skrypt PHP powinien to zaznaczyć. W tym przypadku tego nie zrobiliśmy.
10.1.3. Drugi klient (client2_web_01)
Poprzedni klient wyświetlał wszystko, co wysyłał mu serwer WWW. W praktyce zazwyczaj pomija się nagłówki odpowiedzi HTTP i wykorzystuje się samą treść dokumentu. W tym przypadku staramy się pobrać datę i godzinę wysłane przez skrypt serwera PHP. Informacje te pobierzemy za pomocą wyrażenia regularnego.
<?php
// pobieranie informacji wysłanych przez serwer WWW
// dane
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_01.php";
// nawiązanie połączenia na porcie 80 serwera $HOTE
$connexion = fsockopen($HOTE, $PORT);
// błąd?
if (!$connexion) {
print "Erreur : $erreur\n";
exit;
}
// nagłówki (headers) protokołu HTTP muszą kończyć się pustym wierszem
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Połączenie
fputs($connexion,"Connection: close\n");
// pusty wiersz
fputs($connexion,"\n");
// serwer będzie teraz odpowiadał na kanale $connexion. Wyśle wszystkie
// te dane, a następnie zamknie kanał. Klient odczytuje więc wszystko, co przychodzi z $connexion
// aż znajdzie szukaną linię w formacie dd/mm/rr hh:mm:ss
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
if (preg_match("/(\d\d)\/(\d\d)\/(\d\d) (\d\d):(\d\d):(\d\d)/", $ligne, $champs)) {
// i pobiera # pól
array_shift($champs); // usuwa pierwszy element tablicy pól
// pobieramy 6 pól do 6 zmiennych
list($j, $m, $a, $h, $i, $s) = $champs;
// wyświetlanie wyniku
print "\ndateheure=[$j,$m,$a,$h,$i,$s]\n";
}//if
}//while
// klient z kolei zamyka połączenie
fclose($connexion);
// koniec
exit;
Wyniki
10.2. Pobieranie przez serwer parametrów przesłanych przez klienta
W protokole HTTP klient ma dwie metody przekazywania parametrów do serwera WWW:
- wysyła żądanie usługi URL w postaci
GET url?param1=val1¶m2=val2¶m3=val3… HTTP/1.0
gdzie wartości vali muszą zostać wcześniej zakodowane, tak aby niektóre znaki zarezerwowane zostały zastąpione ich wartościami szesnastkowymi.
- wysyła żądanie do usługi URL w postaci
POST url HTTP/1.0
następnie wśród nagłówków HTTP wysyłanych do serwera umieszcza następujący nagłówek:
Kolejne nagłówki wysyłane przez klienta kończą się pustym wierszem. Następnie może on wysłać swoje dane w postaci
gdzie wartości vali muszą, podobnie jak w przypadku metody GET, zostać wcześniej zakodowane. Liczba znaków wysyłanych do serwera musi wynosić N, gdzie N jest wartością zadeklarowaną w nagłówku
Skrypt PHP, który pobiera poprzednie parametry parami wysłane przez klienta, pobiera ich wartości z tablicy:
- $_GET["parami"] dla polecenia GET
- $_POST["parami"] dla polecenia POST
10.2.1. Klient GET (client1_web_02)
Poniższy skrypt PHP wysyła trzy parametry [nom, prenom, age] do serwera.
<?php
// klient: wysyła imię, nazwisko i wiek do serwera za pomocą metody GET
// dane
$HOTE = "localhost";
$PORT = 80;
$URL = "/exemples-web/web_02.php";
list($prenom, $nom, $age) = array("jean-paul", "de la hûche", 45);
// połączenie z serwerem WWW
$connexion = fsockopen($HOTE, $PORT);
// powrót w przypadku błędu
if (!$connexion) {
print "Echec de la connexion au site ($HOTE,$PORT) : $erreur";
exit;
}//if
// wysyłanie informacji na serwer PHP
// kodowanie informacji
$infos = "prenom=" . urlencode(utf8_decode($prenom)) . "&nom=" . urlencode(utf8_decode($nom)) . "&age=" . urlencode("$age");
// monitorowanie konsoli
print "infos envoyées au serveur (GET)=$infos\n";
print "URL demandée=[$URL?$infos]\n\n";
// nagłówki (headers) protokołu HTTP muszą kończyć się pustym wierszem
// GET
fputs($connexion, "GET $URL?$infos HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Połączenie
fputs($connexion,"Connection: close\n");
// pusty wiersz
fputs($connexion,"\n");
// serwer będzie teraz odpowiadał na kanale $connexion. Będzie wysyłał wszystkie
// odczytuje dane, a następnie zamyka kanał. Klient odczytuje wszystkie dane przychodzące od $connexion aż do zamknięcia kanału
while ($ligne = fgets($connexion, 1000))
print "$ligne";
// klient z kolei zamyka połączenie
fclose($connexion);
Komentarze
- wiersz 7: adres URL skryptu serwera
- wiersz 8: wartości trzech parametrów
- wiersz 10: nawiązanie połączenia z serwerem WWW
- wiersz 18: kodowanie trzech parametrów. Mamy do czynienia ze skryptem napisanym w Netbeans z kodowaniem znaków w formacie UTF-8. Zatem trzy wartości parametrów z wiersza 8 są zakodowane w formacie UTF-8. Funkcja utf8_decode przekształca ich kodowanie na ISO-8859-1. Po wykonaniu tej operacji można je zakodować do postaci URL. Wszystkie znaki niealfabetyczne są zastępowane przez %xx, gdzie xx to wartość szesnastkowa danego znaku. Spacje są natomiast zastępowane znakiem +.
- wiersz 24: żądany format URL to $URL?$infos, gdzie $infos ma postać nom=val1&prenom=val2&age=val3.
10.2.2. Serwer (web_02)
Serwer po prostu wyświetla to, co otrzymuje.
<?php
// obsługa błędów
ini_set("display_errors", "off");
// serwer pobiera informacje wysłane przez klienta
// tutaj imię=P&nazwisko=N&wiek=A
// informacje te są automatycznie dostępne w zmiennych
// $_GET['prenom'], $_GET['nom'], $_GET['age']
// są one odsyłane do klienta
// nagłówek UTF-8
header("Content-Type: text/plain; charset=utf-8");
// parametry wysłane do serwera
$prenom = isset($_GET['prenom']) ? $_GET['prenom'] : "";
$nom = isset($_GET['nom']) ? $_GET['nom'] : "";
$age = isset($_GET['age']) ? $_GET['age'] : "";
// odpowiedź dla klienta
$réponse = "informations reçues du client [" .
utf8_encode(htmlspecialchars($prenom, ENT_QUOTES)) .
"," . utf8_encode(htmlspecialchars($nom, ENT_QUOTES)) .
"," . utf8_encode(htmlspecialchars($age, ENT_QUOTES)) . "]\n";
print $réponse;
Uwagi
- wiersz 13: ustawia nagłówek „Content-Type” o wartości HTTP. Domyślnie serwer WWW wysyła nagłówek
, który informuje, że odpowiedź jest tekstem w formacie HTML. W tym przypadku odpowiedź będzie tekstem bez formatowania, zawierającym znaki zakodowane w formacie UTF-8:
Nagłówki HTTP muszą zostać wysłane przed odpowiedzią serwera. Dlatego też, jak pokazano powyżej, wywołanie funkcji header musi znajdować się przed każdą instrukcją print.
- wiersze 16–18: pobieramy 3 parametry z tablicy $_GET.
- wiersz 21: tworzymy ciąg znaków, który zostanie wysłany w odpowiedzi do klienta. Niektóre znaki mają specjalne znaczenie w HTML i muszą zostać zastąpione przez encje HTML, aby mogły zostać wyświetlone. Funkcja htmlspecialchars($string) zastępuje wszystkie te znaki ich odpowiednikami w ciągu znaków $string. Na przykład znak $ zamienia się na &. Następnie, ponieważ w wierszu 13 określiliśmy, że odpowiedzią będzie tekst UTF-8, odzyskane wartości kodujemy jako UTF-8.
- wiersz 25: odpowiedź jest wysyłana do klienta
Test 1
Uruchommy skrypt [web_02] z poziomu NetBeans. Zostanie wówczas uruchomiona przeglądarka, aby wyświetlić URL [http://localhost/exemples-web/web_02.php]:
![]() |
- w [1], przeglądarka wyświetla URL [http://localhost/exemples-web/web_02.php]. Ponieważ nie dodaliśmy parametrów do tego adresu URL, serwer odpowiedział z pustymi parametrami. Przypomnijmy, że odpowiedź serwera jest zgodna z instrukcją print.
- W przypadku adresu [2] dodajemy parametry do adresu URL. Tym razem skrypt serwera prawidłowo je zwraca.
Warto zauważyć, że do uruchomienia skryptu serwerowego nie jest konieczne użycie programu NetBeans. Wystarczy wpisać adres URL skryptu serwerowego w przeglądarce, aby skrypt ten został uruchomiony.
Test 2
W programie NetBeans uruchamiamy klienta o nazwie [client1_web_02.php]. Otrzymujemy następującą odpowiedź:
- wiersz 1: kodowanie trzech parametrów. Widać, że znak û został zamieniony na %FB.
- wiersz 12: odpowiedź serwera
10.2.3. Klient POST (client2_web_03)
Klient HTTP wysyła do serwera WWW następującą sekwencję tekstową: nagłówki HTTP, pusty wiersz, dokument. W poprzednim kliencie sekwencja ta wyglądała następująco:
Nie było dokumentu. Istnieje inny sposób przekazywania parametrów, tzw. metoda POST. W tym przypadku sekwencja tekstowa wysyłana do serwera WWW wygląda następująco:
Tym razem parametry, które w przypadku klienta GET były zawarte w nagłówkach HTTP, w kliencie POST stanowią część dokumentu wysyłanego za nagłówkami.
Skrypt klienta POST wygląda następująco:
<?php
// klient: wysyła imię, nazwisko i wiek do serwera metodą POST
// dane
$HOTE = "localhost";
$PORT = 80;
$URL = "/exemples-web/web_03.php";
list($prenom, $nom, $age) = array("jean-paul", "de la hûche", 45);
// połączenie z serwerem WWW
$connexion = fsockopen($HOTE, $PORT);
// powrót w przypadku błędu
if (!$connexion) {
print "Echec de la connexion au site ($HOTE,$PORT) : $erreur";
exit;
}//if
// wysyłanie informacji na serwer PHP
// kodowanie informacji
$infos = "prenom=" . urlencode(utf8_decode($prenom)) . "&nom=" . urlencode(utf8_decode($nom)) . "&age=" . urlencode("$age");
print "client : infos envoyées au serveur (POST) : $infos\n";
// nawiązuje się połączenie z serwerem URL $URL poprzez wysłanie (POST) parametrów
// nagłówki (headers) protokołu HTTP muszą kończyć się pustym wierszem
// POST
fputs($connexion, "POST $URL HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Connection
fputs($connexion,"Connection: close\n");
// Content-type
fputs($connexion, "Content-type: application/x-www-form-urlencoded\n");
// Długość treści
// przesyłamy rozmiar (liczbę znaków) informacji, które mają zostać wysłane
fputs($connexion, "Content-length: " . strlen($infos) . "\n");
// wysyłany jest pusty wiersz
fputs($connexion, "\n");
// wysyłane są informacje
fputs($connexion, $infos);
// serwer odpowie teraz na kanale $connexion. Wyśle wszystkie
// swoje dane, a następnie zamknie kanał. Klient odczytuje wszystko, co nadchodzi z $connexion
// aż do zamknięcia kanału
while ($ligne = fgets($connexion, 1000))
print "$ligne";
// klient z kolei zamyka połączenie
fclose($connexion);
Komentarze
- wiersz 7: identyfikator URL serwisu internetowego, z którym połączy się klient POST. Serwis ten zostanie wkrótce opisany.
- wiersz 8: parametry, które należy przekazać do serwisu internetowego
- wiersz 10: połączenie z serwerem internetowym
- wiersz 18: kodowanie parametrów, które mają zostać wysłane do serwisu internetowego
- wiersz 23: polecenie HTTP POST
- wiersz 25: polecenie HTTP Host
- wiersz 27: polecenie HTTP Connection
- wiersz 29: polecenie HTTP Content-type. Z tym nagłówkiem HTTP mieliśmy już do czynienia. Pojawia się on za każdym razem, gdy wysyłany jest dokument. Serwer WWW wysyłający dokument HTML używa nagłówka HTTP
Jeśli wysyła tekst nieformatowany, używa nagłówka HTTP
Nasz klient POST wysyła dokument, który jest tekstem o postaci param1=val1¶m2=val2&.... Ten typ dokumentu ma typ application/x-www-form-urlencoded. Nie będziemy wyjaśniać dlaczego, ponieważ wymagałoby to wyjaśnienia, czym jest formularz internetowy.
- wiersz 32: polecenie Content-length. Z tym nagłówkiem HTTP mieliśmy już do czynienia. Pojawia się on za każdym razem, gdy wysyłany jest dokument. Wskazuje liczbę bajtów dokumentu.
- wiersz 34: pusty wiersz sygnalizujący koniec nagłówków HTTP
- wiersz 36: wysyłanie parametrów
- wiersze 40–41: odczytanie pełnej odpowiedzi serwera
- wiersz 43: zamknięcie połączenia
10.2.4. Serwer (web_03)
Usługa internetowa [web_03] działa tak samo jak usługa internetowa [web_02]. Odczytuje parametry wysłane przez klienta POST i odsyła je z powrotem do klienta. Jej kod wygląda następująco:
<?php
// obsługa błędów
ini_set("display_errors", "off");
// nagłówek UTF-8
header("Content-Type: text/plain; charset=utf-8");
// odzyskiwanie przez serwer informacji wysłanych przez klienta
// tutaj imię=P&nazwisko=N&wiek=A
// informacje te są automatycznie dostępne w zmiennych
// $_POST['prenom'], $_POST['nom'], $_POST['age']
// są one odsyłane do klienta
// parametry wysłane do serwera
$prenom = isset($_POST['prenom']) ? $_POST['prenom'] : "";
$nom = isset($_POST['nom']) ? $_POST['nom'] : "";
$age = isset($_POST['age']) ? $_POST['age'] : "";
// odpowiedź dla klienta
$réponse = "informations reçues du client [" .
utf8_encode(htmlspecialchars($prenom, ENT_QUOTES)) .
"," . utf8_encode(htmlspecialchars($nom, ENT_QUOTES)) .
"," . utf8_encode(htmlspecialchars($age, ENT_QUOTES)) . "]\n";
print $réponse;
Komentarze
- wiersze 14–16: parametry wysłane przez klienta POST stają się dostępne w tablicy $_POST dla serwisu internetowego, który je odbiera.
- wiersz 6: nagłówek HTTP Content-Type. Można się zdziwić, że w nagłówkach HTTP nie ma nagłówka HTTP Content-Length wskazującego rozmiar dokumentu odesłanego do klienta. Widzieliśmy, że serwer WWW domyślnie wysyła nagłówki HTTP. Nagłówek Content-Length jest jednym z nich.
Wyniki
Po napisaniu skryptu serwerowego w NetBeans staje się on natychmiast dostępny za pośrednictwem serwera Apache pod adresem WampServer. Przypomnijmy, że jest to możliwe dzięki odpowiedniej konfiguracji (patrz akapit 10). Uruchamiamy klienta, który wysyła zapytanie do serwera, a następnie otrzymujemy następującą odpowiedź:
- wiersze 2–10: odpowiedź serwera
- wiersze 2–8: nagłówki HTTP
- wiersz 10: dokument
- wiersz 6: nagłówek HTTP Content-Length. Ponieważ nagłówek ten nie został wygenerowany przez skrypt serwera, oznacza to, że został wygenerowany przez serwer WWW.
- wiersz 8: jedyny nagłówek wygenerowany przez skrypt serwera
10.3. Pobieranie zmiennych środowiskowych serwera WEB
Skrypt serwerowy działa w środowisku internetowym, które może rozpoznać. Środowisko to jest zapisane w słowniku $_SERVER. Najpierw piszemy aplikację serwerową, która wysyła do swoich klientów zawartość tego słownika.
10.3.1. Serwer (web_04)
<?php
// obsługa błędów
ini_set("display_errors", "off");
// nagłówek UTF-8
header("Content-Type: text/plain; charset=utf-8");
// do klienta wysyłana jest lista zmiennych dostępnych w środowisku serwera
foreach ($_SERVER as $clé => $valeur) {
print "[$clé,$valeur]\n";
}
- Pary (klucz, wartość) ze słownika $_SERVER są wysyłane do klientów.
Wynik uzyskiwany, gdy klientem jest przeglądarka internetowa, jest następujący:

Oto znaczenie niektórych zmiennych (dla systemu Windows. W systemie Linux byłyby one inne):
CMDE reprezentuje nagłówek HTTP wysłany przez klienta. Mamy dostęp do wszystkich tych nagłówków. | |
ścieżka do plików wykonywalnych na komputerze, na którym uruchomiony jest skrypt serwera | |
ścieżka do interpretera poleceń DOS | |
rozszerzenia plików wykonywalnych | |
katalog instalacyjny systemu Windows | |
podpis serwera WWW. Tutaj nic. | |
typ serwera WWW | |
nazwa internetowa komputera serwera WWW | |
port nasłuchowy serwera WWW | |
adres komputera serwera WWW: IP | |
adres IP klienta. W tym przypadku klient znajdował się na tym samym komputerze co serwer. | |
port komunikacyjny klienta | |
katalog główny drzewa dokumentów obsługiwanych przez serwer WWW | |
adres e-mail administratora serwera WWW | |
pełna ścieżka do skryptu serwera | |
wersja protokołu HTTP używanego przez serwer WWW | |
polecenie HTTP używane przez klienta. Istnieją cztery z nich: GET, POST, PUT, DELETE | |
parametry wysyłane wraz z poleceniem GET /url?parametry | |
URL żądane przez klienta. Jeśli przeglądarka zażąda URL http://machine[:port]/uri, otrzymamy REQUEST_URI=uri | |
$_SERVER['SCRIPT_FILENAME']=$_SERVER['DOCUMENT_ROOT'].$_SERVER['SCRIPT_NAME'] |
10.3.2. Klient (client1_web_04)
Klient po prostu wyświetla wszystko, co wysyła mu serwer.
<?php
// dane
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_04.php";
// nawiązanie połączenia na porcie 80 serwera $HOTE
$connexion = fsockopen($HOTE, $PORT);
// błąd?
if (!$connexion) {
print "Erreur : $erreur\n";
exit;
}
// nawiązywanie połączenia z serwerem WWW o nazwie URL
// nagłówki (headers) protokołu HTTP muszą kończyć się pustym wierszem
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Połączenie
fputs($connexion,"Connection: close\n");
// pusty wiersz
fputs($connexion,"\n");
// serwer będzie teraz odpowiadał na kanale $connexion. Wyśle wszystkie
// swoje dane, a następnie zamknie kanał. Klient odczytuje zatem wszystko, co nadchodzi z $connexion
// aż do zamknięcia kanału
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
}//, podczas gdy
// klient z kolei zamknie połączenie
fclose($connexion);
// koniec
exit;
Wyniki
10.4. Zarządzanie sesjami WEB
W poprzednich przykładach dotyczących relacji klient–serwer działanie wyglądało następująco:
- klient nawiązuje połączenie z portem 80 serwera
- wysyła sekwencję tekstową: nagłówki HTTP, pusty wiersz, [document]
- w odpowiedzi serwer wysyła sekwencję tego samego typu
- serwer zamyka połączenie z klientem
- klient zamyka połączenie z serwerem
Jeśli ten sam klient wkrótce potem wyśle nowe żądanie do serwera internetowego, między klientem a serwerem zostanie nawiązane nowe połączenie. Serwer nie jest w stanie stwierdzić, czy łączący się klient już wcześniej korzystał z serwisu, czy też jest to pierwsze żądanie. Pomiędzy dwoma połączeniami serwer „zapomina” o swoim kliencie. Z tego powodu mówi się, że protokół HTTP jest protokołem bezstanowym. Jednakże przydatne jest, aby serwer zapamiętywał swoich klientów. Jeśli więc aplikacja jest zabezpieczona, klient wysyła do serwera nazwę użytkownika i hasło w celu uwierzytelnienia się. Jeśli serwer „zapomni” o swoim kliencie między dwoma połączeniami, klient będzie musiał uwierzytelniać się przy każdym nowym połączeniu, co jest nie do pomyślenia.
Aby śledzić klienta, serwer postępuje w następujący sposób: przy pierwszym żądaniu od klienta dołącza do odpowiedzi identyfikator, który klient musi następnie odsyłać przy każdym kolejnym żądaniu. Dzięki temu identyfikatorowi, innemu dla każdego klienta, serwer może rozpoznać klienta. Może wówczas zarządzać pamięcią dla tego klienta w postaci pliku jednoznacznie powiązanego z identyfikatorem klienta.
Z technicznego punktu widzenia wygląda to następująco:
- w odpowiedzi dla nowego klienta serwer dołącza nagłówek HTTP Set-Cookie: MotClé=Identyfikator. Czyni to wyłącznie przy pierwszym żądaniu.
- W kolejnych żądaniach klient będzie przesyłał swój identyfikator w nagłówku HTTP Cookie: MotClé=Identyfikator, aby serwer mógł go rozpoznać.
Można się zastanawiać, w jaki sposób serwer rozpoznaje, że ma do czynienia z nowym klientem, a nie z klientem, który już wcześniej odwiedził stronę. Wskazuje na to obecność nagłówka HTTP Cookie w nagłówkach HTTP klienta. W przypadku nowego klienta nagłówek ten nie występuje.
Zbiór wszystkich połączeń danego klienta nazywany jest sesją.
10.4.1. Plik konfiguracyjny
Aby zarządzanie sesjami działało poprawnie z PHP, należy sprawdzić, czy jest on prawidłowo skonfigurowany. W systemie Windows jego plik konfiguracyjny to PHP.ini. W zależności od środowiska uruchomienia (konsola, internet) plik konfiguracyjny [PHP.ini] należy szukać w różnych folderach. Aby je zidentyfikować, należy użyć następującego skryptu:
W wierszu 4 funkcja phpinfo podaje informacje o interpreterze PHP, który wykonuje skrypt. Podaje ona w szczególności ścieżkę do używanego pliku konfiguracyjnego [PHP.ini].
W środowisku konsoli otrzymujemy wynik podobny do poniższego:
wiersz 2: główny plik konfiguracyjny to c:\windows\PHP.ini
wiersz 3: plik konfiguracyjny pomocniczy to C:\serveursSGBD\wamp21\bin\PHP\php5.3.5\PHP.ini. Umożliwia on modyfikację niektórych opcji konfiguracyjnych zawartych w głównym pliku konfiguracyjnym.
W środowisku internetowym otrzymujemy następujący wynik:

Poboczny plik konfiguracyjny nie jest tutaj taki sam jak w środowisku konsoli. To właśnie ten ostatni plik będziemy analizować. W pliku tym znajduje się sekcja session:
- wiersz 1: dane sesji klienta są zapisywane w pliku
- wiersz 3: folder, w którym zapisywane są dane sesji. Jeśli folder ten nie istnieje, nie jest zgłaszany żaden błąd, a zarządzanie sesjami nie działa.
- wiersze 4–5: wskazują, że identyfikator sesji jest zarządzany przez nagłówki HTTP Set-Cookie i Cookie
- wiersz 6: nagłówek Set-Cookie będzie miał postać Set-Cookie: PHPSESSID=identifiant_de_session
- wiersz 7: sesja klienta nie jest uruchamiana automatycznie. Skrypt serwera musi ją wyraźnie zażądać za pomocą instrukcji session_start().
10.4.2. Serwer 1 (web_05)
Zarządzanie identyfikatorem sesji jest przezroczyste dla usługi internetowej. Identyfikator ten jest zarządzany przez serwer internetowy. Usługa internetowa uzyskuje dostęp do sesji klienta za pomocą instrukcji session_start(). Od tego momentu usługa internetowa może odczytywać i zapisywać dane w sesji klienta za pośrednictwem słownika $_SESSION. Poniższy kod przedstawia zarządzanie trzema licznikami w ramach sesji.
<?php
// obsługa błędów
ini_set("display_errors", "off");
// nagłówek UTF-8
header("Content-Type: text/plain; charset=utf-8");
// otwieramy sesję
session_start();
// umieszczamy 3 zmienne w sesji
if (!isset($_SESSION['N1'])) {
$_SESSION['N1'] = 0;
}
if (!isset($_SESSION['N2'])) {
$_SESSION['N2'] = 10;
}
if (!isset($_SESSION['N3'])) {
$_SESSION['N3'] = 100;
}
// inkrementacja trzech zmiennych
$_SESSION['N1']++;
$_SESSION['N2']++;
$_SESSION['N3']++;
// wysyłanie informacji do klienta
print "N1=".$_SESSION['N1']."\n";
print "N2=".$_SESSION['N2']."\n";
print "N3=".$_SESSION['N3']."\n";
// zakończenie sesji
session_close();
- wiersz 9: rozpoczęcie sesji klienta
- wiersze 11–13: tablica $_SESSION jest słownikiem par (klucz, wartość). Dane umieszczone w tym słowniku są zachowywane na przestrzeni kolejnych żądań tego samego klienta. Stanowi to pamięć klienta na serwerze.
- wiersze 11–19: jeśli trzy liczniki N1, N2, N3 nie znajdują się w sesji, są do niej dodawane.
- wiersze 21–23: zwiększa się ich wartość o jeden
- wiersze 25–27: wysyłamy ich wartości do klienta
W relacji klient–serwer zarządzanie sesją klienta na serwerze zależy od obu stron, czyli klienta i serwera:
- serwer ma za zadanie wysłać identyfikator do klienta przy jego pierwszym żądaniu
- klient ma obowiązek odesłać ten identyfikator przy każdym nowym żądaniu. Jeśli tego nie zrobi, serwer uzna, że jest to nowy klient i wygeneruje nowy identyfikator dla nowej sesji.
Wyniki
Jako klienta wykorzystujemy przeglądarkę internetową. Domyślnie (a właściwie zgodnie z konfiguracją) przeglądarka ta prawidłowo odsyła do serwera identyfikatory sesji, które ten jej przesyła. W miarę wysyłania kolejnych żądań przeglądarka będzie odbierać trzy liczniki wysyłane przez serwer i obserwować, jak ich wartości rosną.
![]() |
- na [1], pierwsze żądanie do serwisu internetowego [web_05]
- na [2], trzecie żądanie pokazuje, że liczniki są prawidłowo zwiększane. Wartości liczników są rzeczywiście zapamiętywane w miarę wysyłania kolejnych żądań.
Skorzystajmy z Firebuga, aby sprawdzić nagłówki HTTP wymieniane między serwerem a klientem. Zamykamy przeglądarkę Firefox, aby zakończyć bieżącą sesję z serwerem, ponownie ją otwieramy i włączamy Firebug. Wysyłamy żądanie do serwisu |web_05]:
![]() |
Powyżej widać identyfikator sesji wysłany przez serwer w odpowiedzi na pierwsze żądanie klienta. Wykorzystuje on nagłówek HTTP Set-Cookie.
Wyślijmy nowe żądanie, odświeżając (F5) stronę w przeglądarce internetowej:
![]() |
W powyższym przykładzie można zauważyć dwie rzeczy:
- przeglądarka internetowa zwraca identyfikator sesji wraz z nagłówkiem HTTP Cookie.
- W swojej odpowiedzi serwis internetowy nie zawiera już tego identyfikatora. Teraz to klient jest odpowiedzialny za wysyłanie go w każdym swoim żądaniu.
10.4.3. Klient 1 (client1_web_05)
Teraz piszemy skrypt kliencki na podstawie poprzedniego skryptu serwerowego. W zakresie zarządzania sesją musi on zachowywać się tak samo jak przeglądarka internetowa:
- W odpowiedzi serwera na swoje pierwsze żądanie musi znaleźć identyfikator sesji, który serwer mu przesyła. Wie, że znajdzie go w nagłówku HTTP Set-Cookie.
- W każdym kolejnym żądaniu musi odesłać do serwera otrzymany identyfikator. Zrobi to za pomocą nagłówka HTTP Cookie.
Kod klienta jest następujący:
<?php
// dane
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_05.php";
// testy
$cookie = "";
for ($i = 0; $i < 5; $i++) {
list($erreur, $cookie, $N1, $N2, $N3) = connecte($HOTE, $PORT, $urlServeur, $cookie);
print "----------------------------\n";
print "client(erreur,cookie,N1,N2,N3)=[$erreur,$cookie,$N1,$N2,$N3]\n";
print "----------------------------\n";
}
// koniec
exit;
function connecte($HOTE, $PORT, $urlServeur, $cookie) {
// łączy klienta z ($HOTE,$PORT,$urlServeur)
// wysyła plik cookie $cookie, jeśli nie jest pusty
// wyświetla wszystkie wiersze otrzymane w odpowiedzi
// nawiązanie połączenia na porcie 80 serwera $HOTE
$connexion = fsockopen($HOTE, $PORT);
// błąd?
if (!$connexion)
return array("erreur lors de la connexion au serveur ($HOTE, $PORT)");
// nawiązywanie połączenia z serwerem $urlserveur
// nagłówki (headers) protokołu HTTP muszą kończyć się pustym wierszem
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Połączenie
fputs($connexion, "Connection: close\n");
// wysyłamy plik cookie, jeśli nie jest pusty
if ($cookie) {
fputs($connexion, "Cookie: $cookie\n");
}//if
// wysyłamy pustą linię
fputs($connexion, "\n");
// wyświetla się odpowiedź serwera WWW
// i dbamy o pobranie ewentualnego pliku cookie oraz wartości Ni
$N = "";
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
// plik cookie – tylko w przypadku pierwszej odpowiedzi
if (!$cookie) {
if (preg_match("/^Set-Cookie: (.*?)\s*$/", $ligne, $champs)) {
$cookie = $champs[1];
}
}
// wartość N1
if (preg_match("/^N1=(.*?)\s*$/", $ligne, $champs))
$N1 = $champs[1];
// wartość N2
if (preg_match("/^N2=(.*?)\s*$/", $ligne, $champs))
$N2 = $champs[1];
// wartość pliku N3
if (preg_match("/^N3=(.*?)\s*$/", $ligne, $champs))
$N3 = $champs[1];
}//while
// zamyka się połączenie
fclose($connexion);
// powrót
return array("", $cookie, $N1, $N2, $N3);
}
Komentarze
- wiersze 3–16: program główny
- wiersze 18–67: funkcja connecte
- wiersze 9–14: klient 5 razy wywołuje serwer i wyświetla kolejne wartości liczników N1, N2 oraz N3. Jeśli sesja jest prawidłowo zarządzana, liczniki te powinny być zwiększane o 1 przy każdym nowym żądaniu.
- wiersz 10: funkcja connecte wykorzystuje parametry $HOTE, $PORT, $urlServeur do połączenia klienta z usługą internetową. Parametr $cookie reprezentuje identyfikator sesji. Przy pierwszym wywołaniu jest to pusty ciąg znaków. Przy kolejnych wywołaniach jest to identyfikator sesji wysłany przez serwer w odpowiedzi na pierwsze wywołanie klienta. Funkcja connecte zwraca w wynikach wartości trzech liczników: $N1, $N2, $N3, identyfikator sesji $cookie oraz ewentualny błąd $erreur.
- wiersz 18: funkcja connecte ma cechy typowego klienta HTTP. Omówimy tylko nowe elementy.
- wiersze 30–40: wysyłanie nagłówków HTTP.
- wiersze 36–38: jeśli identyfikator sesji jest znany, wysyłamy go do serwera
- wiersze 44–66: przetwarzanie wszystkich wierszy tekstu wysłanych przez serwer
- wiersze 47–51: jeśli identyfikator sesji nie został jeszcze pobrany, pobiera się go z nagłówka HTTP Set-Cookie za pomocą wyrażenia regularnego.
- wiersze 53–54: licznik N1 jest również uzyskiwany za pomocą wyrażenia regularnego
- wiersze 56–57, 59–60: to samo dotyczy liczników N2 i N3
- wiersz 63: zamknięcie połączenia z serwerem.
- wiersz 65: zwracanie wyników w postaci tablicy.
Wyniki
Uruchomienie skryptu klienckiego powoduje wyświetlenie następującego komunikatu w konsoli NetBeans:
- wiersz 5: w pierwszej odpowiedzi serwer wysyła identyfikator sesji. W kolejnych odpowiedziach już go nie wysyła.
- Wyraźnie widać, że serwer WWW zachowuje wartości (N1, N2, N3) w trakcie kolejnych żądań klienta. Nazywa się to śledzeniem sesji.
Dwa poniższe przykłady pokazują, że można również zapisać wartości tablicy lub obiektu.
10.4.4. Serwer 2 (web_06)
Poniższy skrypt serwera pokazuje, że do sesji można umieścić tablicę lub słownik.
<?php
// obsługa błędów
ini_set("display_errors", "off");
// nagłówek UTF-8
header("Content-Type: text/plain; charset=utf-8");
// otwieramy sesję
session_start();
// zapisywanie tablicy i słownika
// inicjowanie lub modyfikacja tablicy
if (isset($_SESSION['tableau'])) {
for ($i = 0; $i < count($_SESSION['tableau']); $i++) {
$_SESSION['tableau'][$i]++;
}
} else {
for ($i = 0; $i < 10; $i++) {
$_SESSION['tableau'][$i] = $i * 10;
}
}
// inicjowanie lub modyfikacja słownika
if (isset($_SESSION['dico'])) {
foreach (array_keys($_SESSION['dico']) as $clé) {
$_SESSION['dico'][$clé]++;
}
} else {
$_SESSION['dico'] = array("zéro" => 0, "dix" => 10, "vingt" => 20);
}
// wysyłanie informacji do klienta
print "tableau=" . join(",", $_SESSION['tableau']) . "\n";
print "dico=";
foreach ($_SESSION['dico'] as $clé => $valeur) {
print "($clé,$valeur) ";
}
print "\n";
Komentarze
- wiersze 17–19: tablica jest początkowo zapisywana w sesji, jeśli jeszcze tam nie ma
- wiersze 12–15: jeśli już tam jest, wartości jego elementów są zwiększane o 1
- wiersz 27: słownik z wartościami liczbowymi jest umieszczany w sesji, jeśli jeszcze się tam nie znajduje
- wiersze 22–25: jeśli już tam jest, jego wartości liczbowe są zwiększane o 1
- wiersze 30–35: tablica i słownik są wysyłane do klienta
10.4.5. Klient 2 (client1_web_06)
<?php
// dane
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_06.php";
// testy
$cookie = "";
for ($i = 0; $i < 5; $i++) {
connecte($HOTE, $PORT, $urlServeur, $cookie);
}
// koniec
exit;
function connecte($HOTE, $PORT, $urlServeur, &$cookie) {
// łączy klienta z ($HOTE,$PORT,$urlServeur)
// wysyła plik cookie $cookie, jeśli nie jest pusty
// wyświetla wszystkie wiersze otrzymane w odpowiedzi
// plik cookie jest przekazywany przez odwołanie, aby mógł być współdzielony między
// programem wywoływanym i programem wywołującym
// otwarcie połączenia na porcie $PORT programu $HOTE
$connexion = fsockopen($HOTE, $PORT);
// błąd?
if (!$connexion)
return array("erreur lors de la connexion au serveur ($HOTE, $PORT)");
// nagłówki protokołu HTTP muszą kończyć się pustym wierszem
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Połączenie
fputs($connexion, "Connection: close\n");
// ciasteczko jest wysyłane, jeśli nie jest puste
if ($cookie) {
fputs($connexion, "Cookie: $cookie\n");
}
// wysyłanie pustej linii
fputs($connexion, "\n");
// wyświetla się odpowiedź serwera WWW
// i dbamy o pobranie ewentualnego pliku cookie
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
// plik cookie – tylko w przypadku pierwszej odpowiedzi
if (!$cookie) {
if (preg_match("/^Set-Cookie: (.*?)\s*$/", $ligne, $champs)) {
$cookie = $champs[1];
}
}
}
// zamyka się połączenie
fclose($connexion);
// powrót
return "";
}
Kod klienta jest analogiczny do kodu klienta, który został już omówiony.
Wyniki
10.4.6. Serwer 3 (web_07)
Poniższy skrypt serwera pokazuje, że można umieścić obiekt w sesji.
<?php
// obsługa błędów
ini_set("display_errors", "off");
// nagłówek UTF-8
header("Content-Type: text/plain; charset=utf-8");
// otwieranie sesji
session_start();
// inicjowanie lub modyfikacja obiektu „Osoba”
if (isset($_SESSION['personne'])) {
$personne = $_SESSION['personne'];
// zwiększamy wiek
$personne->setAge($personne->getAge() + 1);
} else {
// definiuje się osobę
$_SESSION['personne'] = new Personne("paul", "langévin", 10);
}
// wyświetlanie dla klienta
print "personne=".$_SESSION['personne']."\n";
// koniec
exit;
// ----------------------------------------------------------------
class Personne {
// atrybuty klasy
private $prénom;
private $nom;
private $âge;
// metody pobierające i ustawiające
public function getPrénom() {
return $this->prénom;
}
public function getNom() {
return $this->nom;
}
public function getAge() {
return $this->âge;
}
public function setPrénom($prénom) {
$this->prénom = $prénom;
}
public function setNom($nom) {
$this->nom = $nom;
}
public function setAge($age) {
$this->âge = $age;
}
// konstruktor
function __construct($prénom, $nom, $âge) {
// przechodzimy przez metody set
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// metoda toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
Komentarze
- wiersz 17: obiekt typu Personne jest zapisywany w sesji, jeśli jeszcze tam nie istnieje.
- wiersze 11–15: jeśli obiekt już tam jest, zwiększa się jego wiek o 1
- wiersz 20: wysyłamy obiekt typu Personne do klienta.
10.4.7. Klient 3 (client1_web_07)
<?php
// dane
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_07.php";
// testy
$cookie = "";
for ($i = 0; $i < 5; $i++) {
connecte($HOTE, $PORT, $urlServeur, $cookie);
}//if
// koniec
exit;
function connecte($HOTE, $PORT, $urlServeur, &$cookie) {
...
}
Komentarze
- wiersz 15: funkcja connecte jest identyczna jak w poprzednim skrypcie klienta
Wyniki




















