Dane wejściowe, przesyłane do naszych aplikacji nie zawsze są w pełni bezpieczne. Czasem trafią nam się dane, które z założenia mają nam zaszkodzić. Istnieją również sytuacje, gdy naszym celem jest przyjęcie od użytkownika danych zawierających tagi HTML. Jak poradzić sobie w takiej sytuacji i bezpiecznie przetworzyć te dane?
Język PHP udostępnia kilka funkcji, które pomogą nam poradzić sobie z tym problemem. I tak na przykład, jeżeli nie oczekujemy żadnych tagów HTML w danych wejściowych możemy użyć funkcji strip_tags. Jest ona prosta w użyciu i przy poprawnych danych wejściowych daje nam to, co potrzebujemy. Weźmy dla przykładu taki kod:
<?php
$tekst = '<script>alert("Łódź oblężona!©");</script>';
echo strip_tags($tekst);
W wyniku jego działania otrzymamy taki oto wynik:
alert("Łódź oblężona!©");
Zatem tak, jak można by się spodziewać. Jednakże jak już wcześniej wspomniano, dane wejściowe muszą być poprawne, ponieważ funkcja strip_tags jest prostą funkcją. Niektórzy określiliby ją jako tzw. głupią. Co, gdyby zmienić nasz kod na taki:
<?php
$tekst = '<script alert("Łódź oblężona!©");</script>';
echo strip_tags($tekst);
Tym razem wynik będzie taki:
Tak, zgadza się, otrzymaliśmy pusty ciąg znaków. Otóż tym razem cały tekst został uznany za jeden wielki tag, bo funkcja napotkała nawias zamykający dopiero na końcu. Nie jest tu brana ilość nawiasów otwierających. Nie jest też zwracany żaden błąd, gdy liczba nawiasów otwierających i zamykających jest inna.
A co, jeżeli naszym celem jest zachowanie tagów HTML, które są w danych od użytkownika? Jedno jest pewne, nie możemy sobie pozwolić na przyjęcie ich w naszym systemie bez żadnej obróbki. Możemy ją przeprowadzić między innymi przy pomocy dwóch bardzo podobnie działających funkcji: htmlspecialchars oraz htmlentities.
Funkcja htmlspecialchars ma za zadanie zmienić pięć podstawowych znaków specjalnych na odpowiadające im encje HTML, domyślnie tak jak to przedstawiono poniżej:
| Znak specjalny | Encja HTML |
| & | & |
| „ | " |
| ’ | ' |
| < | < |
| > | > |
Tym razem użyjmy w naszej aplikacji funkcji htmlspecialchars:
<?php
$tekst = '<script>alert("Łódź oblężona!©");</script>';
echo htmlspecialchars($tekst);
Jak teraz będą wyglądać nasze dane? Otóż tak:
<script>alert("Łódź oblężona!©");</script>
Taki kod jest dużo mniej groźny dla naszej aplikacji, niż oryginalny, który moglibyśmy otrzymać od użytkownika.
Wiemy już jak działa funkcja htmlspecialchars. A jak działa htmlentities? Bardzo podobnie, jednakże zmienia ona na encje HTML większy zbiór znaków specjalnych. Gdy zastosujemy ją w naszej aplikacji zamiast htmlspecialchars otrzymamy taki oto wynik:
<script>alert("Łódź oblężona!©");</script>
Jak widzimy, na encje HTML zostały zamienione dodatkowe znaki.
Na koniec drobna uwaga, jeżeli używana przez nas wersja PHP jest poniżej 8.1.0, wtedy należy dodać drugi argument (flagę) w obu funkcjach, ponieważ w wersjach poniżej wymienionej domyślnym zachowaniem obu funkcji jest brak akcji w przypadku pojedynczego cudzysłowa (’). Kod z jawnie ustawioną flagą bez problemu będzie działać też w PHP w wersji 8.1.0 i wyższych, po prostu w tych wersjach flaga ta jest ustawiana domyślnie. Zatem w wersjach poniżej wymienionej kod nasz, w przypadku funkcji htmlspecialchars, wyglądałby następująco:
<?php
$tekst = '<script>alert("Łódź oblężona!©");</script>';
echo htmlspecialchars($tekst, ENT_QUOTES);
Dokumentacja PHP silnie zaleca również jawne ustawianie kodowania, które jest przekazywane jako trzeci parametr. W przypadku jego braku, stosowane jest domyślne kodowanie ustawione w opcjach konfiguracyjnych. Gdy dodamy również kodowanie UTF-8, otrzymamy:
<?php
$tekst = '<script>alert("Łódź oblężona!©");</script>';
echo htmlspecialchars($tekst, ENT_QUOTES, 'UTF-8');
Która z tych funkcji jest zatem lepsza i którą należy stosować? Wszystko zależy od tego, jaki efekt chcemy uzyskać. 😉
Bibliografia: