PHP/Studium przypadku - Księga gości: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Felix (dyskusja | edycje)
m navigator
Linia 3:
{{prognaw|PHP|[[../../Korzystanie z dokumentacji/]]|[[../../Przetwarzanie tekstu/]]}}
 
hbGc9g sd89f984q34slf
== Studium przypadku: Księga gości ==
Dotychczasowe rozdziały miały w sobie więcej teorii i nie ukazywały prawdziwej istoty tworzenia skryptów dla stron WWW. Najlepszym rodzajem nauki jest praktyczne stworzenie skryptu z prawdziwego zdarzenia i pokazanie w ten sposób, jak poszczególne elementy języka ze sobą się łączą. W tym rozdziale stworzymy samodzielnie funkcjonalną księgę w PHP. Wykorzystamy w niej pętle, tablice, instrukcje warunkowe, formularze oraz dołączanie plików zewnętrznych. Ponadto poznamy kilka interesujących funkcji.
 
=== Plan ===
Księgę gości oprzemy o pliki tekstowe. Każdy wpis będzie charakteryzowany przez:
* Tytuł
* Autora
* Datę
* Adres WWW (opcjonalny)
* Treść
Wszystkie te dane zostaną zapisane w pliku w pojedynczym wierszu, a oddzielone będą znakiem "|". Aby wyeliminować sytuację, gdy ktoś wpisze np. w treść taki znak, albo (co gorsza) naciśnie enter, każda kolumna zostanie zakodowana w formacie Base64. Oczywiście nie będziesz musiał sam pisać odpowiedniego algorytmu - PHP posiada odpowiednie funkcje. Base64 został pierwotnie zaprojektowany do przesyłania 8-bitowych wiadomości w 7-bitowych protokołach. Do zapisu są tu używane wyłącznie litery, cyfry, ukośnik oraz znak równości, zatem nie ma obawy o uszkodzenie formatu pliku księgi. Zakodowana wiadomość jest o ok. 33% dłuższa od oryginału.
 
Księga nie będzie zapisywać i odczytywać z pliku bezpośrednio. W zewnętrznym pliku napiszemy sobie dwie funkcje zajmujące się wyłącznie tym. Księga będzie miała dostęp do danych jedynie za ich pomocą. Rozwiązanie to jest bardzo użyteczne. Kiedy poznasz już bazy danych, z pewnością zapragniesz przesiąść się właśnie na nie. Nie będziesz musiał przepisywać całej księgi. Po prostu napiszesz do tych dwóch funkcji nowy kod. Dzięki takiemu rozwiązaniu źródła skryptu będą uporządkowane i czytelne, a ponadto bardzo łatwe do modyfikacji.
 
=== dane.php ===
Plik ''dane.php'' zawierać będzie dwie funkcje: ''dodajWpis()'' oraz ''pobierzWpisy()'' zajmujące się wyłącznie operowaniem na danych. Będziemy go pisać po kawałku.
 
<nowiki><?php
define('WPISY', './wpisy.txt');
function dodajWpis($tytul, $autor, $www, $tresc)
{
// Ucinanie bialych znakow
$tytul = trim($tytul);
$autor = trim($autor);
$www = trim($www);
$tresc = trim($tresc);</nowiki>
 
Nazwę pliku zapisaliśmy za pomocą stałej. To na wypadek, gdyby zachciało nam się go kiedyś przenieść albo zmienić mu nazwę. Pierwszy etap obrabiania danych to ucięcie białych znaków (spacji, tabulatorów itp.) z początku i końca każdego ciągu. Nie są nam one do niczego potrzebne, a jedynie utrudniają nam sprawę.
 
<nowiki> // Kontrola danych
if(strlen($tytul) < 3)
{
return false;
}
if(strlen($autor) < 3)
{
return false;
}
if(strlen($tresc) < 10)
{
return false;
}
if(strlen($www) > 0)
{
// Jesli adres nie zaczyna sie od http:// to dodaj to
if(strpos($www, 'http://') !== 0)
{
$www = 'http://'.$www;
}
}</nowiki>
 
Tutaj zajmujemy się kontrolą danych. Tytuł i autor muszą mieć przynajmniej trzy znaki, a treść 10. Długość pobieramy funkcją ''strlen()''. Jeżeli podaliśmy adres WWW, za pomocą funkcji ''strpos()'' sprawdzamy, czy na jego początku jest na pewno dodany identyfikator protokołu. Zwróć uwagę na użyty operator: ''!==''. Wspomniana funkcja zwraca pozycję pierwszego znaku szukanego ciągu (liczoną od zera), a jeżeli go nie znajdzie, zwraca '''false'''. Normalnie ''0'' i '''false''' są równoważne, dlatego musimy wymusić sprawdzenie także typu, bowiem nam chodzi o ''0'' jako pozycję identyfikatora w adresie, a nie informację, że go nie ma.
 
Jeżeli któraś z informacji nie będzie prawidłowo podana, funkcja zwróci do skryptu wartość '''false'''.
 
<nowiki> // Dodawanie
$f = fopen(WPISY, 'a');
$dane = array(0 =>
base64_encode(htmlspecialchars($tytul)),
base64_encode(htmlspecialchars($autor)),
time(),
base64_encode(htmlspecialchars($www)),
base64_encode(nl2br(htmlspecialchars($tresc)))
);
fwrite($f, implode('|', $dane)."\r\n");
fclose($f);
return true;
} // end dodajWpis();</nowiki>
 
Ostatni akord to zapisanie wpisu w pliku. Na początek otwieramy go w trybie dopisywania (parametr ''a''), następnie budujemy tablicę z danymi wpisu. Parametry przybyłe z formularza kodujemy w Base64, środkowa kolumna to czas dodania wpisu w sekundach od 1.1.1970. Dzięki takiemu jego zapisowi, będziemy go mogli później dowolnie formatować funkcją ''date()''. Przy przetwarzaniu tekstu użyliśmy jeszcze kilku funkcji:
* ''htmlspecialchars()'' - wszystkie wprowadzone tagi HTML są zamieniane na zwykły tekst (ograniczniki są zastępowane odpowiadającymi im encjami, np. ''&lt;'' zmienia się w ''&amp;lt;''). W ten sposób nikt nie rozwali nam księgi złośliwym kodem.
* ''nl2br()'' - zamienia znaki nowej linii na znaczniki ''&lt;br/&gt;''.
* ''implode()'' - łączy tablicę w ciąg tekstowy, wstawiając pomiędzy poszczególne elementy podany w pierwszym parametrze znak. Na końcu utworzonego przez nią rekordu wpisu musimy dodać samodzielnie znaki zejścia do nowej linii: ''\r\n'', koniecznie w cudzysłowach, a nie w apostrofach.
 
Zwróć uwagę na rozbudowane wywołania funkcji:
 
''base64_encode(nl2br(htmlspecialchars($tresc)))''
 
Oznacza ona, że najpierw zawartość zmiennej ''$tresc'' trafia do funkcji najbardziej w prawo, tj. ''htmlspecialchars()''. Z niej przechodzi do ''nl2br()'', a z niej do ''base64_encode()''. Alternatywne kursy preferują w tym miejscu czytelną, ale mniej wydajną formę zapisu:
 
<pre class="lang-php">
$tresc = htmlspecialchars($tresc);
$tresc = nl2br($tresc);
$tresc = base64_encode($tresc);
</pre>
 
Nasz kod ma tę przewagę, że wynik jednej funkcji od razu trafia do drugiego, tymczasem powyżej po drodze trafia do zmiennej, co ma szczególnie negatywny wpływ na wydajność przy dużych danych. Ponadto zapis ten często nie jest opatrzony stosownym komentarzem i wyrabia złe nawyki tworzenia mnóstwa niepotrzebnych zmiennych tymczasowych, o czym już wspominaliśmy. Trzeba zapamiętać, że nawet podawany przez nas wariant konstrukcji księgi nie jest "tym jedynym słusznym". Istnieje jeszcze wiele innych sposobów jej zaprogramowania.
 
Przyszła kolej na funkcję pobierającą wpisy.
 
<nowiki> function pobierzWpisy()
{
$wpisy = array_reverse(file(WPISY));
$i = 1;
$rezultat = array();</nowiki>
 
Wpisy pobieramy funkcją ''file()'', która automatycznie rozbija nam plik na tablicę względem wierszy. Tam jednak najnowsze wpisy są na końcu, a my chcemy je wyświetlić w kolejności odwrotnej: najnowsze na górze. Dlatego od razu przepuszczamy wynik przez funkcję ''array_reverse()'' odwracającą tablicę. Następnie inicjujemy licznik wpisów ''$i'' oraz tablicę ''$rezultat'', do której będziemy pakować sformatowane odpowiednio wpisy. Ją później przekażemy księdze do wyświetlenia.
 
<nowiki> foreach($wpisy as $wpis)
{
$wpis = explode('|', trim($wpis));
$rezultat[] = array(
'id' => $i,
'tytul' => base64_decode($wpis[0]),
'autor' => base64_decode($wpis[1]),
'data' => date('d.m.Y, H:i', $wpis[2]),
'www' => base64_decode($wpis[3]),
'tresc' => base64_decode($wpis[4])
);
$i++;
}
return $rezultat;
} // end pobierzWpisy();
?></nowiki>
 
Po kolei formatujemy każdy wpis. Do ich pobierania wykorzystaliśmy pętlę ''foreach()''. Na wejściu przepuszczamy je przez funkcję ''trim()'', bowiem ''file()'' pozostawia w tablicach znaki zejścia do nowej linii. Dopiero po ich usunięciu możemy funkcją ''explode()'' rozbić ciąg z powrotem na tablicę (czyli wykonać operację odwrotną do ''implode()''). Wpis przepuszczamy przez ''base64_decode()'', aby zdekodować informacje, formatujemy datę i pakujemy to do tablicy ''$rezultat''. Później zwracamy ją.
 
=== ksiega.php ===
W pliku tym znajdzie się główna część funkcjonalna księgi. To jego powinniśmy uruchamiać z poziomu przeglądarki. Zaczynamy jego pisanie od nagłówka HTML oraz dołączenia uprzednio napisanego pliku:
 
<nowiki><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-2">
<title>Księga gości Wikibooks</title>
</head>
<body>
<h1>Księga gości Wikibooks</h1>
<?php
require('./dane.php');</nowiki>
 
Właściwy kod rozpocznie się instrukcją warunkową, która zadecyduje, czy wysłany został formularz dodawania, czy też wystarczy wyświetlić aktualną zawartość księgi. PHP zapisuje informację o użytej metodzie wysyłania żądania w specjalnej zmiennej ''$_SERVER['REQUEST_METHOD']'', która może przyjąć wartości '''POST''' (formularz) albo '''GET''' (zwyczajne żądanie). Z niej właśnie skorzystamy:
 
<nowiki> if($_SERVER['REQUEST_METHOD'] == 'POST')
{
// Dodawanie wpisu
if(dodajWpis($_POST['tytul'], $_POST['autor'], $_POST['www'], $_POST['tresc']))
{
echo '<p>Dziękujemy, wpis został dodany prawidłowo.</p>';
}
else
{
echo '<p>Proszę wypełnić prawidłowo formularz.</p>';
}
echo '<p><a href="ksiega.php">Powrót</a></p>';
}</nowiki>
 
Kontrola danych jest realizowana w pliku ''dane.php'' i nie ma potrzeby jej tu powtarzać. Wprowadzamy do funkcji ''dodajDane()'' poszczególne pola formularza i ifem sprawdzamy, jaki jest rezultat, aby móc wygenerować stosowny komunikat.
 
Jeżeli nie dodajemy aktualnie żadnego nowego wpisu, wyświetlamy te, które już mamy:
 
<nowiki> else
{
// Wyświetlanie wpisów
$wpisy = pobierzWpisy();
foreach($wpisy as $wpis)
{
echo '<hr /><p><b>Tytuł: <i>'.$wpis['tytul'].'</i>;
Autor: '.$wpis['autor'].'; Data: '.$wpis['data'];
if(strlen($wpis['www']) > 0)
{
echo '; <a href="'.$wpis['www'].'" target="_blank">Strona WWW</a>';
}
echo '</b></p>';
echo '<p>'.$wpis['tresc'].'</p>';
}
?><hr /></nowiki>
 
Tablicę z wpisami dostajemy z funkcji ''pobierzWpisy()''. Skanujemy ją pętlą foreach i wyświetlamy każdy z elementów. Zauważ, że skrypt potrafi ominąć pole z adresem WWW, jeśli ten nie został podany. Po prostu funkcją ''strlen()'' sprawdzamy, czy jego długość jest większa od zera.
 
Ostatnim akordem będzie dodanie formularza HTML:
 
<nowiki><form method="post" action="ksiega.php">
<table border="0" width="50%">
<tr>
<td>Tytuł</td>
<td><input type="text" name="tytul"/></td>
</tr>
<tr>
<td>Autor</td>
<td><input type="text" name="autor"/></td>
</tr>
<tr>
<td>WWW</td>
<td><input type="text" name="www"/></td>
</tr>
<tr>
<td>Treść</td>
<td><textarea name="tresc" rows="4" cols="50"></textarea></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Dodaj"/></td>
</tr>
</table>
</form>
<?php
}
?>
</body>
</html></nowiki>
 
Formularz wysyłamy metodą '''POST''' do pliku ''ksiega.php''. Jego wysłanie spowoduje uaktywnienie się dodawania wpisów. Przed wysłaniem ostatnich znaczników musimy dodać jeszcze klamrę kończącą instrukcję warunkową, która decyduje, co należy wykonać. Umieszczenie jej w tym miejscu gwarantuje, że formularz pokaże się tylko podczas wyświetlania wpisów. Jeśli skrypt będzie wysyłać komunikat o dodaniu wpisu, nie zostanie on już dołączony.
 
To już koniec naszej księgi gości. Utwórz teraz pusty plik ''wpisy.txt'' i zacznij korzystanie.
 
=== Co dalej?===
Napisana tutaj księga nie jest wyrafinowanym szczytem techniki. Jej głównym zadaniem było pokazanie podstawowych mechanizmów tworzenia dynamicznych stron WWW w praktyce. Wraz z powiększaniem się twojej wiedzy o języku PHP możesz rozszerzać ją o nowe możliwości:
* Blokadę przed floodem.
* Kasowanie wpisów.
* Dzielenie wyników na strony.
* Łatwy w modyfikacji wygląd.
 
Niektóre z tych rzeczy będą znacznie łatwiejsze do wykonania, kiedy poznasz zasady pracy z bazami danych dającymi nieporównywalnie większe możliwości, niż pliki tekstowe. Na bazach danych oparta jest obecnie zdecydowana większość istniejących aplikacji internetowych. Dzięki temu, że odseparowaliśmy pobieranie danych od ich wyświetlania, przepisanie księgi na MySQL będzie jedynie zabiegiem kosmetycznym. Zdecydowanie polecamy korzystanie z takiego rozwiązania, gdyż daje programiście sporą elastyczność. Nie zawsze bowiem zdarza się, że organizacja naszych danych będzie dokładnie taka, jakiej życzyłby sobie klient. Programując wszystko "na sztywno" wraz z wyglądem i kodem funkcjonalnym aplikacji narażamy się na większe ryzyko popełnienia błędu, zwiększamy rozmiar kodu i czynimy go mniej czytelnym.
 
Na tym kończymy poznawanie podstaw języka PHP. Przyszła pora na dokładniejsze poznanie kilku użytecznych funkcji przydatnych podczas tworzenia własnych skryptów.