Wstęp
Poniższy kurs programowania w języku PHP ma za zadanie zaznajomić osobę kompletnie nieobeznaną z tym językiem na tyle, aby sama była w stanie napisać skrypt o średnim poziomie złożoności. Pomaga także osobie wcześniej nieprogramującej na zaznajomienie się z technikami programistycznymi. Kurs jest uniwersalny - można go stosować do dowolnej wersji PHP - w szczególnych przypadkach, kiedy poszczególne informacje nie dotyczą wszystkich wersji, jest to wyraźniej zaznaczone.
Spis treści
Co to jest PHP
Wstawianie skryptów PHP
Błędy i debugowanie
Oddzielanie instrukcji
Komentarze
Zmienne
Typy zmienych
Zmiana typu
Predefiniowane zmienne
Stałe
Co to jest?
Operatory arytmetyczne
Operator przypisania
Operatory operacji bitowych
Operatory porównania
Operator kontroli błędów
Operator wywołania
Operatory inkrementacji i dekrementacji
Operatory logiczne
Operator ciągu
Instrukcje warunkowe
Pętla FOR
Pętla while
Pętla do…while
Przerywanie wykonań pętli
Składnia switch
Wstęp
Tablica asocjacyjna
Przeglądanie tablic
Sortowanie tablic
Tworzenie ciągów z tablic i odwrotnie
Funkcje
Klasy
Instrukcje include i require
Funkcja readfile()
Zasięg zmiennych
Formularze
Upload plików
Odnośniki
Cookies
register_globals
Wyrażenia regularne
Porównywanie ciągów
Wyciąganie fragmentów ciągów
Podmienianie fragmentów ciągów
Podmienianie znaków w ciągach
Inne funkcje
Otwieranie i zamykanie plików
Wewnętrzny wskaźnik pliku
Odczyt z plików
Zapis do pliku
Przycinanie plików
Blokowanie plików
Funkcje informacyjne
Operacje na plikach i katalogach
Kopiowanie
Przenoszenie i zmiana nazwy
Usuwanie
Tworzenie katalogów
Prawa dostępu (tylko UNIX)
Przetwarzanie ścieżki
Operacje na katalogach
Sprawdzanie poprawności
Pobieranie aktualnej daty
Konwersja daty do formatu timestamp
Część kalendarzowa
Część zegarowa
Strefa czasowa
Część liczbowa
Formatowanie daty
Tworzenie daty względnej do aktualnej (np. `za 2 dni')
Porównywanie dat
Co to jest PHP
PHP jest językiem skryptowym służącym do rozszerzania możliwości stron internetowych. Jego składnia jest bardzo podobna do popularnych języków programowania C/C++, lecz jest bardzo uproszczona - programista PHP zazwyczaj nie musi przejmować się poprawnością typów zmiennych, przydzielaniem dla nich pamięci itp. Dodatkowo wbudowana obsługa wielu popularnych baz danych ułatwia twórcy operacje na tych bazach. Dzięki połączeniu z biblioteką GD możliwe jest także dynamiczne tworzenie obrazków GIF (starsze wersje GD) lub PNG (nowsze wersje).
Osadzanie skryptów PHP
Aby plik był rozpoznany przez serwer WWW jako skrypt PHP musi on mieć odpowiednie rozszerzenie. Rozszerzenia te można zdefiniować w konfiguracji serwera WWW, ale zazwyczaj jest to .php3 (dla PHP w wersji 3), .php lub php4 (dla PHP w wersji 4) i .phtml (dla PHP w wersji starszej niż 3). Po nadaniu plikowi takiego rozszerzenia serwer będzie wiedział, że plik ten nie jest przeznaczony do bezpośredniego wyświetlenia (jak w przypadku plików HTML), ale że najpierw trzeba go przepuścić przez parser PHP.
Jeśli zwykłemu plikowi HTML nadamy rozszerzenie .php, to zostanie on prawidłowo wyświetlony, mimo że nie jest to skrypt PHP. Dzieje się tak dlatego, że parser PHP przetwarzając stronę ma 2 tryby pracy: HTML, gdzie cała treść jest wyświetlana, bez przetwarzania, i PHP, gdzie treść jest traktowana jako skrypt do przetworzenia. Do określenia w pliku co jest kodem HTML a co PHP służą specjalne znaczniki. Początkowo parser jest w trybie HTML. Aby przejść do trybu PHP można użyć jednego z czterech znaczników:
<? echo ("to jest najprostsza metoda, podobna do SGML'a"); ?>
<?php echo("jeśli serwujesz pliki XML, użyj tej metody"); ?>
<script language="php">
echo ("niektóre edytory (np. FrontPage) nie lubią przetwarzania instrukcji");
</script>
<% echo ("Możesz też użyć metody podobnej do tej z ASP"); %>
<%= $variable; # To jest skrót dla "<% echo ..." %>
W powyższych przykładach użyta jest niby-funkcja echo. Niby-funkcja, ponieważ dla większości normalnych funkcji parametry trzeba podawać w nawiasach, a w przypadku funkcji echo można je pominąć. “echo” jest po prostu elementem składni języka. Jak się można łatwo domyślić, służy ona do wysyłania tekstu podanego jako parametr do przeglądarki użytkownika.
Po przeczytaniu powyższego fragmentu każdy powinien być już gotowy do napisania programu, jaki każda osoba pisze zaraz po wstępnym zapoznaniu się z nowym językiem programowania - Hello World!. W przypadku PHP jest to zadanie uproszczone do minimum.
Przykład 1.1. Skrypt Hello World!
<?php echo 'Hello World!'; ?>
Po zapisaniu tego pliku z odpowiednim rozszerzeniem i umieszczeniu go odpowiednim miejscu (czyli w katalogu z którego będzie dostęp będzie miał serwer WWW). Po wejściu na tę stronę z przeglądarki WWW w okienku powinno być widać tylko napis “Hello World!” (bez cudzysłowów). Jedna uwaga: polecenie echo nie wysyła znaku końca linii, więc jeśli chcesz, aby po ciągu znaków (albo w którymkolwiek miejscu tego ciągu) kończyła się linia, w tym miejscu trzeba wstawić `\n'.
Błędy i debugowanie
Parser PHP podczas wykonywania skryptu sprawdza jego poprawność. Jeśli coś się nie zgadza, zostaniemy o tym poinformowani. Skrypt będzie jednak wykonany do miejsca, w którym pojawił się błąd. Przy komunikacie o błędach podana zostanie informacja o typie błędu, pliku w którym ten błąd zaszedł oraz linii zawierającej błąd.
Najczęściej są to błędy składniowe - brak średnika na końcu linii, niedomkniętych nawiasach (bardzo częsty błąd przy złożonych instrukcjach warunkowych), cudzysłowach lub nawiasach klamrowych kończących blok danych (przy instrukcjach warunkowych, pętlach). Błędy przy braku zamykających nawiasów klamrowych łatwo można rozpoznać, ponieważ numer linii zawierającej błąd jest o jeden większa od liczby linii w pliku.
PHP w wersji czwartej nie posiada jako-takiego debuggera. Wersja trzecia miała możliwość debugowania skryptów po ustawieniu odpowiednich opcji w konfiguracji PHP, który będzie się łączył z odpowiednim portem podanym w konfiguracji, na który będą przesyłane dane o błędach. Niektóre edytory wspomagające tworzenie skryptów PHP (jak np. Quanta+ pod Linuksa) posiadają wbudowaną obsługę debuggera. Jest to jednak metoda skomplikowana (więcej o niej w dokumentacji do PHP) i wymaga interwencji administratora serwera (sprawa jest łatwiejsza jeśli programista jest administratorem).
Istnieje metoda dużo prostsza. Po prostu w kluczowych miejscach skryptu (zazwyczaj tych, w których skrypt działa nieprawidłowo lub niezgodnie z zamierzeniami) należy wyświetlić interesujące nas zmienne za pomocą polecenia echo. Można też skorzystać z instrukcji warunkowych, ale o tym w dalszej części kursu.
Na początek warto jest zapoznać się z informacjami, które wyświetlą się po użyciu funkcji phpinfo(). Funkcja ta wyświetla wszystkie informacje o konfiguracji PHP (bardzo przydatne przy poszukiwaniu gdzie powinien znajdować się plik php.ini) oraz wszystkie zmienne środowiskowe, serwera oraz przekazane metodami GET, POST, COOKIE oraz sesyjnymi.
Spis treści
Oddzielanie instrukcji
Jak już można zauważyć w przykładach z poprzedniego rozdziału, jedną z głównych zasad języka PHP (jak i wielu innych - m. in. C i Perla) jest umieszczenie na końcu każdej instrukcji (niekoniecznie linii) znaku średnika (`;'). Można go pominąć tylko jeśli w danym miejscu następuje przejście do trybu HTML, a więc po danej linii następuje symbol przejścia do trybu HTML.
Przykład 2.1. Oddzielanie instrukcji
<?php
echo "To jest test";
?>
<?php echo "To jest test" ?>
Komentarze
Czasem zachodzi potrzeba oznaczenia czegoś w kodzie, dla kogoś innego czy nawet dla siebie samego (zwłaszcza jeśli pracuje się nad dużym projektem można się pogubić). Wtedy można skorzystać z jednej z kilku metod oznaczania, dzięki którym parser PHP będzie wiedział, że dany tekst nie jest częścią skryptu i można go zignorować.
Komentarze przydają się także do tymczasowego “wyłączania” niektórych linii kodu. PHP obsługuje 3 metody oznaczania komentarzy - 2 z nich znane są z języków C/C++ a jedna z powłok (shell) systemów Uniksowych. Poniższe 2 metody służą do oznaczania, że tekst od danego miejsca do końca linii jest komentarzem:
Przykład 2.2. Stosowanie komentarzy
<?php
echo "To jest test komentarzy"; // Ta metoda znana jest z języków C/C++
echo "A to drugi test"; # A ta z powłok Uniksowych
?>
Ostatnia metoda, także znana z języków C/C++, służy do oznaczania wielu linii jako komentarz. Należy przy niej pamiętać, aby nie zagnieżdżać wewnątrz siebie takich komentarzy ponieważ może to doprowadzić do nieprawidłowego funkcjonowania skryptów.
Przykład 2.3. Komentarze wielolinijkowe
<?php
echo "Test komentarzy"; /* Tu jest początek komentarza
tu dalej trwa
a tu się kończy */
?>
Zmienne
Jeśli ktoś nie spotkał się jeszcze z pojęciem zmiennej, to postaram się to wyjaśnić. Otóż zmienna jest to identyfikator znakowy, któremu przypisano jakąś wartość. W języku PHP zmienne oznacza się za pomocą znaku dolara (`$') przed wspomnianym identyfikatorem. Obsługa zmiennych w PHP jest uproszczona do minimum.
W “dużych” językach programowania zmienne trzeba najpierw inicjować (przy czym z góry trzeba określić typ zmiennej), zmienne tekstowe muszą mieć z góry ustalony rozmiar itp. W PHP nie jest to konieczne. Zmienna jest inicjalizowana (to znaczy rezerwowany jest dla niej pewien obszar w pamięci) przy pierwszym jej użyciu.
Nazwy zmiennych muszą zaczynać się od litery (dużej lub małej) lub “underscore” (dolna kreska - `_') a dalej mogą się składać z dowolnej ilości liter, cyfr i znaków o kodzie ASCII powyżej 127. Przy nazwach zmiennych respektowana jest wielkość znaków - zmienne $Test i $test to dwie różne zmienne. Oto przykład przypisywania wartości zmiennym i wykorzystanie ich w poleceniu echo:
Przykład 2.4. Koncepcja zmiennych
<?php
$nazwa = 1; // Zmiennej "nazwa" przypisywana jest wartość liczbowa 1
$druga_nazwa = "Tekst"; // Zmiennej "druga_nazwa" przypisany jest ciąg znaków "Tekst"
$trzecia_nazwa = $nazwa; // Zmiennej "trzecia_nazwa" przypisywana
//jest wartość zmiennej "nazwa"
echo "To jest $druga_nazwa"; // Powinien wyświetlić się napis "To jest Tekst"
echo '$druga_nazwa'; // Powinien wyświetlić się napis "$druga_nazwa"
echo $nazwa; // Powinna wyświetlić się cyfra 1
?>
W powyższym przykładzie można zauważyć, że parametr dla polecenia echo można podawać zarówno w cudzysłowach jak i apostrofach. Jednak te parametry nie są sobie równoznaczne. W przypadku cudzysłowów zmienne zawarte między nimi są zamieniane na ich wartość, a w przypadku apostrofów zmienna pozostaje swoją nazwą (jak można zauważyć w powyższym przykładzie).
Typy zmienych
liczby całkowite (integer)
liczby rzeczywiste (double)
ciągi (string)
tablice (array)
obiekty (object)
Dodatkowo PHP potrafi konwertować zmienne całkowite zapisane w różnych formatach liczbowych.
Przykład 2.5. Formaty liczbowe
<?php
$a = 1234; # liczba dziesiętna
$a = -123; # liczba ujemna
$a = 0123; # liczba ósemkowa (równoznaczne z dziesiętnym 83)
$a = 0x12; # liczba szesnastkowa (równoznaczne z dziesiętnym 18)
?>
Zmiana typu
Zazwyczaj nie jest konieczne określenie typu zmiennej - PHP sam to ustala, zależnie od kontekstu.
Przykład 2.6. Zmiana typu zmiennej
<?php
$blah = "0"; // $blah jest ciągiem (ASCII 48)
$blah++; // $blah jest ciągiem "1" (ASCII 49)
$blah += 1; // $blah jest teraz wartością całkowitą (2)
$blah = $foo + 1.3; // $blah jest wartością rzeczywistą (1.3)
$blah = 5 + "10 Malutkich Świnek"; // $blah jest wartością całkowitą (15)
$blah = 5 + "10 Małych Świń"; // $blah jest wartością całkowitą (15)
?>
Podczas przypisywania zmiennej nowej wartości, poprzednia wartość jest oczywiście zamazywana. W takim przypadku typ zmiennej ustalany jest od nowa.
Jeśli jednak zachodzi potrzeba zmiany typu lub PHP błędnie rozpoznaje typ, to można tego dokonać za pomocą rzutowania (cast - efekt jest jednorazowy) lub za pomocą funkcji settype (efekt trwały).
Rzutowanie typów odbywa się przez podanie nowego typu w nawiasie przed zmienną lub wartością, której typ chcemy zmienić.
Przykład 2.7. Rzutowanie typów
<?php
$liczba_calkowita = 10;
$liczba_rzeczywista = (real) $liczba_calkowita;
?>
Dozwolone typy rzutowań
(int), (integer) - rzutuj do typu całkowitego
(real), (double), (float) - rzutuj do typu rzeczywistego
(string) - rzutuj do ciągu
(array) - rzutuj do tablicy
(object) - rzutuj do obiektu
Drugim sposobem, trwałym, jest użycie funkcji settype. Funkcja ta pobiera 2 argumenty. Pierwszym jest nazwa zmiennej do ustalenia typu, a drugim ciąg określający nowy typ zmiennej.
Dopuszczalne argumenty funkcji settype
“integer”
“double”
“string”
“array”
“object”
Funkcja zwraca wartość “true” gdy wszystko poszło pomyślnie. W przeciwnym razie zwracana jest wartość “false”.
Przykład 2.8. Przykład użycia funkcji settype
<?php
$zmienna = 10.3;
echo "$zmienna <br>"; // Wyświetlona wartość to "10.3"
settype($zmienna, "integer");
echo "$zmienna <br>"; // Wyświetlona wartość to "10"
?>
Predefiniowane zmienne
W każdym skrypcie PHP dostępne jest kilka zmiennych, których wartość jest ustalana na podstawie zmiennych środowiskowych serwera WWW. Dostępne są jak zwykłe zmienne - ze znakiem dolara przed nazwą.
Zmienne ustawiane przez serwer WWW
GATEWAY_INTERFACE
Informacja o specyfikacji CGI używanej przez serwer, np. `CGI/1.1′.
SERVER_NAME
Nazwa hosta serwera na którym skrypt jest uruchamiany. Jeśli skrypt pracuje na wirtualnym hoście, to zmienna przyjmie jako wartość nazwę wirtualnego hosta.
SERVER_SOFTWARE
Ciąg identyfikujący serwera podawany przy odpowiadaniu na zapytania.
SERVER_PROTOCOL
Nazwa i numer wersji protokołu za pomocą którego wysłano zapytanie o stronę, np. `HTTP/1.0′;
REQUEST_METHOD
Metoda zapytania użyta do uzyskania dostępu do strony, np. `GET', `HEAD', `POST', `PUT'.
QUERY_STRING
Ciąg zapytania (jeśli takowy istnieje) za pomocą którego połączono się ze stroną.
DOCUMENT_ROOT
Katalog główny drzewa dokumentów spod którego skrypt jest wykonywany - jest to ustawienie z pliku konfiguracyjnego serwera.
HTTP_ACCEPT
Nagłówek z aktualnego zapytania, jeśli taki istnieje.
HTTP_ACCEPT_CHARSET
Zawartość nagłówka “Accept-Charset” z aktualnego zapytania, jeśli taki istnieje, np. `iso-8859-1,*,utf-8′.
HTTP_ENCODING
Zawartość nagłówka “Accept-Encoding” z aktualnego zapytania, jeśli taki istnieje, np. `gzip'.
HTTP_ACCEPT_LANGUAGE
Zawartość nagłówka “Accept-Language” z aktualnego zapytania, jeśli taki istnieje, np. `en'.
HTTP_CONNECTION
Zawartość nagłówka “Connection” z aktualnego zapytania, jeśli taki istnieje, np. `Keep-Alive'.
HTTP_HOST
Zawartość nagłówka “Host” z aktualnego zapytania, jeśli taki istnieje.
HTTP_REFERER
Adres strony (jeśli taka była), która wskazała przeglądarkę do tej strony. Wartość ta jest ustawiana przez przeglądarkę - nie wszystkie to robią.
HTTP_USER_AGENT
Zawartość nagłówka “User-Agent” z zapytania, jeśli taki istnieje. Jest to ciąg informujący o przeglądarce która została użyta do obejrzenia bieżącej strony, np. Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586). Można użyć funkcji get_browser() aby dopasować funkcjonalność strony do przeglądarki użytkownika.
REMOTE_ADDR
Adres IP z którego użytkownik połączył się z serwerem.
REMOTE_PORT
Port używany do komunikacji pomiędzy użytkownikiem a serwerem.
SCRIPT_FILENAME
Ścieżka do aktualnie wykonywanego skryptu.
SERVER_ADMIN
Wartość podana dla opcji SERVER_ADMIN w konfiguracji serwera WWW. Jeśli skrypt działa na wirtualnym serwerze, to będzie to wartość podana dla tego wirtualnego serwera.
SERVER_PORT
Port na serwerze którego użyto do połączenia. Dla normalnych połączeń będzie to `80′.
SERVER_SIGNATURE
Ciąg zawierający wersję i nazwę wirtualnego hosta który jest dodawany do stron generowanych przez serwer.
SCRIPT_NAME
Zawiera ścieżkę do aktualnie wykonywanego pliku. Jest to przydatne do skyptów, które muszą wskazywać samego siebie.
REQUEST_URI
URI który został podany aby uzyskać dostęp do tej strony.
Zmienne ustawiane przez PHP
argv
Tablica argumentów przkazywanych do skryptu. Jeśli skrypt jest uruchamiany z linii poleceń, to zmienna ta daję dostęp do argumentów w stylu języka C. Jeśli jest wywołany przez metodę GET, to zmienna ta zawierać będzie ciąg parametrów (query string).
argc
Zawiera liczbę parametrów podanych podanych do skryptu w linii poleceń (jeśli skrypt został wywołany z linii poleceń).
PHP_SELF
Nazwa pliku aktualnie wykonywanego skryptu, względna do katalogu głównego dokumentów. Ta zmienna jest niedostępna jeśli PHP jest uruchamiany z linii poleceń.
HTTP_COOKIE_VARS
Tablica asocjacjna zmiennych przekazanych do skryptu przez HTTP cookies. Dostępna tylko jeśli włączone zostało śledzenie zmiennych przez ustawienie w konfiguracji PHP opcji track_vars lub komendą <?php_track_vars?>.
HTTP_GET_VARS
Tablica asocjacjna zmiennych przekazanych do skryptu przez metodę GET. Dostępna tylko jeśli włączone zostało śledzenie zmiennych przez ustawienie w konfiguracji PHP opcji track_vars lub komendą <?php_track_vars?>.
HTTP_POST_VARS
Tablica asocjacjna zmiennych przekazanych do skryptu przez metodę POST. Dostępna tylko jeśli włączone zostało śledzenie zmiennych przez ustawienie w konfiguracji PHP opcji track_vars lub komendą <?php_track_vars?>.
Stałe
W PHP występują także tzw. stałe, czyli identyfikatory znakowe, których wartości nie można zmienić. Stałych, w odróżnieniu od zmiennych, używa się bez znaku dolara na początku. W PHP występuje kilka zmiennych ustawianych przez parser.
Stałe ustawiane przez PHP
__FILE__
Nazwa pliku ze skryptem który jest aktualnie przetwarzany. Jeśli stała ta użyta jest wewnątrz pliku który został zainkludowany (o poleceniu include w dalszej części kursu), to podana zostanie nazwa pliku zainkludowanego, a nie pliku nadrzędnego.
__LINE__
Numer linii w skrypcie która aktualnie jest przetwarzana. Jeśli stała ta użyta jest wewnątrz pliku który został zainkludowany, to podany zostanie numer linii przetwarzanej w pliku zainkludowanym.
PHP_VERSION
Ciąg reprezentujący wersję parsera PHP aktualnie używaną.
PHP_OS
Nazwa systemu operacyjnego na którym uruchamiany jest parser PHP.
TRUE
Logiczna wartość prawdy.
FALSE
Logiczna wartość fałszu.
Stałe mogą być definiowane przez użytkownika za pomocą funkcji define(), która przyjmuje 2 parametry: nazwę stałej i wartość do niej przypisaną.
Przykład 2.9. Definiowanie stałych
<?php
define("STALA", "Hello world.");
echo STALA; // Wyświetla "Hello world."
?>
Spis treści
Co to jest?
Operatory są to najprościej mówiąc symbole, które służą do operacji na zmiennych. Operatory dzielą się na operatory arytmetyczne, które służą do operacji na liczbach, operatory przypisania służące do przypisywania zmiennym wartości, operatory operacji bitowych, operatory porównania niezbędne do instrukcji warunkowych, operator kontroli błędów, operator wykonania służący do uruchamiania zewnętrznych programów, operatory inkrementacji i dekrementacji, operatory logiczne i operatory ciągu.
Operatory arytmetyczne
Operatory te każdy powinien pamiętać z podstawówki
Przykład |
Nazwa |
Wynik |
$a + $b |
Dodawanie |
Suma $a i $b. |
$a - $b |
Odejmowanie |
Różnica $a i $b. |
$a * $b |
Mnożenie |
Iloczyn $a i $b. |
$a / $b |
Dzielenie |
Iloraz $a i $b (bez reszty). |
$a % $b |
Modulo |
Reszta z dzielenia $a przez $b. |
Operator przypisania
Podstawowym operatorem przypisania jest symbol `='. Oczywiście nie oznacza on `jest równe'. Wyrażenie $b = 5 oznacza, że zmienna $b przyjmuje wartość równą 5. Zmiennej można przypisać także wartość innej zmiennej: $b = 5; $a = $b; - zmienna $a przyjmie wartość 5.
Zmiennym można przypisywać nie tylko konkretne wartości, ale też wartości innych zmiennych. Wartości te można przypisywać kaskadowo, przy czym wartości przypisywane będą od prawej do lewej, np.:
<?php
$nazwa = $inna_nazwa = $trzecia_nazwa = 5;
?>
W tym wypadku wszystkim zmiennym zostanie przypisana wartość 5. Operator przypisania można łączyć z operatorami arytmetycznymi i operatorem łączenia ciągów:
Przykład |
Wynik |
$a += 2 |
Do zmiennej $a dodane zostanie 2 |
$a -= 2 |
Od zmiennej $a odjęte zostanie 2 |
$a *= 2 |
Zmienna $a zostanie pomnożona przez 2 |
$a /= 2 |
Zmienna $a dodane podzielona przez 2 |
$a %= 2 |
Zmienna $a przyjmie wartość reszty z dzielenia $a przez 2 |
$a .= ” dalszy ciąg” |
Do zmiennej $a na końcu dodany zostanie ciąg ” dalszy ciąg” |
Operatory operacji bitowych
Operatory operacji bitowych pozwalają na przestawianie pojedyńczych bitów zmiennych. Poniższa tabelka przeznaczona jest dla osób, które miały już jakąkolwiek styczność z operacjami na bitach.
Przykład |
Nazwa |
Wynik |
$a & $b |
AND |
Ustawiane są bity które są ustawione w obu zmiennych. |
$a | $b |
OR |
Ustawiane są bity, które są ustawione w jednej lub drugiej zmiennej. |
$a ^ $b |
XOR |
Ustawiane są bity, które są ustawione w jednej lub drugiej zmiennej, ale nie w obu. |
~ $a |
NOT |
Inwerter - ustawiane są bity które nie są ustawione w zmiennej $a i odwrotnie. |
$a << $b |
Przesunięcie w lewo |
Przesuń bity z $a $b-razy w lewo (każdy krok oznacza pomnożenie przez 2) |
$a >> $b |
Przesunięcie w prawo |
Przesuń bity z $a $b-razy w prawo (każdy krok oznacza podzielenie przez 2) |
Operatory porównania
Operatory porównania są niezbędne do korzystania z instrukcji warunkowych (jeśli coś to zrób coś). Zwracają one wartość TRUE (prawda - 1) lub FALSE (fałsz - 0).
Przykład |
Nazwa |
Wynik |
$a == $b |
Równy |
Prawda jeśli $a jest równe $b. |
$a === $b |
Identyczny |
Prawda jeśli $a jest równe $b i są tego samego typu. (tylko PHP4) |
$a != $b |
Nie równe |
Prawda jeśli $a nie jest równe $b. |
$a !== $b |
Nie identyczny |
Prawda jeśli $a nie jest równe $b lub nie są tego samego typu. (tylko PHP4) |
$a < $b |
Mniejsze |
Prawda jeśli $a jest mniejsze niż $b. |
$a > $b |
Większe |
Prawda jeśli $a jest większe niż $b. |
$a <= $b |
Mniejsze lub równe |
Prawda jeśli $a jest mniejsze lub równe $b. |
$a >= $b |
Większe lub równe |
Prawda jeśli $a jest większe lub równe $b. |
Operator kontroli błędów
Operator kontroli błędów (`@') powoduje, że wyrażenie przed którym postawiono ten znak nie spowoduje wyświetlenia się jakiegokolwiek błędu lub ostrzeżenia.
Przykład 3.1. Przykład użycia operatora kontroli błędów
<?php
/* Jeden z najczęstszych błędów SQL (za dużo o jeden apostrof) */
$res = @mysql_query ("select nazwa, kod from 'lista") or
die ("Zapytanie się nie powiodło: błąd to '$php_errormsg'");
?>
Operator wywołania
Operator ten służy do uruchamiania zewnętrznych programów lub poleceń powłoki. Wystarczy wpisać polecenie pomiędzy znaki odwróconego apostrofu (``') aby zostało ono wykonane.
Przykład 3.2. Przykład użycia operatora wywołania
<?php
$wynik = `ls -l /home/`;
echo $wynik;
?>
Po uruchomieniu tego skryptu wyświetlona zostanie zawartość katalogu /home na serwerze.
Operatory inkrementacji i dekrementacji
Operatory te występują w większości języków programowania. Służą one do zmniejszenia lub zwiększenia wartości danej zmiennej o 1. Każdy operator można stosować na 2 sposoby: preinkrementacja/predekrementacja - najpierw wartość zmiennej zostanie zmieniona, a później zwrócona, lub postinkrementacji/postdekrementacji - najpierw zostanie zwrócona wartość zmiennej, a następnie wartość zmiennej zostanie zmieniona.
Przykład |
Nazwa |
Wynik |
++$a |
Preinkrementacja |
Zwiększa $a o jeden, a następnie zwraca $a. |
$a++ |
Postinkrementacja |
Zwraca $a, a następnie zwiększa $a o jeden. |
-$a |
Predekrementacja |
Zmniejsza $a o jeden, po czym zwraca $a. |
$a- |
Postdekrementacja |
Zwraca $a, po czym zmniejsza $a o jeden. |
Przykład 3.3. Przykład funkcjonowania inkrementacji i dekrementacji
<?php
echo "Postinkrementacja";
$a = 5;
echo "Powinno być 5: " . $a++ . "\n";
echo "Powinno być 6: " . $a . "\n";
echo "Preinkrementacja";
$a = 5;
echo "Powinno być 6: " . ++$a . "\n";
echo "Powinno być 6: " . $a . "\n";
echo "Postdekrementacja";
$a = 5;
echo "Powinno być 5: " . $a-- . "\n";
echo "Powinno być 4: " . $a . "\n";
echo "Predekrementacja";
$a = 5;
echo "Powinno być 4: " . --$a . "\n";
echo "Powinno być 4: " . $a . "\n";
?>
Operatory logiczne
Operatory logiczne służą do budowania bardziej skomplikowanych instrukcji warunkowych - do łączenia kilku warunków w jednej instrukcji.
Przykład |
Nazwa |
Wynik |
$a && $b |
AND |
Prawda, jeśli $a i $b są prawdą |
$a || $b |
OR |
Prawda, jeśli $a lub $b są prawdą |
! $a |
NOT |
Prawda, jeśli $a nie jest prawdą |
Operator ciągu
Operator ciągu (`.' - kropka) służy do łączenia kilku ciągów w jedną całość.
Przykład 3.4. Przykład użycia operatora ciągu
<?php
$zmienna1 = "Wartość zmiennej 'zmienna2' to";
$zmienna2 = 5;
echo $zmienna1." ".$zmienna2; // Powinno się wyświetlić:
// "Wartość zmiennej 'zmienna2' to 5"
?>
Jak widać na tym przykładzie, aby użyć niektórych znaków (między innymi cudzysłowów jeśli ciąg podany jest cudzysłowach, znaków dolara jeśli nie chcemy aby został potraktowany jako zmienna) trzeba zamienić go na tzw. sekwencję escape, to znaczy wstawić przed nim znak backslash - \.
Spis treści
Instrukcje warunkowe
Instrukcje warunkowe są podstawą każdego języka programowania. Używa się jej do wykonania pewnej instrukcji (lub bloku instrukcji), ale tylko w pewnych okolicznościach - zostanie spełniony określony warunek (lub cały zestaw warunków).
Przykład 4.1. Składnia instrukcji warunkowej
<?php
if(wyrażenie_warunkowe)
instrukcja wykonywana jeśli spełniony zostanie warunek
elseif(inne_wyrażenie_warunkowe)
instrukcja wykonywana jeśli spełniony zostanie drugi warunek, a pierwszy nie
else
instrukcja wykonywana jeśli nie zostanie spełniony żaden z warunków
?>
Wyrażeniem warunkowym jest w zasadzie dowolne wyrażenie, ponieważ za warunek uznawane jest wszystko co zwraca wartość, czyli wszystkie zmienne, wyrażenia logiczne, funkcje itp. Za spełniony warunek uznawana jest wartość większa od zera.
Przykład 4.2. Przykład instrukcji warunkowej
<?php
$a = 2;
$b = 5;
$c = 1;
if($a > $b)
echo "$a jest większe od $b";
elseif ($b > $c)
echo "$b jest większe od $c";
else
echo "$c jest większe od $a i $b";
if($a)
echo "Zmienna $a ma wartość większą od zera";
?>
Jeśli chcemy, aby po sprawdzeniu warunku wykonane zostało nie jedno, ale kilka poleceń, to te polecenia trzeba ująć w nawiasy klamrowe. Bez tego warunkiem objęta by była tylko jedna instrukcja po instrukcji if.
Instrukcje mogą być zagnieżdżane wewnątrz siebie.
Przykład 4.3. Zagnieżdżanie instrukcji warunkowych
<?php
$a = 6;
$b = 5;
$c = 1;
if($a > $b){
echo "$a jest większe od $b";
if($a > $c)
echo " i od $c"; // Powinien zostać wyświetlony napis "6 jest większe od 5 i od 1"
}
?>
Oczywiście możliwe jest korzystanie z warunków bardziej złożonych niż pojedyńcze porównanie wielkości zmiennych - do łączenia warunków niezbędne jest wykorzystanie operatorów logicznych opisanych w poprzednim rozdziale. Operator logiczny OR (lub) ma większy priorytet niż operator AND (i), więc aby sprawdzić jakiś warunek gdzie konieczna jest inna kolejność, niezbędne jest użycie nawiasów grupujących warunki.
Na przykład chcemy aby jakaś instrukcja była wykonana jeśli zmienna $a jest większa od $b lub $c, i zmienna $d była równa $e. Jeśli chcielibyśmy zapisać to bez żadnych nawiasów: $a > $b || $a > $c && $d == $e to efekt byłby zupełnie inny od zamierzonego: instrukcja była by wykonana jeśli $a było by większe od $b, lub jeśli $a było by większe od $a i $d było by równe $e. Poprawna konstrukcja to ($a > $b || $a > $c) && $d == $e.
Przykład 4.4. Grupowanie warunków
<?php
$a = 6;
$b = 5;
$c = 7;
$d = 6;
$e = 6;
if( ($a > $b || $a > $c) && // Nawiasy klamrowe nie są potrzebne - to
$d == $e ) // 2 linie ale jedna instrukcja
echo 'Zmienna $a jest większa od $b a zmienna $d jest równa $e, '.
'więc ten tekst pokaże się.'; // Taka konstrukcja jest dozwolona
?>
Pętla FOR
Czasem zachodzi potrzeba wykonania jakiejś czynności określoną ilość razy. Z pomocą przychodzi jedna z najczęściej używanych składni w większości języków programowania, czyli pętla FOR. Ogólny zapis wygląda tak:
Przykład 4.5. Pętla FOR
<?php
for( inicjalizacja zmiennych ; sprawdzenie warunku ; modyfikacja zmiennych) {
blok wyrażeń
}
?>
Jak widać, w tej pętli podaje się 3 wyrażenia jako parametry: inicjalizację zmiennych, czyli ustawienie początkowych wartości dla zmiennych kontrolujących pętlę, sprawdzenie warunku, czyli wyrażenie logiczne kontrolujące pętlę - pętla będzie wykonywana dopóki ten warunek jest prawdziwy, oraz modyfikację zmiennych kontrolujących pętlę - bez tego pętla będzie wykonywała się w nieskończoność (oczywiście wartość tych zmiennych można modyfikować wewnątrz pętli, ale jest to niezalecane). Przykład najprostszej pętli, która wypisze cyfry od 1 do 10:
Przykład 4.6. Przykład użycia pętli for
<?php
for( $x = 1; $x <= 10; $x++ )
echo $x."<br>";
?>
Pętla while
Innym rodzajem pętli jest pętla WHILE. Jest ona wykorzystywana w sytuacjach, kiedy niezbędne jest wykonywanie jakiejś operacji dopóki nie zostanie spełniony warunek.
Przykład 4.7. Pętla while
<?php
while( warunek ){
...
instrukcje
...
}
?>
Można na przykład za pomocą tej pętli zapisać odpowiednik pętli FOR z poprzedniego przykładu.
Przykład 4.8. Przykład użycia pętli while
<?php
$x=1;
while($x <= 10){
echo $x."<BR>";
$x++;
}
?>
Pętla do…while
Odmianą pętli while jest pętla do…while. Od zwykłej pętli while różni się ona tym, że polecenia zawarte w pętli będą przynajmniej raz wykonane - w przypadku pętli while tak być nie musi, to znaczy jeśli za pierwszym razem warunek nie zostanie spełniony to polecenia z pętli nigdy nie zostaną wykonane. W przypadku tej pętli zostano one wykonane przynajmniej ten pierwszy raz.
Przykład 4.9. Pętla do … while
<?php
do {
...
instrukcje
...
} while( warunek );
?>
Przerywanie wykonań pętli
Czasem zachodzi potrzeba przerwania danej iteracji (powtórzenia) pętli i przejścia do następnej iteracji. Z pomocą wtedy przychodzi instrukcja continue. Wystarczy wstawić ją w odpowiednie miejsce wewnątrz pętli. Przykład (niezbyt wyszukany):
Przykład 4.10. Instrukcja continue
<?php
for($x = 1; $x<=100; $x++) {
if($x % 2 != 0)
continue;
echo $x." ";
}
?>
Po uruchomieniu powyższego przykładu powinniśmy zobaczyć liczby parzyste od 1 do 100. Oczywiścje można to zapisać łatwiej.
Przykład 4.11. Wyświetlanie liczb parzystych
<?php
for($x = 2; $x <= 100; $x+=2) {
echo $x." ";
}
?>
Istenie też polecenie, które powoduje całkowite wyjście z pętli - nie tylko z bieżącej iteracji. To polecenie to "literal">brake. Załóżmy, że zmienna $nazwa to zmienna podana z formularza:
Przykład 4.12. Instrukcja brake
<?php
for($x = 0; $x<10; $x++) {
if($x%2==0)
echo $x." ";
if($nazwa == "Test1")
break;
}
?>
Składnia switch
Składnia switch jest instrukcją warunkową, ale jedną zmienną można porównać nie z jedną wartością, ale z kilkoma. Niestety nie można konstruować złożonych warunków - możliwe jest tylko proste porównywanie (równoważne instrukcji: if($zmienna=="wartość") instrukcja).
Przykład 4.13. Składnia switch
<?php
switch($zmienna){
case 'wartość1':
...
instrukcje
...
break;
case 'wartość2':
...
instrukcje
...
break;
default:
...
instrukcje
...
}
?>
Instrukcje zawarte po identyfikatorze “default” wykonywane są jeśli zmienna $zmienna nie przyjęła wartości “wartość1″ i “wartość2″ (dla tego przykładu). Aby móc dobrze wykorzystać tą składnię warto jest dokładnie wiedzieć jak ona działa. Instrukcje są przetwarzane linia po linii. Parser przechodzi do pierwszej linii “case” pasującej do zmiennej. Następnie przetwarzane są wszystkie linie wewnątrz nawiasów klamrowych aż do napotkania instrukcji break - nawet jeśli po drodze znajdują się instrukcje “case”.
Przykład 4.14. Przykład użycia składni switch
<?php
$i = 3;
switch($i){
case 0:
case 1:
case 2:
case 3:
echo "Zmienna $i jest mniejsza bądź równa od trzech\n";
break;
case 4:
echo "Zmienna $i jest równa cztery\n";
break;
default:
echo "Zmienna $i jest większa od czterech\n";
}
?>
Spis treści
Wstęp
Tablice są bardzo specyficznym typem zmiennych - są to, najprościej mówiąc, zmienne zawierające w sobie uporządkowany zbiór zmiennych. Do zmiennych tych uzyskuje się dostęp przez liczbę w nawiasie kwadratowym podane bezpośrednio po nazwie zmiennej - tablicy. Liczba ta to tak zwany indeks - numer kolejny zmiennej w tablicy. Tak samo przypisuje się wartość do tablicy.
Przykład 5.1. Tworzenie tablicy
<?php
$tablica[0] = "Wpis numer 0";
$tablice[1] = "Wpis numer 1";
$tablica[2] = "Wpis numer 2";
echo $tablica[2]; // Wyświetlony zostanie napis "Wpis numer 2";
?>
Aby poprostu dodać kolejny wpis na końcu tabeli wystarczy przy przypisywaniu wartości nie wpisywać indeksu do nawiasów kwadratowych. Jeśli w ten sposób dodawane są wpisy do nowej tablicy, to pierwszy wpis ma indeks 0.
Indeks można też podawać ze zmiennej, z innej tablicy czy funkcji - z dowolnego wyrażenia zwracającego wartość.
Przykład 5.2. Indeksy tablic
<?php
$tab1[] = 1;
$tab1[] = 0;
$tab1[] = 3;
$tab1[] = 2;
$tab2[] = "Pierwszy";
$tab2[] = "Drugi";
$tab2[] = "Trzeci";
$tab2[] = "Czwarty";
echo $tab2[$tab1[2]];
?>
Elementem tablicy może być każdy typ zmiennej (z innymi tablicami i obiektami włącznie).
Tablica asocjacyjna
W PHP występuje też inny rodzaj tablic, tak zwane tablice asocjacyjne (zwane też czasem haszami - hash table). Są to tablice, w których zamiast indeksów liczbowych używa się identyfikatorów znakowych (kluczy):
Przykład 5.3. Tablice asocjacyjne
<?php
$tablica["imie"] = "Jan";
$tablica["nazwisko"] = "Kowalski";
$tablica["adres"] = "Polna 1";
echo $tablica["imie"]." ".$tablica["nazwisko"].", ul. ".$tablica["adres"]."n";
?>
Przeglądanie tablic
Bardzo często zachodzi potrzeba wykonania jakiejś operacji na wszystkich elementach tablicy. Sprawa jest prosta jeśli tablica jest zwykłą tablicą z indeksami liczbowymi i znamy ilość tych elementów:
Przykład 5.4. Przeglądanie tablic pętlą
<?php
$tbl[] = 1;
$tbl[] = 2;
$tbl[] = 3;
$tbl[] = 4;
$tbl[] = 5;
for( $x = 0; $x < 5; $x++ ) { // Pętla wykona się 5 razy (0...4)
echo $tbl[$x];
}
?>
Sprawa się trochę komplikuje jeśli nie znamy ilości elementów tablicy. Wtedy z pomocą przychodzi funkcja count( $nazwa_tablicy ). Zwraca ona ilość elementów w tablicy podanej jako parametr.
Przykład 5.5. Pętla for i funkcja count
<?php
$tbl[] = 1;
$tbl[] = 2;
$tbl[] = 3;
$tbl[] = 4;
$tbl[] = 5;
for( $x = 0, $cnt = count($tbl); $x < $cnt; $x++ ){
echo $tbl[$x];
}
?>
Jeszcze trudniej jest jeśli konieczne jest przejrzenie tablicy asocjacyjnej, ale i to da się załatwić. W tym przypadku należy skorzystać z funkcji list() i each(). Nie będę omawiał ich działania - jesli kogoś to interesuje, to odsyłam do manuala PHP. Przy przechodzeniu przez tablice asocjacyjne trzeba wykorzystać pętlę while.
Przykład 5.6. Przeglądanie tablic asocjacyjnych
<?php
$tablica["imie"] = "Jan";
$tablica["nazwisko"] = "Kowalski";
$tablica["adres"] = "Polna 1";
while( list($klucz, $wartosc) = each($tablica) )
echo "$klucz => $wartosc<BR>";
?>
Jak widać, w każdej iteracji pętli mamy dostępne 2 zmienne, przyjmujące wartości kolejnych kluczy i wartości przypisanych tym kluczom.
Sortowanie tablic
PHP ofertuje cały zestaw funkcji służących do sortowania tablic. Są to:
asort()
arsort()
ksort()
rsort()
sort()
uasort()
usort()
uksort()
Większość funkcji (oprócz trzech ostatnich) przyjmuje jeden parametr: zmienną zawierającą tablicę do posortowania. Żadna z funkcji nie zwraca żadnego wyniku.
Funkcje sortujące
asort()
sortuje tablice asocjacyjne zachowując przypisanie kluczy do wartości
<?php
$owoce = array ("d"=>"mango", "a"=>"papaja", "b"=>"banan", "c"=>"aronia");
asort ($owoce);
reset ($owoce); // Funkcja ta powoduje powrót do pierwszego elementu tablicy
while (list ($klucz, $wartosc) = each ($owoce)) {
echo "$klucz = $wartoscn";
}
?>
Wynikiem działania powyższego przykładu powinno być:
c = aronia
b = banan
d = mango
a = papaja
arsort()
sortuje w odwrotnej kolejności tablice asocjacyjne zachowując przypisanie kluczy do wartości. Funkcja prawie identyczna jak poprzednia, tyle że dane sortowane są “od tyłu”.
ksort()
sortuje tablice asocjacyjne według kluczy. Powyższy przykład po podmianie funkcji asort na ksort powinna dać poniższy wynik:
a = papaja
b = banan
c = aronia
d = mango
rsort()
sortuje zwykłe tablice (nie asocjacyjne) w odwróconej kolejności
sort()
sortuje zwykłe tablice (nie asocjacyjne) w kolejności alfabetycznej
uasort()
funkcja sortująca tablice asocjacyjne za pomocą zdefiniowanej przez użytkownika funkcji porównującej elementy (nazwa funkcji jest podawana za pomocą drugiego parametru)
usort()
funkcja sortująca zwykłe tablice za pomocą funkcji zdefiniowanej przez użytkownika
uksort()
funkcja sortująca tablice asocjacyjne według klucza za pomocą funkcji zdefiniowanej przez użytkownika.
W trzech ostatnich funkcjach sortujących trzeba jako drugi parametr podać funkcję porównującą elementy tablicy. Jak definiuje się funkcje opisane jest w jednym z następnych rozdziałów. Funkcje takie pobierają 2 argumenty. Zwracane jest 0 jeśli argumenty są sobie równe, -1 jeśli pierwszy argument jest mniejszy od drugiego a 1 jeśli jest większy.
Tworzenie ciągów z tablic i odwrotnie
PHP umożliwia zamianę ciągów na tablice i odwrotnie. Zamiana ciągu na tablicę jest bardzo przydatna jeśli zachodzi potrzeba wyciągnięcie jakiegoś fragmentu danych z ciągu. Załóżmy że w odczytaliśmy z pliku z danymi (o odczycie z plików w jednym z kolejnych rozdziałów) linię z logu zapisanego przez licznik WWW: “12/11/2000;19:23:33;Netscape Navigator;192.168.1.1″. Jak widać dane rozdzielone są średnikami.
Do rozdzielania ciągów na tablicę służy funkcja explode(). Jako pierwszy parametr trzeba do niej podać znak lub dłuższy ciąg który oddziela kolejne pola, jako drugi ciąg do rozdzielenia. Opcjonalnie można podać trzeci argument, który oznacza maksymalną liczbę pól - jeśli jest ich więcej niż ta liczba, to ostatnie pole będzie zawierało wszystkie pozostałe pola. Funkcja zwraca tablicę zawierającą kolejne pola.
Przykład 5.7. Rozdzielenie danych separowanych średnikiem
<?php
$dane = "12/11/2000;19:23:33;Netscape Navigator;192.168.1.1";
$tablica = explode(";", $dane);
?>
Jest także rozszerzona wersja funkcji explode: split(). Różni się ona tym, że zamiast prostego ciągu znaków rozdzielających pola, akceptuje ona wyrażenia regularne (co to jest wyrażenie regularne mniej więcej wyjaśniono w rozdziale dotyczącyn ciągów).
Czasem potrzebne jest działanie w drugą stronę: złącznie pól tablicy w jeden ciąg, w którym pola oddzielone są jakimś znakiem (lub kilkoma). Do tego służy funkcja implode(). Jako pierwszy parametr podawany jest ciąg za pomocą którego “sklejane” są elementy tablicy, a jako drugi właśnie tablica do posklejania.
Zwracany jest ciąg zawierający posklejane elementy. Jako przykład zastosowania może posłużyć właśnie zapisywanie danych o użytkowniku w aplikacji licznika odwiedzin - tablica zawiera dane o odwiedzającym, a potrzebny jest ciąg pooddzielany średnikami.
Przykład 5.8. Łączenie danych z tablicy
<?php
$dane = implode(";", $tablica);
?>
Spis treści
Funkcje
Funkcja jest kawałkiem kodu, który można wywołać podając jej nazwę. Już wcześniej podane zostało kilka funkcji dostarczanych przez PHP, takich jak array(), each(), list(), explode() czy implode(). Jak można zauważyć, funkcje rozpoznaje się po nawiasach występujących po ich nazwie. W nawiasach tych (jeśli funkcja tego wymaga) podaje się parametry dla danej funkcji. Niektóre funkcje zwracają jakąś wartość, a więc wywołanie takiej funkcji można wstawić jak dowolne inne wyrażenie do listy parametrów innej funkcji czy np. do obliczenia.
Programista może też tworzyć własne funkcje.
Przykład 6.1. Definicja funkcji
<?php
function suma($parametr1 = 0, $parametr2 = 0)
{
$wartosc = $parametr1 + $parametr2;
return $wartosc;
}
?>
Jak widać, definiowana jest funkcja o nazwie suma. Służy ona do obliczania sumy dwóch wyrażeń podawanych jako parametry (kolejne parametry oddziela się przecinkiem). W przypadku pominięcia któregoś z parametrów przypisana mu będzie wartość 0 - dzieje się tak dzięki zaznaczeniu ” = 0″ po określeniu nazwy parametru w definicji funkcji (nie jest to konieczne). Z parametrów funkcji można korzystać jak z dowolnej innej zmiennej, ale oczywiście tylko wewnątrz tej funkcji. Wewnątrz funkcji dostępne są tylko zmienne w niej definiowane i parametry. Można się dostać też do innych zmiennych, ale o tym w punkcie “Zasięg zmiennych”. Do określania co jest zwracane przez funkcję służy instrukcja return. Może ona być wywołana w dowolnym miejscu funkcji - po dojściu do tej instrukcji kończy się wykonanie funkcji.
Funkcja może nie zwracać żadnych wartości. Taka funkcja przydaje się jeśli często powtarzany jest jakiś fragment kodu. Taka funkcja kończy swoje wykonanie po dojściu do końca jej definicji lub instrukcji return (tym razem wywoływanej bez parametru, ponieważ funkcja nie zwraca żadnych wartości).
Funkcje w PHP nie mogą być ponownie definiowane. Mogą być definiowane w zasadzie w dowolnym miejscu kodu. Wewnątrz funkcji znajdować się może dowolny, prawidłowy pod względem składniowym kod - nawet definicje innych funkcji czy klas.
Klasy
Klasy są ściśle związane z pojęciem obiektowych zasad pisania aplikacji. Jeśli ktoś nie spotkał się jeszcze z taką koncepcją, to postaram się ją objaśnić w kilku zdaniach. Obiekt, tak jak w rzeczywistości, posiada swoje właściwości i można z nim zrobić różne rzeczy. Klasa nie jest obiektem, ale jego definicją (np. klasą jest kamień, ale nie jego konkretny egzemplarz). Definicja klasy zawiera zmienne (właściwości obiektu) i funkcje (rzeczy, które można zrobić z tymi obiektami). Za pomocą takiej konwencji programistycznej czasem można łatwiej i naturalniej opisać interakcje między obiektami. Oto jak się definiuje przykładową klasę i przykładowe działania na niej - jako że to tylko przykład to i klasa nie jest zbyt ambitna.
Przykład 6.2. Przykład definicji klasy
<?php
// Początek definicji klasy Koszyk - definiującej koszyk sklepowy
class Koszyk
{
// Definicja zmiennej - tablicy asocjacyjnej zawierającej numery artykułów i
// ich ilość
var $artykuly;
// Metoda dodająca podaną ilość artykułów do koszyka
function dodaj($numer, $ilosc)
{
$this->artykuly["$numer"] += $ilosc;
}
// Metoda usuwająca podaną ilość artykułów z koszyka
function usun($numer, $ilosc)
{
if($this->artykuly["$numer"]>$ilosc)
$this->artykuly["$numer"]-=$ilosc;
else
$this->artykuly["$numer"]=0;
}
// Metoda wyświetlająca zawartość koszyka
function wyswietl()
{
while(list($k, $v) = each($this->artykuly))
if($v>0)
echo "Artykul nr $k - $v sztuk<br>";
}
}
// Przykład wykorzystania
$koszyk = new Koszyk;
$koszyk->dodaj('20', 2);
$koszyk->dodaj('12', 4);
$koszyk->dodaj('20', 5);
$koszyk->usun('12', 4);
$koszyk->wyswietl();
?>
Jak widać na załączonym przykładzie, aby dostać się do zmiennej lub funkcji będącej składową klasy należy użyć operatora “->”. Wewnątrz funkcji należącej do klasy zmienna $this oznacza właśnie ten obiekt - należy używać go chcąc odwołać się do zmiennej lub funkcji należącej do klasy.
W obiektowej koncepcji programowania znajduje się takie pojęcie jak dziedziczenie. Jako że w PHP obiektowość jest bardzo uboga, tak więc i dziedziczenie jest bardzo uproszczone. Ogólnie rzecz mówiąc dziedziczenie służy do tworzenia nowych klas na podstawie innych, rozszerzając ich możliwości. Do naszej klasy można dodać nowy atrybut - nazwę właściciela (zakładam, że przed podanym listingiem w pliku znajduje się definicja klasy Koszyk).
Przykład 6.3. Przykład dziedziczenia
<?php
class Nazwany_koszyk extends Koszyk{
var $nazwa;
function ustaw_nazwe($nowa_nazwa)
{
$this->nazwa = $nowa_nazwa;
}
}
$koszyk = new Nazwany_koszyk;
$koszyk->ustaw_nazwe('Fredzio');
$koszyk->dodaj('2', 34);
echo 'Właściciel: '.$koszyk->nazwa.'<br/>';
$koszyk->wyswietl();
?>
Kolejnym pojęciem z zakresu obiektowości jest konstruktor. Konstruktor jest to funkcja o takiej samej nazwie jak klasa, która ustala początkowe wartości zmiennych (wywoływana jest automatycznie przy tworzeniu obiektu). Konstruktorowi można podać pewne wartości przy tworzeniu obiektu. Oto kolejna wersja koszyka wyposażona w konstruktor, który ustawia nazwę właściciela na podaną lub “Anonim” jeśli jej nie podano:
Przykład 6.4. Zastosowanie konstruktora
<?
class Auto_koszyk extends Nazwany_koszyki
{
function Auto_koszyk( $nazwa = 'Anonim')
{
$this->ustaw_nazwe($nazwa);
}
}
$koszyk = new Auto_koszyk('Jakiś właściciel');
$koszyk->dodaj('4', 30);
echo 'Właściciel: '.$koszyk->nazwa.'<br/>';
$koszyk->wyswietl();
?>
Instrukcje include i require
W PHP istnieją dwie instrukcje, które pozwalają włączyć do kodu zawartość innego pliku także zawierającego kod PHP. Obu tym instrukcjom podaje się jeden parametr - nazwę pliku do włączenia do kodu (może to być ścieżka do pliku znajdującego się na innym serwerze WWW). Różnica między nimi polega na sposobie włączania tych plików do kodu.
W przypadku instrukcji require pliki dołączane są do kodu jeszcze przed parsowaniem, w każdym miejscu gdzie znajduje się instrukcja require. Dlatego instrukcja ta nie nadaje się do dołączania plików których nazwa pobierana jest ze zmiennej - zamiast tego należy użyć instrukcji include. Używając tych instrukcji należy pamiętać o dwóch rzeczach.
Po pierwsze, przetwarzanie plików zaincludowanych zaczyna się od trybu HTML, a więc jeśli plik zawiera tylko kod PHP, to powinien zaczynać się od jednego ze znaczników otwierających. Po drugie należy pamiętać, że jeśli instrukcja include używana jest w pętli lub instrukcji warunkowej, to pomimo że jest to teoretycznie jedna linia, to musi znajdować się ona w nawiasach klamrowych, ponieważ ta pojedyncza linia zamieniana jest na wiele linii dołączanych z innego pliku.
Funkcja readfile()
Innym typem funkcji służącej do dołączania treści zawartych w innym pliku jest funkcja readfile(). Rzeczą odróżniającą tą funkcję od instrukcji zawartych w poprzednim punkcie jest to, że dane pobrane z pliku nie są przetwarzane przez PHP, więc funkcja ta nadaje się tylko do wyświetlania plików HTML bądź czysto tekstowych.
Zasięg zmiennych
Przy korzystaniu z funkcji i klas pojawia się problem zasięgu zmiennych. Problem ten dotyczy większości języków programowania. Ogólnie mówiąc chodzi o to, że zmienne dostępne są zazwyczaj tylko w tym zasięgu, w którym zostały zdeklarowane. Przez zasięg rozumiem zasięg główny (to znaczy część kodu, która nie należy do żadnej funkcji lub klasy), klasy i funkcje.
Przykład 6.5. Zasięg zmiennych
<?php
$a = 34;
function aaa()
{
echo $a;
}
aaa();
?>
Pomimo, że zmienna $a została zadeklarowana wcześniej, to nic się nie wyświetli, ponieważ zmienna $a nie jest dostępna wewnątrz funkcji. Dostęp do zmiennych globalnych można uzyskać na 2 sposoby. Po pierwsze, można powiadomić PHP że dana zmienna ma być pobierana z zasięgu głównego za pomocą instrukcji global.
Przykład 6.6. Zmiana zasięgu zmiennej
<?
$a = 23;
function aaa()
{
global $a;
echo $a;
}
aaa();
?>
W tym przykładzie zostanie wyświetlona prawidłowa wartość zmiennej $a. Istnieje też druga metoda dostania się do zmiennych globalnych. W każdym miejscu kodu dostępna jest tablica asocjacyjna $GLOBALS, której kluczami są nazwy zmiennych dostępnych w zasięgu głównym.
Istnieje jeszcze jeden aspekt dotyczący zasięgu zmiennych: zmienne statyczne.
Przykład 6.7. Zmienna statyczna
<?
function aaa()
{
$a = 0;
echo $a;
$a++;
}
aaa();
aaa();
aaa();
?>
Powyższy przykład jest w zasadzie bez sensu - za każdym razem wyświetlona będzie wartość 0, ponieważ za każdym wywołaniem funkcji zmienna $a będzie od nowa inicjowana wartością 0 a po wyświetleniu i inkrementacji tej zmiennej będzie ona niszczona (wszystkie zmienne inicjowane w funkcji oprócz statycznych są niszczone po wykonaniu się funkcji).
Przykład 6.8. Zmiana zasięgu zmiennej
<?
function aaa()
{
static $a = 0;
echo $a;
$a++;
}
aaa();
aaa();
aaa();
?>
Natomiast w tym przykładzie wyświetlone zostaną wartości 0, 1 i 2. Dzieje się tak, ponieważ mimo że zmienna jest inicjowana wartością 0, to dzięki instrukcji static dzieje się to tylko raz, a do tego po zakończeniu wykonywania się funkcji zmienna ta nie jest niszczona.
W PHP 4.1.0 wprowadzone zostały tak zwane tablice superglobalne. Są one tworzone przez PHP - użytkownik nie może samemu tworzyć takich tablic. Zawierają one dane przekazywane do PHP metodami GET, POST, informacje o przekazanych plikach, dane z ciasteczek i sesji - odpowiedno $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION. Mają one zastąpić tablice $HTTP_*_VARS, które ze względu na kompatybilność są jeszcze obecne. Różnica między tablicami superglobalnymi a tymi używanymi wcześniej jest taka, że tablice superglobalne dostępne są w dowolnym miejscu kodu, bez potrzeby użycia instrukcji global.
Spis treści
Formularze
Jeśli użytkownik musi podać jakieś dane (np. w celu dodania ich do bazy danych), to jedyną metodą jest pobranie ich ze standardowego formularza HTML. W większości języków programowania należy używać dodatkowych bibliotek aby uzyskać dostęp do danych przesyłanych z formularza. W PHP zostało to maksymalnie uproszczone. Wszystkie dane z formularza trafiają do odpowiednich tablic asocjacyjnych o nazwach kluczy takich, jak nazwy pól formularza. Jeśli w konfiguracji PHP włączona zostanie opcja register_globals (jest ona domyślnie wyłączona od wersji 4.2.0), to stworzone zostaną od razu zmienne o nazwach takich jak nazwy pól formularza.
Są dwie metody przekazywania parametrów do innych stron: metoda “GET” i metoda “POST”. Metody GET używa się kiedy parametrów jest niewiele. Dzieje się tak ponieważ parametry przekazuje się za pomocą adresu URL (np. http://www.coś.pl/strona.php?parametr1=wartość1¶metr2=wartość2), którego długość jest ograniczona. Należy też pamiętać że parametry są widoczne w pasku adresu przeglądarki, więc tej metody nie należy używać jeśli przekazywane są np. hasła. Jak widać, sam adres od parametrów oddzielany jest za pomocą znaku zapytania, a kolejne pary parametr=wartość za pomocą znaku ampersand (“&”). Tą metodę można wykorzystać także przy przekazywaniu parametrów przez odnośnik (zobacz dalej).
Metoda “POST” do przekazywania parametrów wykorzystuje nagłówek zapytania - wystarczy wiedzieć, że metoda ta umożliwia przekazywanie dużo większych parametrów, a także że parametrów nie widać w pasku przeglądarki.
Zależnie od metody, zmienne trafiają do odpowiednich tablic asocjacyjnych. Dane przesłane metodą GET trafiają do tablicy $_GET (lub $HTTP_GET_VARS w wersjach starszych niż 4.1.0) a dane z metody POST to tablicy $_POST (lub $HTTP_POST_VARS). Tablice $_GET i $_POST są superglobalne. Oznacza to, że są widoczne w każdym miejscu kodu PHP bez konieczności użycia składni globals.
Przykład 7.1. Odczytywanie wartości z formularza
Plik jeden.html
<html>
<head>
<title>
Test formularza
</title>
</head>
<body>
<form action="dwa.php" method="GET">
Imię: <input type=text name="imie"/><br/>
Nazwisko: <input type=text name="nazwisko"/><br/>
Proszę o fakturę do zamówienia: <input type=checkbox name="faktura"/><br/>
Chcę zamówić:<br/>
<input type=radio name=zamow value="kola"/>Coca-colę<br>
<input type=radio name=zamow value="fanta"/>Fantę<br>
<input type=radio name=zamow value="sprite"/>Sprite'a<br>
<input type=submit value="Wyślij"/>
</form>
</body>
</html>
Plik dwa.php
<html>
<head>
<title>
Wyniki
</title>
</head>
<body>
Imię: <?php echo $_GET['imie']?><br>
Nazwisko: <?php echo $_GET['nazwisko']?><br>
Faktura: <?php echo ($_GET['faktura'] == 'on' ? 'Tak' : 'Nie')?><br>
Zamówienie: <?php switch($_GET['zamow']){
case "kola":
echo "Coca-cola";
break;
case "fanta":
echo "Fanta";
break;
case "sprite":
echo "Sprite";
break;
}
?>
</body>
</html>
Upload plików
Często zachodzi też potrzeba przekazania jakiegoś pliku na serwer, na przykład dodając zdjęcie do galerii. Plik przesyła się korzystając z pola formularza typu “file”. Należy pamiętać o tym, że w tagu otwierającym formularz musi znaleźć się parametr ENCTYPE=”multipart/form-data” a formularz musi być wysyłany metodą POST.
Na stronie do której został wysłany formularz dostępna będzie wielowymiarowa tablica asocjacyjna $_FILES ($HTTP_POST_FILES w starszych wersjach PHP), której pierwszym wymiarem będą pola typu file z formularza (klucze są nazwami tych pól), a w drugim informacje o przesłanym pliku.
Informacje o przesyłanym pliku
tmp_name
nazwa tego pliku na serwerze wraz ze ścieżką; używając tego pola można uzyskać dostęp do przesłanego pliku
name
nazwa pliku jaką posiadał u użytkownika
type
typ MIME pliku, np. text/plain lub image/gif; informacja ta jest dostępna tylko jeśli przeglądarka klienta dostarczyła takiej informacji.
size
wielkość pliku w bajtach
Dokładniejsze informacje wraz z przykładami użycia znajdują się w rozdziale Odbieranie plików od użytkownika.
Odnośniki
Istnieje możliwość przekazywania niedużej liczby parametrów za pomocą zwykłych odnośników dostępnych w języku HTML. W takim przypadku wykorzystuje się metodę GET - konstruuje się odnośnik, na końcu którego należy umieścić znak zapytania a po nim oddzielone ampersandami pary parametr=wartość, np: <a href=”strona.php?imie=Franek&nazwisko=Kowalski”>Kliknij tu</a>
Cookies
Metodą nie tyle przekazywania parametrów, co przechowywania niewielkich ilości danych na komputerze oglądającego stronę (np. informacje o imieniu i nazwisku lub nazwie użytkownika w tym serwisie) jest mechanizm cookies (ciasteczka). Ciasteczka ustawione przez dany serwis dostępne są tylko dla niego i ustawiane są na jakiś czas.
Ciasteczka przekazywane są za pomocą nagłówków HTTP. Muszą być one wysłane zanim do przeglądarki zostanie wysłana jakakolwiek inna treść. W związku z tym przed zapisaniem ciasteczka nie może być żadnego wywołania funkcji echo i pochodnych, a także tag otwierający tryb PHP musi być pierwszymi znakiami w pliku - nie może być żadnej spacji ani pustych wierszy. Ograniczenie to można obejść używając buforowania wyjścia - po szczegóły odsyłam do podręcznika PHP.
PHP automatycznie odczytuje ciasteczka i zamienia je na zmienne. Są one przechowywane w superglobalnej tablicy asocjacyjnej $_COOKIE (dawniej $HTTP_COOKIE_VARS), w której kluczami są nazwy ciasteczek. Ciasteczka ustawia się je pomocą funkcji setcookie( nazwa, wartość, czas_wygaśnięcia, ścieżka, domena, bezpieczeństwo). Tylko pierwszy parametr jest niezbędny. Oznacza on nazwę cookiesa - taką nazwą będzie miała zmienna stworzona przez PHP po ponownym odczytaniu ciastek. Funkcja parametru “wartość” jest chyba oczywista - taka wartość będzie przechowana w ciasteczku o podanej nazwie.
Parametr czas_wygaśnięcia oznacza czas, po jakim ciastko zostanie skasowane. Czas ten należy podać jako ilość sekund od 1.1.1970 - tak jest przechowywany czas w systemach UNIX'owych. Aktualny czas w tym formacie zwracany jest przez funkcję time(). Jeśli cookie ma być trzymany przez godzinę, to do czasu zwróconego przez time() należy dodać ilość sekund zawartych w godzinie - “time() + 3600″. Podobnie należy postępować w przypadku innych przedziałów czasu.
Przedziały czasu dla funkcji setcookie
godzina - time()+3600
dzień - time()+86400
miesiąc - time()+30*86400
Jeśli czas będzie wcześniejszy niż aktualny czas, ciasteczko zostanie skasowane. Jeśli będzie równy zero - ciasteczko będzie ważne tylko do zamknięcia przeglądarki.
Dwa następne parametry używane są do wskazania adresu, dla którego dostępne będą cookiesy. Jeśli ostatni parametr jest ustawiony na 1, to cookie będzie przesłany za pomocą szyfrowanego połączenia HTTPS.
Standardowo nie ma możliwości przechowywania tablic w ciasteczkach, lecz można to zrobić “na około”. Przed zapisaniem tablicy w ciasteczku należy użyć funkcji serialize(). Zamienia ona tablicę na ciąg znaków. Do ponownego odczytania takiej tablicy służy funkcja unserialize().
Przykład 7.2. Serializacja i deserializacja tablicy
<?php
// zapis
$tablica = Array('a' => 'pierwszy', 'b' => 'drugi');
setcookie('tablica', serialize($tablica), time()+3600);
// odczyt zabezpieczony przed nieistniej±cym ciasteczkiem
if (isset($_COOKIE['tablica'])) {
$tablica = unserialize($_COOKIE['tablica']);
} else {
$tablica = Array();
}
?>
W PHP nowszych od 4.1.0 istnieje jeszcze superglobalna tablica $_REQUEST, która łączy w sobie tablice $_GET, $_POST, $_COOKIE i $_FILES.
register_globals
PHP posiada możliwość ustawienia w pliku konfiguracyjnym php.ini dyrektywy register_globals. Jest ona odpowiedzialna za rejestrowanie danych otrzymanych z formularzy, ciastek, sesji czy serwera jako zmienne globalne. Oznacza to, że jeśli dyrektywa register_globals została ustawiona na on to wszystkie zmienne przekazane do skryptu dostępne są w postaci $nazwa_zmiennej, bez potrzeby stosowania żadnych tablic. Wydaje się to wygodniejsze i łatwiejsze, lecz powoduje pewne niebezpieczeństwo. Mianowicie używając zmiennych globalnych nie można stwierdzić, czy dana wartość pochodzi z sesji czy może została podana w URLu metodą GET. Przy źle napisanych skryptach można tak obchodzić zabezpieczenia.
W związku z powyższym, używanie odpowiednich tablic jest mocno zalecane. Ostatnio twórcy PHP dodali do tego jeszcze jeden powód. Począwszy od wersji 4.2.0, dyrektywa register_globals jest domyślnie wyłączona. Tak więc pisząc skrypt dla nieznanego serwera trzeba się liczyć z ewentualnością braku dostępu do zmiennych globalnych.
Mechanizm sesji był najważniejszą ze zmian oczekiwanych w PHP 4. Umożliwia on przekazywanie parametrów między stronami w łatwy sposób. Zmienne są przechowywane po stronie serwera a u klienta trzymane jest tylko ID sesji. Te ID jest zapisane w cookie lub przekazywane przez URL. PHP jest w stanie sam rozpoznać czy na komputerze klienta włączony jest mechanizm cookies i w razie potrzeby dodać identyfikator sesji do każdego URLu i formularza. Wymaga to jednak posiadania PHP skompilowanego z opcją --enable-trans-sid.
Jako że sesje mogą bazować na ciasteczkach, także i w tym przypadku przed rozpoczęciem sesji do przeglądarki nie mogą być wysłane żadne inne dane.
Po otrzymaniu żądania klienta PHP automatycznie (jeśli w konfiguracji PHP włączona została opcja auto_start) lub “ręcznie” przez programistę (za pomocą funkcji session_start()) sprawdza, czy przypisano już ID sesji. Jeśli tak, to PHP odczytuje zmienne zarejestrowane w tej sesji. Jeśli nie, generowany jest nowy, unikalny identyfikator sesji.
Aby PHP zaczęło śledzić wartość zmiennej, najpierw trzeba ją zarejestrować za pomocą funkcji session_register( nazwa_zmiennej). Istnieje też odwrotna wersja tej funkcji - funkcja session_unregister( nazwa_zmiennej ) powoduje, że PHP “zapomni” o tej zmiennej.
W PHP 4.1.0 wprowadzone zostały opisane wcześniej zmienne superglobalne. Jedna z tych zmiennych, $_SESSION, przechowuje zmienne zarejestrowane w sesji. Kluczem tej tablicy jest oczywiście nazwa zarejestrowanej zmiennej.
Tablica ta ma jednak pewną różnicę w stosunku do innych tablic superglobalnych. Mianowicie można jej użyć do rejestrowania zmiennych sesyjnych. Wystarczy przypisać wartość odpowiedniemu kluczowi tej tablicy aby zmienna została zarejestrowana.
Przykład 8.1. Zliczanie ile dana osoba odczytała daną stronę z czasie jednej sesji.
<?php
session_start(); // można pominąć jeśli jest się pewnym że włączona jest opcja auto_start
if (!isset($_SESSION['count'])) { // jeśli zmienna nie jest zarejestrowana
$_SESSION['count'] = 0; // przypisz jej początkową wartość
} else { // jeśli jest zarejestrowana
$_SESSION['count']++; // zwiększ jej wartość
}
echo 'Strona odczytana '.$_SESSION['count'].' razy w ciągu tej sesji';
?>
Skrypt z tego przykładu będzie pamiętał ilość odwiedzin przez cały czas działania przeglądarki, jeśli w przeglądarce włączony jest mechanizm cookies, lub dopóki strona odświeżana jest z takim samym numerem sesji przekazanym przez URL.
Użycie sesji rodzi pewne wątpliwości: co jeśli ktoś `ukradnie' numer sesji? W ten sposób uzyska dostęp do danych zapisanych w tej sesji. Mimo że istnieje taka teoretyczna możliwość, to ilość dostępnych identyfikatorów sesji jest tak duża, że taka `kradzież' byłaby całkiem przypadkowa.
Spis treści
Wyrażenia regularne
PHP obsługuje 2 rodzaje wyrażeń regularnych: zgodne ze standardem POSIX (które tu skrótowo opiszę) i te zastosowane w języku Perl (opis tych wyrażeń zostanie tu umieszczony w terminie późniejszym). Wyrażenia regularne są to ciągi znaków, które można dopasować do różnych innych ciągów. Można to porównać do tzw. wildcardów używanych przy operacjach na plikach, gdzie gwiazdka (`*') zastępowała dowolną ilość dowolnych znaków, czyli wyrażenie `*.*' (w przypadku systemów dosowych) będzie pasowało do plików o dowolnej nazwie i dowolnym rozszerzeniu.
Wyrażenia regularne są o wiele bardziej skomplikowane i też działają trochę inaczej. W wildcardach gwiazdka zastępowała dowolną ilość dowolnych znaków, natomiast w wyrażeniach regularnych działa niejako `wstecz' - opisuje dowolną ilośc powtórzeń (zero lub więcej) poprzedniego znaku, czyli wyrażenie `a*' będzie pasowało do `aaa', `aaaaa' ale i `b', ponieważ w tym wyrażeniu nie ma ograniczenia że nie może być nic oprócz `a'.
Takie ograniczenie można uzyskać dzięki znakom `^' i `$'. Znak `^' rozumiany jest jako początek linii, a `$' jako koniec. Tak więc jeśli chcemy znaleźć ciąg, który będzie pusty lub będą w nim same litery `a', to powinien on wyglądać tak: `^a*$'. Natomiast jeśli `a' musi wystąpić przynajmniej raz, to zamiast znaku `*' należy użyć znaku `+' - oznacza on jedno lub więcej powtórzeń ostatniego znaku. Istnieje też możliwość użycia znaku `?', który oznacza żadne lub jedno wystąpienie poprzedzającego ten znak atomu, znaku lub zakresu.
Można także podać konkretną ilość wystąień znaku, atomu lub przedziału przez użycie za raz po nich nawiasów klamrowych. Jeśli będzie w nich jedna liczba, to będzie ona określała dokładnie daną liczbę powtórzeń. Jeśli będzie w nich liczba a po niej przecinek, to wyrażenie będzie musiało wystąpić przynajmniej tyle razy ile wynosi podana liczba. Istnieje także możliwość podania w nawiasach klamrowych dwóch liczb oddzielonych przecinkiem, co oznacza powtórzenie wyrażenia minimalnie tyle razy ile pierwsza liczba, a maksymalnie tyle ile druga (włącznie).
Zamiast pojedyńczego znaku można podać zakres wyrazów lub całe wyrażenie - tzw. atom. Zakres znaków podaje się w nawiasach kwadratowych. W tych nawiasach można podać pojedyńcze znaki jeden po drugim (np. `[egt]`), przedział liter (np. wszystkie małe litery: `[a-z]` - uwaga, zakres ten nie obejmuje polskich znaków diakratycznych), lub połączenie tych dwóch typów (np. `[a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]` określa wszystkie litery).
W nawiasach kwadratowych można podawać także symbole. Jeśli w przedziale potrzebny jest znak myślnika, który normalnie używany jest do określania przedziałów znaków, to trzeba umieścić go na pierwszej lub ostatniej pozycji w nawiasach kwadratowych. W nawiasach kwadratowych znak `^' ma inne znaczenie. Oznacza ono zaprzeczenie, czyli jeśli umieści się je przed znakiem lub zakresem, to ten znak lub zakres nie będzie mógł się pojawić w tym miejscu.
Jeśli znak może być dowolny, to zamiast konkretnej litery, znaku czy przedziału można użyć symbolu kropki (`.'). Przykładowo wyrażenie `^.*$' opisuje dowolny ciąg składający się z dowolnej ilości dowolnych znaków.
Atom, czyli wyrażenie zawarte w nawiasach okrągłych, może zawierać (prawie) dowolną ilość znaków, zakresów i innych atomów. Pozwala to na dopasowywanie powtarzających się fragmentów ciągów znaków. Dobrym przykładem jest sprawdzenie, czy dany ciąg znaków jest ścieżką w systemie uniksowy. Przykładowy ciąg to `/usr/local/bin/php'.
Wyrażenie regularne powinno wyglądać tak: `(/([a-Z])+)*(/([a-Z\.]))'. Pierwszy atom określa dowolną ilość katalogów (na początku znak slash a po nim dowolna ilość liter o dowolnej wielkości) po czym nazwa pliku - po atomie nie ma żadnego znaku określającego ilość wystąpień, a więc musi wystąpić dokładnie raz.
Pomiędzy atomami, znakami lub zakresami można postawić znak `|', który oznacza logiczną operację `OR', czyli poprostu oznacza że może wystąpić jeden lub drugi atom (ten przed znakiem `|' i ten po).
Jeśli w wyrażeniu regularnym musisz podać znak, który byłby interpretowany inaczej niż zamierzamy (np. jeśli musisz znaleźć ciąg zaczynający się od gwiazdki po której jest dowolna ilość liter A, to nie można `normalnie' podać znaku gwiazdki, ponieważ byłby on interpretowany jako dowolna ilość powtórzeń ostatniego znaku), to należy zamienić ten znak na tzw. `escape sequence' - poprostu należy przed tym znakiem wstawić znak ukośnika (`\'). Takie znaki to: `(`, `)', `[', ']`, `{`, `}', `\', `*', `|', `^', `$', `?'. Jeśli w wyrażeniu trzeba użyć właśnie znaku ukośnika, to należy wpisać dwa ukośniki, jeden po drugim.
Porównywanie ciągów
Podstawową funkcją służącą do porównywania ciągów jest strcmp(). Jako jedyne 2 parametry przyjmuje ona ciągi tekstowe, które mają być porównane. Funkcja ta zwraca wartość 0 jeśli ciągi są takie same, wartość większą od zera jeśli pierwszy ciąg jest większy od drugiego lub wartość mniejszą od zera jeśli pierwszy ciąg jest mniejszy od drugiega.
Funkcja ta rozróżnia wielkość znaków. Jeśli zachodzi potrzeba porównania dwóch ciągów, to należy użyć funkcji strcasecmp() (parametry i wartości zwracane takie jak przy funkcji strcmp). Istnieje także funkcja strncmp(), która porównuje tylko taką ilość początkowych znaków z podanych ciągów, jaka została podana jako trzeci parametr tej funkcji. Oczywiście istnieje też wersja funkcji strncmp() ignorująca wielkość znaków: strncasecmp().
Istnieje racjonalne wytłumaczenie dlaczego ciągi należy porównywać za pomocą funkcji strcmp() lub pochodnych a nie zwykłego operatora porównania `=='. Interpreter języka PHP stara się być mądrzejszy od programisty automatycznie konwertując typy zmiennych aby przy porównywaniu ich były takie same.
Przykład 9.1. Proste porównywanie ciągów
<?php
$a=0;
$b="0papa";
if($a==$b)
echo "Tak";
else
echo "Nie";
?>
Powyższy przykład wyświetli “Tak”, pomimo że te zmienne są różne. Dlaczego? Ponieważ PHP automatycznie konwertuje zmienną $b do typu liczbowego, przez co zamieniana jest ona na liczbową wartość 0 (która faktycznie jest na pierwszym miejscu ciągu - pozostałe znaki są odrzucane ponieważ nie są liczbami). Można teoretycznie użyć operatora “===” - porównania nie tylko wartości, ale też typu.
Przykład 9.2. Operator identyczności
<?php
$a=0;
$b="0";
if($a===$b)
echo "Tak";
else
echo "Nie";
?>
Powyższy przykład wyświetli “Nie”, bo pomimo że obie zmienne mają wartość 0, to zmienna $a jest liczbą, a zmienna $b ciągiem tekstowym.
Funkcja strstr() służy do sprawdzania, czy podany ciąg jest fragmentem innego ciągu. Funkcja przyjmuje dwa parametry: przeszukiwany ciąg ('stóg siana') i szukany ciąg (`igła'). Jeśli dany ciąg jest fragmentem podanego, to zwracany jest ciąg - fragment przeszukiwanego ciągu od pierwszego wystąpienia szukanego ciągu do końca.
Przykład 9.3. Zastosowanie funkcji strstr
<?php
$email = "prezydent@polska.pl";
$domena = strstr($email, "@");
echo $domena;
?>
Powyższy przykład wyświetli “@polska.pl”. Jeśli ciąg nie jest znaleziony, to zwracana jest wartość FALSE, dzięki czemu funkcję tą można używać w instrukcjach warunkowych.
Przykład 9.4. Użycie funkcji strstr() w warunku
<?php
$email = "prezydent@polska.pl";
if(strstr($email, "polska")!==False)
echo "Email ma w sobie słowo 'polska'";
?>
Przy używaniu tej funkcji trzeba pamiętać o jednej rzeczy. Łatwo jest pomylić zwracaną wartość `znaleziono na pozycji 0′ i `nie znaleziono', ponieważ wartość logiczna `true' przy porównaniach może być skonwertowana do wartości liczbowej 0. Aby tego uniknąć należy używać operatora porównania ze sprawdzaniem typu (`===' lub `!==').
Istnieje także wersja tej funkcji ignorująca wielkość znaków: stristr()(przyjmowane parametry i zwracane wartości takie jak przy funcji strstr).
Pomimo, że funkcji strstr() można używać do sprawdzania czy jeden ciąg jest częścią drugiego, to jest ona nieefektywna. Lepiej skorzystać z funkcji strpos().
Do sprawdzania, czy ciąg tekstowy pasuje do wyrażenia regularnego używa się funkcji ereg() która jako pierwszy parametr przyjmuje wyrażenie regularne, a jako drugi ciąg który ma być porównany z wyrażeniem. Istnieje także wersja tej funkcji ignorująca wielkość znaków: eregi(). Zwracana jest wartość true jeśli ciąg pasuje do wyrażenia regularnego, a false jeśli nie pasuje.
Zazwyczaj przy instrukcjach warunkowych w którch korzysta się z funkcji sprawdzającej jakiś warunek, funkcja ta zwraca wartość TRUE jeśli warunek jest spełniony, np. funkcja ereg zwraca tą wartość jeśli dany ciąg pasuje do danego wyrażenia regularnego.
Przykład 9.5. Użycie funkcji ereg w warunku
<?php
if(ereg(".*", $ciag))
echo "Znalazłem!";
?>
W przypadku funkcji strcmp() i pochodnych jest trochę inaczej, gdyż jeśli ciągi są identyczne to zwracana jest wartość 0 uznawana za logiczne FALSE.
Przykład 9.6. Porównywanie ciągów przy użyciu funkcji strcmp
<?php
if(!strcmp("cośtam", $string))
echo "$string to cośtam!";
?>
Wyciąganie fragmentów ciągów
Bardzo często zachodzi potrzeba wyciągnięcia ze zmiennej tekstowej tylko pewnego jej fragmentu. Najłatwiej jest jeśli znana jest długość wyciąganego fragmentu i pozycja w której się znajduje w zmiennej. Np. jeśli ze zmiennej zawieracjącej “1992/11/19″ chcemy wyciągnąć rok. Wiadomo, że rok jest na samym początku i ma 4 znaki.
Najłatwiej jest użyć funkcji substr(). Jako pierwszy paramter pobiera ona ciąg z którego będzie wycinany fragment, jako drugi miejsce, z którego będzie rozpoczęte wycinanie (0 jeśli od pierwszego znaku, liczba ujemna jeśli ma to być ilość znaków od końca), a ostatni, opcjonalny parametr wskazuje ilość znaków do wycięcia (jeśli pominie się ten parametr, to zwrócony zostanie pod-ciąg od wskazanego znaku początkowego do końca ciągu).
Przykład 9.7. Użycie funkcji substr()
<?php
$data = "1992/11/19";
$rok = substr($data, 0, 4);
?>
Ale to oczywiście najprostsza z sytuacji. Bardziej skomplikowanym przykładem będzie wyciągnięcie z tej samej daty wszystkich pól. Można oczywiście 3 razy używać funkcję substr, ale wydajniejszą metodą jest rozbicie tekstu na tablicę korzystając z opisanej przy okazji tablic funkcji explode.
Przykład 9.8. Zastosowanie funkcji explode
<?php
$data = "1992/11/19";
$tablica = explode("/", $data);
?>
W powyższym przykładzie, w pierwszym elemencie tablicy znajdować się będzie rok, w drugim a w trzecim dzień z podanej daty. Można także użyć tej funkcji w bardziej skomplikowany sposób - do rozbicia ciągu zawierającego datę i czas.
Przykład 9.9. Rozszerzony przykład użycia funkcji explode
<?php
$tekst = "19/11/1982 01:43:12";
$dataiczas = explode(" ", $tekst);
$data = explode("/", $dataiczas[0]);
$czas = explode(":", $dataiczas[1]);
?>
Teraz tablica $data zawiera dzień, miesiąc i rok a tablica $czas godzinę, minutę i sekundę. Ale co jeśli godzina zawiera setne części sekundy, które podawane są po kropce? Robić jeszcze jedno rozbicie? To już za dużo.
Lepiej jest użyć funkcji split(), która funcjonuje w podobny sposób co explode, ale rozbija tekst nie za pomocą zwykłych ciągów znaków, ale za pomocą wyrażeń regularnych. Tak więc cały string zawierający datę i czas (z setnymi sekundami włącznie) można rozbić za pomocą jednego wywołania funkcji split().
Przykład 9.10. Zastosowanie funkcji split()
Teraz w tablicy $tablica znajować się będą po kolei: dzień, miesiąc, rok, godzina, minuta, sekunda i setna część sekundy.
Może też zajść potrzeba wyciągnięcia fragmentu ciągu do jakiegoś znaku, np. pierwszego zdania z jakiegoś tekstu. Wtedy można użyć połączenia funkcji substr() i strpos(), która zwraca numer znaku gdzie znajduje się pierwsze wystąpienie ciągu podanego jako drugi parametr w ciągu podanym jako pierwszy parametr, lub false jeśli pierwszy ciąg nie zawiera w sobie drugiego. A więc pierwsze zdanie podanego ciągu można uzyskać tak:
Przykład 9.11. Zastosowanie funkcji strpos()
<?php
$tekst = "To jest tekst. Tego zdania nie będzie widać.";
$zdanie = substr($tekst, 0, strpos($tekst, "."));
?>
Zmienna $zdanie powinna zawierać “To jest tekst” - bez kropki na końcu.
Podmienianie fragmentów ciągów
Do podmiany całych fragmentów ciągu służy funkcja str_replace(), która przyjmuje 3 parametry: ciąg który ma być podmieniony, ciąg na który ma być podmieniony i ciąg którego fragmenty będą podmieniane. A więc wszystkie wystąpienia pierwszego ciągu w trzecim ciągu są zamieniane na drugi ciąg.
Notatka
Zmienna podawana jako trzeci parametr nie jest zmieniana. Poprawiony ciąg jest zwracany przez funkcję.
Przykład 9.12. Podmiana tekstu przy pomocy funkcji str_replace()
<?php
$tekst = "Jeśli jesteś za podnieś rękę";
$wynik = str_replace("za", "przeciw", $tekst);
?>
Zmienna $wynik będzie zawierała tekst “Jeśli jesteś przeciw podnieś rękę”.
Od wersji PHP 4.0.5 każdy z parametrów funkcji str_replace może być tablicą. A więc jeśli trzeci parametr jest tablicą, to operacja podmany tekstów jest wykonywana jest na każdym elemencie tablicy, a zwracana zmienna także jest tablicą. Natomiast jeśli tablicami są pierwszy i drugi parametr, to każdy element z pierwszej tablicy jest podmieniany na odpowiadający mu element drugiej tablicy. Jeśli pierwsza tablica ma więcej elementów niż druga, to te elementy z pierwszej tablicy które nie mają odpowiednika w drugiej zamieniane są na puste ciągi. Pozwala to na wiele podmian za jednym wywołaniem funkcji str_replace.
Podmienianie znaków w ciągach
W PHP można także znaleźć funkcję, która zamieni wszystkie wystąpienia podanych znaków na inne znaki. Dzięki temu można np. usunąć wszystkie polskie znaki diakratyczne albo skonwertować te znaki na inną stronę kodową. Funkcja ta nazywa się strtr i przyjmuje 3 parametry: ciąg w którym będą podmieniane znaki, ciąg zawierający znaki do podmiany i ciąg zawierający znaki, na które te podane w drugim parametrze będą podmienione. W poniższym przykładzie polskie znaki diakratyczne zostaną zamieniane na odpowiadające im znaki zestawu ASCII.
Przykład 9.13. Usuwanie polskich znaków diakrytycznych
<?php
$tekst = 'Zażółć gęślą jaźń';
$wynik = strtr($tekst, 'ĘÓĄŚŁŻŹŃęóąśłżźćń', 'EOASLZZCNeoaslzzcn');
?>
Przy pomocy tej funkcji możliwe jest też konwertowanie ciągów tekstowych pomiędzy stronami kodowymi. Poniżej zdefiniowane zostały dwie funkcje - pierwsza konwertuje polskie znaki diakrytyczne ze standardu Win-1250 na ISO-1250-2, natomiast druga - odwrotnie.
Przykład 9.14. Translacja polskich znaków diakrytycznych
<?php
function win2iso($str)
{
return strtr($str, "\xA5\x8C\x8F\xB9\x9C\x9F",
"\xA1\xA6\xAC\xB1\xB6\xBC");
}
function iso2win($str)
{
return strtr($str, "\xA1\xA6\xAC\xB1\xB6\xBC",
"\xA5\x8C\x8F\xB9\x9C\x9F");
}
?>
Inne funkcje
htmlspecialchars($string)
funkcja ta zamienia znaki używane w kodzie HTML na takie, które zostaną wyświetlone prawidłowo, a nie będą interpretowane przez przeglądarkę jako znacznik HTML. Wszystkie wystąpienia znaku < zostają zamienione na znak < a znaku > na >. Funkcja ta jest bardzo przydatna gdy zachodzi potrzeba wyświetlenia kodu źródłowego HTML, który nie powinien być interpretowany przez przeglądarkę.
htmlentities($string)
jest to rozszerzona wersja funkcji htmlspecialchars(). Zamienia wszystkie znaki na odpowiadające im kody HTML, jeśli takowe istnieją. Np. wszystkie wystąpienia znaku ó zamieniane są na ó.
chop($string), trim($string), "function">ltrim($string), rtrim($string)
funkcje te mają za zadanie usunięcie `białych znaków' (spacja, tabulator, znacznik nowego wiersza) z początku lub końca ciągu. Funkcja chop(), tak jak i rtrim(), usuwa te znaki z końca ciągu, ltrim() z początku a trim() i z początku i końca.
nl2br($string)
bardzo przydatna funkcja służąca do zamiany znaków końca wiersza na HTML'owe znaczniki <BR> (bardzo przydatne przy wyświetlaniu sformatowanego tekstu w oknie przeglądarki).
strip_tags($string)
usuwa wszystkie znaczniki HTML z podanego jako parametr ciągu. Możliwe jest podanie opcjonalnego drugiego parametru - ciągu, który zawiera nazwy znaczników HTML, które mają zostać pozostawione.
Jak wspomniano wcześniej, PHP “umie” odbierać pliki od użytkownika. Robi się to przy pomocy pola typu “file” w formularzu i odpowiednich zmiennych w skrypcie odbierającym dane.
Przykład 10.1. Odbieranie pliku od użytkownika
plik1.html:
<html>
<body>
<form action="plik2.php" method="POST" ENCTYPE="multipart/form-data">
<input type="file" name="plik"/><br/>
<input type="submit" value="Wyślij plik"/>
</form>
</body>
</html>
plik2.php:
<?php
$max_rozmiar = 1024*1024;
if (is_uploaded_file($_FILES['plik']['tmp_name'])) {
if ($_FILES['plik']['size'] > $max_rozmiar) {
echo 'Błąd! Plik jest za duży!';
} else {
echo 'Odebrano plik. Początkowa nazwa: '.$_FILES['plik']['name'];
echo '<br/>';
if (isset($_FILES['plik']['type'])) {
echo 'Typ: '.$_FILES['plik']['type'].'<br/>';
}
move_uploaded_file($_FILES['plik']['tmp_name'],
$_SERVER['DOCUMENT_ROOT'].'/foto/'.$_FILES['plik']['name']);
}
} else {
echo 'Błąd przy przesyłaniu danych!';
}
?>
Przesyłanie plików na serwer jest sprawą dosyć niebezpieczną, dlatego należy odpowiednio się zabezpieczyć. W powyższym przykładzie użyta została funkcja is_uploaded_file(). Sprawdza ona czy podany plik faktycznie został odebrany od użytkownika - sprawdzenie takie jest istotne, gdyż w przypadku źle napisanego skryptu “włamywacz” będzie mógł odczytać z serwera dowolny plik, do którego prawo odczytu posiada użytkownik jako który pracuje serwer WWW.
Po kolei wykorzystywane są dostępne informacje o pliku. Jeśli wszystkie próby przebiegną pomyślnie, plik jest przenoszony w docelowe miejsce przy pomocy funkcji move_uploaded_file(). Oczywiście jeśli plik o takiej samej nazwie już istnieje, zostanie nadpisany, dlatego też należy najpierw to sprawdzić przy pomocy funkcji file_exists(), ale o tym w następnym rozdziale.
Kolejnym niebezpieczeństwem jest możliwość wstawienia na serwer skryptu PHP zawierającego “niebezpieczne instrukcje”. Można się przeciw temu zabezpieczyć sprawdzając rozszerzenie lub typ przesyłanego pliku. Jeśli rozszerzenie pliku to .php (lub inne, które jest przetwarzane przez serwer WWW jako skrypt PHP) lub typ pliku jest inny od oczekiwanego (na przykład wszystkie inne niż image/gif czy image/jpeg), plik można albo usunąć albo zmienić mu rozszerzenie. Jak - opis w następnym rozdziale.
Aby plik mógł zostać przeniesiony w docelowe miejsce, docelowy katalog musi mieć odpowiednie prawa dostępu. Mianowicie użytkownik, jako który pracuje serwer WWW musi mieć prawo zapisu do tego katalogu. Wszystkie niezbędne informacje można uzyskać od administratora serwera, lub szukając dyrektywy User w pliku /etc/httpd/httpd.conf.
Spis treści
Otwieranie i zamykanie plików
Wszystkie funkcje obsługi plików (oprócz tej otwierającej plik) jako parametr pobierają tzw. „wskaźnik do pliku” (ang. “file pointer”). Jest to wartość zmiennej określająca otwarty plik. Jest to niezbędne, ponieważ skrypt może otworzyć jednocześnie wiele plików i na wszystkich jednocześnie pracować.
Wskaźnik to pliku jest zwracany przez funkcję fopen( nazwa pliku, string tryb ). Drugi parametr określa tryb otwarcia pliku. Tryb trzeba dobrać odpowiednio do tego, co się chce z plikiem robić. Możliwe tryby to:
`r'
plik tylko do odczytu; wewnętrzny wskaźnik pliku umieszczany jest na początku pliku
`r+'
plik do odczytu i zapisu; wewnętrzny wskaźnik pliku umieszczany jest na początku pliku
`w'
plik tylko do zapisu; wewnętrzny wskaźnik pliku umieszczany jest na końcu pliku; zawartość pliku jest niszczona (długość pliku jest zmieniana na zero); jeśli plik nie istnieje PHP próbuje go stworzyć
`w+'
plik do odczytu i do zapisu; wewnętrzny wskaźnik pliku umieszczany jest na końcu pliku; zawartość pliku jest niszczona (długość pliku jest zmieniana na zero); jeśli plik nie istnieje
`a'
plik tylko do zapisu; wewnętrzny wskaźnik pliku umieszczany jest na końcu pliku; jeśli plik nie istnieje PHP próbuje go stworzyć
Pozycja “wewnętrznego wskaźnika pliku” określa, w którym miejscu zaczęłoby się pisać do pliku, gdyby zaczęło się pisać lub czytać z tego pliku zaraz po otwarciu pliku. Jeśli jest na końcu - to znaczy że dane dopisywane są na końcu.
Przykład 11.1. Otwarcie pliku do odczytu
<?
$fp = fopen("dane.txt", "r");
?>
Zmienna $fp zawiera teraz wskaźnik do pliku dane.txt. Wskaźnik ten trzeba podać przy każdej funkcji, która w jakiś sposób operuje na tym pliku.
Jeśli otworzyliśmy ten plik, to teraz trzeba go jakoś zamknąć. Jeśli nie zamkniemy pliku ręcznie, to PHP zrobi to za nas po zakończeniu działania skryptu. Nie sprawia to różnicy jeśli na stronie operujemy tylko jednym plikiem lub np. po zapisaniu danych do pliku już się nim nie interesujemy. Inaczej sprawa wygląda jeśli po zapisaniu danych do pliku chcemy później go odczytać - dopiero po zamknięciu pliku zmiany w nim będą widoczne. A do zamknięcia pliku służy funkcja fclose(int wskaźnik).
Wewnętrzny wskaźnik pliku
Wewnętrzny wskaźnik pliku, jak już napisałem wyżej, oznacza miejsce w pliku oznaczające `bieżącą lokalizację' - czyli miejsce w którym zaczęłoby się pisanie lub czytanie. Większość funkcji, które operują na plikach powodują przesunięcie tego wskaźnika - każde zapisanie i odczyt z pliku powodują przesunięcie tego wskaźnika. Można jednak wymusić takie przesunięcie - na przykład żeby zacząć czytanie od pewnego miejsca lub żeby pominąć jakiś fragment danych. Służy do tego funkcja fseek(int wskaźnik, int przesunięcie [, int typ_przesunięcia]) .
Jak widać, funkcja pobiera 2 obowiązkowe argument i jeden opcjonalny. Pierwszy parametr to wskaźnik pliku - funkcja musi wiedzieć w którym pliku ma przesuwać wskaźnik. Drugi to numer znaku na który ma być przesunięty wskaźnik. Ostatni określa typ przesunięcia (możliwe wartości to: SEEK_SET, SEEK_CUR i SEEK_END).
Domyślną wartością jest SEEK_SET. Oznacza to, że wewnętrzny wskaźnik pliku zostanie ustawiony na pozycji przesunięcie. Ustawienie ostatniego parametru na SEEK_CURR spowoduje, że wskaźnik pliku zostanie przesunięty o przesunięcie znaków od bieżącego miejsca. Natomiast wybranie typu SEEK_END spowoduje, że wskaźnik zostanie ustawiony o przesunięcie znaków za końcem pliku. Istnieje też funkcja rewind( int wskaźnik ), który przesuwa wewnętrzny wskaźnik pliku na początek pliku.
Odczyt z plików
Odczyt z pliku może być przeprowadzany na 2 sposoby jeden to “niskopoziomowe” czytanie danych z pliku za pomocą funkcji fread( int wskaźnik, int długość). Czyta ona dane odczytane z pliku, określonego przez utworzony wcześniej „wskaźnik” (jak pisałem wcześniej, wskaźniki są zwracane przez funkcję fopen()). Dane są czytane do długości określonej w drugim parametrze. Jeśli danych jest mniej niż podana długość, to poprostu zwrócone zostaną wszystkie dane z pliku.
Funkcja fread() powoduje przesunięcie wewnętrznego wskaźnika pliku - do miejsca, w którym zakończyło się czytanie. Może teraz jakiś przykład. Mamy przykładowy plik test.txt - z dowolną treścią.
Przykład 11.2. Odczyt danych z pliku
<?php
$fp = fopen("test.txt", "r");
$tekst = fread($fp, 10);
?>
Funkcją fopen otwarty został plik do odczytu a następnie odczytanych zostało z niego 10 znaków, a więc zmienna $tekst będzie zawierała “To jest pr”. Przesunięty został wewnętrzny wskaźnik pliku, a więc następne wywołanie linii “$tekst = fread($fp, 10)” spowoduje, że w tej zmiennej będzie tekst “zykładowy ” - poprostu następne czytanie zacząło się od miejsca, w który zakończyło czytać poprzednie wywołanie tej funkcji.
Jeszcze może praktyczny przykład - jak wczytać cały plik do zmiennej? Trzeba do tego użyć jeszcze jednej funkcji - filesize( string nazwa_pliku ). Jak widać, różni się ona od pozostałych funkcji tym, że nie pobiera jako parametr wskaźnika do pliku ale nazwę pliku. Pobieranie całości pliku do zmiennej można załatwić jedną linijką.
Przykład 11.3. Wczytywanie całości pliku
<?php
$dane = fread(fopen("nazwa_pliku", "r"), filesize("nazwa_pliku"));
?>
Funkcja fread() będzie czytać dane bez przerwy - od początku pliku do końca, ignorując znaki końca linii - dla tej funkcji to poprostu zwykły znak.
Cały plik można wczytać też w jeszcze jeden sposób. Funkcja file($nazwa_pliku) zwraca tablicę, w której każdy element jest osobnym wierszem z pliku, którego nazwa jest podana w parametrze. Funkcję tą można wykorzystać do wczytania całego pliku do jednego stringa.
Przykład 11.4. Wczytywanie całości pliku przy użyciu funkcji file
<?php
$plik = implode('', file('nazwa_pliku'));
?>
Samo wczytanie pliku do tablicy może być przydatne. Traktując plik jako bazę danych, w której każdy wiersz to jeden rekord, wczytanie takiego pliku od razu do tablicy oszczędza wiele pracy przy ręcznym rozbijaniu pliku na wiersze.
Zapis do pliku
Dane do pliku można zapisać przy pomocy funkcji fputs( int wskaznik, string napis, int długość). Jak przy większości funkcji operujących na plikach, niezbędne jest podanie wskaźnika pliku na którym chcemy operować. Zapisać można albo całą zawartość zmiennej podanej jako drugi parametr, albo tylko do pewnej długości, którą to nalezy podać jako trzeci, opcjonalny parametr (oczywiście przy pominięciu tego parametru zapisywana jest cała zmienna podana w drugim parametrze).
Zapis odbywa się w miejscu, na który wskazuje wewnętrzny wskaźnik pliku, nadpisując dane jeśli wskaźnik ten nie znajduje się na końcu pliku. Nie ma żadnej możliwości bezpośredniego zapisania danych na początku lub w środku pliku. Jedyna możliwość to wczytanie pliku do tymczasowej zmiennej, poprawienie tych danych i ponowny zapis tego pliku.
Przykład 11.5. Zapis do pliku
<?
// wczytanie starych danych
// otwarcie pliku do odczytu
$fp = fopen("plik.txt", "r");
//odczytanie danych
$stareDane = fread($fp, filesize("plik.txt"));
// zamknięcie pliku
fclose($fp)
// stworzenie nowych danych
$noweDane = "To, co chcesz, żeby było na początku\n";
$noweDane .= $stareDane;
// zapisanie nowych danych
// otwarcie pliku do zapisu
$fp = fopen("plik.txt", "w");
// zapisanie danych
fputs($fp, $noweDane);
// zamknięcie pliku
fclose($fp);
?>
Zapis na koniec pliku jest łatwy - wystarczy otworzyć plik w trybie “a” i od razu można dodować dane do pliku.
Przycinanie plików
PHP zawiera funkcję służącą do zmniejszania rozmiaru pliku do zadanej wielkości. Funkcja ftruncate(int wskaźnik, int rozmiar) służy właśnie do czegoś takiego. Należy pamiętać, że wszelkie dane, które znajdują się powyżej podanego rozmiaru, będą utracone.
Blokowanie plików
Blokowanie plików jest jednym z ważniejszych zagadanień przy używaniu plików do przechowywania danych. W zastosowaniach internetowych może dojść do takiej sytuacji, że dwie lub więcej osób jednocześnie wejdzie na stronę czy po prostu uruchomi skrypt.
Jeśli będzie to na przykład licznik odwiedzin przechowujący ilość odwiedzin w pliku, to te kilka osób będzie chciało zapisać dane do tego pliku jednocześnie. Może to doprowadzić do utraty danych z tego licznika. Wystarczy jednak zastosować mechanizm blokad aby zapobiec takiej sytuacji.
Funkcja flock( int wskaźnik, int operacja ) zakłada blokadę lub ją zdejmuje, zależnie od wartości drugiego parametru. Są 2 typy blokad: blokada dzielona, używana jeśli plik ma być odczytywany (dzielona, ponieważ więcej niż jeden skrypt może utrzymywać taką blokade na pliku) , i blokada wyłączna, zakładana jeśli plik ma być zapisywany. Drugi parametr funkcji może mieć takie wartości:
LOCK_SH
aby założyć blokadę dzieloną
LOCK_EX
aby założyć blokadę wyłączną
LOCK_UN
aby zdjąć blokadę, wszystko jedno jaką
Teraz wiadomo jak założyć i zdjąć blokadę. Ale jak wykorzystać to w praktyce? Otóż funkcja flock() zwraca wartość true lub false w zależności od tego, czy udało się założyć blokadę czy nie.
Przykładowo, jeśli na pliku założona jest blokada dzielona, to można ten plik jeszcze raz zablokować do odczytu, ale do zapisu już nie. Jeśli natomiast założona jest blokada wyłączna, to żaden inny skrypt nie może już założyć blokady do czasu aż ta blokada zostanie zdjęta.
Zależnie od zastosowania, można różnie reagować na niemożność założenia blokady. Można albo przerwać skrypt albo czekać na zdjęcie blokady.
W przypadku licznika jedne odwiedziny w tą czy tamtą nie mają znaczenia w obliczu konieczności czekania na zakończenie działania innego skryptu - pewnie będą to ułamki sekund, ale bywa z tym różnie (zwłaszcza, jeśli takich czekających jest więcej). Natomiast jeśli chodzi o blokadę bazy danych, to czekanie na zdjęcie blokady jest koniecznością.
Przykład 11.6. Licznik odwiedzin z blokowaniem bazy
<?
// Konfiguracja
// Nazwa pliku zawierającego licznik - względna do katalogu, w którym
// jest strona na której ma być licznik
$df = "lib/count.dat";
// Próba otwarcia pliku do odczytu
if(!($fp=@fopen($df, "r"))){
// Jeśli plik jeszcze nie istnieje, to jest inicjowany wartością 0
$count=0;
}
else { // jeśli istnieje, to jego wartość jest odczytywana a plik zamykany
$count = fgets($fp, 100);
fclose($fp);
}
// Zwiększenie licznika o 1
$count+=1;
// Otwarcie pliku do zapisu
$fp = fopen($df, "w");
// Blokada - jeśli plik już jest zablokowany, to skrypt go zamyka i kończy
// działanie
if(!flock($fp, LOCK_EX)){
fclose($fp);
return;
} else { // Jeśli nie jest zablokowany, to następuje blokada i zapis danych
fputs($fp, $count);
flock($fp, LOCK_UN);
fclose($fp);
}
// Wyświetlenie stanu licznika
echo $count;
?>
Ten plik możemy zapisać np. jako count.php i w odpowiednim miejscu na stronie, gdzie ma się pojawić licznik, należy wpisać <?include "count.php"?>. Jeśli pojawią się błedy w stylu “Permission denied” oznacza to, że coś jest nie tak z prawami dostępu do pliku z danymi, a jeśli jeszcze on nie istnieje, to z prawami do katalogu gdzie ma być ten licznik. Serwer WWW powinien mieć prawa zapisu do tego pliku/katalogu.
Funkcje informacyjne
Przy skryptach przeznaczonych do obsługi serwera czy na przykład analizujących system plików niezbędne jest uzyskanie informacji o konkretnym pliku. PHP oferuje cały zestaw funkcji zwracających dane o pliku o podanej ścieżce. Chyba najlepiej je wypunktować.
Funkcje informacyjne
fileatime($nazwa_pliku)
zwraca czas ostatniego odczytu pliku; czas ten jest zwracany w postaci timestamp (co to jest timestamp i jak tego używać - w następnym rozdziale)
filectime($nazwa_pliku)
zwraca czas ostatniej modyfikacji i-węzła (dotyczy tylko systemów Unix) w formacie timestamp
filemtime($nazwa_pliku)
zwraca czas ostatniej modyfikacji pliku w formacie timestamp
fileowner($nazwa_pliku)
zwraca identyfikator użytkownika, który jest właścicielem pliku
filegroup($nazwa_pliku)
zwraca identyfikator grupy, do której należy plik (tylko Unix)
fileinode($nazwa_pliku)
zwraca numer i-węzła do którego przypisany jest plik (tylko Unix)
fileperms($nazwa_pliku)
zwraca prawa dostępu do pliku
filesize($nazwa_pliku)
zwraca wielkość pliku w bajtach
filetype($nazwa_pliku)
zwraca typ pliku (tylko UNIX); możliwe typy to “fifo”, “char”, “dir”, “block”, “link”, “file”, “unknown” dla odpowiednio kolejek fifo, urządzeń znakowych, katalogów, urządzeń blokowych, dowiązań, zwykłych plików i nieznanych typów
stat($nazwa_pliku)
funkcja ta zwraca tablicę zawierającą pełne informacje o pliku. Kolejne indeksy zawierają:
urządzenie
i-węzeł
tryb zabezpieczenia i-węzła
liczba dowiązań
id właściciela
id grupy
typ urządzenia jeśli urządzenie jest oparte na i-węzłach
rozmiar w bajtach
czas ostatniego dostępu
czas ostatniej modyfikacji i-węzła
czas ostatniej zmiany
rozmiar bloku
liczba bloków
Jeśli funkcja ta jest wywołana na dowiązaniu symbolicznym, to informacje te będą dotyczyły pliku, na który wskazuje dowiązanie. Aby uzyskać informacje o samym dowiązaniu, należy użyć funkcji lstat() (zwracane wartości są takie same jak w przypadku funkcji stat() )
Funkcje logiczne (zwracają wartość true lub false)
is_dir($nazwa_pliku)
czy plik o podanej ścieżce jest katalogiem
is_executable($nazwa_pliku)
czy plik jest wykonywalny
is_file($nazwa_pliku)
czy plik jest normalnym plikiem
is_link($nazwa_pliku)
czy plik jest dowiązaniem
is_readable($nazwa_pliku)
czy plik można czytać
is_writable($nazwa_pliku)
czy do pliku można pisać
is_uploaded_file($nazwa_pliku)
czy plik został przesłany z formularza
Operacje na plikach i katalogach
Kopiowanie
Do kopiowania plików służe funkcja o jakże zaskakującej nazwie copy(). Pierwszy parametr to plik źródłowy a drugi to plik lub katalog docelowy. Funkcja ta zwraca wartość true jeśli kopiowanie się powiodło lub false w przeciwnym przypadku. Dobrze jest sprawdzać czy kopiowanie się powiodło.
Przykład 11.7. Sprawdzanie powodzenia kopiowania
<?php
copy($source, $destination) or die("Błąd przy kopiowaniu");
?>
Przenoszenie i zmiana nazwy
Funkcja służaca do przenoszenia i zmiany nazwy pliku sugeruje tylko tą drugą funkcję, jednak bardzo dobrze spisuje się w obu zastosowaniach. Funkcja rename() pobiera 2 argumenty: nazwę pliku źródłowego oraz nazwę pliku docelowego jeśli funkcja ma zmienić nazwę, nazwę katalogu jeśli plik ma być przeniesiony, lub ścieżkę wraz z nową nazwą, jeśli plik ma być przeniesiony ze zmianą nazwy.
Przykład 11.8. Sposoby użycia funkcji rename
<?
rename("aaa", "bbb"); // zmiana nazwy pliku "aaa" na "bbb"
rename("bbb", "test/"); // przeniesienie pliku "bbb" do katalogu "test"
rename("aaa", ".."); // przeniesienie pliku "aaa" do katalogu nadrzędnego
rename("aaa", "test/bbb"); // przeniesienie pliku "aaa" do katalogu "test"
// ze zmianą nazwy na "bbb"
?>
Usuwanie
Usuwanie plików jest rzeczą sprawiającą najwięcej trudności początkującym programistom PHP. Dzieje się tak głównie dlatego, że funkcja usuwająca pliki nazywa się unlink($nazwa_pliku), co jest wynikiem tego, że PHP powstało początkowo pod systemy Uniksowe. Funkcja ta może nie działać pod systemami Windows - tam najoczywistszym rozwiązaniem jest wywołanie programu del z odpowiednim parametrem.
Do usuwania katalogów służy funkcja rmdir($nazwa).
Tworzenie katalogów
Tworzeniem katalogów zajmuje się funkcja mkdir($nazwa_katalogu, $tryb). Drugi parametr określa tryb utworzenia katalogu (prawa dostępu). Nie ma w zasadzie co tu opisywać - funkcja zwraca wartość true jeśli katalog został utworzony lub false w przeciwnym przypadku.
Prawa dostępu (tylko UNIX)
Unix i pochodne, jako systemu przeznaczone dla wielu użytkowników, zawierają system zabezpieczania dostępu do plików przez niepowołane osoby. System ten opiera się o przydzielanie praw poszczególnym osobom (a konkretniej ich kontom systemowym) oraz grupom, do których użytkownicy należą.
Każdemu plikowi i katalogowi w systemie można przypisać 3 komplety praw. Każdy z tych kompletów to: prawo wykonywania (litera `x' lub liczba 1) - w przypadku katalogów oznacza to możliwość `wejścia' w niego, prawo zapisu (litera `w' lub liczba 2) i prawo odczytu (litera `r' lub liczba 4).
Pierwszy komplet tych praw dotyczy właściciela pliku, drugi grupy a trzeci użytkowników, którzy nie są właścicielami ani nie należą do grupy. Liczby przypisane konkretnym prawom służą do zapisu ósemkowego. Zapis taki to 3 cyfry, z których każda odpowiada kompletowi praw - sumie liczb oznaczających prawa.
Przyładowo, liczba 7 to komplet praw wykonywania, zapisu i odczytu (1+2+4=7) a liczba 5 to prawo odczytu i wykonywania (1+4=5). Czyli aby nadać właścicielowi komplet praw, grupie odczyt i zapis a reszcie tylko odczyt, należy ustawić prawa “0764″ (cyfra zero na początu służy do poinformowania PHP, że liczba zapisana jest w formacie ósemkowym).
Do ustawiania praw dostępu służy funkcja chmod($nazwa_pliku, $tryb), gdzie drugi parametr to prawa dostępu zapisane w formacie ósemkowym. Inne funkcje przydatne przy pracy z systemem zabezpieczeń to chown($nazwa_pliku, $user), zmieniająca właściciela pliku, i chgrp($nazwa_pliku, $grupa), zmieniająca grupę.
Ustawienie odpowiednich praw dostępu to sprawa bardzo ważna w przypadku skryptów zapisujących coś do plików. Błąd “Permission denied” zdarza się bardzo często i można go rozwiązać właśnie przez ustawienie odpowiednich praw. Aby skrypt mógł coś zapisać w pliku, niezbędne jest ustawienie prawa zapisu do tego pliku. PHP zazwyczaj pracuje jako użytkownik nobody lub http - można to sprawdzić wywołując funkcję phpinfo().
Przetwarzanie ścieżki
PHP posiada wiele funkcji do analizy i przetwarzania zmiennych tekstowych, które zawierają ścieżkę do pliku. Funkcja basename($path) zwraca nazwę pliku a dirname($path) wszystko oprócz nazwy pliku.
Z kolei funkcja pathinfo($path) zwraca tablicę asocjacyjną zawierającą informację o ścieżce podanej jako parametr - klucz “dirname” zawiera nazwę katalogu, “basename” nazwę pliku a “extension” - rozszerzenie pliku.
Przykład 11.9. Przetwarzanie ścieżki
<?php
$path = "/home/httpd/html/index.html";
echo dirname($path); // wyświetli "/home/httpd/html"
echo basename($path); // wyświetli "index.html"
$arr = pathinfo($path);
echo $arr["dirname"]; // wyświetli "/home/httpd/html"
echo $arr["basename"]; // wyświetli "index.html"
echo $arr["extension"]; // wyświetli "html"
?>
Operacje na katalogach
Istnieją 2 mechanizmy przeglądania zawartości katalogów. Pierwszy to mechanizm oparty na dwóch funkcjach: opendir($katalog) i readdir($handle). Funkcja opendir($katalog) otwiera katalog o podanej nazwie i zwraca uchwyt do niego. Z kolei funkcja readdir($handle) za każdym wywołaniem zwraca nazwę kolejnego pliku/katalogu z otwartego katalogu.
Przykład 11.10. Wyświetlenie wszystkich nazw plików z katalogu /tmp
<?php
if ($dir = @opendir("/tmp")) {
while($file = readdir($dir)) {
echo "$file\n";
}
closedir($dir);
}
?>
Drugi sposób oparty jest na mechanizmie pseudo-obiektowym.
Przykład 11.11. Odczytywanie zawartości katalogu przy uzyciu funcji dir
<?php
$d = dir("/etc");
echo "Handle: ".$d->handle."<br>\n";
echo "Path: ".$d->path."<br>\n";
while($entry=$d->read()) {
echo $entry."<br>\n";
}
$d->close();
?>
Kilka słów omówienia. Obiekt zwraceny przez funkcję dir($katalog) posiada 3 metody: metoda handle() zwraca zwykły uchwyt, który może być używany w funkcji readdir(), metoda path() zwraca string zawierający ścieżkę do katalogu a metoda read() zwraca kolejne nazwy plików/katalogów, podobnie jak funkcja readdir().
Dla funkcji readdir() i metody read() nie ma różnicy między plikiem lub katalogiem - zwracane są wszystkie nazwy z katalogu. A czy to jest katalog programista musi sam sprawdzić za pomocą funkcji is_dir().
Spis treści
PHP posiada wiele funkcji, dzięki którym można przetwarzać zapis daty.
Podstawowym sposobem zapisu daty w systemie Unix i pochodnych jest tzw. timestamp. Jest to ilość sekund jaka upłynęła od 1.1.1970 (moment ten nazywany jest Epoch). Zapis taki daje najwięcej możliwości - łatwo go przetwarzać na inne zapisy, dodawać, odjemować odpowiednie przedziały czasu i zapisywać w bazach danych.
Sprawdzanie poprawności
Jedną z podstawowych spraw przy odbieraniu danych od użytkownika to sprawdzenie ich poprawności. Funkcja checkdate() przyjmuje 3 argumenty - odpowiedno miesiąc, dzień i rok (kolejność może się wydawać nielogiczna, lecz w takiej kolejności Amerykanie zapisuję datę), których poprawność ma być sprawdzony. Funkcja zwraca logiczną wartość TRUE jeśli data jest poprawna.
Funkcja ta sprawdza, czy rok ma wartości pomiędzy 1 a 32767, miesiąc między 1 a 12 a dzień od jeden do liczby zależnej od danego miesiąca. Uwzględniane są lata przestępne. W poniższym przykładzie sprawdzane są dane przekazane metodą GET. Dla wywołania test.php?dzien=12&miesiac=10&rok=1992 skrypt wyświetli “Data jest poprawna” a dla test.php?dzien=2&miesiac=14&rok=1980 - “Data jest niepoprawna”.
Przykład 12.1. Przykład skryptu sprawdzającego poprawność daty
<?php
if (checkdate( $_GET['miesiac'], $_GET['dzien'], $_GET['rok'])) {
echo 'Data jest poprawna';
} else {
echo 'Data jest niepoprawna';
}
?>
Pobieranie aktualnej daty
Aktualną datę można uzyskać tylko w formacie timestamp. Datę taką zwraca funkcja time(). Dokładniejszy czas można uzyskać dzięki funkcji microtime() - dane zwracane przez tą funkcję zapisane są nieco dziwnie, ponieważ zwracany jest string zawierający oddzielone spacją odpowiednio część mikrosekundową i sekundową, czyli “msec sec”.
Przykład 12.2. Funkcja zwracająca czas z mikrosekundami
<?php
function getmicrotime()
{
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
?>
Informacja ta może zostać użyta do sprawdzenia czasu wykonania danego skryptu.
Przykład 12.3. Liczenie czasu generowania strony
<?php
$start = getmicrotime();
for ($i = 0; $i < 10000; $i++) {
$str = 'test';
}
$end = getmicrotime();
echo '<!-- strona wygenerowana w '.($end - $start).' sekund -->';
?>
W ten sposób można też sprawdzać wydajność różnych rozwiązań. Skrypty wykonywane są zazwyczaj tak szybko, że mikrosekundy to za duża jednostka. Ograniczenie to można obejść przez wykonywanie konkretnych instrukcji w pętli, 100 czy nawet 1000 razy, podobnie jak w powyższym przykładzie.
Funkcję konwertujące datę do podanego formatu jako parametr przyjmują timestamp daty do przekonwertowania. Parametr ten można jednak pominąć i zamiast określonej daty użyta zostanie aktualna data i czas. Pozwala to na uzyskanie aktualnego czasu w formacie innym niż timestamp.
Konwersja daty do formatu timestamp
Timestamp inny niż aktualny można uzyskać na różne sposoby, które trzeba wykorzystać odpowiednio do zastosowania.
Jeśli dostępna jest `rozbita' data, czyli w osobnych zmiennych dzień, miesiąc, rok itp., lub można do takiej sytuacji doprowadzić przez odpowiednie użycie funkcji explode() lub substr(), można użyć funkcji mktime(). Funkcja ta jako argumenty przyjmuje odpowiednio godzinę, minutę, sekundę, miesiąc, dzień, rok i opcjonalnie informację o “daylight saving”, czyli czasie letnim (wartość 1 oznacza czas letni, 0 w przeciwnym przypadku, lub -1, wartość domyślną, jeśli PHP ma samo zgadywać).
Przykład 12.4. Generowanie timestampu
<?php
$dzien = 10;
$miesiac = 4;
$rok = 2002;
$godzina = 12;
$minuta = 32;
$sekunda = 0;
$ts = mktime($godzina, $minuta, $sekunda, $miesiac, $dzien, $rok);
?>
Jeśli data jest zapisana jako string, lecz w jednym z formatów rozpoznawanych przez PHP, string ten można przekonwertować do timestamp używając funkcji strtotime(). Data składa się z kilku elementów, oddzielonych „białymi znakami” (spacja, znak tabulacji). Białe znaki można pominąć, jeśli nie powoduje to żadnych wieloznaczności. Elementy daty to część kalendarzowa, część zegarowa, strefa czasowa, część wyłącznie liczbowa. Kolejność tych elementów nie ma znaczenia. Dwa inne elementy, dzień tygodnia i przesunięcie czasowe, zostaną opisane w dalszej części rozdziału.
Część kalendarzowa
Część ta określa konkretny dzień roku. Może być podana na jeden z wielu sposobów.
1970-09-17 # Zapis zgodny z ISO 8601.
70-9-17 # Domyślnie przyjmuje się bieżący wiek
70-09-17 # Wszystkie początkowe zera są ignorowane
9/17/72
24 September 1972
24 Sept 72 # Specjalny skrót słowa September
24 Sep 72 # Wszędzie dopuszczalne są trzyliterowe skróty
Sep 24, 1972
24-sep-72
24sep72
Dopuszczalne są angielskie nazwy miesięcy: `January', `February', `March', `April', `May', `June', `July', `August', `September', `October', `November' `December' oraz ich trzyliterowe skróty.
Część zegarowa
Dopuszczalne formaty:
<pre>
20:02:0
20:02
8:02pm
20:02-0500 # z podaniem strefy czasowej
Mówiąc ogólnie, podstawowy format to gg:mm:ss, przy czym część sekundową można pominąć. Jeśli na końcu dodany zostanie wskażnik am (rano - inna forma to a.m.) lub pm (po południu - p.m.), to część godzinowa ograniczona jest do zakresu 1-12. W takim zapisie północ to 12am, południe - 12pm; część minutowa może być pominęta.
Opcjonalnie, od razu po czasie może zostać podana strefa czasowa w formacie “zggmm”, gdzie “z” to odpowiedni znak + lub -, zależnie od strefy, gg to ilość godzin a mm ilość minut przesunięcia.
Strefa czasowa
Strefa czasowa może zostać określona tak samo jak w przypadku informacji “doklejonej” do części zegarowej.
Część liczbowa
Liczby w postaci rrrrmmdd, jeśli wcześniej nie było części kalendarzowej, traktowane są jako te części. Podobnie liczby w postaci ggmm jest traktowana jako część zegarowa, jeśli nie było takiej wcześniej.
Dokładny opis formatów rozpoznawanych przez funkcję strtotime() można znaleźć pod adresem http://www.gnu.org/software/tar/manual/html_chapter/tar_7.html
Formatowanie daty
PHP udostępnia kilka funkcji służących do zapisywania daty w preferowanym formacie. Podstawowa to date. Pierwszym jej argumentem jest ciąg tekstowy, który służy jako opis formatu. Każda litera wstawiona do tego ciągu zostanie zamieniona na pewien element daty. Na przykład litera `Y' zostanie zamieniona na rok w postaci czterocyfrowej. Pełną listę elementów formatu można znaleźć w opisie funkcji date().
Przykład 12.5. Przykład użycia funkcji date
<?php
// Zakładając, że dzisiaj jest 7 luty 2005, 22:31:44
$today = date("F j, Y, g:i a"); // February 7, 2005, 22:31 pm
$today = date("m.d.y"); // 07.02.05
$today = date("j, n, Y"); // 7, 2, 2005
$today = date("Ymd"); // 20050207
$today = date('h-i-s, j-m-y, it is w Day z '); // 22-31-44, 7-02-05, 3128 3144 1 Monpm05 37
$today = date('\i\t \i\s \t\h\e jS \d\a\y.'); // It is the 7th day.
$today = date("D M j G:i:s T Y"); // Mon Feb 7 22:31:44 CET 2005
$today = date('H:m:s \m \t\o\ \m\i\e\s\i\a\c'); // 22:02:44 m to miesiac
$today = date("H:i:s"); // 22:02:44
?>
Jak widać, większość liter ma swoje znaczenie, więc nie ma możliwości wstawienia zwykłego tekstu, oprócz zamieniania ich na sekwencje escape.
Domyślnie wyświetlana jest odpowiednio sformatowana data i czas bieżący. Można to zmienić podając opcjonalny, drugi parametr - czas w formacie timestamp. Wtedy format będzie dotyczył właśnie tego czasu.
Funkcja date wszelkie “tekstowe” wartości zwraca w języku angielskim. Istnieje jednak inna funkcja, strftime, która, podobnie jak funkcja date, służy do formatowania daty, jednak różni się trochę zachowaniem. Po pierwsze, elementy formatu (inne niż w funkcji date) są nie pojedyńczymi literami, ale zawsze poprzedzone są znakiem procenta, przez co można wstawiać do formatu zwykły tekst. Druga ważna różnica to uwzględnianie ustwień regionalnych systemu locale. Wystarczy ustawić odpowiednie locale (dla języka polskiego - pl_PL i strftime zacznie mówić po naszemu).
Przykład 12.6. Użycie funkcji strftime
<?php
setlocale(LC_TIME, "pl_PL");
echo strftime("%A");
?>
Powyższy program wyświetli:
poniedziałek
Tworzenie daty względnej do aktualnej (np. `za 2 dni')
W PHP niejako standardowym sposobem przechowywania informacji o dacie jest wspomniany wcześniej format timestamp. Modyfikacje takiego zapisu przeprowadza się przez dodanie lub odjęcie odpowiedniej liczby sekund. Na przykład, aby stworzyć datę o godzinę w przód od aktualnej, wystarczy dodać do niej 3600 sekund, czyli tyle, ile jest w sekund w godzinie.
Przykład 12.7. Tworzenie daty o godzinę w przód
<?php
$czas_akt = time();
$za_godz = $czas_akt + 3600;
echo date("r", $za_godz); // Wyświetli datę 'za godzinę'
?>
Podobnie sprawa wygląda z dodawaniem dni czy tygodni. Gorzej jest w przypadku miesięcy - przecież nie wiadomo z góry ile sekund ma miesiąc. Problem ten można rozwiązać na kilka sposobów. Można rozbić datę na poszczególne części (dzień, miesiąc, rok), dodać jedynkę do miesiąca, sprawdzić, czy przypadkiem nie wyszedł nam miesiąc trzynasty (co się stanie jeśli dodamy miesiąc do grudnia) i w takim przypadku odpowiednio zareagować.
Przykład 12.8. Data “za miesiąc”
<?php
$day = date('d'); // dzień
$month = date('m'); // miesiąc
$year = date('Y'); // rok
// dodanie jedynki do miesiąca
$month++;
// sprawdzenie czy licznik się nie przekręcił
if ($month == 13) {
$month = 1;
$year++;
}
?>
Jest jednak prostrza metoda tworzenia daty względnej. Można do tego użyć funkcji strtotime(). Jako jej argument można podać względny czas.
Przykład 12.9. Tworzenie względnej daty za pomocą funkcji strtotime
<?php
echo strtotime("now"), "\n"; // teraz
echo strtotime("+1 day"), "\n"; // jutro
echo strtotime("+1 week"), "\n"; // za tydzień
echo strtotime("+1 week 2 days 4 hours 2 seconds"), "\n"; // za tydzień, dwa dni,
// 4 godziny i 2 sekundy
echo strtotime("next Thursday"), "\n"; // następny czwartek
echo strtotime("last Monday"), "\n"; // poprzedni poniedziałek
?>
Porównywanie dat
Daty mogą być porównywane tylko i wyłącznie jeśli są przechowywane w tym samym formacie. Jako że w PHP nie ma zmiennej typu “data”, musi być ona przechowywana jako timestamp lub tekst. Z kolei postać tekstowa może być skrajnie różna zależnie od standardów narodowych czy też fantazji programisty - tu widać przewagę formatu timestamp.
Jeśli daty są już w tej samej postaci, można je porównać po prostu przez operator porównania. Dodatkowo, jeśli data jest w formacie timestamp, można użyć operatorów matematycznych (< czy >) dla ustalenia która data jest “nowsza”.
Przykład 12.10. Porównywanie daty w formacie timestamp
<?php
$time1 = mktime(19, 30, 0);
$time2 = mktime(20, 0, 0);
if ($time1 > $time2) {
echo "Czas w zmiennej time1 jest późniejszy";
} else {
echo "Czas w zmiennej time2 jest późniejszy";
}
?>
Porównywanie dat w formacie timestamp jest łatwe, jeśli potrzebne jest porównanie z dokładnością “co do sekundy”. Sprawa się komplikuje, jeśli potrzebne jest stwierdzenie, na przykład czy dwie daty są z tego samego dnia. Aby to stwierdzić, trzeba rozbić datę i porównywać składowe. Kod taki można przenieść do osobnej funkcji, aby wygodnie porównywać daty.
Przykład 12.11. Sprawdzanie czy daty są z tego samego dnia
<?php
function sameDay($ts1, $ts2)
{
if (date("Y", $ts1) != date("Y", $ts2)) {
return False;
}
if (date("m", $ts1) != date("m", $ts2)) {
return False;
}
if (date("d", $ts1) != date("d", $ts2)) {
return False;
}
return True;
}
$date1 = mktime(19, 30, 0, 12, 10, 2001);
$date2 = mktime(10, 12, 0, 12, 10, 2001);
$date3 = mktime(19, 30, 0, 12, 11, 2001);
if (sameDay($date1, $date2)) {
echo "Daty 1 i 2 są z tego samego dnia";
}
if (sameDay($date1, $date3)) {
echo "Daty 1 i 3 są z tego samego dnia";
}
?>