Kursy mojej produkcji

3.2 Superglobalne

Tablice superglobalne są jednym z kolejnych bardzo istotnych elementów języka PHP. Pomijając już wywołanie samego pliku (skryptu), to dzięki nim między innymi wiemy, jakie argumenty ($_GET, $_POST) przyszły od użytkownika do skryptu. Ponadto zawierają masę przydatnych informacji o samym środowisku oraz użytkowniku. Do superglobalnych zmiennych tablicowych zaliczamy:
  • $GLOBALS
  • $_SERVER - informacje o środowisku i serwerze
  • $_GET - zmienne HTTP GET
  • $_POST - zmienne HTTP POST
  • $_FILES - zmienne HTTP FILES odpowiedzialne za przesyłanie plików
  • $_COOKIE - zmienne odpowiedzialne za ciasteczkowego potwora
  • $_SESSION - zmienne sesyjne
  • $_REQUEST - mix zmiennych $_GET, $_POST i $_COOKIE
  • $_ENV - zmienne środowiskowe
Jedną z ważniejszych kwestii jest fakt, że są one dostępne w każdym miejscu skryptu i nie potrzebne są dodatkowe zabiegi z global czy przestrzenią dostępności zmiennych. Przestrzenie zostaną dokładnie opisane w dziale dotyczącym własnych funkcji.

Pozostałe predefiniowane zmienne

Po za zmiennymi wbudowanymi przedstawionymi powyżej mamy także do dyspozycji następujące:
  • $php_errormsg - poprzedni komunikat o błędzie
  • $HTTP_RAW_POST_DATA - czyli tzw. surowe dane POST
  • $http_response_header - nagłówki odpowiedzi HTTP
  • $argc - liczba argumentów przekazanych do skryptu
  • $argv - tablica argumentów przekazanych do skryptu
Zmienna $php_errormsg zostanie opisana w dziale dotyczącym błędów pochodzących z parsera PHP. Zastosowanie zmiennej $http_response_header poznacie w dziale dotyczącym obsługi plików i strumieni. Pozostałe zmienne zostaną szeroko opisane w dziale dotyczącym wywołań programów systemowych.

"Tajemnica" tablicy $_REQUEST

Tablica $_REQUEST jest de facto połączeniem trzech tablic tzn. $_GET, $_POST i $_COOKIE. Oznacza to, że jeżeli wystąpi klucz test z wartością test2 w tablicy $_GET, a następnie wystąpi ten sam klucz, lecz z inną wartością np. test3 w tablicy $_POST to w rezultacie na wyjściu otrzymamy tablicę z wartością test3. Dlatego właśnie zaleca się nie stosowanie omawianej tablicy gdyż może ona przysporzyć problemów osobom niedoświadczonym.

Style zmiennych i dyrektywa register_globals

W standardowej książce dotyczącej PHP jest mowa o trzech stylach zmiennych, których listing wygląda mniej więcej tak:
Kod:
<?php
$test// Styl krótki
$_GET['test']; // Styl średni
$HTTP_GET_VARS['test']; // Styl długi
?>
Sytuacja rozbija się o wywołanie skryptu index.php z parametrem test=cokolwiek czyli index.php?test=cokolwiek lub ?test=cokolwiek (w zależności od defaulowego pliku). W największym skrócie mówiąc o stylu krótkim i długim możecie z miejsca zapomnieć.

Styl długi dostępny był w starszych wersjach PHP i został de facto już dawno wyparty. Czyli jeżeli wpadnie Wam do głowy pomysł użycia $HTTP_*_VARS to wybijcie sobie go z głowy na starcie, bo nikt potem nie będzie chciał poprawiać takich skryptów. Ponadto, jeżeli zmodyfikowalibyście przykładowo wartość $HTTP_POST_VARS['test'] to ta zmiana nie wpłynęłaby na wartość zawartości $_POST['test']! W nowszych wersjach PHP styl ten nie jest wspierany. Ponadto, aby był dostępny to w konfiguracji PHP (php.ini) dyrektywa register_long_arrays powinna być na On. Dyrektywa dostępna od wersji 5.0.0, uznana za przestarzałą w wersji 5.3.0, natomiast usunięta w wersji 5.4.0. Wyłączenie długich tablic przyspiesza nieznacznie parser. W połączeniu z innymi zmianami w konfiguracji parsera skrypt może szybciej się wykonywać.

Używanie stylu krótkiego wiąże się z dyrektywą register_globals ustawioną na On. Włączona opcja może mieć wpływ na bezpieczeństwo aplikacji. Czysto teoretycznie w takiej sytuacji wystarczy, że odpalimy poniższy skrypt z parametrem np. GET zalogowany=1 i wyświetli się nam piękny komunikat.
Kod:
<?php
if($zalogowany)
{
 echo 'Jesteś zalogowany';
}
?>
O systemie autoryzacji i jego problemach będzie mowa w segmencie kursu dotyczącym sesji. Na szczęście w większości cywilizowanych skryptów, CMS'ów, etc. wymagane jest wyłączenie register_globals.

Magiczne phpinfo()

Zanim wymienię kilka ważniejszych węzłów tablicy $_SERVER wspomnę o funkcji phpinfo() przyjmującym jeden argument opcjonalnie. Owa funkcja służy do wyświetlenia dużej ilości ciekawych danych, w tym konfiguracji serwera i dostępnych modułach. Więcej informacji znajdziecie w dokumentacji.

Ciekawostką jest fakt, że logo, które widzicie po wygenerowaniu informacji o serwerze zazwyczaj w prawym górnym rogu tabelki wyciągane jest bezpośrednie z PHP. Zwróćcie uwagę na adres dla img, który zazwyczaj wygląda tak http://adres.do/strony/nazwa_skryptu.php?=PHPE9568F34-D428-11d2-A769-00AA001ACF42. W ten sposób można było zidentyfikować niektóre wersje PHP używane na serwerze. Aby uzyskać więcej informacji wpiszcie w wyszukiwarkę Google PHP Easter Egg.

Tablica $_SERVER i jej zawartość

Poniżej zamieszczam tabele, która mówi, co może zawierać konkretny klucz. Miedzy innymi można w niej znaleźć nazwę i lokalizację skryptu, nagłówki i takie tam szmery bajery. Nigdy nie mamy gwarancji, że wszystkie z poniżej wymienionych parametrów zostaną dostarczone do naszej dyspozycji. Może się także zdarzyć taka sytuacja, że będziemy mieli coś udostępnione ponadprogramowo. Dlatego właśnie tak jak poprzednio zalecam użycie funkcji print_r() bądź var_dump().
Zmienna Opis wartości
$_SERVER['PHP_SELF'] Posiada nazwę aktualnie wykonywanego pliku
$_SERVER['argc'] To samo, co $argc objaśnione na początku wpisu, czyli liczba parametrów przesłanych do skryptu uruchomionego z linii poleceń
$_SERVER['argv'] To samo, co $argv objaśnione na początku wpisu, czyli tablica argumentów przesłanych do skryptu
$_SERVER['GATEWAY_INTERFACE'] Jest to tak zwana wersja specyfikacji CGI używana przez serwer
$_SERVER['SERVER_ADDR'] Adres IP maszyny, na której wykonany jest skrypt
$_SERVER['SERVER_NAME'] Nazwa serwera, na którym wykonywany jest skrypt
$_SERVER['SERVER_SOFTWARE'] Podaje oprogramowanie serwera w tym wersje PHP, czyli np. Apache/2.2.17 (Win32) mod_ssl/2.2.17 OpenSSL/0.9.8o PHP/5.3.4 mod_perl/2.0.4 Perl/v5.10.1
$_SERVER['SERVER_PROTOCOL'] Zawiera użyty protokół i jego wersje (np. HTTP/1.1) w celu uzyskania zasobów z naszej maszyny
$_SERVER['REQUEST_METHOD'] Metoda użyta przez użytkownika w celu uzyskania dostępu do zasobów np. GET, POST, HEAD, PUT
$_SERVER['REQUEST_TIME'] Czas wystąpienia zapytania do serwera w formacie timestamp (UNIX)
$_SERVER['QUERY_STRING'] Wszystko to, co zostało przekazane do serwera przez parametr GET, czyli to co znajduje się po ?
$_SERVER['DOCUMENT_ROOT'] Ścieżka (zdefiniowana w konfiguracji serwera) do magicznego katalogu /root/, w którym wykonuje się skrypt. Nie zalecam używania tej zmiennej chyba, że lubisz tracić czas na dochodzenie gdzie jest błąd!
$_SERVER['HTTP_ACCEPT'] Zawartość nagłówka Accept-Charset, czyli deklaracji akceptacji strony kodowej z bieżącego żądania, który może wyglądać np. tak: utf-8, iso-8859-2;q=0.8
$_SERVER['HTTP_ACCEPT_ENCODING'] Zawartość nagłówka Accept-Encoding, czyli deklaracji akceptowanego kodowania z bieżącego żądania, który może wyglądać np. tak: gzip, deflate
$_SERVER['HTTP_ACCEPT_LANGUAGE'] Zawartość nagłówka Accept-Language, czyli deklaracji języka z bieżącego żądania, która może wyglądać następująco: pl-PL,pl;q=0.9,en;q=0.8
$_SERVER['HTTP_CONNECTION'] Zawartość nagłówka Connection pochodzącego z bieżącego żądania, jeśli taki istnieje to może przyjąć np. taką wartość: keep-alive.
$_SERVER['HTTP_HOST'] Zawartość nagłówka Host z aktualnego zapytania, jeśli wystąpił
$_SERVER['HTTP_USER_AGENT'] Zawartość nagłówka User-Agent z bieżącego żądania, jeśli wystąpił
$_SERVER['HTTP_REFERER'] Adres strony, z której zostaliśmy przekierowani. Nie zawsze przeglądarki zezwalają na przesyłanie tego nagłówka! Ponadto każdy może go zmieniać, dlatego uważaj na manipulatorów!
$_SERVER['HTTPS'] Jeżeli użyto protokołu HTTPS to pojawia się zawartość tej zmiennej, która może być rożna
$_SERVER['REMOTE_ADDR'] Przysłowiowy IP, czyli adres komputera, z którego przeglądana jest strona
$_SERVER['REMOTE_HOST'] Host, czyli nazwa komputera, z którego użytkownik przegląda daną stronę
$_SERVER['REMOTE_PORT'] Numer portu (zazwyczaj 80 dla HTTP i 443 dla HTTPS na transporcie SSL rzecz jasna) użyty do nawiązania połączenia
$_SERVER['SCRIPT_FILENAME'] Bezwzględna ścieżka do aktualnie wykonywanego skryptu. W przypadku skryptu wywołanego z tak zwanego CLI może wystąpić ścieżka względna.
$_SERVER['SERVER_ADMIN'] Zawartość dyrektywy serwera (np. Apache), w której znajdują się dane kontaktowe administratora serwisu bądź maszyny.
$_SERVER['SERVER_PORT'] Numer portu służący do nawiązywania komunikacji z użytkownikami
$_SERVER['SERVER_SIGNATURE'] Sygnatura serwera, czyli to, co jest w podpisie, gdy nie ma np. zdefiniowanej strony błędu pokroju 404. Przykładowo może ona wyglądać następująco: Apache/2.2.17 (Win32) mod_ssl/2.2.17 OpenSSL/0.9.8o PHP/5.3.4 mod_perl/2.0.4 Perl/v5.10.1 Server at 127.0.0.1 Port 80
$_SERVER['PATH_TRANSLATED'] Tak zwana bazowa ścieżka do aktualnie wykonującego się skryptu. Nie mylić z $_SERVER['DOCUMENT_ROOT']! Zajrzyj do dokumentacji PHP, bo tam ładnie to opisali, serio
$_SERVER['REQUEST_URI'] Adres URL żądanego zasobu, czyli to, co jest po np. http://127.0.0.1 czyli /testy/tablice.php
$_SERVER['PHP_AUTH_DIGEST'] Zawartość nagłówka Authorization służący do autoryzacji Digest HTTP
$_SERVER['PHP_AUTH_USER'] Nazwa użytkownika służąca do autoryzacji
$_SERVER['PHP_AUTH_PW'] Hasło służące do autoryzacji
$_SERVER['AUTH_TYPE'] Tak zwany tryb autoryzacji
$_SERVER['PATH_INFO'] Zawiera informacje dotyczące ścieżki udostępnionej przez użytkownika łącznie z nazwą aktualnie wykonywanego skryptu

Tablica z danymi środowiskowymi

Klucze tablicy $_ENV są na tyle banalne, że bezproblemowo wydedukujecie, jakie mogą przyjąć wartości Wink
Kod:
<?php
$_ENV['PROCESSOR_ARCHITECTURE'];
$_ENV['PROCESSOR_IDENTIFIER'];
$_ENV['ALLUSERSPROFILE'];
$_ENV['USERPROFILE'];
$_ENV['CLASSPATH'];
$_ENV['APPDATA'];
$_ENV['QTJAVA'];
$_ENV['Path'];
$_ENV['OS'];
?>

Konkluzja

Powtórzę się i powiem, że ścieżki będą dokładnie opisane w dziale dotyczącym obsługi plików i strumieni. Oczywiście poza phpinfo() możecie także podejrzeć zawartości wybranych superglobalnych za pomocą var_dump(). Po drugie nigdy nie ufajcie danym przychodzącym od użytkownika (np. HTTP_REFERER czy HTTP_USER_AGENT). Można nimi dowolnie manipulować, co w połączeniu z brakiem zabezpieczeń może spowodować spore szkody. Ta sama sytuacja tyczy się danych, które zostały przesłane np. przez GET, POST, FILE i tak dalej. Przeczytaj o nagłówkach HTTP. Ta wiedza przyda Ci się w późniejszych częściach kursu.

Zapewne zwróciliście uwagę na zmienna $_SERVER['REMOTE_ADDR'], która zawiera IP naszej potencjalnej ofiary. Jeżeli osobnik ten używa proxy to istnieje możliwość detekcji tego faktu, jeżeli nie są to tak zwane high anonymous proxy aka elite proxy. Próbę detekcji można dokonać w ten sposób:
Kod:
<?php
// Taka detekcja może być zwodnicza!

if($_SERVER['HTTP_X_FORWARDED_FOR'])
{
 if($_SERVER['HTTP_CLIENT_IP'])
 {
  $proxy $_SERVER['HTTP_CLIENT_IP'];
 }
 else
 {
  $proxy $_SERVER['REMOTE_ADDR'];
 }

 $ip $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
 if($_SERVER['HTTP_CLIENT_IP'])
 {
  $ip $_SERVER['HTTP_CLIENT_IP'];
 }
 else
 {
  $ip $_SERVER['REMOTE_ADDR'];
 }
}

echo 'Twoje IP to: '.$ip;

if($proxy)
{
 echo '<br>Adres IP Twojego proxy to: '.$proxy;
}

// PS: Powyższy kod można zoptymalizować do jednej linijki przy pomocy operatora trójkowego [i (dla zaawansowanych) oprawić w funkcję "inline" bądź metodę]
?>
Nieco inny format tego kodu można znaleźć w artykule jak odczytać adres IP odwiedzającego stronę.