PHP/Obsługa ciastek: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Zyx (dyskusja | edycje)
początek rozdziału
 
Zyx (dyskusja | edycje)
rozbudowa materiałów o ciastka i nagłówki.
Linia 3:
== Obsługa ciastek ==
=== Czym są nagłówki HTTP? ===
Serwer w odpowiedzi na żądanie HTTP wysyła nie tylko kod HTML, lecz także zestaw nagłówków pomagających przeglądarce na zidentyfikowanie dostarczanych treści. Nagłówki precyzują typ MIME danych, np. ''text/html'' dla dokumentu HTML, kodowanie znaków, zachowanie się serwerów proxy, ustawienia cache'owania danych itd. PHP posiada funkcję ''header()'' pozwalającą skryptowi wysłać własne nagłówki. Muszą być one jednak zdefiniowane przed wysłaniem jakiegokolwiek kodu HTML (są to przecież NAGŁÓWKI). W przeciwnym wypadku dostaniemy niemiły komunikat ''Cannot add header information''. OtoProgramiści przykładoweczęsto zastosowaniewykorzystują nagłówkównagłówki do zdefiniowania typu oraz kodowania w nadsyłanym dokumencie:
 
<nowiki><?php
Linia 11:
 
?></nowiki>
 
Ale nie tylko. Wiele stron udostępnia swe archiwa nie poprzez bezpośredni dostęp do katalogu, w którym są trzymane, ale poprzez specjalny skrypt, który wysyła ich zawartość do ściągnięcia. Nagłówki umożliwiają powiadomienie przeglądarki, że teraz będzie szedł plik o takiej i takiej nazwie, który internauta chce pobrać na swój dysk twardy. Nie będzie on jednak ujawniać katalogu na serwerze, gdzie on się znajduje. Cała komunikacja prowadzona jest za pośrednictwem PHP.
 
<nowiki><?php
if(!isset($_GET['plik'])) // 1
{
die('Podaj nazwę pliku!');
}
$_GET['plik'] = basename($_GET['plik']); // 2
if(@is_file('./pdf/'.$_GET['plik']))
{
// 3
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="'.$_GET['plik'].'"');
readfile('./pdf/'.$_GET['plik']);
}
else
{
// 4
header('HTTP/1.1 404 Not Found');
}
?></nowiki>
 
Powyższy kod może być częścią jakiegoś serwisu, który swoje artykuły udostępnia także w formacie PDF do ściągnięcia, gdyż aktualnie tylko takie pliki można nim wysyłać. Przeanalizujmy go krok po kroku.
# Na początku dokonujemy sprawdzenia, czy ktoś w ogóle zainteresował się podaniem nazwy dokumentu do pobrania.
# Bezpieczeństwo na miejscu pierwszym - wszystko, co jest nazwą pliku i pochodzi od internauty, powinno być przepuszczone przez funkcję ''basename()'', która wyciągnie z niego wyłącznie nazwę i odrzuci jakieś przejścia międzykatalogowe, co mogłoby zagrozić bezpieczeństwu. Wyobraź sobie, że ktoś wpisze sobie np. ''../strona_hasla.php''. Bez tego zabezpieczenia dostałby hasła dostępu do naszej strony, lecz ''basename()'' odrzuci niebezpieczny fragment ''../''. Mamy więc pewność, że internauta będzie ściągać TYLKO i WYŁĄCZNIE to, co chcemy, aby ściągał.
# Jeśli stwierdzimy, że plik istnieje, powiadamiamy nagłówkami, że oto nadejdzie dokument PDF jako załącznik o odpowiedniej nazwie. Funkcją ''readfile()'' wysyłamy jego zawartość.
# Gdyby ktoś podał niewłaściwą nazwę pliku, możemy wysłać mu komunikat błędu 404.
 
Powyższy przykład możemy nieco przerobić tak, aby z powodu podania błędnej nazwy internauta odsyłany był do naszego własnego komunikatu. Nagłówki umożliwiają robienie przekierowań HTTP i właśnie pragniemy pokazać, jak to się robi.
 
<nowiki><?php
if(!isset($_GET['plik']))
{
die('Podaj nazwę pliku!');
}
$_GET['plik'] = basename($_GET['plik']);
if(@is_file('./pdf/'.$_GET['plik']))
{
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="'.$_GET['plik'].'"');
readfile('./pdf/'.$_GET['plik']);
}
else
{
header('Location: http://localhost/~kurs/notfound.php');
exit;
}
?></nowiki>
 
Źródło jest zasadniczo podobne do poprzedniego przykładu. Zmiany widać jedynie w bloku '''else''', gdzie wysyłamy tym razem nagłówek ''Location''. Informuje on przeglądarkę, że treści nie będzie i powinna raczej skontaktować się z podanym plikiem. Innymi słowy, robimy przekierowanie internauty pod inny adres. Protokół HTTP 1.1 wymaga, aby w nagłówku był podany pełen adres do żądanego zasobu. HTTP 1.0 nie miał takich ograniczeń.
 
{{Uwaga|Po wysłaniu nagłówka ''Location'' powinniśmy wywołać komendę '''exit;''' albo '''die()''', aby zatrzymać nasz skrypt!}}
 
Kiedy omówiliśmy sobie już właściwości oraz niektóre możliwości nagłówków, możemy przejść do ciastek (ang. ''cookies'') ustawianych właśnie za ich pomocą.
 
=== Ciastka w PHP ===
Chyba każdy internauta słyszał o ciastkach i wyolbrzymianych "zagrożeniach" z nimi związanych. W rzeczywistości są to zwyczajne informacje umieszczane przez witryny WWW w przeglądarkach po to, aby był do nich dostęp między wywołaniami kolejnych podstron w obrębie witryny. Jedyny problem może pojawić się z tzw. ciastkami publicznymi, które może odczytać każda strona w Internecie. Jednak poza tym jest to bardzo pożyteczne narzędzie wykorzystywane m.in. w autoryzacji użytkowników.
 
Ciastka są ustawiane za pomocą nagłówków HTTP i mają pewien określony termin ważności. Po jego upływie przestają istnieć. Do wysyłania ciastek służy w PHP funkcja ''setcookie()'', a do pobierania wartości tych ustawionych przez wcześniejsze żądania HTTP - specjalna tablica ''$_COOKIE''. Napiszemy teraz prosty skrypt, który robił furorę kilka lat temu, w okresie popularyzacji dynamicznych witryn WWW. Chodzi o umieszczenie prostej informacji dot. ostatniej wizyty internauty u nas. Aby to wykonać, wystarczy przy pierwszym wejściu umieścić na np. miesiąc czasu ciastko z datą ostatniej wizyty, po czym ją sukcesywnie odczytywać.
 
<nowiki><?php
if(!isset($_COOKIE['wizyta']))
{
setcookie('wizyta', time(), time() + 30 * 86400);
echo 'Witaj, gościu.';
}
else
{
setcookie('wizyta', time(), time() + 30 * 86400);
echo 'Witaj, ostatni raz odwiedziłeś nas '.date('d.m.Y, H:i', $_COOKIE['wizyta']);
}
?></nowiki>
 
Trzy pierwsze parametry ''setcookie()'' są najważniejsze (ma ona ich trochę więcej). Jest to kolejno: nazwa ciastka, jego wartość oraz data ważności w sekundach od 1.1.1970. Data, a nie okres ważności, stąd przy jego ustawianiu przydaje się funkcja ''time()''. W powyższym skrypcie sprawdzamy, czy ustawialiśmy już ciastko dla danego internauty. Jeśli nie, tworzymy je i wyświetlamy komunikat powitania. W przeciwnym wypadku także aktualizujemy wartość, ale też wyświetlamy datę ostatniej wizyty odczytaną właśnie z ciastka.
 
Zauważ, że wywołanie ''setcookie()'' nie nadpisuje wartości w tablicy ''$_COOKIE''. Dlatego bez problemu można uprościć powyższy skrypt:
 
<nowiki><?php
setcookie('wizyta', time(), time() + 30 * 86400);
if(!isset($_COOKIE['wizyta']))
{
echo 'Witaj, gościu.';
}
else
{
echo 'Witaj, ostatni raz odwiedziłeś nas '.date('d.m.Y, H:i', $_COOKIE['wizyta']);
}
?></nowiki>
 
Aby istniejące ciastko skasować, wywołujemy funkcję ''setcookie()'' z jakąś przeszłą datą ważności:
 
<nowiki><?php
setcookie('wizyta', '', 0);
?></nowiki>
=== Funkcje buforowania wyjścia ===