PHP/Formularze: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Styl.
Zyx (dyskusja | edycje)
dodanie ustępu o protokole HTTP i korekta formatowania
Linia 1:
{{Podświetl|php}}
 
{{prognaw|PHP|[[../Zmienne i tablice/]]|[[../Struktury kontrolne/]]}}
 
== Formularze ==
W tym rozdziale zajmiemy się podstawami komunikacji skryptu PHP z przeglądarką.
 
=== Protokół HTTP ===
 
[[Plik:Http-request-pl.png|400px|thumb|Działanie protokołu HTTP.]]
 
Podstawą funkcjonowania stron WWW jest protokół HTTP, którego używa przeglądarka i serwer. Zasada jego działania jest bardzo prosta. Gdy chcemy obejrzeć dokument pod podanym adresem URL, wysyłamy do serwera tzw. '''żądanie HTTP''' zawierające lokalizację zasobu oraz garść informacji o nas samych. Serwer odnajduje lub generuje (np. przy pomocy PHP) odpowiedni dokument i odsyła wszystko jako '''odpowiedź HTTP'''. Odpowiedź zawsze zawiera pewną ilość nagłówków informacyjnych oraz opcjonalną treść, w której przesyłany jest dokument. Przeglądarka odbiera wszystko i rozpoczyna działanie. Protokół jest stosowany zarówno do pobierania kodu HTML strony, jak i znajdujących się na niej obrazków, ściągania plików i innych danych multimedialnych. Rodzaj pobieranej zawartości jest określany przez nagłówki.
 
Skrypty PHP zawsze pracują po stronie serwera, generując odpowiedzi HTTP na przychodzące do niego żądania. Przeważnie koncentrujemy się jedynie na budowaniu treści, ponieważ interpreter potrafi samodzielnie skonstruować podstawowy zestaw odpowiednich nagłówków, który co najwyżej uzupełniamy. Bardzo często do wygenerowania strony potrzebne są dodatkowe informacje, które najczęściej przechowywane są w bazie danych, a rzadziej - w plikach. Skrypty pobierają z nich dane, poddają je obróbce i osadzają w kodzie HTML, który jest odsyłany do klienta.
 
{{Uwaga|Gdy przeglądarka zaczyna wyświetlać dokument, skrypt PHP już dawno skończył swoją pracę. Pamiętaj, że działanie Twoich skryptów nie może wykroczyć poza ramy protokołu HTTP, w szczególności reagować na zdarzenia w przeglądarce (np. kliknięcie myszką), ani modyfikować fizycznie wysłanej treści. Do takich celów wykorzystywane są inne języki i technologie: JavaScript, AJAX.}}
 
Istotną częścią protokołu HTTP są rodzaje żądań (zwane "metodami") informujące o tym, co próbujemy zrobić. Dwa podstawowe to:
 
# Żądania '''GET''' - zwyczajne pobieranie dokumentu z serwera.
# Żądania '''POST''' - wysłanie pewnych danych na serwer.
 
Istnieją jeszcze inne metody, które są coraz powszechniej stosowane w większych aplikacjach WWW, jednak na niektórych serwerach są one z nieznanych powodów poblokowane. Protokołem HTTP zajmiemy się dokładniej w dalszej części podręcznika, tymczasem na razie będą nas interesować te dwie. Pierwsza z nich jest wykorzystywana podczas zwykłego pobierania z serwera dokumentu, natomiast druga - przy formularzach.
 
=== Ogólnie o danych wejściowych ===
Interaktywne aplikacje PHP odbierają od użytkownika setki informacji. Pozwalają one nie tylko zorientować się, kto nas odwiedził, ale także odczytywać zawartość formularzy oraz adresów URL. Mechanizm ich odbierania ewoluował stopniowo. Pierwsze wersje rejestrowały wszystkie nadesłane parametry jako zwyczajne zmienne, lecz począwszy od PHP 4 zarzucono to, gdyż zagrażało bezpieczeństwu wielu skryptów. Dodając nowe parametry można było rejestrować nowe zmienne, które mogły nadpisać zmienne używane w kodzie aplikacji powodując jego błędne działanie (np. zyskanie praw administratora strony przez atakującego). Programista nie mógł także policzyć, ile danych w ogóle do niego trafiło i w jakich zmiennych są zawarte.
 
W żądaniu HTTP przenoszonych jest wiele informacji o tym, co użytkownik chce obejrzeć oraz o nim samym. Wielu danych dostarcza także sam serwer HTTP. Wszystkie one są podstawą dla aplikacji PHP do wygenerowania odpowiedzi. Mechanizm ich odbierania ewoluował stopniowo. Pierwsze wersje języka rejestrowały wszystkie nadesłane parametry, dane formularzy itd. jako zmienne, lecz było to wyjątkowo niebezpieczne. Dodając nowe parametry można było rejestrować nowe zmienne, które mogły nadpisać zmienne używane w kodzie aplikacji powodując jego błędne działanie (np. zyskanie praw administratora strony przez atakującego). Programista nie mógł także policzyć, ile danych właściwie trafiało do skryptu i gdzie są one zawarte.
Obecnie wszystkie pola są rejestrowane w specjalnych, tworzonych przez skrypt, tablicach asocjacyjnych posegregowane według miejsca, z którego nadeszły. PHP potrafi odbierać informacje:
 
* Metodą GET (parametry w adresach URL)
Wszystko zmieniło się wraz z pojawieniem się PHP4. Obecnie wszystkie pola są rejestrowane w specjalnych, tworzonych przez skrypt tablicach asocjacyjnych posegregowane według miejsca, z którego nadeszły. PHP potrafi odbierać informacje:
* Metodą POST (formularze)
 
* Charakterystyczne dla metody GET (adresy URL)
* Charakterystyczne dla metody POST (zawartość formularzy)
* z serwera
* z ciasteczek
Linia 19 ⟶ 36:
 
=== Adresy URL ===
Dane pochodzące z adresu URL przechowywane są w tablicy ''$_GET''.
 
Do metodęadresu należyURL używaćmożna dołączać po znaku zapytania dodatkowe zmienne, np. <code>www.example.com/strona.php?zmienna=wartosc&inna_zmienna=wartosc</code>. Są one przechowywane w tablicy <code>$_GET</code>. Ten sposób przekazywania danych tylko, gdy skrypt nie wykonuje operacji mających efekty uboczne (np. może być wyszukiwanie, ale już nie dodawanie lub usuwanie rekordów) lub do przesyłania danych kontrolnych. W przeciwnym wypadku roboty indeksujące stronę i proxy ładujące strony z wyprzedzeniem mogą niechcący wykonywać operacje na serwerze. Z drugiej stronyPonadto cache przeglądarki i dostawców internetowych może spowodować zignorowanie zapytań.
 
Przyjrzymy się zawartości tablicy:
Możemy prosto obejrzeć sobie jej konstrukcję:
 
<nowikisource lang="php"><?php
var_dump($_GET);
 
</source>
var_dump($_GET);
 
?></nowiki>
 
Wywołując skrypt normalnie: http://localhost/~programowanie_php/nazwaskryptu.php otrzymamy następujący rezultat:
Linia 35 ⟶ 49:
array(0) { }
 
Oznacza to, że nie otrzymaliśmy tą metodądrogą żadnych danych. Dodajmy teraz do adresu ciąg ''?parametr=wartosc''. Po odświeżeniu zobaczymy:
 
array(1) { ["parametr"]=> string(7) "wartosc" }
Linia 43 ⟶ 57:
Napiszemy teraz prosty skrypt wyświetlający informacje powitalne na podstawie danych z adresu:
 
<nowikisource lang="php"><?php
if(sizeof($_GET) == 2)
{
echo 'Witaj, '.$_GET['imie'].' '.$_GET['nazwisko'].'!';
}
else
{
echo 'Nieprawidłowa liczba parametrów!';
}
</source>
 
Nie przejmuj się istnieniem konstrukcji, której jeszcze nie poznaliśmy. Niektórzy pewnie domyślili się, co ona robi, ale szczegóły będą podane już w następnym rozdziale. Na razie wpiszmy ją tak, jak jest. Funkcja <code>sizeof()</code> pojawiająca się w kodzie zwraca ilość elementów w tablicy. Sprawdzamy w ten sposób, czy użytkownik podał to, co trzeba. Kontrola nadchodzących danych jest niezwykle istotna i '''nigdy''' nie wolno jej zlekceważyć. Pominięcie tego aspektu zazwyczaj kończy się dla skryptu tragicznie, bo jeżeli coś jest do zepsucia, na pewno znajdzie się ktoś, kto tego dokona.
if(count($_GET) == 2)
{
echo 'Witaj, '.$_GET['imie'].' '.$_GET['nazwisko'].'!';
}
else
{
echo 'Nieprawidłowa liczba parametrów!';
}
 
Wywołując skrypt z parametrami "imie" oraz "nazwisko" możemy wpływać na wyświetlane informacje: [http://localhost/~programowanie_php/nazwaskryptu.php?imie=Adam&nazwisko=Kowalski http://localhost/~programowanie_php/nazwaskryptu.php?imie=Adam&nazwisko=Kowalski]. Dla lepszego efektu stwórzmy prosty formularz HTML wysyłający dane metodą GET:
?></nowiki>
 
<source lang="html4strict"><?xml version="1.0" encoding="utf-8" standalone="no"?>
Nie przejmuj się istnieniem konstrukcji, której jeszcze nie poznaliśmy. Niektórzy pewnie domyślili się, co ona robi, ale szczegóły będą podane już w następnym rozdziale. Na razie wpiszmy ją tak, jak jest. Funkcja ''count()'' pojawiająca się w kodzie zwraca ilość elementów w tablicy. Sprawdzamy w ten sposób, czy użytkownik podał to, co trzeba. Kontrola nadchodzących danych jest niezwykle istotna i '''nigdy''' nie wolno jej zlekceważyć. Pominięcie tego aspektu zazwyczaj kończy się dla skryptu tragicznie, bo jeżeli coś jest do zepsucia, na pewno znajdzie się ktoś, kto tego dokona.
 
Wywołując skrypt z parametrami "imie" oraz "nazwisko" możemy wpływać na wyświetlane informacje: [http://localhost/~programowanie_php/nazwaskryptu.php?imie=Adam&nazwisko=Kowalski http://localhost/~programowanie_php/nazwaskryptu.php?imie=Adam&nazwisko=Kowalski]. Dla lepszego efektu stwórzmy prosty formularz XHTML wysyłający dane metodą GET:
 
<nowiki><?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
Linia 79 ⟶ 91:
</form>
</body>
</html></nowiki>
</source>
 
Choć tworzenie formularzy teoretycznie pasuje do następnej sekcji, tak naprawdę w tym momencie zwyczajnie oszukujemy. Wypełnij ten formularz i wyślij go, a zobaczysz, że przeglądarka dokleiła do pliku podanego w znaczniku FORM parametry utworzone na podstawie pól! Tak więc nasz skrypt nawet nie ma możliwości stwierdzenia, skąd dane do niego przyszły! Poznajmy zatem metodę POST...
 
=== Formularze ===
Obsługa formularzy z prawdziwego zdarzenia, którymi można przesyłać setki informacji, odbywa się dosyć podobnie, jak adresów. Różnica jest taka, że wszystko wysyła się wyłącznie z formularza, który posiada parametr "method" ustawiony na "post" oraz że korzysta się z tablicy ''$_POST'' wewnątrz samego skryptu. Przeróbmy nasze ostatnie dzieło tak, aby pracowało w ten sposób.
 
Obsługa formularzy z prawdziwego zdarzenia, którymi można przesyłać setki informacji, odbywa się dosyć podobnie, jak adresów. Różnica jest taka, że wszystko wysyła się wyłącznie z formularza, który posiada parametr "method" ustawiony na "post" oraz że korzysta się z tablicy <code>$_POST</code> wewnątrz samego skryptu. Przeróbmy nasze ostatnie dzieło tak, aby pracowało w ten sposób.
<nowiki><?php
 
<source lang="php"><?php
if(count($_POST) == 2)
if(count($_POST) == 2)
{
{
echo 'Witaj, '.$_POST['imie'].' '.$_POST['nazwisko'].'!';
echo 'Witaj, '.$_POST['imie'].' '.$_POST['nazwisko'].'!';
}
}
else
else
{
{
echo 'Nieprawidłowa liczba parametrów!';
echo 'Nieprawidłowa liczba parametrów!';
}
}
</source>
 
W skrypcie podmieniamy jedynie nazwy tablic na <code>$_POST</code>. W formularzu musimy jeszcze zmienić metodę:
?></nowiki>
 
<source lang="html4strict"><html>
W skrypcie podmieniamy jedynie nazwy tablic na ''$_POST''. W formularzu musimy jeszcze zmienić metodę:
<head>
<title>Formularz HTML</title>
</head>
<body>
<form method="post" action="nazwaskryptu.php">
Podaj imię: <input type="text" name="imie"/><br/>
Podaj nazwisko: <input type="text" name="nazwisko"/><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
</source>
 
I gotowe. Wyślij teraz formularz. Zauważ, że żadna informacja nie jest doklejana do adresu, ponieważ transmisja odbywa się niejako innym kanałem.
<nowiki><html>
<head>
<title>Formularz HTML</title>
</head>
<body>
<form method="post" action="nazwaskryptu.php">
Podaj imię: <input type="text" name="imie"/><br/>
Podaj nazwisko: <input type="text" name="nazwisko"/><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html></nowiki>
 
{{Infobox|Nazwy tablic są trochę nieprecyzyjne. To, że wysłaliśmy żądanie metodą POST wcale nie oznacza, że tablica <code>$_GET</code> będzie wtedy zawsze pusta. Możliwe jest jednocześne wysłanie danych formularzem wraz ze zmiennymi w adresie URL, co sprawi, że obie tablice będą posiadać jakąś zawartość.}}
I gotowe. Wyślij teraz formularz. Zauważ, że żadna informacja nie jest doklejana do adresu, ponieważ transmisja odbywa się niejako innym kanałem.
 
Z kursów języka HTML wiadomo, że istnieją różne typy pól formularzy. Oto, jakie wartości otrzymuje od nich PHP:
 
* <pre><nowiki><input type="text" name="nazwa"/></nowiki></pre> - skrypt otrzymuje ''<code>$_POST['nazwa']''</code> z wartością wpisaną w pole formularza.
* <pre><nowiki><input type="hidden" name="nazwa"/></nowiki></pre> - skrypt otrzymuje ''<code>$_POST['nazwa']''</code> z wartością wpisaną w danym znaczniku. Użyteczne do przesyłania formularzem ukrytych informacji, o których typowy użytkownik wiedzieć nie musi.
* <pre><nowiki><input type="radio" name="nazwa" value="wartosc"/></nowiki></pre> - pozycje należące do tej samej grupy muszą mieć identyczną nazwę. '<code>$_POST['nazwa']''</code> będzie zawierać wartość tej pozycji, która jest aktualnie zaznaczona.
* <pre><nowiki><input type="checkbox" name="nazwa"/></nowiki></pre> - jeśli pole jest zaznaczone, ''<code>$_POST['nazwa']''</code> zawierać będzie słowo "on".
* <pre><nowiki><select name="nazwa">...</select></nowiki></pre> - ''<code>$_POST['nazwa']''</code> zawierać będzie wartość wybranego z listy elementu.
* <pre><nowiki><input type="submit" name="nazwa"/></nowiki></pre> - zmienna ''<code>$_POST['nazwa']''</code> zostanie utworzona, jeżeli akurat ten przycisk zostanie wciśnięty.
Dzięki temu można do formularzy wstawiać kilka przycisków "submit"
i reagować inaczej w zależności od tego, który z nich został naciśnięty.
Linia 130 ⟶ 145:
Na sam koniec zostawiliśmy sobie kilka informacji przekazywanych interpreterowi przez serwer WWW (np. Apache). Zacznijmy od określenia adresu IP gościa:
 
<nowikisource lang="php"><?php
echo 'Witaj, twój adres IP to '.$_SERVER['REMOTE_ADDR'].'!';
</source>
 
Ten skrypt pokaże nam adres IP komputera lub sieci, w której znajduje się internauta. W tym drugim przypadku dalsze informacje są niepewne. Serwerowi potrzebny jest wyłącznie ten adres, aby móc gdzieś wysłać rezultat, a pola <code>$_SERVER['HTTP_X_FORWARDED_FOR']</code> lub <code>$_SERVER['HTTP_CLIENT_IP']</code> są bardzo niepewne - generuje je właśnie serwer proxy, ale nic nie stoi na przeszkodzie, by podszył się pod nie hacker. Uznawanie ważności informacji tu zawartych było przyczyną wielu błędów bezpieczeństwa w popularnym skrypcie forów dyskusyjnych phpBB i jeżeli naprawdę zależy Ci na nim, pozostań przy ''REMOTE_ADDR'', a resztę traktuj wyłącznie jako ciekawostkę.
echo 'Witaj, twój adres IP to '.$_SERVER['REMOTE_ADDR'].'!';
 
Korzystając z funkcji <code>gethostbyaddr()</code> możemy uzyskać nazwę hosta, którego dotyczy adres IP:
?></nowiki>
 
<source lang="php"><?php
Ten skrypt pokaże nam adres IP komputera lub sieci, w której znajduje się internauta. W tym drugim przypadku dalsze informacje są niepewne. Serwerowi potrzebny jest wyłącznie ten adres, aby móc gdzieś wysłać rezultat, a pola ''$_SERVER['HTTP_X_FORWARDED_FOR']'' lub ''$_SERVER['HTTP_CLIENT_IP']'' są bardzo niepewne - generuje je właśnie serwer proxy, ale nic nie stoi na przeszkodzie, by podszył się pod nie hacker. Uznawanie ważności informacji tu zawartych było przyczyną wielu błędów bezpieczeństwa w popularnym skrypcie forów dyskusyjnych phpBB i jeżeli naprawdę zależy Ci na nim, pozostań przy ''REMOTE_ADDR'', a resztę traktuj wyłącznie jako ciekawostkę.
echo 'Witaj, twój host to '.gethostbyaddr($_SERVER['REMOTE_ADDR']).'!';
 
</source>
Korzystając z funkcji ''gethostbyaddr()'' możemy uzyskać nazwę hosta, którego dotyczy adres IP:
 
<nowiki><?php
 
echo 'Witaj, twój host to '.gethostbyaddr($_SERVER['REMOTE_ADDR']).'!';
 
?></nowiki>
 
Spróbujmy zidentyfikować przeglądarkę użytkownika:
 
<nowikisource lang="php"><?php
echo 'Twoja przeglądarka została zidentyfikowana jako: '.$_SERVER['HTTP_USER_AGENT'].'!';
 
</source>
echo 'Twoja przeglądarka została zidentyfikowana jako: '.$_SERVER['HTTP_USER_AGENT'].'!';
 
?></nowiki>
 
Pole to zawiera wyłącznie surowe informacje. Każda przeglądarka wpisuje tu co innego i dlatego wyciągnięcie ładnych i pogrupowanych w odpowiednie kategorie danych to zadanie na więcej, niż jeden artykuł. Pozostańmy zatem przy takiej postaci, a przetwarzaniem nagłówków przeglądarek zajmiemy się kiedy indziej.
 
Adres strony, z której przybyliśmy do naszego skryptu, znajduje się w zmiennej ''<code>$_SERVER['HTTP_REFERER']''</code>. Można wykorzystać go do utworzenia linków "Cofnij" albo do detekcji, jakich słów kluczowych używają ludzie trafiający do nas z wyszukiwarek. Zauważ - szukane frazy zazwyczaj dołączane są właśnie do adresów URL i w ten sposób można je zdobyć.
 
Uwaga: nie można polegać na obecności i prawidłowości tej informacji. Istnieją przeglądarki i zapory ogniowe, które ją usuwają lub wstawiają tam dowolny adres podany przez użytkownika.
 
<nowikisource lang="php"><?php
echo 'Przybyłeś do nas ze strony: '.$_SERVER['HTTP_REFERER'].'!';
 
</source>
echo 'Przybyłeś do nas ze strony: '.$_SERVER['HTTP_REFERER'].'!';
 
?></nowiki>
 
W chwili obecnej to tyle, jeżeli chodzi o pobieranie danych. Dalszych informacji dowiemy się w trakcie następnych rozdziałów w miarę potrzeby.