Jeśli kiedykolwiek miałeś do czynienia z PHP w jego starszych wersjach, to pewnie słyszałeś o czymś takim jak register_globals. Ta funkcja (a właściwie dyrektywa konfiguracyjna) była kiedyś bardzo popularna i powszechnie używana. Wielu programistów z lat 2000-2010 doskonale ją pamięta – często z nostalgią, ale też z lekkim dreszczem grozy. Dlaczego? Bo register_globals to narzędzie, które w teorii miało ułatwić życie, ale w praktyce… często je komplikowało, i to bardzo poważnie.
W tym artykule opowiem Ci co to jest register_globals, do czego się go używało, dlaczego zostało wyłączone i czym je można zastąpić w nowoczesnych projektach. Jeśli interesujesz się bezpieczeństwem, PHP lub administracją serwerów, to koniecznie przeczytaj do końca.
Czym właściwie jest register_globals?
register_globals to ustawienie konfiguracyjne w PHP, które automatycznie „rejestrowało” zmienne pochodzące z różnych źródeł (takich jak formularze, ciasteczka, adres URL czy sesje) jako globalne zmienne w skrypcie.
Brzmi skomplikowanie? Przykład najlepiej to wyjaśni.
Załóżmy, że masz prosty formularz HTML:
<form method="GET" action="test.php"> <input type="text" name="imie"> <input type="submit" value="Wyślij"> </form>
Teraz, gdy użytkownik wpisze w pole „imie” wartość np. Janek i wyśle formularz, przeglądarka wywoła adres:
test.php?imie=Janek
W nowoczesnym PHP, żeby pobrać wartość z tego pola, musisz napisać:
<?php $imie = $_GET['imie']; echo "Cześć, $imie!"; ?>
Ale kiedyś, gdy register_globals było włączone, PHP automatycznie tworzyło zmienną $imie z tą wartością. Nie musiałeś używać $_GET, $_POST ani żadnych superglobalnych tablic. Po prostu:
<?php echo "Cześć, $imie!"; ?>
Do czego używało się register_globals?
W latach 90. i na początku 2000. register_globals wydawało się genialnym rozwiązaniem. Programiści nie musieli pamiętać, z jakiego źródła pochodzi dana zmienna – wszystko było dostępne „z automatu”.
Używano tego głównie do:
- Szybkiego prototypowania – można było błyskawicznie napisać działający kod, bez zbędnych tablic.
- Prostych aplikacji formularzowych – np. strony kontaktowe, loginy, rejestracje.
- Skryptów CMS i forów – wczesne wersje takich systemów jak phpNuke, Mambo czy stare fora oparte o PHPBB często wykorzystywały
register_globals. - Skryptów serwerowych – admini serwerów często włączali to ustawienie w php.ini, żeby ułatwić działanie starszych aplikacji.
W skrócie – register_globals miał być wygodny. Nie musiałeś sprawdzać, czy coś przyszło przez $_POST, $_GET, $_COOKIE czy $_SESSION. Po prostu używałeś zmiennych globalnych jak $user, $id, $message, i gotowe.
Dlaczego register_globals to był błąd?
Problem z register_globals polegał na tym, że włączał niebezpieczne skróty. W zasadzie każdy mógł „wstrzyknąć” wartość do zmiennej globalnej przez adres URL, formularz lub ciasteczko.
Spójrz na ten przykład:
<?php
if ($is_admin) {
echo "Witaj w panelu administratora!";
}
?>
Jeśli register_globals było włączone, użytkownik mógł wywołać stronę tak:
panel.php?is_admin=1
I bum! PHP automatycznie utworzyło zmienną $is_admin = 1. W efekcie każdy mógł uzyskać dostęp do panelu admina, bez logowania, bez hasła, bez autoryzacji.
To był koszmar bezpieczeństwa.
W ten sposób można było łatwo ominąć walidację, nadpisać zmienne, a nawet wykonywać kod w kontekście serwera.
Z tego powodu register_globals zaczęto uznawać za jedną z największych dziur bezpieczeństwa w historii PHP.
Jak wyłączyć register_globals?
W nowszych wersjach PHP (od PHP 4.2.0, czyli od 2002 roku) register_globals domyślnie było już wyłączone, a od wersji PHP 5.4 (2012 rok) – całkowicie usunięte z języka.
Ale jeśli korzystasz z jakiegoś starego serwera lub retro aplikacji, może się zdarzyć, że natrafisz na taki zapis w pliku php.ini:
register_globals = On
Aby to wyłączyć, wystarczy zmienić na:
register_globals = Off
i zrestartować serwer Apache lub Nginx.
Alternatywnie można to ustawić w pliku .htaccess:
php_flag register_globals off
Lub nawet w samym kodzie PHP (choć to niezalecane):
ini_set('register_globals', 0);
Co zamiast register_globals?
Dziś mamy o wiele bezpieczniejsze i bardziej przejrzyste metody pracy z danymi użytkownika. Zamiast automatycznych zmiennych globalnych używamy superglobalnych tablic, czyli:
$_GET– dane przekazane przez adres URL,$_POST– dane z formularzy,$_COOKIE– dane z ciasteczek,$_SESSION– dane sesji,$_SERVER– informacje o serwerze i zapytaniu,$_FILES– pliki przesłane przez formularz.
Przykład poprawnego, bezpiecznego kodu:
<?php
if (isset($_POST['username'])) {
$username = htmlspecialchars($_POST['username']);
echo "Witaj, $username!";
} else {
echo "Podaj swoje imię.";
}
?>
Jak widzisz, wszystko jest jawne – od razu wiadomo, skąd pochodzi dana zmienna. Dodatkowo, dzięki funkcjom takim jak htmlspecialchars(), możemy chronić się przed atakami XSS.
Dlaczego nie warto polegać na starym kodzie z register_globals
Często spotykam się z sytuacją, gdy ktoś odziedziczył stary projekt napisany w PHP 3 lub 4. W kodzie roi się od linii typu:
if ($user == "admin" && $pass == "tajnehaslo") {
include("panel.php");
}
Na pierwszy rzut oka wygląda to dobrze, ale jeśli register_globals było włączone, wystarczyło dopisać do adresu:
login.php?user=admin&pass=tajnehaslo
i system wpuszczał każdego.
Dlatego przy modernizacji starego kodu pierwszym krokiem powinno być całkowite usunięcie zależności od register_globals i przepisanie logiki na superglobalne tablice.
Jak sprawdzić, czy kod używa register_globals
Jeśli chcesz sprawdzić, czy Twoja aplikacja opiera się na register_globals, możesz poszukać miejsc, w których zmienne są używane bez wcześniejszego przypisania.
Na przykład:
echo $id;
bez żadnego $_GET['id'] wcześniej.
Możesz też napisać prosty skrypt PHP, który przeskanuje pliki projektu i znajdzie podejrzane zmienne. Oto przykładowy kod:
<?php
$directory = './'; // katalog z kodem
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
$pattern = '/\$\w+\s*[^=]*;/'; // szuka użyć zmiennych
foreach ($rii as $file) {
if ($file->isDir()) continue;
$content = file_get_contents($file->getPathname());
if (preg_match_all($pattern, $content, $matches)) {
foreach ($matches[0] as $match) {
echo "Znaleziono potencjalne użycie zmiennej w pliku: " . $file->getPathname() . "\n";
}
}
}
?>
Ten prosty skrypt przeanalizuje pliki PHP i wypisze miejsca, w których mogą być używane niezainicjalizowane zmienne.
Najczęstsze błędy po wyłączeniu register_globals
Jeśli wyłączysz register_globals w starym kodzie, może się okazać, że nic nie działa. Strony przestaną widzieć dane z formularzy, sesje nie będą się zapisywać, a użytkownicy nie będą mogli się logować.
Typowy przykład błędu:
Warning: Undefined variable: login
Wtedy wystarczy dopisać kilka linii kodu:
$login = $_POST['login'] ?? ''; $haslo = $_POST['haslo'] ?? '';
lub w starszym PHP:
if (isset($_POST['login'])) $login = $_POST['login'];
Dzięki temu kod będzie działał poprawnie bez potrzeby register_globals.
Czy da się dziś jeszcze używać register_globals?
Technicznie rzecz biorąc – nie. Od wersji PHP 5.4 ta opcja została trwale usunięta z silnika PHP. Nie da się jej włączyć, nawet jeśli ustawisz ją w php.ini.
Istnieją jednak „obejścia” – np. ręczne pisanie funkcji, które symulują działanie register_globals. Ale naprawdę – nie rób tego.
Oto przykład, jak można to zrobić (czysto edukacyjnie!):
<?php
function fake_register_globals() {
foreach ($_REQUEST as $key => $value) {
$GLOBALS[$key] = $value;
}
}
fake_register_globals();
Ten kod robi dokładnie to, co dawniej robił register_globals. Ale zauważ – jest potencjalnie niebezpieczny, bo każda zmienna przekazana w adresie lub formularzu stanie się globalna.
Taki kod to zaproszenie dla hakerów. Nigdy nie używaj go w prawdziwej aplikacji.
Podsumowanie – register_globals to przeszłość
Podsumujmy najważniejsze rzeczy, które warto zapamiętać:
– register_globals to stara funkcja PHP, która automatycznie tworzyła zmienne globalne z danych przesłanych przez użytkownika.
– Było to wygodne, ale skrajnie niebezpieczne – umożliwiało łatwe ataki i wstrzykiwanie danych.
– Od wersji PHP 5.4 funkcja została usunięta z języka.
– Zamiast tego należy używać superglobalnych tablic ($_GET, $_POST, $_COOKIE, $_SESSION itd.).
– Jeśli masz stary kod, koniecznie go zmodernizuj i usuń wszelkie zależności od register_globals.
Na koniec: moja rada dla Ciebie
Jeśli zajmujesz się programowaniem PHP, pamiętaj – bezpieczeństwo to nie opcja, to obowiązek. Nawet jeśli coś wydaje się prostsze i szybsze, może być jednocześnie bardziej niebezpieczne.
register_globals to świetny przykład na to, jak „magiczne” ułatwienia mogą obrócić się przeciwko nam. Dziś mamy lepsze narzędzia, standardy i praktyki, które nie tylko chronią nasze aplikacje, ale też czynią kod bardziej czytelnym i zrozumiałym.
Więc jeśli kiedykolwiek spotkasz register_globals w kodzie – potraktuj to jak czerwoną flagę i znak, że czas na refaktoryzację. Twój serwer i Twoi użytkownicy będą Ci wdzięczni.