Pobierz ksiazke

Transkrypt

Pobierz ksiazke
Spis Treści
SPIS TREŚCI............................................................................................................................................................ 1
WSTĘP ...................................................................................................................................................................... 7
Dla kogo jest przeznaczona ta książka ............................................................................................................... 7
Konwencje .......................................................................................................................................................... 7
Omówienie książki.............................................................................................................................................. 7
Od autora ........................................................................................................................................................... 8
Przykłady kodu ................................................................................................................................................... 8
CZYM JEST PHP ...................................................................................................................................................... 8
DLACZEGO POWINIENEŚ UŻYĆ PHP......................................................................................................................... 9
GDZIE SZUKAĆ POMOCY .......................................................................................................................................... 9
PODZIĘKOWANIA ................................................................................................................................................... 10
O AUTORZE............................................................................................................................................................ 10
ROZDZIAŁ 1. KOMPILACJA I INSTALOWANIE PHP................................................................................ 11
WSTĘP ................................................................................................................................................................... 11
POBIERANIE PHP................................................................................................................................................... 11
INSTALOWANIE WERSJI BINARNEJ .......................................................................................................................... 11
Binarna instalacja dla Windows ...................................................................................................................... 11
Instalowanie PHP w postaci modułu ISAPI................................................................................................. 12
Użycie PHP jako CGI................................................................................................................................... 14
Inne instalacje binarne..................................................................................................................................... 14
KOMPILOWANIE PHP ............................................................................................................................................ 15
Kompilowanie PHP w Uniksach ...................................................................................................................... 15
Kompilacja modułu CGI .............................................................................................................................. 15
Kompilacja PHP jako statycznie dołączanego modułu Apache................................................................... 17
Kompilacja PHP do postaci dynamicznie ładowanego modułu Apache ..................................................... 17
Podsumowanie kompilacji PHP w systemach Unix .................................................................................... 18
Kompilowanie PHP w środowisku Windows ................................................................................................... 18
Podsumowanie kompilacji PHP....................................................................................................................... 20
KONFIGUROWANIE PHP ........................................................................................................................................ 20
Korzystanie z pliku php.ini ............................................................................................................................... 20
Inne metody zmiany konfiguracji PHP............................................................................................................. 21
PODSUMOWANIE ................................................................................................................................................... 22
ROZDZIAŁ 2. JĘZYK .......................................................................................................................................... 23
WSTĘP ................................................................................................................................................................... 23
OGÓLNE INFORMACJE NA TEMAT SKŁADNI ............................................................................................................ 23
TYPY ..................................................................................................................................................................... 24
Liczby — całkowite i zmiennoprzecinkowe ...................................................................................................... 24
Ciągi ................................................................................................................................................................. 24
Tablice.............................................................................................................................................................. 25
ZMIENNE I STAŁE ................................................................................................................................................... 26
Zmienne predefiniowane .................................................................................................................................. 26
Zasięg zmiennych ............................................................................................................................................. 30
Stałe.................................................................................................................................................................. 31
OPERATORY I KOLEJNOŚĆ OPERATORÓW ............................................................................................................... 31
PROGRAMOWANIE PRZEPŁYWU STEROWANIA ....................................................................................................... 32
if, else, elseif ..................................................................................................................................................... 32
while ................................................................................................................................................................. 32
do .. while ......................................................................................................................................................... 32
for ..................................................................................................................................................................... 33
foreach.............................................................................................................................................................. 33
switch................................................................................................................................................................ 33
break i continue ................................................................................................................................................ 35
include i require ............................................................................................................................................... 36
FUNKCJE ................................................................................................................................................................ 36
Klasy i programowanie obiektowe................................................................................................................... 37
PORÓWNYWANIE WZORCÓW ................................................................................................................................. 39
Podsumowanie ................................................................................................................................................. 39
ROZDZIAŁ 3. FORMULARZE I COOKIE....................................................................................................... 40
WSTĘP ................................................................................................................................................................... 40
OBSŁUGA FORMULARZY W PHP............................................................................................................................ 41
Skalarne i wielowartościowe elementy formularza.......................................................................................... 41
Alternatywne metody odczytywania wartości z formularza ............................................................................. 42
Użycie formularzy do przesyłania plików ........................................................................................................ 45
Użycie rysunku jako przycisku wysłania danych.............................................................................................. 45
KONTROLA POPRAWNOŚCI DANYCH FORMULARZA................................................................................................ 46
Kontrola danych za pomocą wyrażeń regularnych.......................................................................................... 46
Kontrola poprawności za pomocą sprawdzania typów.................................................................................... 47
Klasa Validator ................................................................................................................................................ 48
COOKIE ................................................................................................................................................................. 49
WAŻNE ZAGADNIENIA PROGRAMOWANIA DLA WWW .......................................................................................... 50
Obsługa nieprawidłowych danych ................................................................................................................... 50
Obsługa i formatowanie wyświetlanych danych .............................................................................................. 52
PODSUMOWANIE ................................................................................................................................................... 57
ROZDZIAŁ 4. OPERACJE NA PLIKACH........................................................................................................ 58
WSTĘP ................................................................................................................................................................... 58
ODCZYT I ZAPIS PLIKÓW ........................................................................................................................................ 58
UŻYCIE GNIAZD ..................................................................................................................................................... 59
UŻYCIE POTOKÓW ................................................................................................................................................. 60
KLASA FILE ........................................................................................................................................................... 61
PODSUMOWANIE ................................................................................................................................................... 61
ROZDZIAŁ 5. WYSYŁANIE PLIKÓW PRZEZ FORMULARZ.................................................................... 62
WSTĘP ................................................................................................................................................................... 62
WYSYŁANIE POJEDYNCZEGO PLIKU ....................................................................................................................... 62
PUŁAPKI ................................................................................................................................................................ 64
PRZESYŁANIE WIELU PLIKÓW ................................................................................................................................ 64
BEZPIECZEŃSTWO ................................................................................................................................................. 65
PODSUMOWANIE ................................................................................................................................................... 66
ROZDZIAŁ 6. WSPÓŁPRACA Z BAZAMI DANYCH.................................................................................... 67
WSTĘP ................................................................................................................................................................... 67
WPROWADZENIE ................................................................................................................................................... 67
FUNKCJE BAZ DANYCH .......................................................................................................................................... 67
MYSQL................................................................................................................................................................. 68
2
Spis Treści
Rozpoczynamy pracę z MySQL ........................................................................................................................ 68
Użycie MySQL.................................................................................................................................................. 68
ODBC................................................................................................................................................................... 71
Podstawy ODBC .............................................................................................................................................. 71
Instalowanie i kompilowanie unixODBC .................................................................................................... 72
Kompilowanie PHP z obsługą unixODBC .................................................................................................. 72
Instalowanie sterownika OOB...................................................................................................................... 72
Konfigurowanie OOB .................................................................................................................................. 72
Korzystanie z ODBC ........................................................................................................................................ 73
PHPLIB ................................................................................................................................................................ 74
PRZECHOWYWANIE DANYCH Z FORMULARZY ........................................................................................................ 75
WYKORZYSTANIE MOŻLIWOŚCI BAZY DANYCH ..................................................................................................... 77
PODSUMOWANIE ................................................................................................................................................... 78
ROZDZIAŁ 7. SESJE I STAN APLIKACJI....................................................................................................... 80
WSTĘP ................................................................................................................................................................... 80
PODSTAWY MECHANIZMU SESJI ............................................................................................................................. 80
WBUDOWANY W PHP MECHANIZM ZARZĄDZANIA SESJAMI .................................................................................. 81
Rozpoczęcie pracy z sesjami w PHP ................................................................................................................ 81
Przesyłanie identyfikatora sesji bez użycia cookie........................................................................................... 83
Zapisywanie zmiennych sesji w bazie danych .................................................................................................. 85
Inne funkcje i opcje dotyczące sesji.................................................................................................................. 89
UŻYCIE PHPLIB DO OBSŁUGI SESJI ....................................................................................................................... 90
TWORZENIE WŁASNEGO MECHANIZMU SESJI ......................................................................................................... 92
INŻYNIERIA PROGRAMOWANIA A SESJE ................................................................................................................. 92
PODSUMOWANIE ................................................................................................................................................... 94
ROZDZIAŁ 8. UWIERZYTELNIANIE.............................................................................................................. 95
WSTĘP ................................................................................................................................................................... 95
PODSTAWOWE UWIERZYTELNIANIE W APACHE ..................................................................................................... 95
AKTUALIZACJA PLIKU .HTACCESS PRZY UŻYCIU PHP............................................................................................ 97
PODSTAWOWE UWIERZYTELNIANIE ZA POMOCĄ PHP ........................................................................................... 99
KOMPLETNY SYSTEM UWIERZYTELNIANIA OPARTY O PHP ................................................................................. 100
PODSUMOWANIE ................................................................................................................................................. 104
ROZDZIAŁ 9. NIEZALEŻNOŚĆ OD PRZEGLĄDARKI ............................................................................. 105
WSTĘP ................................................................................................................................................................. 105
ROZPOCZYNAMY ................................................................................................................................................. 105
WEWNĘTRZNE FUNKCJE PHP .............................................................................................................................. 106
Dodatkowe informacje na temat Browscap ................................................................................................... 106
BROWSERHAWK .................................................................................................................................................. 109
WYKORZYSTANIE DANYCH O PRZEGLĄDARCE..................................................................................................... 113
PODSUMOWANIE ................................................................................................................................................. 114
ROZDZIAŁ 10. URUCHAMIANIE................................................................................................................... 115
WSTĘP ................................................................................................................................................................. 115
INŻYNIERIA PROGRAMOWANIA A URUCHAMIANIE ............................................................................................... 115
Projekt aplikacji ............................................................................................................................................. 115
Definiowanie standardów programowania.................................................................................................... 116
Przegląd oprogramowania............................................................................................................................. 116
Testowanie...................................................................................................................................................... 117
Uruchamianie................................................................................................................................................. 117
PROGRAMOWANIE DEFENSYWNE ......................................................................................................................... 118
WŁASNA OBSŁUGA BŁĘDÓW................................................................................................................................ 122
PHP – Kompendium wiedzy
3
ZAAWANSOWANA OBSŁUGA BŁĘDÓW ................................................................................................................. 125
PODSUMOWANIE ................................................................................................................................................. 129
BIBLIOGRAFIA ..................................................................................................................................................... 130
ROZDZIAŁ 11. PONOWNE WYKORZYSTANIE KODU ............................................................................ 131
WSTĘP ................................................................................................................................................................. 131
PONOWNE WYKORZYSTANIE KODU A INŻYNIERIA PROGRAMOWANIA .................................................................. 131
PONOWNE UŻYCIE ISTNIEJĄCEGO KODU .............................................................................................................. 132
PHP ................................................................................................................................................................ 132
C/C++ ............................................................................................................................................................ 133
Java ................................................................................................................................................................ 138
Dodawanie obsługi Javy w PHP na *niksach ............................................................................................ 138
Dołączanie obsługi Javy w PHP dla Windows .......................................................................................... 139
Opcje konfiguracji Javy.............................................................................................................................. 139
COM ............................................................................................................................................................... 141
Inne metody .................................................................................................................................................... 143
PODSUMOWANIE ................................................................................................................................................. 144
BIBLIOGRAFIA ..................................................................................................................................................... 144
ROZDZIAŁ 12. ODDZIELANIE KODU HTML OD PHP ............................................................................. 145
WSTĘP ................................................................................................................................................................. 145
WPROWADZENIE ................................................................................................................................................. 145
ODDZIELENIE I INTEGRACJA PRZY UŻYCIU WBUDOWANYCH FUNKCJI PHP.......................................................... 146
Motywacja ...................................................................................................................................................... 146
Implementacja ................................................................................................................................................ 147
Czego należy unikać ....................................................................................................................................... 151
Podsumowanie: Oddzielanie i integracja przy wykorzystaniu funkcji PHP.................................................. 151
WYKORZYSTANIE SYSTEMU SZABLONÓW............................................................................................................ 152
FastTemplate .................................................................................................................................................. 152
Zaawansowane techniki użycia FastTemplate ............................................................................................... 157
PODSUMOWANIE ................................................................................................................................................. 159
BIBLIOGRAFIA ..................................................................................................................................................... 159
ROZDZIAŁ 13. FAJNY PHP.............................................................................................................................. 160
WSTĘP ................................................................................................................................................................. 160
WYSYŁANIE DO PRZEGLĄDARKI PLIKÓW INNYCH NIŻ HTML.............................................................................. 160
SKRYPTY AUTOMATYZUJĄCE .............................................................................................................................. 164
WDDX................................................................................................................................................................ 168
MONITOROWANIE SIECI ....................................................................................................................................... 172
PODSUMOWANIE ................................................................................................................................................. 174
ROZDZIAŁ 14. WITRYNY OPARTE O SZABLONY ................................................................................... 175
PODSTAWY WYKORZYSTANIA SZABLONÓW ......................................................................................................... 175
ZAPOŻYCZANIE ................................................................................................................................................... 183
PERSONALIZACJA WITRYNY................................................................................................................................. 185
OBSŁUGA WIELU JĘZYKÓW .................................................................................................................................. 187
PODSUMOWANIE ................................................................................................................................................. 189
ROZDZIAŁ 15. WITRYNY OPARTE O BAZĘ DANYCH............................................................................ 190
WSTĘP ................................................................................................................................................................. 190
PROJEKT BAZY DANYCH ...................................................................................................................................... 190
ZARZĄDZANIE DANYMI APLIKACJI....................................................................................................................... 192
WYŚWIETLANIE DANYCH .................................................................................................................................... 199
PODSUMOWANIE ................................................................................................................................................. 204
Spis Treści
4
ROZDZIAŁ 16. GENEROWANIE STATYCZNYCH STRON HTML W OPARCIU O DYNAMICZNE
DANE..................................................................................................................................................................... 205
WSTĘP ................................................................................................................................................................. 205
KONCEPCJA ......................................................................................................................................................... 205
GENEROWANIE STRON STATYCZNYCH ................................................................................................................. 205
Użycie buforowania........................................................................................................................................ 205
Użycie FastTemplate ...................................................................................................................................... 207
TECHNIKI BUFOROWANIA .................................................................................................................................... 208
PODSUMOWANIE ................................................................................................................................................. 210
ROZDZIAŁ 17. WITRYNY HANDLU ELEKTRONICZNEGO ................................................................... 211
WSTĘP ................................................................................................................................................................. 211
BEZPIECZEŃSTWO ............................................................................................................................................... 211
Zastosowanie SSL........................................................................................................................................... 211
Certyfikaty ...................................................................................................................................................... 211
Bezpieczeństwo bazy danych .......................................................................................................................... 212
PRZETWARZANIE PŁATNOŚCI ............................................................................................................................... 212
DOSTARCZANIE PRODUKTÓW .............................................................................................................................. 219
PODSUMOWANIE ................................................................................................................................................. 220
DODATEK A. FUNKCJE ................................................................................................................................... 221
DODATEK B. PREDEFINIOWANE ZMIENNE I STAŁE PHP................................................................... 367
ZMIENNE ............................................................................................................................................................. 367
Zmienne Apache ............................................................................................................................................. 367
Zmienne środowiska....................................................................................................................................... 369
Zmienne PHP ................................................................................................................................................. 369
STAŁE .................................................................................................................................................................. 370
DODATEK C. OPCJE KOMPILACJI PHP..................................................................................................... 372
BAZY DANYCH .................................................................................................................................................... 372
HANDEL ELEKTRONICZNY ................................................................................................................................... 374
GRAFIKA ............................................................................................................................................................. 374
RÓŻNE ................................................................................................................................................................. 375
--enable-inline-optimization........................................................................................................................... 376
SIEĆ ..................................................................................................................................................................... 379
DZIAŁANIE PHP .................................................................................................................................................. 379
SERWER ............................................................................................................................................................... 380
TEKST I JĘZYK ..................................................................................................................................................... 380
XML ................................................................................................................................................................... 381
DODATEK D. OPCJE KONFIGURACJI PHP ............................................................................................... 382
OGÓLNE DYREKTYWY KONFIGURACJI ................................................................................................................. 382
DYREKTYWY KONFIGURACJI POCZTY .................................................................................................................. 385
DYREKTYWY KONFIGURACJI TRYBU BEZPIECZNEGO ........................................................................................... 385
DYREKTYWY KONFIGURACJI DEBUGGERA ........................................................................................................... 385
DYREKTYWY ŁADOWANIA ROZSZERZEŃ ............................................................................................................. 385
DYREKTYWY KONFIGURACJI MYSQL ................................................................................................................. 386
DYREKTYWY KONFIGURACJI MSQL .................................................................................................................... 386
DYREKTYWY KONFIGURACJI POSTGRESQL ........................................................................................................ 386
DYREKTYWY KONFIGURACJI SYBASE .................................................................................................................. 387
DYREKTYWY KONFIGURACJI SYBASE-CT ........................................................................................................... 387
DYREKTYWY KONFIGURACJI INFORMIX .............................................................................................................. 388
DYREKTYWY KONFIGURACJI BC MATH .............................................................................................................. 389
5
PHP – Kompendium wiedzy
DYREKTYWY KONFIGURACJI MOŻLIWOŚCI PRZEGLĄDAREK ................................................................................ 389
DYREKTYWY KONFIGURACJI ZUNIFIKOWANEGO ODBC ..................................................................................... 389
DODATEK E. ZASOBY SIECI.......................................................................................................................... 390
Spis Treści
6
Wstęp
Książka ta jest przeznaczona dla programistów tworzących aplikacje WWW za pomocą PHP. Należy
zwrócić uwagę, że zostało użyte określenie aplikacje WWW a nie strony WWW lub witryny WWW. W
przeszłości w Sieci znajdowały się w większości proste strony HTML o ograniczonej możliwości interakcji.
Dzisiejszy obraz Sieci jest o wiele bardziej skomplikowany. Użytkownicy i firmy oczekują od Sieci coraz więcej.
Powoduje to powstanie coraz większej ilości dynamicznych aplikacji WWW. PHP jest idealny do tworzenia
takich aplikacji, ponieważ został zaprojektowany właśnie do realizacji tego zadania.
Dla kogo jest przeznaczona ta książka
Książka ta powinna być użyteczna dla szerokiego grona programistów WWW, ale pisana była z myślą o
średnio zaawansowanych lub zaawansowanych programistach. PHP jest językiem programowania a nie językiem
opisu strony, więc przydatne będzie doświadczenie w programowaniu. Programiści znający C lub Perla powinni
uznać PHP za język bardzo przyjazny, natomiast programiści pracujący w ASP Microsoftu (Active Server Pages)
uznają PHP za język o podobnej strukturze.
Ponieważ książka ta nie jest kierowana do początkujących programistów, podstawowe pojęcia dotyczące
programowania zostaną przedstawione bardzo skrótowo. Zakłada się, że Czytelnik zna takie pojęcia
programowania, jak funkcje, zmienne i stałe.
Konwencje
W książce przyjęto następujące konwencje:
• Kod programu i jego wyniki zaznaczone są czcionką o stałej
• Nazwy plików i katalogów zaznaczone są czcionką pochyłą.
• Komendy i elementy języka zaznaczone są czcionką o stałej
szerokości.
szerokości.
Omówienie książki
Książka zawiera zwięzłe wprowadzenie do PHP, oraz opis języka. Został w niej również przedstawiony
sposób instalacji i konfiguracji PHP.
Druga część, „Specjalne wymagania przy programowaniu WWW”, przeznaczona jest dla programistów
tradycyjnych aplikacji rozpoczynających pracę przy aplikacjach WWW. W części tej przedstawione zostały takie
zagadnienia jak: przetwarzanie formularzy, interakcję z użytkownikiem, utrzymywanie stanu oraz niezależność
od przeglądarki.
Następna część, „Zarządzanie projektem aplikacji WWW” opisuje zalety modularności i powtórnego
użycia kodu.
Część „Przykłady zastosowań” pokazuje użycie PHP na podstawie fragmentów działających już aplikacji.
Część ta łączy zagadnienia przedstawione w poprzednich częściach i pokazuje przykłady pełnej wymiany
informacji pomiędzy przeglądarką użytkownika i aplikacją zainstalowaną na serwerze WWW.
Na końcu książki znajduje się skorowidz zawierający wszystkie funkcje PHP4.
Od autora
Od około trzech lat tworzę aplikacje WWW przy użyciu PHP i ASP, jako niezależny przedsiębiorca.
Fundamentem mojego sukcesu było użycie PHP, ponieważ pozwala on na szybkie budowanie prototypów, oraz
jest wystarczająco wydajny i pewny nawet do tworzenia dużych aplikacji WWW.
Celem tej książki jest przekazanie innym programistów użytecznych informacji. Nie będę opisywał różnic
pomiędzy PHP i innymi tego typu narzędziami i nie będę zajmował się historią PHP. Wszystkie te informacje
można znaleźć na oficjalnej witrynie PHP, www.php.net. Zamiast tego pokażę zastosowanie PHP do stworzenia
aplikacji WWW. Omówię również inżynierię programowania w projektach WWW, sposoby przeniesienia
istniejącego kodu do nowych projektów WWW. Przedstawię również kilka przydatnych narzędzi napisanych dla
PHP.
Przykłady kodu
Zamieszczone przykłady kodu były tworzone i testowane pzy użyciu PHP 4.0.1 (poprawka 2) na Apache
1.3.11 działającym w systemie RedHat 6.1. Do edycji plików HTML i PHP wykorzystuję edytor Allaire Homeite
4.5.1 zainstalowany na Windows NT.
Do testowania małych fragmentów kodu stosowałem następujący szablon HTML do którego wklejałem
odpowiedni kod PHP:
<html>
<head>
<title>Nazwa przykładu</title>
</head>
<body>
<!-- Kod PHP wkleić poniżej -->
</body>
</html>
Większe fragmenty kodu były tworzone od razu razem z kodem HTML.
Czym jest PHP
PHP to język programowania przeznaczony dla programistów WWW pozwalający na szybkie tworzenie
dynamicznych aplikacji WWW. Oficjalnym rozwinięciem skrótu PHP jest „PHP: Hypertext Preprocessor”
(preprocesor hipertekstu). Jest to język programowania osadzany w HTML składniowo podobny do C, Perla i
Javy. Na wydruku 1. przedstawiony jest przykład kodu PHP.
Wydruk 1. Prosty przykład kodu PHP
<html>
<head>
<title>Prosty przykład kodu PHP</title>
</head>
<body>
<?php
echo "Witajcie w PHP!" ;
?>
</body>
</html>
Po uruchomieniu tego przykładu (poprzez odpowiednio skonfigurowany serwer WWW) generowany jest
kod HTML zamieszczony na wydruku 2.
Wydruk 2. Wynik działania wydruku 1
<html>
<head>
<title>Prosty przykład kodu PHP</title>
</head>
<body>
Witajcie w PHP! </body>
</html>
Preprocesor PHP wykonuje cały kod zawarty pomiędzy znacznikami <?php i ?> umieszczonymi w kodzie
HTML i zwraca wynik w postaci tekstu. Nie jest to szczególnie interesujący, ale pokazuje jak łatwo można
umieszczać kod PHP w kodzie HTML. Należy pamiętać, że kod ten jest wykonywany na serwerze WWW a nie
na kliencie. Oznacza to, że przeglądarka nie wie, że do stworzenia strony był używany PHP. Otrzymuje ona po
prostu strumień kodu HTML, identycznie jak w przypadku zwykłych stron. Więcej na ten temat znajduje się w
Wstęp
8
części „Specjalne wymagania przy programowaniu WWW”.
Dlaczego powinieneś użyć PHP
PHP jest pełnowartościowym językiem programowania pozwalający na tworzenie aplikacji WWW z
wszystkimi potrzebnymi funkcjami. PHP współpracuje z wieloma systemami baz danych. Pozwala to na bardzo
łatwe tworzenie aplikacji WW korzystających z informacji zapisanych w bazie danych. Możliwy jest również
dostęp do usług sieciowych takich jak IMAP, POP3, NNTP i TTP. Pozwala on również na otwieranie gniazd
sieciowych i podłączanie się do innych protokołów TCP/IP.
PHP może być użyty we wielu konfiguracjach serwerów. Ponieważ PHP jest rozprowadzany głównie w
postaci kodu źródłowego, może być skompilowany na wielu różnych platformach, na przykład na Linuksie,
FreeBSD i nawet na Windows. Dostępne są również binarne dystrybucje dla Win32.
PHP może działać jako program CGI lub może być zainstalowany jako moduł Apache lub rozszerzenie
ISAPI. Dzięki temu może on działać z praktycznie każdym serwerem WWW, od Apache na Linuksie do IIS na
Windows NT. W celu utworzenia najbardziej elastycznego środowiska pracy należy samodzielnie skompilować i
zainstalować PHP. Jeżeli wolisz szybko zacząć pracę, możesz zastosować binarną dystrybucję PHP.
Gdzie szukać pomocy
Pomoc można uzyskać na witrynie PHP oraz poprzez kilka grup dyskusyjnych i wysyłkowych. W lutym
2000 roku około 1400000 domen korzystało z PHP. Ponieważ jest on tak popularny, istnieje ogromna grupa
programistów i konsultantów, którzy mogą odpowiedzieć na pytania. Więcej informacji na temat dostępnych
zasobów Sieci znajduje się w części „Zasoby” na końcu książki.
9
PHP – Kompendium wiedzy
Podziękowania
Na początku chciałbym podziękować wszystkim z wydawnictwa McGraw-Hill za umożliwienie mi
zrealizowania tego zadania. Szczególne podziękowania należą się Rebece Young za wsparcie i pomoc w
technicznych aspektach pisania książki. Dziękuję Johnowi Steele, mojemu redaktorowi technicznemu, który
niezmiernie pomógł mi swoimi trafnymi uwagami i informacjami.
Oczywiście, należy podziękować całemu zespołowi tworzącemu PHP. Wiele osób z tego zespołu
pomagało mi w pracy nad książką. Cała część zawierająca skorowidz funkcji jest ich zasługą. To oni spędzili
setki lub tysiące godzin tworząc ten wspaniały język programowania i bogatą dokumentację.
Dziękuję Mattowi Wilson za umożliwienie mi wykorzystania w przykładzie do książki kodu MWeather.
Dziękuję Nickowi Bradbury za pozwolenie wykorzystania informacji i rysunków z edytora TopStyle.
Podziękowania dla Nate Weiss za pomoc przy użyciu deserializera WDDX dla JavaScript, dla Johna Kos za
pomoc przy unixODBC i EasySoft ODBC-ODBC Bridge. Dla Martina Evans, głównego programisty ODBCODBC Bridge, za stworzenie tego świetnego produktu. Dziękuję Michaelowi Justin za pomoc przy konwerterze
RTF do HTML firmy Scrooge. Dziękuję również Michaelowi C. Battilana za pomoc przy Cloanto Currency
Server. Dla Sama Ockman za umożliwienie wykorzystania w książce rysunku serwera Penguin 1U. Dziękuję
Richardowi Litofski za pomoc przy BrowserHawk. Podziękowania dla Ali Ersheid za umożliwienie
wykorzystania w książce dokumentacji CyberCash. Dziękuję Josephowi Harris (znany jako CDI) za klasę
FastTemplate oraz inne fantastyczne narzędzia dostępne na witrynie The Webmasters.net.
Dziękuję rodzicom i braciom za nieustanne wsparcie nawet, gdy w latach osiemdziesiątych spędzałem
całe noce na pisaniu programów w Apple Basicu. Dziękuję pani Barton, pani Smith i panu Wakefield, moim
nauczycielom angielskiego z liceum, którzy mieli ogromny wpływ na moje pisanie. Dziękuję Garemu Rogers i
Jasonowi Wallin za wskazanie mi PHP i Linuksa w czasie gdy coraz bardziej pogrążałem się wykorzystując ASP
i Windows. Dziękuję Tracy Ard za pożyteczne komentarze do tej pracy oraz za jego niezmienną przyjaźń.
Na koniec najważniejsze podziękowania należą się mojej żonie i córce za umożliwienie mi zakończenia tej
pracy. Teraz znów możemy wieczorami chodzić skakać na trampolinie.
O autorze
Blake Schwendiman rozpoczął programowanie w 1980 roku rozpoczynając od Apple IIe i języka Basic.
Zdobył licencjat na uniwersytecie Arizona State University w roku 1994. W chwili obecnej Blake zarządza firmą
Intechra LLC, http://www.intechra.net/, firmą konsultingową specjalizującą się w oprogramowaniu, która ma
siedzibę w Rexburg, Idaho. Intechra LLC specjalizuje się w tworzeniu oprogramowania dla WWW. Blake ma
żonę Holy i trzyletnią córkę. Można się z nim skontaktować pod adresem [email protected].
Wstęp
10
Rozdział 1. Kompilacja i instalowanie
PHP
Wstęp
Zanim rozpoczniemy naukę języka PHP, należy go poprawnie zainstalować i skonfigurować w używanym
środowisku interpreter PHP. Ponieważ pakiet PHP może działać na wielu serwerach WWW i systemach
operacyjnych, w rozdziale tym znajdą się szczegółowe opisy instalacji na jedynie kilku platformach, ale podane
informacje są wystarczająco uniwersalne i mogą być wykorzystane przy konfigurowaniu środowiska pracy na
innych platformach.
W rozdziale tym opisane zostaną szczegółowo Apache dla Linuksa oraz IIS dla Windows NT. Są to często
spotykane konfiguracje serwerów WWW i są one na tyle różne, że ilustrują ogólne zasady instalacji pakietu PHP
na większości platform. Szczegółowe dane na temat określonej platformy można również znaleźć na witrynie
www.php.net.
Pobieranie PHP
Pierwszym krokiem do rozpoczęcia pracy z PHP jest zaopatrzenie się w kopię interpretera PHP. Na
witrynie www.php.net umieszczone jest kilka wariantów tego pakietu. Najnowsza wersja zawsze znajduje się na
górze listy. W przypadku serwerów uniksowych zaleca się pobranie pakietu zawierającego kompletny kod
źródłowy i przeprowadzenie samodzielnej kompilacji. Platformy uniksowe to między innymi Linux, BSD, Solaris
itp. W przypadku Windows zaleca się pobranie binarnej instalacji PHP.
Ze strony zawierającej pakiety instalacyjne można również pobrać poprzednie wersje programów,
dokumentację i narzędzia pomocnicze. Poprzednie wersje mogą być potrzebne, jeżeli masz już gdzieś
zainstalowane PHP i nie chcesz ryzykować niekompatybilności.
Instalowanie wersji binarnej
Po pobraniu binarnej dystrybucji PHP, instalacja jest banalna. Najczęściej binarna instalacja PHP jest
przeznaczona dla Windows. Ponieważ jednak niektóre dystrybucje Uniksa zawierają binarną dystrybucję PHP,
opisany zostanie również taki przypadek.
Binarna instalacja dla Windows
W PHP prawie wszystkie operacje można wykonać na kilka sposobów. Instalacja binarna dla Windows
zawiera zarówno wersję CGI (Common Gateway Interface) PHP, jak również wersję ISAPI. Jeżeli korzystasz z
serwera IIS (Internet Information Server) lub PWS (Personal Web Server) zalecane jest użycie modułu ISAPI.
Wersja CGI powoduje, że PHP jest uruchamiany za każdym odwołaniem do strony, więc jest mniej efektywny od
dynamicznego modułu jakim jest rozszerzenie ISAPI. Moduł ISAPI jest również ze swojej natury bezpieczniejszy
od programu CGI.
Instalowanie PHP w postaci modułu ISAPI
Jeżeli korzystasz z serwera IIS, PWS lub innego serwera WWW obsługującego moduły ISAPI,
najlepszym rozwiązaniem będzie użycie PHP w postaci modułu ISAPI. Aby zainstalować taką wersję, należy
skopiować pliki php4ts.dll i msvcrt.dll do katalogu systemowego Windows (zwykle \windows\system w Windows
95 lub \winnt\system32 w Windows NT). Są to współdzielone biblioteki niezbędne do prawidłowej pracy każdej
wersji PHP dla Windows. Dodatkowo można skopiować do katalogu systemowego inne pliki .dll, ale nie jest to
konieczne do ich użycia.
Następnie należy tak skonfigurować IIS lub PWS, aby korzystał z modułu ISAPI do obsługi plików php.
Serwer IIS można konfigurować za pomocą konsoli konfiguracji zainstalowanej w menu Option Pack. Na
rysunku 1.1. znajduje jest rozwinięte menu pokazujące położenie tego programu w Windows NT.
Rysunek 1.1.
Uruchamianie
aplikacji
konfigurującej IIS
Po uruchomieniu konsoli Menedżer usług internetowych należy kliknąć prawym przyciskiem myszy na
węźle serwera WWW (prawdopodobnie zatytułowany Domyślna witryna sieci Web) i wybrać Właściwości, tak
jak jest to pokazane na rysunku 1.2. Następnie w oknie Właściwości należy przejść na zakładkę Katalog
macierzysty i kliknąć przycisk Konfiguracja. Opcja ta pozwala na dodawanie i edycję skojarzeń.
Rysunek 1.2.
Konfigurowanie IIS
Teraz należy kliknąć przycisk Dodaj i wprowadzić potrzebne informacje. Na rysunku 1.3. pokazany jest
proces dodawania mapowania rozszerzenia phtml do modułu ISAPI PHP.
Rozdział 1 – Kompilacja i instalowanie PHP
12
Rysunek 1.3.
Dodawanie
mapowania dla
rozszerzenia w IIS
Po dodaniu mapowania zmiany są od razu widoczne w oknie dialogowym Konfiguracja aplikacji.
Czasami może być pożyteczne skojarzenie niektórych rozszerzeń z modułem ISAPI a niektórych z programem
CGI. Na rysunku 1.4. pokazana jest konfiguracja mojego serwera WWW. Na rysunku widać mapowania dla
PHP3, dla PHP4 jako CGI oraz PHP4 jako ISAPI. Jest to przydatne przy testowaniu różnic pomiędzy wersjami 3
i 4 PHP.
Rysunek 1.4.
Mapowanie
rozszerzeń PHP
Po zakończeniu konfiguracji należy ponownie uruchomić serwer WWW. Można to zrobić przy użyciu
modułu Usługi w Panelu sterowania, lub uruchamiając z linii poleceń następujące polecenia:
net stop iisadmin
net start w3svc
Po uruchomieniu serwera należy go przetestować tworząc prosty plik testowy, na przykład taki, jak
pokazany na wydruku 1.1. i otwierając go poprzez twój serwer. Jeżeli wszystko jest skonfigurowane poprawnie,
powinieneś zobaczyć ekran z informacjami na temat instalacji PHP.
Wydruk 1.1. Testowy skrypt PHP
<html>
<head>
<title> phpinfo() </title>
</head>
<body>
<?php
phpinho();
?>
</body>
</html>
13
PHP – Kompendium wiedzy
Trzeba pamiętać, że w pakiecie instalacyjnym PHP znajduje się uwaga na temat stanu modułu ISAPI która
ostrzega, że nie powinien być stosowany w środowisku produkcyjnym. Sugeruje się, że w celu zapewnienia
odpowiedniej stabilności powinna być użyta wersja CGI. Następna część rozdziału opisuje użycie PHP jako CGI.
Użycie PHP jako CGI
Jeżeli nie masz zainstalowanego serwera WWW obsługującego moduły ISAPI lub istnieją inne powody
wyboru wersji CGI, należy przeprowadzić instalację PHP jako CGI. Instalacja jest bardzo podobna do tej
przedstawionej powyżej, różnice występują jedynie przy mapowaniu rozszerzeń. Zamiast wybierać bibliotekę .dll
ISAPI, należy wybrać plik php.exe. Serwer IIS lub PWS wysyła parametry do pliku wykonywalnego CGI, więc
oprócz nazwy pliku wykonywalnego należy podać opcje linii poleceń %s %s. Jest to pokazane na rysunku 1.4. dla
rozszerzenia .php4.
Różne serwery WWW mają różne metody określenia mapowania rozszerzeń. Do Apache dla Windows
istnieje świetny podręcznik dostępny pod adresem www.php.net/manual/config-apache-nt.html. Zasoby sieci na
temat instalacji PHP na różnych serwerach WWW dla Windows można odszukać za pomocą wyszukiwarki
umieszczonej na witrynie www.php.net.
Inne instalacje binarne
Niektóre instalacje Uniksa posiadają instalację binarną PHP zintegrowaną z instalacją serwera WWW.
Niektórzy dostawcy, na przykład Red Hat, udostępniają również binarną instalację na swoich witrynach.
Instalacja taka jest wykonana w formie plików RPM (Red Hat Package Manager). Zaletą użycia plików RPM jest
łatwość instalacji. Nie trzeba martwić się szczegółami procesu kompilacji, ponieważ plik RPM zawiera gotową do
użycia odpowiednio skompilowaną wersję programu. Wadą jest to, że z powodu wielu możliwych wariantów
platform dla Uniksa, problemem dla początkujących może być nawet wybór właściwego pliku. Poza tym w pliku
RPM nie zawsze są ustawione wszystkie potrzebne opcje konfiguracji, niezbędne do prawidłowego działania
programu.
Jeżeli masz plik RPM z PHP, możesz go zainstalować wydając polecenie rpm -i <plikrpm.rpm>.
Powoduje to zainstalowanie plików binarnych do katalogów określonych przez twórcę pliku RPM. Dla
większości użytkowników katalogi te są prawidłowe. Po instalacji należy ręcznie skonfigurować serwer WWW
tak, aby korzystał z zainstalowanych właśnie plików binarnych PHP. Poniżej przedstawimy sposób konfiguracji
Apache. Inne serwery WWW wymagają przeprowadzenia podobnych czynności.
Niezależnie od tego, czy PHP będzie działało jako program CGI czy w postaci modułu, pierwszy krok
konfiguracji jest zawsze taki sam. Trzeba utworzyć skojarzenie pomiędzy rozszerzeniem pliku a wewnętrznym
typem stosowanym przez serwer. Robi się to dodając do pliku konfiguracyjnego następujące linie:
AddType application/x-httpd-php .php
AddType application/x-httpd-php .phtml
AddType application/x-httpd-php .inc
Dyrektywy te powodują, że Apache uważa wszystkie pliki z rozszerzeniami .php, .phtml i .inc jako pliki
typu application/x-httpd-php. Do przetwarzania tego typu plików wykorzystywane jest PHP.
Zakładając, że masz zainstalowane PHP w postaci modułu Apache, kolejnym krokiem będzie modyfikacja
pliku konfiguracyjnego httpd.conf tak, aby Apache załadował moduł PHP:
LoadModule php4_module
libexec/libphp4.so
Jeżeli zainstalowana została wersja CGI, należy wprowadzić nieco inne zmiany do pliku konfiguracji
httpd.conf. Dyrektywa konfiguracji jest podobna do poprzedniej, ale odwołuje się do programu w postaci pliku
wykonywalnego.:
Action application/x-httpd-php
/cgi-bin/php
Dyrektywa Action definiuje typ pliku powodujący uruchomienie PHP po otrzymaniu żądania ściągnięcia
strony z serwera WWW. Oczywiście należy podać właściwą ścieżkę do pliku wykonywalnego.
Po wprowadzeniu zmian należy ponownie uruchomić serwer WWW, aby zaczęły działać nowe
ustawienia. Serwer Apache można zrestartować za pomocą polecenia:
/ścieżka/do/apachectl restart
Aby przetestować konfigurację można wczytać za pomocą przeglądarki skrypt testowy, przedstawiony na
wydruku 1.1.
Binarna dystrybucja PHP ułatwia szybkie rozpoczęcie pracy z PHP w Uniksach, ale może ona sprawiać
problemy. Z powodu istnienia wielu wariantów Uniksów, znalezienie gotowej wersji działającej na określonym
Rozdział 1 – Kompilacja i instalowanie PHP
14
systemie może być czasami trudne. W wielu przypadkach będzie to bardziej czasochłonne niż ściągnięcie kodu
źródłowego, skompilowanie i zainstalowanie PHP. Proces ten zostanie opisany w kolejnej części rozdziału.
Kompilowanie PHP
Jeżeli chcesz skorzystać z elastyczności własnej instalacji PHP lub jeżeli przewidujesz dodawanie
własnych rozszerzeń do języka PHP (opisane w rozdziale 11. „Ponowne wykorzystanie kodu”), musisz dokładnie
poznać proces kompilowania PHP. Jeżeli pracujesz na platformie, dla której nie ma instalacji binarnej, możesz nie
mieć innego wyboru jak tylko samodzielnie kompilować PHP.
Kompilowanie PHP w Uniksach
W tej części rozdziału przedstawione zostaną informacje na temat kompilowania PHP na platformie Unix.
Należy pamiętać, że Unix określa całą rodzinę systemów, np.: Linux, BSD, Solaris i inne. Oczywiście systemy te
różnią się między sobą, ale wiele z kroków niezbędnych do kompilacji PHP jest identycznych. Więcej informacji
na temat określonej platformy można odszukać za pomocą wyszukiwarki dostępnej na witrynie www.php.net.
Dla każdej platformy istnieje kilka sposobów kompilacji PHP. Jeżeli serwerem WWW jest Apache, można
skompilować PHP jako plik wykonywalny, jako moduł ładowany dynamicznie lub jako statyczną bibliotekę.
Jeżeli nie korzystasz z Apache, należy odszukać w dokumentacji PHP i serwera WWW szczegóły postępowania.
Przy okazji możemy zarekomendować korzystanie z PHP w postaci dynamicznie ładowanego modułu, jako
najlepsze rozwiązanie dla większości aplikacji. Jeżeli PHP zostanie statycznie dołączony do Apache, każda
zmiana konfiguracji wymaga większego nakładu pracy. W przypadku modułu CGI, występują problemy z
bezpieczeństwem.
W kolejnych częściach zakładamy, że ściągnąłeś już źródła PHP i rozpakowałeś je. Proces kompilacji jest
właściwie taki sam dla każdego typu pliku wynikowego. Na początku trzeba uruchomić skrypt configure, który
ustawia opcje kompilacji. Następnie przy pomocy narzędzia make przeprowadza się kompilację. Na koniec trzeba
zainstalować gotowe PHP i zrestartować serwer WWW. Informacje na temat skryptu konfiguracyjnego są
przedstawione w części poświęconej kompilowaniu modułu CGI, więc zaleca się przeczytanie tego fragmentu
jako wprowadzenia.
Kompilacja modułu CGI
Kompilacja PHP do postaci wykonywalnego modułu CGI jest najprostszą metodą kompilacji i dobrym
rozwiązaniem, jeżeli nigdy wcześniej nie kompilowałeś programów dla Uniksa. Poniżej przedstawiona jest
kompletna lista operacji jakie należy wykonać. Niektóre z nich nie są obowiązkowe. Operacje opcjonalne są
zaznaczone czcionką pochyłą. Odwołanie do <php_dir> powinno być zamienione na nazwę twojego katalogu
bazowego PHP.
cd <php_dir>
rm config.cache
make clean
./configure
make
make install
Wykonanie tych operacji spowoduje usunięcie podręcznych danych konfiguracji, usunięcie plików
wynikowych a następnie skompilowanie PHP do postaci CGI. Jest to najprostsza metoda kompilacji, przytoczona
jedynie jako przykład. W prawdziwej kompilacji do skryptu konfiguracyjnego dołącza się opcje określające
atrybuty PHP.
Druga i trzecia linia jest nieobowiązkowa, ponieważ polecenia w nich umieszczone są używane jedynie do
wyczyszczenia poprzedniej konfiguracji i pozostałości po poprzedniej kompilacji. Jeżeli wcześniej nie
konfigurowałeś ani nie kompilowałeś PHP, nie są one potrzebne. Można również nie korzystać z tych opcji przy
kompilacji PHP, choć czasami ich wykonanie jest niezbędne. Jeżeli wprowadzane są poważne zmiany w
konfiguracji lub zmieniasz typ kompilacji z CGI na inny, może okazać się, że wykonanie czyszczenia jest
niezbędne, aby kompilacja przebiegła prawidłowo. W zależności od szybkości komputera, na którym
wykonywana jest kompilacja, przeprowadzenie całej konfiguracji i kompilacji może zająć dosyć dużo czasu.
15
PHP – Kompendium wiedzy
Pozostawienie zapisanych opcji konfiguracji oraz obiektów binarnych spowoduje znaczne skrócenie czasu
tworzenia PHP.
Wszyscy, którzy nigdy nie przeprowadzali takiego procesu powinni wiedzieć, że skrypt konfiguracyjny
poszukuje w systemie narzędzi, plików i innych danych systemowych. Następnie na podstawie tych danych
tworzy specyficzny dla systemu skrypt za pomocą można skompilować kod. Jeżeli w czasie działania skryptu
konfiguracyjnego nastąpi awaria, często zdarza się, że wymagany plik lub narzędzie nie jest odnajdywane lub
niewłaściwie skonfigurowane. Po zakończeniu działania skryptu konfiguracyjnego tworzony jest plik
tymczasowy config.cache zawierający szczegóły na temat systemu, więc badanie systemu nie musi być
powtarzane przy ponownym uruchomieniu konfiguracji. Jeżeli wprowadzisz duże zmiany do konfiguracji
systemu, musisz usunąć plik tymczasowy przed kolejnym uruchomieniem skryptu konfiguracyjnego. W ten
sposób upewniamy się, że zmiany te zostaną wykryte.
Po wykonaniu wszystkich podanych poleceń zostanie utworzony nowy plik wykonywalny — php. Można
przetestować poprawność kompilacji za pomocą następującego polecenia:
php < /dev/null
Jeżeli zobaczysz wynik podobny do poniżej przedstawionego, udało ci się poprawnie skompilować i
zainstalować PHP w postaci CGI.
X-Powered-By: PHP/4.0.2
Content-type: text/html
Trzeba zauważyć, że skompilowana właśnie wersja PHP nie posiada funkcji, które być może będziemy
chcieli wykorzystywać w aplikacjach, ponieważ została skompilowana z użyciem tylko ustawień domyślnych.
Trzeba ponownie uruchomić skrypt konfiguracyjny, ustawić opcje potrzebne w aplikacji a następnie ponownie
skompilować i zainstalować PHP.
Pożyteczną cechą zestawu domyślnych ustawień jest to, że dołączone jest do niego wiele często
używanych opcji konfiguracji, w tym obsługa bazy danych MySQL, sesji i wiele, wiele innych. Oznacza to, że
przytoczone polecenia umożliwiają skompilowanie PHP, który pozwala na rozpoczęcie nauki języka.
Jeżeli potrzebujesz obsługi innej bazy danych lub innego rozszerzenia, trzeba dodać odpowiednią opcję
konfiguracji. Lista dostępnych opcji jest wyświetlana po wpisaniu:
./configure --help
Większość opcji konfiguracji wpływających na dostępne funkcje PHP ma postać --enable-FUNKCJA lub -Aby dodać funkcję do PHP należy użyć jednej z poniższych form:
with-PAKIET.
--enable-FUNKCJA
--enable-FUNKCJA=yes
Aby usunąć funkcję z PHP, należy użyć:
--disable-FUNKCJA
--enable-FUNKCJA=no
Pełna lista opcji konfiguracji znajduje się w skorowidzu na końcu książki. Funkcje korzystające ze składni
--enable są to zwykle wbudowane opcje PHP, takie jak możliwość wykorzystywania krótkich znaczników lub
obsługa protokołu FTP. Pakiety są to zwykle moduły zewnętrzne, które mogą być dołączone do PHP, na przykład
obsługa bazy danych Oracle lub Javy. Te własności wymagają zwykle wskazania zewnętrznego pliku i do jego
włączania korzysta się z następującego zapisu:
--with-PAKIET=/ścieżka/do/pakietu
Aby wyłączyć pakiet należy użyć poleceń:
--with-PAKIET=no
--without-PAKIET
Jako przykład przedstawimy następującą konfigurację:
./configure --with-apxs=/www/bin/apxs --with-java --with-cybercash=/home/blake/mck-3.2.0.6-i586-pc-linuxgnulibc2.1 --withunixODBC=/usr/local/unixODBC --disable-debug --enabletrack-vars -- enable-fin-funcs --withsnmp=/home/blake/ucd-snmp-4.1.2 --enable-ucd-snmp-hack
Powyższe wywołanie konfiguracji powoduje dodanie do PHP obsługi Javy, CyberCash, SNMP (Simple
Network Management Protocol) oraz unixODBC. Nie zostało podane położenie katalogu Javy, więc skrypt
konfiguracyjny użyje domyślnej ścieżki do katalogu z tym pakietem. Dodatkowo została dodana opcja -withapxs, która powoduje, że PHP jest kompilowane do postaci dynamicznie ładowanego modułu Apache a nie jako
program typu CGI. Później omówimy to zagadnienie dokładniej. W przedstawianej konfiguracji wyłączono
informacje dla debuggera oraz włączono opcje track-vars, fin-funcs oraz ucd-snmp-hack. Opcja fin-funcs
powoduje dodanie własnego modułu rozszerzeń opisanego w dalszej części książki (rozdział 11.), natomiast
pozostałe są standardowymi elementami konfiguracji opisanymi w skorowidzu na końcu książki.
Rozdział 1 – Kompilacja i instalowanie PHP
16
Wiele z pakietów oprogramowania jakie chcemy dodać do PHP musi być osobno zainstalowane. Więcej
informacji na temat tego, gdzie można zaopatrzyć się w potrzebne pakiety, można znaleźć w dokumentacji na
witrynie www.php.net.
Po utworzeniu PHP w postaci CGI, należy skonfigurować serwer WWW do współpracy z nowym
programem. Aby skonfigurować serwer Apache należy dodać następujące dyrektywy do pliku httpd.conf:
AddType application/x-httpd-php .php
AddType application/x-httpd-php .phtml
AddType application/x-httpd-php .inc
Action application/x-httpd-php /cgi-bin/php
Pierwsze trzy dyrektywy definiują zawartość plików z rozszerzeniami php, phtml i inc jako typ
application/x-httpd-php. Ostatnia dyrektywa powoduje wysłanie wszystkich plików tego typu do pliku
wykonywalnego php. Zakładamy, że plik ten jest umieszczony w katalogu cgi-bin serwera WWW.
Dyrektywy te są minimum wymaganym do konfiguracji PHP w Apache, ale ta sama czynność może być
zrealizowana jeszcze na kilka sposobów. Więcej szczegółów można znaleźć w dokumentacji do Apache.
Kompilacja PHP jako statycznie dołączanego modułu Apache
Apache pozwala na statyczne dołączanie modułów bezpośrednio do pliku binarnego Apache. W
porównaniu z wersją CGI użycie modułu pozwala poprawić wydajność aplikacji oraz zwiększyć bezpieczeństwo
systemu,. Wadą tej metody jest konieczność powtórnej kompilacji Apache po każdej kompilacji PHP. Może być
to czasochłonne i frustrujące, ponieważ w przypadku wystąpienia kłopotów z konfiguracją PHP, Apache może
również przestać działać. Jednak niektóre aplikacje wymagają zastosowania statycznie dołączanego modułu
Apache, opiszemy teraz sposób jego tworzenia.
Przed skonfigurowaniem i skompilowaniem PHP niezbędne jest skonfigurowanie Apache. Zakładamy, że
na dysku jest już katalog z kodem źródłowym Apache. Aby skonfigurować Apache, należy użyć następujących
poleceń:
cd <apache_dir>
./configure
Po zakończeniu działania tego skryptu można zająć się konfigurowaniem i kompilowaniem PHP.
cd <php_dir>
./configure --with-apache=<apache_dir>
make
make install
Opcja --with-apache powoduje kompilację do postaci statycznej biblioteki oraz pozwala podać katalog z
plikami źródłowymi Apache. Następnie należy skompilować serwer Apache za pomocą poleceń:
cd <apache_dir>
./configure --prefix=/www --activate-module=src/modules/php4/libphp4.a
make
make install
Dyrektywa prefix może być inna w twoim systemie, ponieważ wskazuje ona katalog gdzie zostaną
zainstalowane pliki zależne od architektury. Teraz należy uruchomić serwer Apache i przy wykorzystaniu skryptu
testowego z wydruku 1.1. sprawdzić poprawność konfiguracji.
Aby Apache prawidłowo przetwarzał pliki PHP należy odpowiednio zmodyfikować plik httpd.conf. W
zależności od rozszerzeń jakie zostały wybrane do reprezentowania plików PHP, należy wprowadzić odpowiednie
zmiany. I tym razem standardowa konfiguracja wygląda następująco:
AddType application/x-httpd-php .php
AddType application/x-httpd-php .phtml
AddType application/x-httpd-php .inc
Przedstawiony opis przedstawia jedynie bardzo prostą wersję PHP, która zawiera jedynie opcje domyślne.
Więcej informacji o zmianie konfiguracji kompilacji PHP znajduje się w części na temat kompilacji wersji CGI.
Kompilacja PHP do postaci dynamicznie ładowanego modułu Apache
Sposób kompilacji PHP do postaci dynamicznie ładowanego modułu Apache nie różni się zbytnio od
innych przedstawionych do tej pory metod. Zaletą tej metody jest możliwość kompilacji PHP bez konieczności
równoczesnej kompilacji Apache. Również niektóre moduły rozszerzeń (na przykład Java) wymagają do
poprawnej pracy, aby PHP był skompilowany do postaci dynamicznie ładowanego modułu. Aby Apache
obsługiwał dynamicznie ładowane moduły należy go przekompilować z następującymi opcjami konfiguracji:
cd <apache_dir>
make clean
./configure --enable-module=so --enable-rule=SHARED_CORE --prefix=/www
make
17
PHP – Kompendium wiedzy
make install
Oprócz kompilacji Apache przedstawione polecenia przygotowują skrypt apxs, który jest niezbędny do
kompilacji dynamicznego modułu PHP. Jeżeli wystąpią kłopoty ze skryptem apxs można powtórnie wykonać
przedstawione polecenia, co spowoduje ponowne wygenerowanie prawidłowo skonfigurowanego skryptu. Po
skompilowaniu Apache z obsługą dynamicznie ładowanych modułów, należy skompilować PHP w następujący
sposób:
cd <php_dir>
make clean
rm config.cache
./configure --with-apxs=/www/bin/apxs (pozostałe opcje)
make
make install
Polecenia porządkujące są zalecane, jeżeli PHP był już kompilowany w innej konfiguracji. Ścieżka podana
w dyrektywie konfiguracji --with-apxs powinna być pełną ścieżką do skryptu apxs na serwerze.
Tak jak w przypadku poprzednich sposobów kompilacji należy prawidłowo skonfigurować Apache, aby
przetwarzał pliki PHP. Po zmodyfikowaniu konfiguracji należy uruchomić Apache i wywołać skrypt testowy.
Podsumowanie kompilacji PHP w systemach Unix
Celem tego fragmentu książki nie było podawanie szczegółowego i wyczerpującego opisu wszystkich
możliwych opcji konfiguracji, ale pokazanie podstawowych metod kompilowania PHP do różnych postaci. Jeżeli
nie kompilowałeś wcześniej PHP, powinieneś na początku spróbować skompilować podstawową konfigurację, a
później uzupełniać potrzebne opcje. Po zapoznaniu się z procesem kompilacji jest już bardzo łatwo testować
różne konfiguracje i dodawać niestandardowe rozszerzenia.
Po skompilowaniu PHP i sprawdzeniu, czy działa z Apache, można zapoznać się z opcjami konfiguracji,
które można ustawiać bez potrzeby ponownej kompilacji. Zostały one opisane w dalszej części rozdziału.
Kompilowanie PHP w środowisku Windows
Kompilowanie PHP dla Windows jest na początku bardziej skomplikowanym procesem niż kompilacja
PHP dla Uniksa. Dokumentacja zaleca użycie Visual C++ wersja 6, choć wersja 5 również powinna działać.
Próbowałem sprawdzić, czy można użyć pakietu Borland C++ Builder, ale nie udało mi się tego zrobić. Problem
stanowiły prekompilowane pliki lib, ponieważ Microsoft i Borland korzystają z różnych formatów tych plików.
Prawdopodobnie można zastosować kompilator Borlanda, ale trzeba wcześniej przekompilować wszystkie
biblioteki. W poniższym opisie zakładamy użycie Visual C++.
Przed rozpoczęciem pracy należy się zaopatrzyć w kilka programów i plików pomocniczych. Tabela 1.1.
zawiera wszystkie dodatkowe programy oraz adresy w Internecie, gdzie były dostępne w czasie pisania książki.
Tabela 1.1. Dodatkowe pliki pomocnicze i ich adresy w Sieci
Program
Położenie
Kod źródłowy PHP
www.php.net/download.php
Pakiet Cygwin
http://sources.redhat.con/cygwin/
Narzędzia do kompilacji PHP dla
www.php.net/extra/win32build.zip
Win32
Obsługa BCMath
www.php.net/version4/downloads/num
ber.tar.gz
Zastępnik pliku resolv.lib
www.php.net/version4/downloads/bind
lib_w32.zip
Pakiet Cygwin zawiera popularne narzędzia GNU, takie jak gcc, make i bison. Niektóre z tych programów
są wykorzystywane w procesie kompilacji, więc trzeba wcześniej zainstalować ten pakiet. Inne potrzebne pliki są
integralną częścią dystrybucji PHP. Kod źródłowy PHP jest identyczny jak ten, który jest używany do utworzenia
wersji dla Uniksa.
Potrzebny jest również program do rozpakowywania plików. Ja używam programu Winzip, ponieważ bez
problemu radzi sobie z plikami .tar.gz. Również inne programy posiadają takie możliwości. Na początku należy
zainstalować narzędzia Cygwin. Trzeba ręcznie dodać zmienną środowiska wskazując na położenie plików
Cygwin. Jeżeli pracujesz w Windows 95, trzeba dodać tą zmienną ręcznie do pliku autoexec.bat. W Windows NT
należy kliknąć prawym przyciskiem myszy ikonę Mój komputer i wybrać z menu Właściwości. Teraz trzeba
Rozdział 1 – Kompilacja i instalowanie PHP
18
kliknąć zakładkę Środowisko i dodać nową zmienną, tak jak jest to pokazane na rysunku 1.5. Zmienna nazywa się
CYGWIN a jej wartością jest ścieżka do katalogu, gdzie zainstalowane są narzędzia Cygwin.
Rysunek 1.5.
Ustawienie
zmiennej
środowiskowej
CYGWIN
Następnie utwórz katalog i rozpakuj do niego zawartość pliku win32build.zip. Uruchom Visual C++ i
wybierz Options z menu Tools. Teraz wybierz zakładkę Directories (rysunek 1.6.) i przy użyciu listy rozwijalnej
opisanej Show directories for, wybierz opcję Executable files i dodaj katalog z plikami Cygwin. Teraz z listy
rozwijalnej wybierz Include files i dodaj katalog z win32build\include (rysunek 1.6.). Na koniec wybierz Library
files i dodaj katalog win32build\lib. Od tej pory kompilator Visual C++ będzie mógł korzystać z zainstalowanych
narzędzi i plików.
Rysunek 1.6.
Ustawienie
katalogów w Visual
C++
Kolejnym krokiem będzie skompilowanie nowej wersji pliku resolv.lib. Najpierw utwórz nowy katalog i
rozpakuj do niego pliki z archiwum bindlib_w32.zip. W Visual C++ otwórz projekt bindlib.dsp. Z menu Build
wybierz Set Active Project Configuration i wybierz wersję handlową biblioteki lub wersję do uruchamiania.
Naciśnij klawisz F7, aby skompilować projekt. Po zakończeniu kompilacji należy skopiować plik resolv.lib do
katalogu win32build\lib.
Następnie rozpakuj źródła PHP i plik number.tar.gz za pomocą zewnętrznego programu lub narzędzia tar
z pakietu Cygwin. Skopiuj rozpakowane pliki number.c i number.h do katalogu ext/bcmath w katalogu z kodem
źródłowym PHP.
19
PHP – Kompendium wiedzy
Jeżeli wykonałeś wszystkie opisane wcześniej czynności, jesteś gotowy do kompilacji PHP. Uruchom
Visual C++ i otwórz plik projektu php4ts.dsp, znajdujący się w podkatalogu win32 katalogu z kodem źródłowym
PHP. Projekt ten zawiera kilka konfiguracji. Najłatwiej jest rozpocząć od skompilowania wersji CGI wybierając
wersję handlową lub wersję z danymi dla debuggera, tak jak jest to pokazane na rysunku 1.7.
Rysunek 1.7.
Wybór konfiguracji
dla wersji CGI
Skompiluj projekt i jeżeli wszystko pójdzie dobrze posiadasz już własną wersję PHP. Jeżeli potrzebujesz
wersji PHP jako ISAPI lub NSAPI, wystarczy wybrać odpowiednią konfigurację dla kompilacji i ponownie
skompilować projekt. Jak wspomniałem wcześniej, najtrudniejszą częścią było wstępne przygotowanie
środowiska. Gdy wszystko jest już gotowe, cała reszta jest tak samo prosta jak w Uniksie.
Podsumowanie kompilacji PHP
Kompilowanie wersji PHP dla Windows jest za pierwszym razem dużo trudniejsze od wersji dla Uniksa,
ale gdy wszystkie potrzebne dodatki zostaną odpowiednio skonfigurowane, jest już proste. Gdy poznałeś już
proces kompilowania PHP dla obu platform możesz tworzyć wysoce specjalizowane wersje PHP, spełniających
precyzyjnie potrzeby konkretnej witryny. Dokładna wiedza na temat procesu kompilacji PHP jest również
niezbędna, aby móc tworzyć rozszerzenia PHP. Zagadnienie to zostało opisane w rozdziale 11.
Konfigurowanie PHP
Niezależnie od platformy na której działa PHP, sposób jego konfigurowania jest taki sam. Wykorzystuje
się w tym celu plik php.ini. Plik ten jest dostarczany w dystrybucji PHP jako php.ini-dist i php.ini-optimized.
Jeżeli nie znasz dobrze opcji konfiguracji, powinieneś rozpocząć do podstawowych ustawień z pliku php.ini-dist.
Pierwszym krokiem będzie skopiowanie i zmiana nazwy pliku. Plik powinien być nazwany php.ini i skopiowany
do katalogu zależnego od używanej platformy. W tabeli 1.2. zamieszczone są podstawowe warianty.
Tabela 1.2. Platformy PHP i położenie pliku php.ini
Platforma
Położenie pliku php.ini
Windows
Katalog <windows> zwykle \windows w Windows 95 i \winnt w
Windows NT
Unix
Można to sprawdzić za pomocą funkcji phpinfo(), ale zwykle jest
to /usr/local/lib.
Po umieszczeniu pliku konfiguracyjnego w odpowiednim katalogu, należy do niego wprowadzić
odpowiednie zmiany. Plik php.ini jest podzielony na sekcje, rozpoczynające się od linii [nazwa_sekcji] podobnie,
jak w standardowych plikach ini systemu Windows. Plik ten zawiera obszerne komentarze opisujące
przeznaczenie sekcji i opcji konfiguracji. W pozostałej części książki czasami będą przytaczane opcje niezbędne
do uruchomienia przykładów. Zwykle przykład taki zawiera nazwę sekcji, nazwę opcji oraz wartość. Aby
wprowadzić zmiany najczęściej zmienia się plik php.ini i ponownie uruchamia Apache, ale istnieją również inne
mechanizmy zmiany opcji. Mechanizmy te opisane zostaną w późniejszej części rozdziału.
Korzystanie z pliku php.ini
Zalecaną metodą zmiany konfiguracji jest modyfikacja pliku php.ini i ponowne uruchomienie serwera
WWW. Jeżeli korzystasz z PHP w postaci programu CGI nie musisz restartować serwera, ponieważ plik php.ini
jest odczytywany za każdym uruchomieniem programu CGI. Dla przykładu można zmienić sposób raportowania
błędów przez PHP, korzystając z odpowiednich opcji konfiguracji. Opcje te mają następujące wartości domyślne:
Rozdział 1 – Kompilacja i instalowanie PHP
20
error_reporting
display_errors
log_errors
error_log
=
=
=
=
E_ALL & ~E_NOTICE
; Pokaż wszystkie błędy oprócz informacji
On ; Wypisuj błędy (jako część wynikowego HTML)
Off ; Zapisuj błędy do pliku błędów
syslog
; Zapisuj błędy do dziennika systemowego
Pierwsza opcja powoduje generowanie komunikatów dla wszystkich typów błędów poza typem E_NOTICE.
Następna linia powoduje wstawianie komunikatów błędów do wynikowego kodu HTML. Następne dwa wiersze
powodują zapisywanie komunikatów błędów w pliku. Załóżmy, że w instalacji produkcyjnej nie chcemy
wyświetlać błędów, a zamiast tego błędy będą zapisywane do określonego pliku. Można to zrealizować
zmieniając konfigurację w następujący sposób:
error_reporting
display_errors
log_errors
error_log
=
=
=
=
E_ALL ; Pokaż wszystkie błędy
Off ;
On ; Zapisuj błędy
/tmp/php_log ; Zapisuj błędy do pliku /tmp/php_log
Taka konfiguracja powoduje, że wszystkie komunikaty błędów, w tym informacje, będą zapisywane w
pliku /tmp/php_log. Oczywiście plik ten powinien mieć odpowiednio ustawione prawa dostępu, aby serwer
WWW mógł zapisać w nim dane.
Z powodu dużej ilości opcji konfiguracji, nie zostaną tu przedstawione wszystkie możliwe opcje. Pełna
lista znajduje się w skorowidzu na końcu książki. Tutaj przedstawione zostaną jedynie ogólne sposoby
wykorzystywania tych opcji. Aby zmienić opcję konfiguracji, należy otworzyć w edytorze plik php.ini i odszukać
opcję. Zwykle znajduje się tam sporo komentarzy opisujących możliwe wartości danej opcji.
Inne metody zmiany konfiguracji PHP
Istnieją dwie metody zmiany konfiguracji PHP bez konieczności modyfikacji pliku php.ini. Pierwszym
sposobem jest wstawienie tych opcji do pliku konfiguracyjnego Apache httpd.conf lub do pliku .htaccess.
Pierwsza metoda jest użyteczna, jeżeli chcemy mieć różne ustawienia PHP dla różnych serwerów wirtualnych lub
różnych katalogów. Druga metoda jest wykorzystywana, gdy nie jest możliwy dostęp do plików php.ini i
httpd.conf. Jest to częsta sytuacja, witryna jest umieszczona na dzierżawionym serwerze zewnętrznej firmy. Jest
to jednak najmniej zalecana metoda, ponieważ plik .htaccess jest wczytywany i analizowany za każdym
odwołaniem do stron znajdujących się w tym katalogu. Powoduje to znaczne spowolnienie serwera WWW.
W obu tych przypadkach sposób zmiany konfiguracji PHP jest tak sam. Należy użyć dyrektyw
konfiguracji php_value i php_flag do ustawienia potrzebnych opcji. Na przykład, aby ustawić poprzednio opisane
opcje konfigurujące sposób raportowania błędów, należy użyć następujących dyrektyw Apache:
<VirtualHost 192.1.1.1>
ServerAdmin [email protected]
DocumentRoot /www/hosts/wwwprojects/
ServerName www.testserver.com
php_value error_reporting 2047
php_flag display_errors off
php_flag log_errors on
php_value error_log /tmp/php_log
</VirtualHost>
Umieszczenie tych ustawień w pliku httpd.conf spowoduje, że zostanie ustawiony sposób raportowania
błędów dla serwera wirtualnego o nazwie www.testserver.com. Jeżeli na tej samej maszynie istnieją inne serwery
wirtualne, używają one konfiguracji określonej przez plik php.ini. Pozwala to na posiadanie różnych konfiguracji
PHP dla różnych serwerów wirtualnych lub katalogów.
Jeżeli musisz zmienić konfigurację PHP a nie masz dostępu do pliku php.ini ani do httpd.conf, możesz
wykorzystać pliki Apache .htaccess. Jest to również użyteczne, jeżeli określony katalog musi mieć inne
ustawienia konfiguracji niż reszta witryny. Na przykład, można zmienić sposób raportowania błędów dla jednego
katalogu na czas uruchamiania skryptów w nim się znajdujących. W tym celu należy stworzyć plik .htaccess z
następującą zawartością:
php_value error_reporting 2039
php_flag log_errors off
php_flag display_errors on
Należy zauważyć, że w obu przykładowych plikach konfiguracyjnych Apache wartość zmiennej
konfiguracji error_reporting jest ustawiana za pomocą wartości numerycznej a nie stałej. Jest o jedyny sposób
poprawnego ustawienia wartości. Należy pamiętać, że konfigurując PHP poprzez dyrektywy Apache nie można
używać jako wartości żadnych stałych PHP. W przeciwnym wypadku efekty mogą być niespodziewane.
Aby zilustrować potęgę dostępnego mechanizmu konfiguracji na rysunku 1.8. przedstawiony został
schemat możliwości konfiguracji środowiska PHP.
21
PHP – Kompendium wiedzy
Rysunek 1.8.
Elastyczność
konfiguracji z
zastosowaniem
php.ini oraz plików
konfiguracyjnych
Apache
Podsumowanie
W tym rozdziale przedstawiono kilka informacji niezbędnych do rozpoczęcia pracy z PHP. Z powodu
elastyczności i dużej ilości obsługiwanych platform niemożliwe jest szczegółowe opisanie wszystkich dostępnych
konfiguracji. Korzystając jednak z informacji umieszczonych w tej książce, oraz na witrynie www.php.net
powinieneś być w stanie zainstalować i skonfigurować PHP na twojej platformie.
Trzeba zauważyć, że PHP posiada wiele własnych funkcji zmieniających ustawienia konfiguracji.
Przykładami takich funkcji są error_reporting() oraz set_time_limit(). Więcej informacji na temat tych funkcji
można znaleźć w skorowidzu na końcu książki.
Rozdział 1 – Kompilacja i instalowanie PHP
22
Rozdział 2. Język
Wstęp
W rozdziale tym znajduje się zwięzły opis języka programowania PHP. Jak wspomniałem we wstępie do
książki nie jest moją intencją poświęcać zbyt wiele czasu na omawianiu ogólnych koncepcji programowania. W
tym rozdziale znajduje się opis składni podstawowych konstrukcji programowania, na przykład zmiennych,
stałych i funkcji. Przykłady przytoczone w tym rozdziale nie pokazują najlepszych technik programowania a
jedynie ilustrują składnię i użycie omawianych elementów. Pełny opis języka znajduje się w dokumentacji języka
dostępnej na witrynie http://www.php.net.
Ogólne informacje na temat składni
Ponieważ PHP jest zwykle wbudowywany w kod HTML istnieją specjalne znaczniki ograniczające bloki
PHP. Użycie tych znaczników jest nazywane czasem wyjściem z trybu HTML.
Wydruk 2.1. Sposoby oznaczania bloku kodu PHP w HTML
<? echo "użycie krótkich znaczników PHP do wyjścia z trybu HTML<br>"; ?>
<?php echo "wyjście przy użyciu pełnych znaczników PHP<br>"; ?>
<script language="php">
echo "niektóre edytory HTML nie obsługują instrukcji przetwarzania<br>";
</script>
<% echo "można stosować również znaczniki w stylu ASP<br>"; %>
Pierwsza metoda oznaczania bloków PHP jest dostępna jedynie wtedy, gdy uaktywnione są krótkie
znaczniki. Aby to zrobić należy użyć funkcji short_tags(), włączyć w pliku konfiguracyjnym opcję
short_tag_open lub skompilować PHP z opcją -enable-short-tags. Znaczniki w stylu ASP są dostępne jedynie
wtedy, gdy uaktywniona jest opcja konfiguracji asp_tags. Więcej informacji na temat kompilowania i
konfiguracji PHP znajduje się w rozdziałach „Kompilacja i instalowanie PHP” oraz dodatku D - „Opcje
konfiguracji”.
PHP jest syntaktycznie bardzo podobny do C. Na przykład, instrukcje są oddzielone średnikiem. Znacznik
?> jest niejawnym końcem instrukcji, więc poniższe przykłady są poprawne składniowo:
Wydruk 2.2. Koniec instrukcji
<?php
echo "Test, test...<br>";
?>
<?php
echo "Test, test...<br>"
?>
Komentarze w PHP można oznaczać symbolami komentarzy pochodzącymi z C, C++ lub stosowanych w
skryptach Uniksa. Komentarze jednoliniowe komentują tekst do końca linii lub do końca bieżącego bloku PHP w
zależności od tego, co będzie pierwsze. Nie można zagłębiać wielowierszowych komentarzy w stylu C.
Wydruk 2.3. Komentarze
<?php
echo "Witaj świecie!<br>"; // To jest jednowierszowy komentarz w stylu C++
/* To jest wielowierszowy
blok komentarza */
echo "Witamy ponownie.<br>"; # To jest komentarz w stylu skryptów Uniksa
?>
<?php
/* Poniższa linia spowoduje wypisanie "To wyświetli
nic."
*/
?>
To wyświetli <?php # echo "coś"; ?> nic.<br>
<?php
/*
echo "A tutaj mamy problem."; /* Komentarz ten jest
nieprawidłowy */
*/
?>
Typy
PHP posiada następujące typy: liczby zmiennoprzecinkowe, liczby całkowite, ciągi, tablice i obiekty. Typ
zmiennej jest ustalany w oparciu o kontekst w jakim jest użyta zmienna i nie jest on jawnie ustalany przez
programistę. Jest to ważna cecha o której należy pamiętać podczas programowania aplikacji PHP, ponieważ
niejawna konwersja typów może spowodować trudne do odnalezienia błędy. Na przykład poniższa instrukcja jest
prawidłowa i spowoduje wyświetlenie liczby 9:
print( 3* "3 małe świnki");
Aby można było zapanować nad typami, PHP posiada funkcje gettype() i settype() oraz kilka funkcji
przeznaczonych dla określonych typów, na przykład is_integer() lub is_array(). W skorowidzu funkcji na
końcu książki znajduje się pełne omówienie tych funkcji. Teraz zostanie opisany każdy z typów zmiennych
(oprócz obiektów). Obiekty PHP zostaną opisane w dalszej części rozdziału.
Liczby — całkowite i zmiennoprzecinkowe
Liczby całkowite można podawać używając notacji dziesiętnej, ósemkowej i szesnastkowej. Liczby
zmiennoprzecinkowe można podawać używając notacji zwykłej lub zapisu naukowego. Na poniższym wydruku
pokazana jest składnia PHP dla wszystkich tych notacji.
Wydruk 2.4. Reprezentacja liczb
<?php
$int1 = 523; // liczba dziesiętna
$int2 = -523; // dziesiętna ujemna
$int3 = 01013; // ósemkowa reprezentacja liczby 523
$int4 = 0x20B; // szesnastkowa reprezentacja liczby 523
$float1 = 523.197; // zwykły zapis liczby zmiennoprzecinkowej
$float2 = 5.23197e2; // notacja naukowa liczby zmiennoprzecinkowej
/* Wypisanie wszystkich liczb.
Wyświetla "523, -523, 523, 523, 523.197, 523.197". */
print( "$int1, $int2, $int3, $int4, $float1, $float2<br>" );
?>
Ciągi
Ciągi w PHP są ograniczane apostrofami (') lub cudzysłowami ("). Zapisy te różnią się sposobem
interpretacji ciągu. Jeżeli ciąg jest otoczony cudzysłowami, zmienne zapisane w ciągu zostają zamienione na ich
wartości. Aby zapisać znaki specjalne w ciągach otoczonych cudzysłowami, należy użyć znaku lewego ukośnika
(\), tak jak zostało to pokazane w tabeli 2.1.
Tabela 2.1. Znaki specjalne w ciągach otoczonych cudzysłowami
Sekwencja znaków
Znaczenie
\n
nowa linia
\r
powrót karetki (CR)
\t
tabulacja
\\
lewy ukośnik
\"
cudzysłów
\$
znak dolara
W ciągach otoczonych apostrofami zmienne nie są zastępowane. Jedynymi dopuszczalnymi sekwencjami
sterującymi są te oznaczające lewy ukośnik (\\) i apostrof (\'). Sekwencje te pozwalają na wpisanie do ciągu
znaku apostrofu i lewego ukośnika. Ciągi mogą być łączone przy użyciu operatora kropki (.). Dokładniej jest to
opisane w części rozdziału na temat operatorów. Podobnie jak w języku C, mamy dostęp do poszczególnych
znaków ciągu, traktując go jak tablicę znaków.
Wydruk 2.5. Przykład operacji na ciągach
<?php
Rozdział 2 – Język
24
$aStr1
print(
$aStr2
print(
$aStr3
= "To jest zwykły ciąg.";
"$aStr1<br>" );
= "Thatcher";
"$aStr2<br>" );
= "Nazywam się $aStr2";
// $aStr3 = "Nazywam się Thatcher"
print( "$aStr3<br>" );
$aStr4 = "Nazywam się \$aStr2";
// $aStr4 = "Nazywam się $aStr2"
print( "$aStr4<br>" );
$aStr5 = 'Nie rozwijaj \'$aStr2\'';
// $aStr5 = "Nie rozwijaj '$aStr2'"
print( "$aStr5<br>" );
// wypisuje "Nazywam się Thatcher i Nazywam się $aStr2"
print( "$aStr3" . " i " . "$aStr4" );
?>
Z powodu ulotnej natury typów w PHP, zmienne mogą zmieniać swój typ w zależności od kontekstu w
jakim występują. Liczby mogą być konwertowane niejawnie na ciągi, jeżeli zostaną użyte jako argument
operatora operującego na ciągach. Ciągi mogą również zostać skonwertowane na liczby, jeżeli będą użyte w
wyrażeniach matematycznych. Jeżeli PHP próbuje skonwertować ciąg na liczbę, korzysta z następujących zasad:
• Jeżeli ciąg zaczyna się od danych numerycznych, zostaną one skonwertowane na liczbę.
• Jeżeli ciąg nie zaczyna się prawidłowymi danymi liczbowymi, wartością ciągu będzie zero (0).
• Jeżeli dane numeryczne zawierają jeden ze znaków .,e lub E, wartość będzie liczbą zmiennoprzecinkową
a w przeciwnym przypadku liczbą całkowitą.
Prawidłowymi danymi numerycznymi są: opcjonalny znak po którym następuje jedna lub więcej cyfr,
opcjonalna kropka dziesiętna oraz opcjonalny znak wykładnika. Znakiem wykładnika jest „e” lub „E”, po którym
następuje jedna lub więcej liczb.
Wydruk 2.6. Niejawna konwersja pomiędzy ciągiem i liczbą
<?php
$aVar = 123;
print( "\$aVar = $aVar, typ = " . gettype( $aVar ) . "<br>" );
$aVar2 = $aVar . " niejawnie skonwertowane do ciągu";
print( "\$aVar2 = $aVar2, typ = " . gettype( $aVar2 ) . "<br>" );
$aVar3 = $aVar2 + 1; // niejawna konwersja na liczbę całkowitą
print( "\$aVar3 = $aVar3, typ = " . gettype( $aVar3 ) . "<br>" );
$aVar3 = $aVar2 * 1.1; // niejawna konwersja na liczbę zmiennoprzecinkową
print( "\$aVar3 = $aVar3, typ = " . gettype( $aVar3 ) . "<br>" );
$aNotNumber = "abc";
$aVar4 = $aNotNumber * 1; // próba konwersji na liczbę, zwracane jest 0
print( "\$aVar4 = $aVar4, typ = " . gettype( $aVar4 ) . "<br>" );
$aIsNumber = "3 małe świnki";
$aVar5 = $aIsNumber + 1; // konwersja $aIsNumber na liczbę 3
print( "\$aVar5 = $aVar5, typ = " . gettype( $aVar5 ) . "<br>" );
?>
Tablice
Tablice w PHP zachowują się zarówno tak jak tablice indeksowane (wektory) oraz jak tablice mieszające
(asocjacyjne). PHP pozwala również na tworzenie tablic wielowymiarowych. Z powodu unikalnej konstrukcji
tablic w PHP, można indeksować jeden wymiar tablicy wielowymiarowej liczbami a inny w sposób asocjacyjny.
Tablice mogą być tworzone przy użyciu funkcji list() lub array() albo poprzez jawne podanie każdej z
wartości. W skorowidzu funkcji na końcu książki zostały opisane wszystkie funkcje do manipulacji tablicami.
Jednowymiarowe tablice mogą zamieniane w ciągach przez mechanizm zastępowania zmiennych na
wartości w sposób identyczny jak wszystkie inne zmienne. W przypadku tablic wielowymiarowych należy użyć
nawiasów klamrowych do zaznaczenia indeksów. Poniższy wydruk pokazuje przykłady użycia różnych typów
tablic.
Wydruk 2.7. Inicjowanie i użycie tablic
<?php
// Jawne tworzenie prostej tablicy
$a[0] = "Ryan";
$a[1] = "Scott";
$a[] = "Randall"; // jawne przypisanie do indeksu (klucza) 2
$a[] = "Sherie"; // jawne przypisanie do indeksu (klucza) 3
25
PHP – Kompendium wiedzy
print( "$a[3], $a[2], $a[1], $a[0]<br>" );
// Tworzenie tablicy asocjacyjnej
$color["niebieski"] = "#0000FF";
$color["zielony"] = "#00FF00";
$color["czerwony"] = "#FF0000";
print( "Wartość szesnastkowa koloru czerwonego wynosi {$color['czerwony']}<br>" );
// Tworzenie tej samej co poprzedniej tablicy asocjacyjnej
// tylko nieco prościej
$color = array( "niebieski" => "#0000FF",
"zielony" => "#00FF00",
"czerwony" => "#FF0000" );
print( "Wartość szesnastkowa koloru zielonego wynosi {$color['zielony']}<br>" );
// Ręczne tworzenie tablicy wielowymiarowej
$m[0][0] = "Zero Zero";
$m[0][1] = "Zero Jeden";
print( "Wartością \$m[0][1] jest {$m[0][1]}<br>" );
// Ręczne tworzenie asocjacyjnej tablicy wielowymiarowej
$counties["Idaho"][0] = "Ada";
$counties["Idaho"][1] = "Adams";
$counties["Idaho"][2] = "Bannock";
$counties["Arizona"][0] = "Apache";
$counties["Arizona"][1] = "Cochise";
$counties["Arizona"][2] = "Coconino";
print( "\$counties['Idaho'][0] = {$counties['Idaho'][0]}<br>" );
?>
Zmienne i stałe
Zmienne PHP są oznaczane znakiem dolara ($), po którym następuje nazwa zmiennej. Wielkość liter w
nazwach zmiennych jest rozróżniana. Prawidłowe nazwy zmiennych muszą zaczynać się literą lub znakiem
podkreślenia, po których może nastąpić litera, liczba lub znak podkreślenia. Prawidłowymi literami w zmiennych
są a-z, A-Z lub dowolne znaki ASCII z zakresu 127-255 (0x7f-0xff).
Wydruk 2.8. Nazwy zmiennych
<?php
$variable1 = "Ryan";
$variable2 = "Scott";
print( "$variable1, $variable2<br>" ); // wypisuje "Ryan, Scott"
$1variable = 123; // nieprawidłowa nazwa zmiennej
$_test = "test";
// prawidłowo, rozpoczyna się podkreśleniem
$_ąęć = "test2";
// prawidłowo
?>
Wartości mogą być przypisywane do zmiennych przez wartość lub przez referencję. Gdy przypisanie jest
realizowane przez wartość, obliczona wartość wyrażenia jest przepisywana do docelowej zmiennej. Po
przypisaniu zmienne są niezależne i zmiana wartości w jednej nie wpływa na wartość drugiej zmiennej.
Gdy wartości są przypisywane przez referencję, nowa zmienna staje się odwołaniem do oryginalnej
zmiennej. Zmiana wprowadzona do dowolnej zmiennej powoduje zmianę drugiej. Aby wykonać przypisanie
przez referencję, należy poprzedzić nazwę znakiem &.
Wydruk 2.9. Przypisywanie zmiennych
<?php
$variable1 = "Ryan";
$variable2 = $variable1;
// przypisanie wartości
print( "$variable1, $variable2<br>" ); // wypisuje "Ryan, Ryan"
$variable2 = "Scott";
print( "$variable1, $variable2<br>" ); // wypisuje "Ryan, Scott"
$variable3 = &$variable1;
// przypisanie przez referencję
print( "$variable1, $variable3<br>" ); // wypisuje "Ryan, Ryan"
$variable3 = "Katie";
print( "$variable1, $variable3<br>" ); // wypisuje "Katie, Katie"
?>
Zmienne predefiniowane
Oprócz zmiennych definiowanych przez użytkownika, w PHP istnieją zmienne tworzone przez system.
Lista tych zmiennych zależy od kontekstu wykonania skryptu (na przykład, czy jest uruchamiany samodzielnie,
Rozdział 2 – Język
26
czy poprzez serwer WWW), wersji PHP i typu serwera WWW. Ponieważ lista zmiennych jest zależna od wielu
czynników, niektóre z nich mogą nie być nigdy dostępne.
PHP generuje również zmienne dla cookie i danych formularzy przesyłanych za pomocą metod GET i
POST. Szczegółowe omówienie tych zmiennych zawarte jest w rozdziale 3 „Formularze i cookie”.
Część ta zawiera podzbiór dostępnych zmiennych dostępnych w czasie pracy PHP4 wraz z serwerem
Apache 1.3.11. Aby zobaczyć wszystkie zmienne dostępne w środowisku można użyć funkcji phpinfo().
Kompletniejsza lista predefiniowanych zmiennych znajduje się w skorowidzu na końcu książki. Tabela 2.2.
zawiera podzbiór zmiennych środowiska Apache, tabela 2.3., podzbiór zmiennych środowiska systemu a tabela
2.4. zawiera zmienne generowane przez PHP. W tabeli 2.5. zebrane są operatory arytmetyczne, natomiast
operatory bitowe w tabeli 2.6. Tabela 2.7. zawiera operatory porównania, tabela 2.8 operatory zwiększania i
zmniejszania a tabela 2.9. zawiera operatory logiczne. Ostatnia tabela, 2.10. zawiera operatory przypisania.
Tabela 2.2. Zmienne środowiska serwera Apache
Zmienna
Definicja
HTTP_HOST
Zawartość nagłówka Host: o ile został
wysłany przez przeglądarkę.
HTTP_USER_AGENT
Zawartość nagłówka User Agent:
wysłanego przez przeglądarkę. Nagłówek ten
opisuje przeglądarkę żądającą strony, na
przykład: „Mozilla/4/0 (compatible; MSIE
5.01; Windows NT)”. Więcej na temat
wykorzystania tej zmiennej znajduje się w
rozdziale 9 „Niezależność od przeglądarki”.
REMOTE_ADDR
Adres IP użytkownika oglądającego
stronę.
SERVER_PROTOCOL
Nazwa i wersja protokołu za pomocą
którego zostało wysłane żądanie strony, na
przykład HTTP/1.1.
GATEWAY_INTERFACE
Wersja specyfikacji CGI używanej
przez serwer, na przykład CGI/1.1.
Tabela 2.3. Zmienne środowiska systemu
Zmienna
HOSTNAME
HOSTTYPE
PATH
OSTYPE
Definicja
Nazwa komputera serwera.
Typ komputera, na przykład i386.
Systemowa ścieżka serwera.
System operacyjny działający
serwerze, na przykład Linux.
na
Tabela 2.4. Zmienne generowane przez PHP
Zmienna
PHP_SELF
HTTP_COOKIE_VARS
HTTP_GET_VARS
HTTP_POST_VARS
27
Definicja
Nazwa pliku z wykonywanym
skryptem.
Tablica
asocjacyjna
zmiennych
przekazanych do skryptu poprzez cookie
HTTP.
Tablica
asocjacyjna
zmiennych
przekazanych do skryptu za pomocą metody
GET.
Tablica
asocjacyjna
zmiennych
przekazanych do skryptu za pomocą metody
POST.
PHP – Kompendium wiedzy
Tabela 2.5. Operatory arytmetyczne
Operator
Nazwa
+
Dodawanie
Odejmowanie
Przykład
Wynik
Suma $a i $b
Różnica $a i
$a + $b
$a - $b
$b
*
/
%
$a * $b
Mnożenie
Dzielenie
Reszta
dzielenia
$a / $b
z
$a % $b
Tabela 2.6. Operatory bitowe
Operator
Nazwa
&
Iloczyn bitowy
$a & $b
|
$a | $b
Suma bitowa
Przykład
^
Różnica
symetryczna
$a ^ $b
~
Negacja
~$a
<<
Przesunięcie w
$a << $b
Przesunięcie w
$a >> $b
lewo
>>
prawo
Tabela 2.7. Operatory porównania
Operator
Nazwa
==
Równy
$a == $b
===
Identyczny
$a === $b
!=
Różny
$a != $b
<
Mniejszy
$a < $b
>
Większy
$a > $b
<=
Mniejszy
lub
$a <= $b
Większy
lub
$a >= $b
Przykład
równy
>=
równy
Iloczyn $a i $b
Iloraz $a i $b
Reszta
z
dzielenie $a przez $b
Wynik
Bity ustawione
w $a i $b są ustawione
Bity ustawione
w $a lub $b są
ustawione
Bity ustawione
w $a lub $b, ale nie w
obu
na
raz
są
ustawione
Bity ustawione
nie są teraz ustawione
i odwrotnie
Przesunięcie
bitów w $a w lewo o
$b kroków
Przesunięcie
bitów w $a w prawo o
$b kroków
Wynik
jeżeli $a
jest równe $b
True, jeżeli $a
jest równe $b i są one
tych samych typów
True, jeżeli $a
jest różne od $b
True, jeżeli $a
jest mniejsze od $b
True, jeżeli $a
jest większe od $b
True, jeżeli $a
jest mniejsze lub
równe $b
True, jeżeli $a
jest
większe
lub
równe $b
True,
Tabela 2.8. Operatory zwiększania i zmniejszania
Rozdział 2 – Język
28
Operator, przykład
$a++
Nazwa
Postinkrementacja
++$a
Preinkrementacja
$a--
Postdekrementacja
--$a
Predekrementacja
Tabela 2.9. Operatory logiczne
Operator
Nazwa
and
Iloczyn
logiczny
or
Wynik
Zwraca $a, a następnie
zwiększa $a o jeden
Zwiększa $a o jeden i
zwraca $a
Zwraca $a, a następnie
zmniejsza $a o jeden
Zmniejsza $a o jeden i
zwraca $a
Przykład
$a and $b
i
$b
True
Suma logiczna
$a or $b
Wynik
True, jeżeli $a
mają wartość
True,
lub
$b
jeżeli $a
mają wartość
True
xor
!
&&
Różnica
symetryczna
Negacja
$a xor $b
!$a
$a && $b
Iloczyn
logiczny
True,
jeżeli $a
mają wartość
True, ale nie razem
True, jeżeli $a
nie jest True
True, jeżeli $a
i $b mają wartość
lub
$b
True
||
Suma logiczna
$a || $b
True,
lub
$b
jeżeli $a
mają wartość
True
Tabela 2.10. Operatory przypisania
Operator
Przykład
=
$a = $b
+=
$a += $b
-=
$a -= $b
*=
$a *= $b
/=
$a /= $b
.=
$a .= $b
%=
$a %= $b
|=
$a |= $b
Wynik
Przypisuje wartość
$b
do $a.
29
Przypisuje
wartość
($a+$b)
do $a. Jest to
identyczne z $a=$a+$b.
Przypisuje
wartość
($a-$b)
do $a. Jest to
identyczne z $a=$a-$b.
Przypisuje
wartość
($a*$b)
do $a. Jest to
identyczne z $a=$a*$b.
Przypisuje
wartość
($a/$b)
do $a. Jest to
identyczne z $a=$a/$b.
Przypisuje
wartość
($a.$b)
do $a. Jest to
identyczne z $a=$a.$b.
Przypisuje
wartość
($a%$b)
do $a. Jest to
identyczne z $a=$a%$b.
Przypisuje
wartość
PHP – Kompendium wiedzy
do $a. Jest to
identyczne z $a=$a|$b.
Przypisuje
wartość
($a&$b)
do $a. Jest to
identyczne z $a=$a&$b.
Przypisuje
wartość
($a^$b)
do $a. Jest to
identyczne z $a=$a^$b.
Przypisuje
wartość
($a<<$b) do $a. Jest to
identyczne z $a=$a<<$b.
Przypisuje
wartość
($a>>$b) do $a. Jest to
identyczne z $a=$a>>$b.
($a|$b)
&=
$a &= $b
^=
$a ^= $b
<<=
$a <<= $b
>>=
$a >>= $b
Zasięg zmiennych
Ogólnie rzecz ujmując, zmienne globalne PHP mają taki sam zasięg. Rozciąga się on również na pliki
dołączane. Wewnątrz funkcji definiowanych przez użytkownika zmienne mają zasięg lokalny. Zmienne globalne
muszą być deklarowane jako globalne, aby mogły być wykorzystywane wewnątrz funkcji. PHP posiada również
zmienne statyczne, które deklarowane wewnątrz funkcji zapewniają utrzymywanie swojej wartości pomiędzy
kolejnymi wywołaniami funkcji.
Wydruk 2.10. Zasięg zmiennych
<?php
$aGlobal1 = "To jest test";
/*
Dołączamy inny plik z kodem PHP. POwyższa zmienna
$aGlobal1, będzie dostępna w dołączanym pliku.
*/
include( "example10_inc.php" );
function DoPrint( )
{
/*
Poniższa instrukcja wydrukuje tylko <br>
ponieważ zmienna $aGlobal1 wewnątrz funkcji
jest poza zasięgiem.
*/
print( "$aGlobal1<br>" );
}
DoPrint();
function DoPrint2( )
{
global $aGlobal1;
/*
Poniższa instrukcja wypisze wartość zmiennej
ponieważ została zadeklarowana jako globalna.
*/
print( "$aGlobal1<br>" );
}
DoPrint2();
function StaticFunc( )
{
static $aVal = 0;
print( "$aVal<br>" );
$aVal++;
}
// Poniższe wywołania spowodują wypisanie 0, a następnie 1
StaticFunc();
StaticFunc();
?>
--- Zawartość pliku example10_inc.php3 --<?php
print( "$aGlobal1<br>" );
?>
Rozdział 2 – Język
30
Stałe
PHP posiada kilka predefiniowanych stałych oraz pozwala na definiowanie własnych. Pełna lista stałych
znajduje się w skorowidzu na końcu książki. Aby zdefiniować nową stałą używa się funkcji define(). Zauważ, że
stałe PHP nie są makrami w stylu C i dlatego muszą być wartościami skalarnymi.
Wydruk 2.11. Stałe
<?php
define( "aString", "To jest stały ciąg znaków" );
define( "aNumber", 1 );
print( "Mamy tutaj zdefiniowane " . aNumber . " stałych.<br>" );
print( "Jej wartością jest '" . aString . "'<br>" );
?>
Operatory i kolejność operatorów
PHP posiada zestaw operatorów znanych programistom C i C++. W tabelach od 2.5. do 2.10.
zamieszczone zostało zestawienie dostępnych operatorów.
Oprócz operatorów umieszczonych w tabelach istnieje jeszcze kilka operatorów, ale są one trudniejsze do
klasyfikacji. Operator trójskładnikowy, zapisywany jako ?: jest dostępny zarówno w PHP jak i w C. Wyrażenie
$wart = (wyrażenie1) ? (wyrażenie2) : (wyrażenie3); przypisuje do zmiennej $wart wartość wyrażenie2, jeżeli
wyrażenie1 będzie miało wartość True, natomiast w przeciwnym przypadku $wart będzie miało wartość
wyrażenie3.
Operator wykonania oznaczany przez znak ` (na jednym klawiszu ze znakiem ~) jest podobny do
operatora dostępnego we wielu językach programowania powłoki. Wyrażenie otoczone znakami ` jest
wykonywane na serwerze a zwracana wartość przekazywana do zmiennej.
PHP posiada również operator kontroli błędów @. Gdy operator ten jest umieszczony przed wyrażeniem,
nie są generowane komunikaty błędów powodowanych przez to wyrażenie. Użycie tego operatora pozwala na
stworzenie lepszej obsługi błędów, o ile uaktywniona jest opcja track_errors. Gdy opcja ta jest aktywna,
komunikaty błędów zatrzymane przez operator @ są zapamiętywane w zmiennej globalnej $php_errormsg.
Zmienna ta jest nadpisywana przez kolejne błędy, więc aby kontrola błędów działała poprawnie, zmienna ta
powinna być sprawdzana możliwie szybko.
Wydruk 2.12. Niektóre działania z operatorami
<?php
$aNum1 = 1;
$aNum2 = 2;
$aVal
= ( $aNum1 == $aNum2 ) ? "Wartości są równe" :
"Wartości są różne";
print( "$aVal<br>" ); // drukuje "Wartości są różne"
$aVal
= ( 1 == "1" ) ? "Wartości są równe" :
"Wartości są różne";
print( "$aVal<br>" ); // drukuje "Wartości są równe"
$aVal
= ( 1 === "1" ) ? "Wartości są identyczne" :
"Wartości nie są identyczne";
print( "$aVal<br>" ); // prints "Wartości nie są identyczne"
/*
Poniższy fragment powoduje przypisanie do $aListing
zawartości bieżącego katalogu serwera,
a następnie konwersję znaków nowej linii
na znaczniki <br> I wypisanie wyników
*/
$aListing = `ls -l`;
$aFmtList = nl2br( $aListing );
print( "<br>Zawartość katalogu:<br><b>$aFmtList</b><br>" );
?>
31
PHP – Kompendium wiedzy
Programowanie przepływu sterowania
PHP posiada standardowe instrukcje programowania przepływu sterowania takie jak if oraz pętle while i
for. Programiści C nie będą mieli kłopotu ze składnią tych instrukcji. Dodatkowo PHP posiada dwie funkcje
dołączania plików z kodem źródłowym: include() i require().
if, else, elseif
Jest to oczywiście najważniejszy element języka. Instrukcja
tworzenie rozgałęzień na podstawie wyrażeń logicznych.
Wydruk 2.13. Przykład użycia if, else i elseif
if
organizuje przepływ sterowania poprzez
<?php
if ( 1 < 2 )
print( "To zostanie wydrukowane.<br>" );
else
print( "To nie zostanie wydrukowane.<br>" );
$aValue = 2;
if ( $aValue == 1 )
{
// Używamy nawiasów klamrowych do otaczania bloków instrukcji
print( "\$aValue == 1<br>" );
}
elseif ( $aValue == 2 )
{
print( "\$aValue == 2<br>" );
}
elseif ( $aValue == 3 )
{
print( "\$aValue == 3<br>" );
}
else
{
print( "\$aValue nie jest 1, 2 ani 3<br>" );
}
?>
while
Jest to najprostszy typ pętli w PHP, która zachowuje się identycznie jak w C i innych językach wysokiego
poziomu.
do .. while
Mimo, że jest to pętla podobna do while, to w pętli do..while warunek pętli jest sprawdzany po
pierwszym przebiegu pętli. Gwarantuje to, że ciało pętli zostanie wykonane co najmniej raz.
Wydruk 2.14. Przykład użycia while i do..while
<?php
print( "Liczenie w górę przy użyciu <b>while</b>.<br>" );
$nIndex = 0;
// wypisuje liczby od 0 do 9
while ( $nIndex < 10 )
{
print( "$nIndex<br>" );
$nIndex++;
}
print( "Liczenie w dół przy użyciu <b>do..while</b>.<br>" );
// wypisuje liczby od 10 do 1
do
{
print( "$nIndex<br>" );
$nIndex--;
} while ( $nIndex > 0 );
?>
Rozdział 2 – Język
32
for
Pętla for jest najbardziej złożoną instrukcją pętli w PHP, ale jest ona składniowo identyczna z instrukcją
for w języku C. Jej składnia jest następująca:
for (wyr1; wyr2; wyr3) instrukcja
Wartość pierwszego wyrażenia (wyr1) jest obliczana raz, na początku pętli. Wartość drugiego (wyr2) jest
obliczana na początku każdego przebiegu pętli. Jeżeli będzie ono miało wartość True, pętla będzie się nadal
wykonywała i zostaną wykonane instrukcje ciała pętli. Jeżeli drugie wyrażenie jest puste, przyjmowane jest, że
ma ono wartość True. Na końcu każdego przebiegu pętli wykonywane jest trzecie wyrażenie (wyr3). Każde z tych
trzech wyrażeń może być puste.
Wydruk 2.15. Przykład użycia for
<?php
// Wypisuje liczby od 0 do 9
for ( $nIndex = 0; $nIndex < 10; $nIndex++ )
{
print( "$nIndex<br>" );
}
/*
$nIndex ma wartość 10. Pokażemy teraz, że
każde z trzech wyrażeń może zostać opuszczone.
Nie jest to zalecane ze względu na czytelność kodu.
Pętla powoduje wypisanie liczb od 10 do 1
*/
for ( ; $nIndex > 0; $nIndex-- )
{
print( "$nIndex<br>" );
}
?>
foreach
Wyrażenie foreach jest wygodnym sposobem na przeglądanie tablic. Podobne konstrukcje znajdują się w
VBScript, Perl i innych językach. PHP posiada dwa warianty składni:
foreach ( tablica as zmienna_wartosc) instrukcja
foreach ( tablica as zmienna_klucz => zmienna_wartosc) instrukcja
Pierwsza postać pętli przebiega po podanej tablicy i w każdym przebiegu wartość bieżącego elementu
tablicy jest przypisywana do zmiennej (zmienna_wartosc) a wskaźnik bieżącego elementu tablicy jest przesuwany.
Druga postać realizuje to samo, ale dodatkowo do zmiennej (zmienna_klucz) jest przypisywany klucz bieżącej
pozycji.
Wydruk 2.16. Przykład użycia foreach
<?php
$aArray = array( "Czerwony", "Zielony", "Niebieski" );
foreach( $aArray as $aValue )
{
print( "Bieżąca wartość to $aValue<br>" );
}
$aColorArray = array(
"Czerwony" => "#FF0000",
"Zielony" => "#00FF00",
"Niebieski" => "#0000FF" );
foreach( $aColorArray as $aKey => $aValue )
{
print( "Wartość szesnastkowa $aKey to $aValue<br>" );
}
?>
switch
Instrukcja switch upraszcza tworzenie wielokrotnych warunków. Jest ona często używana zamiast
skomplikowanych konstrukcji if...elseif...else zawierających wiele wystąpień elseif. Składnia i
implementacja tej instrukcji jest identyczna jak w C. Korzystnym ulepszeniem w PHP jest możliwość używania
ciągów jako wyrażeń instrukcji switch.
33
PHP – Kompendium wiedzy
Programiści Delphi i Pascala mają zwykle kłopoty z zapamiętaniem, że w konstrukcji switch w C
występują instrukcje break. Czasami opuszczenie tej instrukcji jest wygodne. Poniższy przykład ilustruje częste
zastosowania instrukcji switch.
Wydruk 2.17. Przykłady użycia switch
<?php
$nIndex = 2;
// Najprostsza instrukcja switch
switch ( $nIndex )
{
case 0:
print( "zero<br>" );
break;
case 1:
print( "jeden<br>" );
break;
case 2:
print( "dwa<br>" );
break;
}
// Użycie frazy 'default'
$nIndex = 17;
switch ( $nIndex )
{
case 0:
print( "zero<br>" );
break;
case 1:
print( "jeden<br>" );
break;
case 2:
print( "dwa<br>" );
break;
default:
print( "Nie jest to zero, jeden ani dwa<br>" );
break;
}
// Switch z użyciem ciągu
$aColor = "niebieski";
switch( $aColor )
{
case "czerwony":
print( "#FF0000<br>" );
break;
case "zielony":
print( "#00FF00<br>" );
break;
case "niebieski":
print( "#0000FF<br>" );
break;
default:
print( "inny<br>" );
break;
}
/*
Opuszczenie instrukcji break spowoduje
wykonanie wszystkich wyrażeń po pasującej pozycji.
Jeżeli $nIndex jest 0, zostaną wykonane wszystkie
trzy instrukcje print. Jeżeli $nIndex jest 1, wykonane zostaną
ostatnie dwie instrukcje print.
*/
$nIndex = 0;
switch ( $nIndex )
{
case 0:
print( "zero<br>" );
case 1:
print( "jeden<br>" );
case 2:
print( "dwa<br>" );
}
/*
opuszczenie instrukcji break może być czasami przydatne
*/
$aColor = "Czerwony";
switch( $aColor )
Rozdział 2 – Język
34
{
case "czerwony":
case "Czerwony":
// Poniższa instrukcja zostanie wykonana, jeżeli $aColor
// będzie miał wartość "Czerwony" lub "czerwony"
print( "#FF0000<br>" );
break;
case "zielony":
case "Zielony":
print( "#00FF00<br>" );
break;
case "niebieski":
case "Niebieski":
print( "#0000FF<br>" );
break;
default:
print( "inny<br>" );
break;
}
?>
break i continue
PHP posiada również znane z C instrukcje break i continue, które pozwalają na dodatkowe sterowanie
pętlami. Obie te instrukcje pozwalają na podanie im parametru numerycznego, który określa ilość zagłębionych
pętli, które należy przerwać lub rozpocząć od początku.
Wyrażenie break kończy wykonanie bieżącej konstrukcji sterującej (pętli lub wyrażenia switch).
Wyrażenie continue jest używane jedynie w pętlach. Powoduje ono opuszczenie pozostałych instrukcji ciała pętli
i rozpoczęcie nowej iteracji.
Najczęściej instrukcje break i continue są stosowane w zagnieżdżonych pętlach. W przypadku pętli
prostych, wyrażenia warunkowe są wystarczające do realizacji tych zadań.
Wydruk 2.18. Przykłady użycia break i continue
<?php
$aArray = array( 4, 5, 15, 12, 7, 3, 20, 11, 31 );
$aCurMax = 17;
/*
Sprawdzamy, czy istnieje w tablicy wartość większa
od bieżącej wartości maksymalnej.
*/
foreach( $aArray as $aValue )
{
/*
Wyrażenie będzie prawdziwe, gdy osiągnięta zostanie wartość
20. Ponieważ wykonujemy instrukcję break,
nie sprawdzamy wartości które są w tablicy po wartości 20
*/
if ( $aValue > $aCurMax )
{
$aCurMax = $aValue;
break; // możemy napisać 'break 1;'
}
}
// wypisuje "Bieżącym maksimum jest 20"
print( " Bieżącym maksimum jest $aCurMax<br>" );
// wypisuje liczby nieparzyste od 0 do 20
$nIndex = 0;
for ( $nIndex = 0; $nIndex < 20; $nIndex++ )
{
if ( ( $nIndex % 2 ) == 0 )
continue; // opcjonalnie 'continue 1;'
print( "$nIndex<br>" );
}
?>
PHP osiada alternatywną składnię dla konstrukcji sterujących if, while, for i switch. W każdej z tych
konstrukcji otwierająca klamra jest zamieniona na dwukropek (:) a zamykająca klamra na odpowiednio endif,
endwhile, endfor i endswitch. Gdy tworzysz duże skrypty wbudowane w HTML, składnia alternatywna może być
użyteczna, ponieważ zapewnia wyraźną identyfikację końca struktur sterujących.
Wydruk 2.19. Przykład użycia alternatywnej składni PHP na stronie HTML
<html>
<head>
<title>Przykład 19</title>
35
PHP – Kompendium wiedzy
</head>
<body>
<!-- Używamy PHP do utworzenia listy opcji -->
<form action="someotherpage.phtml" method="post">
<table>
<tr>
<td>
Wybierz swój rok urudzenia:
</td>
<td>
<select name="BirthYear" size="1">
<?php
/*
Generujemy znaczniki dla lat 1920-2000
w odwrotnej kolejności
*/
$aCurYear = 2000;
while( $aCurYear >= 1920 ):
?>
<option value="<?php print( $aCurYear ); ?>">
<?php print( $aCurYear ); ?>
</option>
<?php
$aCurYear--;
endwhile;
/*
zakładając, że pomiędzy while i endwhile jest dużo więcej tekstu,
może być trudno znaleźć końcowy średnik,
jeżeli użyjemy zwykłej składni.
*/
?>
</select>
</td>
</tr>
</table>
</form>
</body>
</html>
include i require
PHP posiada dwa mechanizmy dołączania plików zewnętrznych: include() i require(). Wyrażenie
jest zwykłą funkcją PHP, natomiast require() jest konstrukcją językową, która posiada kilka
ograniczeń. W obu przypadkach po dołączeniu pliku PHP przechodzi do trybu HTML na początku dołączanego
pliku. Na końcu pliku analizator wraca do trybu PHP. Oznacza to, że dowolny kod zawarty w pliku dołączanym
musi być otoczony prawidłowymi znacznikami PHP.
Funkcja include() jest wykonywana za każdym jej wywołaniem i może znajdować się wewnątrz pętli lub
instrukcji warunkowych. Pozwala to warunkowo włączać pliki, lub włączać grupy plików przy pomocy
odpowiednio skonstruowanej pętli. Funkcja include() pozwala również, aby dołączany plik zwracał wartość,
którą można następnie przypisać do zmiennej. Przetwarzanie pliku w instrukcji include() kończy się, gdy
zostanie napotkana instrukcja return.
Wyrażenie require() różni się tym od include(), że nie wchodzi w skład konstrukcji sterujących.
Oznacza to, że pliki nie mogą być warunkowo dołączane za pomocą require(). Wyrażenie to jest wykonywane
raz, jeżeli znajduje się w pętli lub nawet, jeżeli znajduje się w instrukcji warunkowej, której warunek ma wartość
False. Inną różnicą jest to, że pliki dołączane za pomocą require() nie mogą zwracać wartości. Próba zwrócenia
wartości w wyrażeniu require() powoduje błąd składni.
include()
Funkcje
PHP pozwala na tworzenie funkcji definiowanych przez użytkownika. Funkcje nie muszą być
deklarowane przed ich użyciem w kodzie PHP4. Funkcje w PHP mogą posiadać następujące cechy: zmienne
nazwy funkcji, zmienna liczba argumentów, argumenty domyślne i argumenty przekazywane przez referencję.
PHP pozwala na wykonywanie dowolnego kodu w ciele funkcji, włączając w to wywołania innych funkcji.
Zdolność ta pozwala również na tworzenie funkcji rekurencyjnych. PHP nie pozwala na przeciążanie funkcji, nie
ma również mechanizmu usuwania lub przedefiniowania wcześniej zdefiniowanych funkcji.
Rozdział 2 – Język
36
Domyślnie argumenty są przekazywane przez wartość. Aby przekazać argument przez referencję, należy
poprzedzić nazwę zmiennej znakiem &. Używając argumentów domyślnych, muszą być one umieszczone po
wszystkich argumentach obowiązkowych. W przypadku zmiennej listy argumentów, dostępne są funkcje
func_num_args(), func_get_arg() i func_get_args(), za pomocą których można pobrać dane przekazane jako
argumenty. Poniższe przykłady pokazują użycie funkcji w PHP.
Wydruk 2.20. Przykłady funkcji definiowanych przez użytkownika
<?php
// prosta funkcja
function ReturnSum( $a, $b )
{
return $a + $b;
}
// przekazanie argumentu przez referencję
function StringAppend( &$BaseString, $AddString )
{
// ponieważ jest to przekazane przez referencję, wartość
// $BaseString może być zmieniona poza tą funkcją
$BaseString .= $AddString;
}
// wartości domyślne
/*
Funkcja ta może być wywołana przy użyciu jednej z postaci:
PrintAnchorTag( "href", "text" );
PrintAnchorTag( "href", "text", "target" );
*/
function PrintAnchorTag( $aHREF, $aText, $aTarg = "" )
{
if ( $aTarg == "" )
{
print( "<a href=\"$aHREF\">$aText</a>" );
}
else
{
print( "<a href=\"$aHREF\" target=\"$aTarg\">$aText</a>" );
}
}
// zmienna lista argumentów
function PrintEverything( )
{
$aNumArgs = func_num_args();
for ( $nIndex = 0; $nIndex < $aNumArgs; $nIndex++ )
{
$aArgVal = func_get_arg( $nIndex );
print( "Argument $nIndex: $aArgVal<br>" );
}
}
print( "ReturnSum( 3, 5 ): " . ReturnSum( 3, 5 ) . "<br>" );
$aString = "Marysia miała ";
StringAppend( $aString, "małą owieczkę" );
print( "$aString<br>" ); // wypisuje "Marysia miała małą owieczkę"
PrintAnchorTag( "example10.phtml",
"Zobaczmy jeszcze raz przykład 10" );
print( "<br>" );
PrintAnchorTag( "example10.phtml",
"Zobaczmy jeszcze raz przykład 10 w nowym oknie",
"_blank" );
print( "<br>" );
print( "Wywołanie PrintEverything( 1, 2, 3, 4, 5 ):<br>" );
PrintEverything( 1, 2, 3, 4, 5 );
?>
Klasy i programowanie obiektowe
PHP posiada zdolność tworzenia klas za pomocą składni podobnej jak w C++. PHP posiada również
bardzo prostą implementację programowania obiektowego, która jest jednak wystarczająca dla większości
aplikacji WWW. Dostępne jest dziedziczenie jednobazowe, nie ma dziedziczenia wielobazowego. Istnieją
konstruktory klas, ale nie ma destruktorów. PHP posiada (i wymaga używania) wskaźnik $this, który jest
37
PHP – Kompendium wiedzy
stosowany do odwoływania się do metod i zmiennych obiektu. Poniższy przykład pokazuje tworzenie prostej
klasy. Więcej przykładów na ten temat znajdzie się w późniejszych rozdziałach książki.
Wydruk 2.21. Przykłady użycia klas w PHP
<?php
// tworzenie prostej klasy
class ShoppingBasket
{
var $fItems;
var $fCurValue;
/*
jest to konstruktor klasy,
ponieważ ma taką samą nazwę jak klasa.
Tak samo jak w C++ konstruktor może posiadać argumenty
W tym przypadku jest to początkowa wartość koszyka.
Może być to stała prowizja lub rabat..
*/
function ShoppingBasket( $aInitialValue = 0.0 )
{
$this->fCurValue = $aInitialValue;
}
// Dodanie określonej ilości przedmiotów
function AddItem( $aName, $aValue, $aQuantity = 1 )
{
$this->fItems[$aName]["Quantity"] += $aQuantity;
$this->fItems[$aName]["Value"] = $aValue;
$this->fCurValue += $aValue * $aQuantity;
return True;
}
function RemoveItem( $aName, $aQuantity = 1 )
{
// Usuwamy określoną ilość przedmiotów
// jedynie, gdy była dostępna wystarczająca ich ilość
if ( $this->fItems[$aName]["Quantity"] > $aQuantity )
{
$this->fItems[$aName]["Quantity"] -= $aQuantity;
$this->fCurValue -= $this->fItems[$aName]["Value"] *
$aQuantity;
}
else
{
return False;
}
}
function PrintBasket( )
{
if ( count( $this->fItems ) > 0 )
{
print( "Zawartość koszyka:<blockquote>" );
foreach( $this->fItems as $aKey => $aValue )
{
print( "{$aValue['Quantity']} $aKey<br>" );
}
print( "Wartość całkowita: $" .
number_format( $this->fCurValue, 2 ) );
print( "</blockquote>" );
print( "<br>" );
}
else
{
print( "<i>Koszyk jest pusty</i><br><br>" );
}
}
}
/*
Tworzenie nowego obiektu ShoppingBasket. Dodanie kilku przedmiotów
usunięcie kilku przedmiotów i wypisanie zawartości koszyka
*/
$aBasket = new ShoppingBasket( 3.50 );
$aBasket->PrintBasket();
$aBasket->AddItem( "gizmo", 1.50 ); // dodanie 1 gizmo
$aBasket->PrintBasket();
$aBasket->AddItem( "foobar", 2.10, 6 ); // dodanie 6 foobarów
$aBasket->PrintBasket();
$aBasket->RemoveItem( "foobar", 15 );
Rozdział 2 – Język
38
$aBasket->PrintBasket();
$aBasket->RemoveItem( "foobar", 3 );
$aBasket->PrintBasket();
?>
Porównywanie wzorców
PHP posiada dwa typy funkcji do porównywania wzorców (lub wyrażeń regularnych). Pierwszy typ jest
zgodny ze specyfikacją POSIX i są to funkcje ereg(), eregi(), ereg_replace(), eregi_replace() oraz split().
Każda z tych funkcji jako pierwszego argumentu wymaga wyrażenia regularnego. PHP korzysta z rozszerzonych
wyrażeń regularnych zdefiniowanych przez POSIX 1003.2. PHP zawiera w katalogu regex strony podręcznika,
które w pełni opisują wyrażenia regularne POSIX.
Drugi typ funkcji porównywania wzorców jest zgodny z wyrażeniami regularnymi Perl. Nazwy tych
funkcji są poprzedzone ciągiem preg_. Pełna lista tych funkcji znajduje się w skorowidzu na końcu książki.
Składnia tych wyrażeń jest taka sama jak w Perl 5 z kilkoma różnicami. Bieżąca implementacja tych funkcji
odpowiada Perl 5.005. Różnica pomiędzy implementacją w Perl 5.005 i w PHP jest dokładnie opisana w
dokumentacji PHP dostępnej z witryny http://www.php.net.
Podsumowanie
Rozdział ten jest zwięzłym opisem języka PHP i nie zawiera szczegółowo opisanych podstaw
programowania. Dlatego nie zawiera on dyskusji na temat tego kiedy lub dlaczego należy używać określonych
konstrukcji. Zamieszczone zostały za to przykłady ilustrujące składnię i dostępne funkcje. PHP zawiera wszystkie
własności potrzebne do tworzenia złożonych i łatwych do zarządzania aplikacji WWW. Język jest wystarczająco
sprawny do realizacji większości zadań, ale jest przygotowany do tworzenia aplikacji dla WWW, co zostanie
pokazane w kolejnych rozdziałach.
39
PHP – Kompendium wiedzy
Rozdział 3. Formularze i cookie
Wstęp
W czasie tworzenia dowolnego typu aplikacji utworzenie dobrego mechanizmu interakcji z
użytkownikiem jest jednym z najważniejszych zadań programisty. HTML posiada elementy formularzy, które są
używane do zbierania danych od użytkownika, natomiast PHP zapewnia prosty mechanizm przetwarzania tych
formularzy. Ponieważ PHP został zaprojektowany jako język programowania dla WWW, obsługuje on
automatycznie wiele szczegółów przetwarzania formularzy. Rozdział ten zawiera informacje nie tylko na temat
sposobu użycia formularzy HTML w PHP, ale również na temat kontroli poprawności i przetwarzania danych
formularza. Dla programistów, którzy przechodzą od pisania zwykłych aplikacji do tworzenia aplikacji WWW
przeznaczona jest część zatytułowana „Ważne zagadnienia programowania dla WWW”, która sygnalizuje
niektóre problemy jakie powstają gdy jako urządzenie wyjściowe używana jest przeglądarka WWW. W rozdziale
tym znajduje się również omówienie mechanizmu cookie, ponieważ jest ono składniowo podobne do obsługi
elementów formularzy. Cookie mogą również pomóc w zrealizowaniu mechanizmu utrzymywania stanu, który
jest zwykle potrzebny w czasie dialogu z użytkownikiem.
Konwencje nazw plików
We wszystkich przykładach oraz w mojej aktualnej pracy do oznaczania skryptów PHP które generują strony
HTML używam rozszerzenia .phtml oraz rozszerzeń .php lub .php3 do plików dołączanych. Nie używam
najczęściej używanych rozszerzeń .php i .php3 do stron wyświetlających dane jedynie dlatego, że uważam że
rozszerzenie .phtml lepiej wygląda. Jest to jedyny powód. Do plików dołączanych używam innego
rozszerzenia i chcemy zaznaczyć, że jest to kod PHP. Nie używam typowego rozszerzenia inc.
Możesz używać dowolnego rozszerzenia dla skryptów PHP. Wszystkie rozszerzenia jakich używasz do
skryptów PHP i plików dołączanych powinny zostać dołączone do konfiguracji serwera WWW. Rozszerzenia
te konfiguruje się używając opcji konfiguracji, które zostały opisane w rozdziale 1, „Kompilacja i instalowanie
PHP”. Na przykład, jeżeli używasz rozszerzeń php i inc do oznaczania skryptów PHP i plików dołączanych,
powinieneś się upewnić, że serwer WWW został tak skonfigurowany, że będzie traktował oba te rozszerzenia
jako pliki PHP i przetwarzał je przed wysłaniem do przeglądarki użytkownika. Jeżeli nie zrobisz tego,
użytkownik może zapisać twoje skrypty. Rozważmy następujący przykład:
<!-- Plik: securityhole.phtml -->
<html>
<head>
<title>Przykład: błędny plik dołączany otwiera dziurę
w systemie zabezpieczeń</title>
</head>
<body>
<?php
/*
Plik dołączany bogus.inc, zawiera błąd
ale również znajduje się w nim nazwa użytkownika bazy danych i hasło.
*/
include( "bogus.inc" );
print( "Poznajmy dziurę w systemie bezpieczeństwa.<br>" );
?>
</body>
</html>
<!-- Plik: bogus.inc -->
<?php
// Jest to dołączany plik PHP demonstrujący
// potencjalną dziurę w systemie zabezpieczeń,
// powatającą, gdy źle skonfigurowany zostanie serwer WWW.
$aDatabaseIP
= "12.34.56.123";
$aDatabaseUser = "secretuser";
$aDatabasePass = "secretpassword";
/*
Zagnieżdżony komentarz powoduje błąd.
/* właśnie tutaj */
*/
?>
W przykładzie tym do głównego pliku, securityhole.phtml, dołączany jest plik bogus.inc. Dołączany plik
zawiera dane na temat połączenia z bazą danych, w tym nazwę użytkownika i hasło. Zawiera on również błąd
syntaktyczny. Gdy otwarty zostanie plik securityhole.phtml, wyświetlony zostanie błąd: „Parse error: parse
error in bogus.inc on line 12”.
Dociekliwy użytkownik może spróbować obejrzeć plik bogus.inc wpisując odpowiedni URL w pasku adresu.
Jeżeli serwer WWW jest skonfigurowany taj aby traktować pliki .inc jako tekst (tak jak mój), cały tekst pliku
pojawi się w przeglądarce. Jeżeli serwer WWW jest tak skonfigurowany, aby traktować pliki .inc jak każdy inny
skrypt PHP, użytkownik zobaczy jedynie wcześniej wspomniany komunikat błędu.
Podsumowując. W trakcie tworzenia aplikacji PHP możesz użyć dowolnego rozszerzenia, ale aby uniknąć
potencjalnego zagrożenia bezpieczeństwa należy tak skonfigurować serwer WWW, aby analizował wszystkie
pliki posiadające używane przez ciebie rozszerzenia.
Obsługa formularzy w PHP
Do pobierania danych od użytkownika w HTML stosuje się formularze. W domyślnej konfiguracji PHP
po przesłaniu danych formularza do skryptu PHP, konwertuje wszystkie elementy formularza na zmienne PHP.
Poniższa strona HTML zawiera prosty formularz, do którego należy wpisać nazwę użytkownika i jego hasło. Po
przesłaniu formularza do skryptu post1.phtml, zmienne $UserName i $Password będą zawierały wartości wpisane
jako nazwę użytkownika i hasło.
Wydruk 3.1. Strona HTML i skrypt PHP ilustrujące procedurę logowania się użytkownika.
<!-- To jest strona HTML, listing1.html -->
<html>
<head>
<title>Wydruk 3.1 - listing1.html</title>
</head>
<body>
<form action="post1.phtml" method="post">
Nazwa użytkownika: <input type="text" name="Username"><br>
Hasło: <input type="password" name="Password"><br>
<input type="submit" name="Submit" value="Wyślij">
</form>
</body>
</html>
<!-- To jest skrypt PHP, post1.html -->
<html>
<head>
<title>Wydruk 3.1: post1.phtml</title>
</head>
<body>
<?php
print( "Nazwa użytkownika: $Username<br>" );
print( "Hasło: $Password<br>" );
?>
</body>
</html>
Skalarne i wielowartościowe elementy formularza
Elementy formularzy HTML zawierają zwykle wartości skalarne. Zamieszczony na wydruku 1 przykład
zawiera formularz z dwoma wartościami skalarnymi — nazwą użytkownika i hasłem. Można również tworzyć
elementy formularza zawierające wiele wartości, na przykład listę wielokrotnego wyboru. Aby użyć
nieskalarnych elementów formularza w PHP, należy dodać do nazwy nawiasy kwadratowe oznaczające zmienną
tablicową. Formularz na wydruku 2 pokazuje takie wielowartościowe elementy formularza.
Wydruk 3.2. Formularz HTML z elementami wielowartościowymi
<form action="displayall.phtml" method="post">
<table>
<tr>
41
PHP – Kompendium wiedzy
<td valign="top">
Wybierz kolory które lubisz:
</td>
<td valign="top">
<!-- Nazwy są indeksami tablicy -->
<select name="Colors[]" size="5" multiple>
<option value="Red">Czerwony</option>
<option value="Green">Zielony</option>
<option value="Blue">Niebieski</option>
<option value="Purple">Purpurowy</option>
<option value="Yellow">Żółty</option>
</select>
</td>
</tr>
<tr>
<td valign="top">
Wprowadź twój adres:
</td>
<td valign="top">
<!-- Trzy linie na dane adresowe. Używamy notacji tablicowej
aby zaznaczyć użycie wielu wierszy tablicy -->
<input type="text" name="address[]"><br>
<input type="text" name="address[]"><br>
<input type="text" name="address[]"><br>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="Submit" value="Wyślij">
</td>
</tr>
</table>
</form>
Po przesłaniu danych formularza z wydruku 2 do skryptu PHP, każda z tablic
będzie zawierać zero lub więcej wartości.
$Colors[]
i
$adress[]
Alternatywne metody odczytywania wartości z formularza
PHP posiada alternatywną metodę dostępu do danych przesłanych do skryptu. Predefiniowane zmienne
tablicowe HTTP_GET_VARS i HTTP_POST_VARS zawierają tablice asocjacyjne elementów przesłanych do skryptu przy
pomocy metod odpowiednio GET i POST. Skrypt wyświetlający dane z wydruku 1 może zostać przepisany w
następujący sposób:
<!-- To jest skrypt PHP, post2.html -->
<html>
<head>
<title>Wydruk: post2.phtml</title>
</head>
<body>
<?php
error_reporting( 255 );
print( "Nazwa użytkownika: {$HTTP_POST_VARS['Username']}<br>" );
print( "Hasło: {$HTTP_POST_VARS['Password']}<br>" );
?>
</body>
</html>
W niektórych przypadkach preferowane jest użycie zmiennych HTTP_GET_VARS lub HTTP_POST_VARS zamiast
korzystania ze zmiennych globalnych. Na przykład możesz chcieć wyświetlić w czasie uruchamiania skryptu
wartości wszystkich danych wysłanych z formularza. Jeżeli bardzo przejmujesz się wydajnością serwera WWW,
można tu nieco zyskać, ponieważ PHP nie będzie musiał tworzyć zmiennych globalnych dla każdego z
elementów formularza. Można więc tak skonfigurować PHP, aby nie udostępniał tych zmiennych globalnych i tak
pisać skrypty, aby korzystały z wartości zawartych w tablicach HTTP_GET_VARS i HTTP_POST_VARS. Więcej na temat
tej dyrektywy konfiguracji napisane zostało na końcu książki przy opisie opcji konfiguracji register_globals.
Poniższa funkcja demonstruje użycie tablic HTTP_GET_VARS i HTTP_POST_VARS do wyświetlenia wszystkich
danych przekazanych z formularza do skryptu:
function DisplayGetVars()
{
global $HTTP_GET_VARS;
DisplayArray( $HTTP_GET_VARS );
}
function DisplayPostVars()
{
Rozdział 3 – Formularze i cookie
42
global $HTTP_POST_VARS;
DisplayArray( $HTTP_POST_VARS );
}
Obie z tych funkcji opierają się o funkcję DisplayArray przedstawioną na wydruku 3.3. Jest to prosta
funkcja wyświetlająca wszystkie elementy tablicy w tablicy HTML. Obsługuje ona rekurencyjnie elementy
tablicy, które same są tablicami.
Wydruk 3.3. Funkcja DisplayArray
function DisplayArray( $aArray )
{
// Upewniamy się, czy $aArray jest na pewno tablicą
if ( is_array ($aArray ) && (count( $aArray ) > 0 ))
{
// Rozpoczęcie tabeli
print ("<table border = \"1\">");
// Wyświetlenie nagłówka tabeli
print ( " <tr><th>Klucz</th><th>Wartość</th></tr>");
// Wyświetlenie wszystkich par klucz/wartość z tabeli
foreach( $aArray as $aKey => $aValue )
{
print( "<tr>" );
// Jeżeli bieżąca wartość jest tablicą
// wywołujemy rekurencyjnie funkcję
// w przeciwnym wypadku wyświetlamy wartość
if (!is_array( $aValue ))
{
// jeżeli wartość jest pusta, poinformujmy o tym
if (empty( $aValue ))
{
print( "<td>$aKey</td><td><i>pusty</i></td>");
}
else
{
print( "<td>$aKey</td><td><i>$aValue</i></td>");
}
}
else
{
print( "<td>$aKey(array)</td><td>");
DisplayArray( $aValue );
print ("</td>" );
}
print ("</tr>");
}
print ("</table>");
}
else
{
print("<i>pusty lub nieprawidłowy</i>");
}
}
Używając tej funkcji można pisać własne skrypty PHP wyświetlające wartości wszystkich przesłanych
elementów formularza. Poniższy skrypt, displayall.phtml powoduje wyświetlenie wszystkich danych przesłanych
przez HTTP GET, HTTP POST i cookie odesłane przez przeglądarkę (cookie zostaną omówione w dalszej części
tego rozdziału).
Wydruk 3.4. Skrypt displayall.phtml.
<html>
<head>
<title>Wyświetlenie wszystkich elementów formularza</title>
</head>
<body>
<?php
error_reporting( 255 );
include( "../include/gen_form_funcs.php" );
?>
<h2>Cała zawartość HTTP_GET_VARS</h2>
<?php
DisplayGetVars();
?>
<br><br>
<h2>Cała zawartość HTTP_POST_VARS</h2>
<?php
DisplayPostVars();
?>
<br><br>
<h2>Cała zawartość HTTP_COOKIE_VARS</h2>
<?php
43
PHP – Kompendium wiedzy
DisplayCookieVars();
?>
<br><br>
</body>
</html>
Na rysunkach 3.1. i 3.2. korzystając z formularza z wydruku 2. przedstawiono formularz wprowadzania
danych i wyniki wysłania danych do skryptu displayall.phtml. Zauważmy, że na rysunku 3.2, tablica
HTTP_POST_VARS zawiera trzy elementy: Colors, Address i Submit. Wartości dwóch pierwszych elementów są, jak
się tego można było spodziewać, tablicami. Wartością elementu Submit jest napis umieszczony na przycisku.
Pisząc skrypt obsługujący te wartości należy pamiętać, że element Submit jest zawsze umieszczany w tablicy
HTTP_POST_VARS.
Rysunek 3.1.
Przykład
wielowartościowyc
h elementów
formularza
Rozdział 3 – Formularze i cookie
44
Rysunek 3.2. Wynik
przesłania
formularza
wielowartościoweg
o do
displayall.phtml
Użycie formularzy do przesyłania plików
Większość nowoczesnych przeglądarek posiada zdolność przesyłania plików z dysku komputera
użytkownika na serwer WWW. PHP posiada obsługę przesyłania plików wbudowaną bezpośrednio w język. Jest
ona dokładniej opisana w rozdziale 5 „Wysyłanie plików przez formularz”.
Użycie rysunku jako przycisku wysłania danych
Jeżeli projekt aplikacji WWW tak przewiduje, możesz użyć rysunku w miejsce przycisku HTML
wysyłającego dane formularza do serwera. Dla PHP nie ma znaczenia, czy jest to przycisk czy rysunek, ale jeżeli
używasz rysunku oprócz danych do serwera zostaną wysłane dodatkowo współrzędne x i y (względem lewego
górnego rogu rysunku) punktu gdzie został kliknięty rysunek. Nazwy zmiennych przechowujących współrzędne
są tworzone poprzez dodanie _x i _y do nazwy elementu reprezentującego rysunek. Na przykład na wydruku 5
nazwą elementu rysunku jest SubmitImg. Zmienne reprezentujące współrzędne będą się nazywały SubmitImg_x i
SubmitImg_y. Mechanizm ten jest wygodny do tworzenia map obrazów po stronie serwera.
Wydruk 3.5. Przykład użycia rysunku w formularzu
<!-- Strona HTML, imgsubmit.html -->
<html>
<head>
<title>Użycie rysunku zamiast przycisku</title>
</head>
<body>
<form action="displayall.phtml" method="post">
Nazwa użytkownika: <input type="text" name="Username"><br>
Hasło: <input type="password" name="Password"><br>
<input type="image" name="SubmitImg" src="submit.gif">
</form>
</body>
</html>
45
PHP – Kompendium wiedzy
Niektóre przeglądarki posiadają mechanizm pozwalający wykorzystać klawisz Enter zamiast klikania w
przycisk na formularzu. Gdy użyjemy rysunku zamiast przycisku, mechanizm ten nadal będzie działał, ale nie
zostaną wtedy przesłane dane na temat współrzędnych.
Kontrola poprawności danych formularza
Część ta jest poświęcona kontroli poprawności danych formularza przez mechanizmy umieszczone na
serwerze a nie na komputerze klienta. Języki skryptowe działające na kliencie, takie jak JavaScript mogą być
wykorzystywane do kontroli poprawności elementów formularza przez wysłaniem ich do serwera. Kontrola taka
jest zalecana w przypadku tworzenia wysoce interaktywnych aplikacji WWW, ale nie jest ona całkowicie pewna,
ponieważ może być niedostępna w wielu przeglądarkach i systemach operacyjnych. Dlatego dane muszą być
kontrolowane na serwerze nawet, jeżeli były one już kontrolowane na komputerze klienta. PHP pozwala na
stosowanie kilku metod kontroli poprawności danych, wykorzystując wyrażenia regularne, kontrolę typów
danych lub przeszukiwanie słowników w bazie danych.
Kontrola danych za pomocą wyrażeń regularnych
Prawdopodobnie najskuteczniejszym mechanizmem kontroli danych jest użycie wyrażeń regularnych i
funkcji wyrażeń regularnych w PHP. Wyrażenia te są potężnym narzędziem, ale jeżeli wcześniej nie miałeś z
nimi doświadczenia, są dość skomplikowane w użyciu.
PHP obsługuje dwa rodzaje wyrażeń regularnych — w stylu POSIX i Perl. Skupimy się tutaj na
wyrażeniach w stylu POSIX, ale wyrażenia w stylu Perl dają podobne możliwości. Nazwy funkcji wyrażeń w
stylu Perl są poprzedzone przedrostkiem preg_ i są opisane w skorowidzu na końcu tej książki. Ponieważ lepiej
znam wyrażenia regularne w stylu POSIX, są one używane we wszystkich przytoczonych tu przykładach, ale
należy pamiętać, że funkcje wyrażeń w stylu Perl są szybsze i mają większe możliwości.
Funkcje wyrażeń regularnych w stylu POSIX to: ereg(), ereg_replace(), eregi(), eregi_replace() oraz
split(). Do kontroli poprawności używa się funkcji ereg() i eregi(). Ogólna składnia tych funkcji jest
następująca:
int ereg( string wzorzec, string ciag [, array dopasowanie] )
int eregi( string wzorzec, string ciag [, array dopasowanie] )
Obie funkcje wymagają wzorca wyrażenia regularnego, ciągu do przeszukania oraz opcjonalnej tablicy,
która będzie zawierać dopasowania wzorca odnalezione w przeszukiwanym ciągu. Każda funkcja zwraca true,
jeżeli wzorzec został odnaleziony w ciągu. Funkcja eregi() jest identyczna z ereg() poza tym, że przy
przeszukiwaniu ignoruje ona wielkość liter.
Unikanie kontroli poprawności
Chociaż kontrola poprawności jest ważna, jeżeli nie musisz czegoś kontrolować, to nie rób tego. Zamiast tego można zastosować
takie mechanizmy wprowadzania danych, które zmniejszają szansę pomyłki użytkownika. Na przykład zastosowanie listy rozwijalnej z
miesiącami jest mniej pracochłonne niż kontrola poprawności wpisanych nazw. Zamiast wszędzie korzystać ze zwykłych pól
tekstowych należy znaleźć miejsca, gdzie można zastosować listę, pole wyboru lub przyciski opcji.
Poniższy przykład pokazuje zastosowanie wyrażeń regularnych do kontroli poprawności amerykańskiego
kodu pocztowego oraz dat w formacie ISO (YYYY-MM-DD). Zauważ, że w przykładach tych jest sprawdzany
jedynie format a nie wartości.
Wydruk 3.6. Kontrola poprawności kodu pocztowego i daty ISO
<html>
<head>
<title>Kontrola poprawności amerykańskiego kodu pocztowego i daty ISO</title>
</head>
<body>
<?php
$aCode1 = "83440";
$aCode2 = "83440-1607";
$aCode3 = "834";
$aCode4 = "M6K 3E3";
$aCodeFormat = "[0-9]{5}(-[0-9]{4})?";
if ( ereg( $aCodeFormat, $aCode1 ) == True )
Rozdział 3 – Formularze i cookie
46
print( "'$aCode1' jest poprawnym kodem pocztowym<br>" );
else
print(
if ( ereg(
print(
else
print(
if ( ereg(
print(
else
print(
if ( ereg(
print(
else
print(
"'$aCode1' nie jest poprawnym kodem pocztowym<br>" );
$aCodeFormat, $aCode2 ) == True )
"'$aCode2' jest poprawnym kodem pocztowym<br>" );
"'$aCode2' nie jest poprawnym kodem pocztowym<br>" );
$aCodeFormat, $aCode3 ) == True )
"'$aCode3' jest poprawnym kodem pocztowym<br>" );
"'$aCode3' nie jest poprawnym kodem pocztowym<br>" );
$aCodeFormat, $aCode4 ) == True )
"'$aCode4' jest poprawnym kodem pocztowym<br>" );
"'$aCode4' nie jest poprawnym kodem pocztowym<br>" );
$aDate1 = "2000-06-29";
$aDate2 = "2000-7-4";
$aDate3 = "June 29, 2000";
$aDate4 = "0000-99-99";
$aDateFormat = "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}";
if ( ereg( $aDateFormat, $aDate1 ) == True )
print( "'$aDate1' jest poprawnym formatem daty ISO<br>" );
else
print( "'$aDate1' nie jest poprawnym formatem daty ISO<br>"
if ( ereg( $aDateFormat, $aDate2 ) == True )
print( "'$aDate2' jest poprawnym formatem daty ISO<br>" );
else
print( "'$aDate2' nie jest poprawnym formatem daty ISO<br>"
if ( ereg( $aDateFormat, $aDate3 ) == True )
print( "'$aDate3' jest poprawnym formatem daty ISO<br>" );
else
print( "'$aDate3' nie jest poprawnym formatem daty ISO<br>"
if ( ereg( $aDateFormat, $aDate4 ) == True )
print( "'$aDate4' jest poprawnym formatem daty ISO<br>" );
else
print( "'$aDate4' nie jest poprawnym formatem daty ISO<br>"
);
);
);
);
?>
</body>
</html>
Wyniki działania skryptu z wydruku 6 są następujące:
'83440' jest poprawnym kodem pocztowym
'83440-1607' jest poprawnym kodem pocztowym
'834' nie jest poprawnym kodem pocztowym
'M6K 3E3' nie jest poprawnym kodem pocztowym
'2000-06-29' jest poprawnym formatem daty ISO
'2000-7-4' jest poprawnym formatem daty ISO
'June 29, 2000' nie jest poprawnym formatem daty ISO
'0000-99-99' jest poprawnym formatem daty ISO
Programiści programujący wcześniej w języku Perl i ci, którzy używali już wyrażeń regularnych uważają
taką kontrolę poprawności za łatwą i wydajną. Ci zaś, którzy nie znają wyrażeń regularnych mogą wybrać inne
metody kontroli poprawności, opisane w następnych dwóch częściach.
Kontrola poprawności za pomocą sprawdzania typów
W niektórych przypadkach wystarczy sprawdzić typ wprowadzonej danej i nie przejmować się
wprowadzoną wartością. Metoda ta jest odpowiednia do kontrolo prostych typów, takich jak liczby i ciągi, ale
również pozwala na nieco więcej. Jeżeli zostanie użyta w połączeniu z dodatkowym kodem kontroli poprawności,
będzie wystarczająca dla wielu aplikacji. Poniższy przykład sprawdza typy zmiennych, aby upewnić się, że
zostały wprowadzone tylko liczby.
<html>
<head>
<title>Kontrola liczb przy użyciu kontroli typów</title>
</head>
<body>
<?php
$aValue1 = "123";
$aValue2 = "123.446";
$aValue3 = "1.56e18";
$aValue4 = "3 małe świnki";
if ( is_numeric( $aValue1 ) == True )
print( "'$aValue1' jest liczbą<br>" );
else
print( "'$aValue1' nie jest liczbą<br>" );
47
PHP – Kompendium wiedzy
if ( is_numeric( $aValue2 ) == True )
print( "'$aValue2' jest liczbą<br>" );
else
print( "'$aValue2' nie jest liczbą<br>" );
if ( is_numeric( $aValue3 ) == True )
print( "'$aValue3' jest liczbą<br>" );
else
print( "'$aValue3' nie jest liczbą<br>" );
if ( is_numeric( $aValue4 ) == True )
print( "'$aValue4' jest liczbą<br>" );
else
print( "'$aValue4' nie jest liczbą<br>" );
?>
</body>
</html>
Skrypt przedstawiony na wydruku 7 interpretuje pierwsze trzy wartości jako liczby natomiast ostatnią nie.
Więcej na temat funkcji kontroli typów znajduje się przy opisie funkcji is_xxx() w części „Funkcje zmiennych”
w skorowidzu funkcji na końcu książki.
Klasa Validator
Jedną z najpiękniejszych cech oprogramowania typu open-source jest dostępność świetnych narzędzi
uzupełniających podstawowy produkt. Dodatkowe oprogramowanie dla PHP można pozyskać z wielu źródeł.
Witryna Webmasters Net (http://www.thewebmasters.net) zawiera nieco świetnych klas i modułów z kodem
źródłowym. Do kontroli poprawności przeznaczona jest klasa Validator zawierająca wiele funkcji
upraszczających wiele zadań i oszczędzających czas. Przykładowymi funkcjami kontroli poprawności są
is_email(), is_url() i is_phone() przeznaczone do sprawdzania adresów e-mail, URL i numerów telefonów.
Więcej informacji na temat tej klasy i innych dostarczanych przez Webmasters Net znajduje się w części „PHP
Tools and Extras” — ich witryny.
Wydruk 3.8. Kontrola poprawności danych przy użyciu klasy Validator
<?php
error_reporting( 0 );
include( "../include/class.Validator.php3" );
$aValidator = new Validator;
$aPhoneNum1 = "(208) 359-1540";
$aPhoneNum2 = "+1 208-359-1540";
$aPhoneNum3 = "[email protected]";
if ( $aValidator->is_phone( $aPhoneNum1 ) == True )
print( "'$aPhoneNum1' jest prawidłowym numerem telefonu<br>" );
else
print( "'$aPhoneNum1' nie jest prawidłowym numerem telefonu<br>" );
if ( $aValidator->is_phone( $aPhoneNum2 ) == True )
print( "'$aPhoneNum2' jest prawidłowym numerem telefonu<br>" );
else
print( "'$aPhoneNum2' nie jest prawidłowym numerem telefonu<br>" );
if ( $aValidator->is_phone( $aPhoneNum3 ) == True )
print( "'$aPhoneNum3' jest prawidłowym numerem telefonu<br>" );
else
print( "'$aPhoneNum3' nie jest prawidłowym numerem telefonu<br>" );
/*
Funkcja is_email kontroluje nie tylko poprawność formatu adresu email
ale również sprawdza, czy istnieje w Internecie podany host
Oczywiście wymaga to podłączenia z Internetem.
W chwili pisania tego przykładu host 'invalidhost.com'
nie był zarejestrowany.
*/
$aEmail1 = "[email protected]";
$aEmail2 = "john";
$aEmail3 = "[email protected]";
if ( $aValidator->is_email( $aEmail1 ) == True )
print( "'$aEmail1' jest prawidłowym adresem email<br>" );
else
print( "'$aEmail1' nie jest prawidłowym adresem email<br>" );
if ( $aValidator->is_email( $aEmail2 ) == True )
print( "'$aEmail2' jest prawidłowym adresem email<br>" );
else
print( "'$aEmail2' nie jest prawidłowym adresem email<br>" );
if ( $aValidator->is_email( $aEmail3 ) == True )
print( "'$aEmail3' jest prawidłowym adresem email<br>" );
else
print( "'$aEmail3' nie jest prawidłowym adresem email<br>" );
?>
Rozdział 3 – Formularze i cookie
48
Klasa Validator jest potężnym zestawem funkcji przyspieszających tworzenie oprogramowania, ale tak
jak w przypadku wszystkich narzędzi zewnętrznych należy sprawdzić, czy spełnia twoje wymagania.
Cookie
Z powodu trwającej debaty na temat użycia cookie, większość programistów WWW i użytkowników jest
zaznajomiona z koncepcją cookie. Cookie są plikami tekstowymi zapisanymi na komputerze klienta i są one ze
swojej natury niewinne. Jednak wielu użytkowników nie przyjmuje cookie wysłanych do przeglądarek z powodu
plotek na temat ich wykorzystania. Jeżeli twoja aplikacja opiera swoje działanie na cookie, niektórzy użytkownicy
nie będą mogli jej używać. Jednak jeżeli korzystasz z cookie, ale nie wymagasz ich do prawidłowej pracy, twoja
aplikacja będzie działała z większością przeglądarek.
PHP posiada tylko jedna funkcję przeznaczoną do tworzenia cookie, setcookie(). Ponieważ cookie są
wysyłane jako część nagłówka HTTP, funkcja setcookie() musi być wywołana przed wysłaniem jakichkolwiek
danych do przeglądarki lub należy zastosować buforowanie wyjścia w celu opóźnienia wysyłania danych do
przeglądarki do chwili zdefiniowania wszystkich cookie. To samo ograniczenie obowiązuje również dla funkcji
header().
Dowolne cookie odesłane do aplikacji przez przeglądarkę jest automatycznie konwertowane na zmienną
PHP tak samo, jak dzieje się to w przypadku metod GET i POST. Cookie mogą przenosić wartości skalarne jak
również tablice wartości. Funkcja setcookie() jest zdefiniowana w sposób następujący:
int setcookie( string nazwa, string wartość, int czas, string ścieżka,
string domena, int bezpieczny )
Wszystkie argumenty funkcji poza nazwą są opcjonalne. Jeżeli funkcja jest wywołana tylko z nazwą,
cookie o podanej nazwie jest usuwane. Dowolny z ciągów może zostać opuszczony podając pusty ciąg ("").
Dowolna wartość numeryczna może zostać opuszczona podając wartość zero. Argument czas jest standardowym
czasem z systemu Unix w postaci liczby, którą można uzyskać jako wynik funkcji mktime() lub time(). Parametr
bezpieczny wskazuje, że cookie może być przesyłane jedynie przez połączenie bezpieczne (HTTPS).
Należy pamiętać o następujących pułapkach i częstych błędach użycia cookie:
• Ustawione cookie nie będą widoczne w skrypcie do czasu jego powtórnego załadowania.
• Przeglądarki różnie obsługują cookie. Sprawdź aplikację na możliwie dużej ilości przeglądarek.
• Każda przeglądarka przechowuje cookie niezależnie. Oznacza to, że jeżeli użytkownik obejrzy witrynę
przy użyciu jednej przeglądarki i zostanie ustawione cookie, to cookie nie będzie dostępne, jeżeli
użytkownik ponownie obejrzy witrynę za pomocą innej przeglądarki.
Więcej ogólnych informacji na temat cookie można znaleźć w specyfikacji cookie firmy Netscape, która
jest dostępna pod adresem http://www.netscape.com/newsref/std/cookie_spec.html.
Poniższe dwa przykłady pokazują użycie funkcji setcookie(). Wydruk 3.9 pokazuje jak ustawiać i
wyświetlać cookie. Na wydruku 3.10 pokazane jest jak używać buforowania wyjścia w połączeniu z funkcją
setcookie().
Wydruk 3.9. Użycie cookie
<?php
// Sprawdzenie czy istnieje zmienna cookie $LastTime
if ( !empty( $LastTime ) )
{
$aMessage = "Ostatnia wizyta miała miejsce ";
$aMessage .= date( "d F Y", $LastTime );
$aMessage .= " o ";
$aMessage .= date( "h:i:s a", $LastTime );
}
else
{
$aMessage = "Nie byłeś tu przez ostatnie ";
$aMessage .= "dwa tygodnie.";
}
// Ustawienie cookie ważnego przez dwa tygodnie
$aTwoWeeks = time() + ( 60 * 60 * 24 * 14 );
setcookie( "LastTime", time(), $aTwoWeeks );
// sprawdzenie istnienia niezwykle ważnej tablicy z cookie
$aValMessage = "";
if ( !empty( $CookieArray ) )
{
$aValMessage = "Wartości: " . $CookieArray[0];
$aValMessage .= ", " . $CookieArray[1];
49
PHP – Kompendium wiedzy
$aStartValue
= $CookieArray[1] + 1;
}
else
{
$aValMessage = "Wartości nie są dostępne!";
$aStartValue = 0;
}
// usunięcie niezwykle istotnej tablicy wartości
setcookie( "CookieArray[0]" );
setcookie( "CookieArray[1]" );
// dodanie niezwykle istotnej tablicy wartości
setcookie( "CookieArray[0]", $aStartValue, $aTwoWeeks );
setcookie( "CookieArray[1]", $aStartValue + 1, $aTwoWeeks );
?>
<html>
<head>
<title>Użycie cookie</title>
</head>
<body>
<?php
print( $aMessage . "<br><br>" . $aValMessage );
?>
</body>
</html>
Wydruk 3.10. Użycie setcookie() razem z buforowaniem wyjścia
<?php
/*
Uruchomienie buforowania wyjścia. Jeżeli funkcja ob_start()
jest zakomentowana, skrypt spowoduje błąd.
*/
ob_start();
?>
<html>
<head>
<title>Użycie setcookie() wraz z buforowaniem wyjścia</title>
</head>
<body>
<?php
setcookie( "anyname", "anyvalue", time() + 60 );
?>
Działa świetnie.
</body>
</html>
<?php ob_end_flush(); ?>
Ostatnia uwaga na temat cookie
W poprzedniej wersji PHP jeżeli chciałeś ustawić wiele cookie za pomocą jednego skryptu, musiałeś wywoływać setcookie() w
odwrotnej kolejności do tej, w jakiej chciałeś obsługiwać cookie. Na przykład, jeżeli chciałeś usunąć cookie a następnie ustawić nowe
o tej samej nazwie, należało najpierw wywołać setcookie(), aby ustawić nową wartość a następnie usunąć poprzednią wartość. W
PHP4 zostało to usunięte. Należy wywoływać setcookie() w takiej kolejności jak się spodziewasz, że będą przetwarzane przez
przeglądarkę. Proces ten jest pokazany na wydruku 3.9.
Mimo, że debata na temat tego, czy należy używać cookie będzie nadal trwała, ich tworzenie w PHP jest
łatwe i proste. Dalsze rozważania na temat cookie będą kontynuowane w rozdziale 7 „Sesje i stan aplikacji”.
Ważne zagadnienia programowania dla WWW
Część ta zawiera niektóre tematy, jakie muszą brać pod uwagę programiści przechodzący z pisania
zwykłych aplikacji na aplikacje oparte o WWW. Problemy te powstają zwykle w czasie przetwarzania i
wykorzystywania danych przesłanych z formularza HTML.
Obsługa nieprawidłowych danych
Pierwszym problemem jest sposób obsługi nieprawidłowych danych. W tradycyjnych aplikacjach dane
wprowadzone przez użytkownika są często kontrolowane natychmiast po ich wprowadzeniu. Pozwala to
natychmiast informować o nieprawidłowych danych. W aplikacjach WWW nie ma niezawodnego mechanizmu
kontroli danych po wyjściu z poszczególnych pól, więc cała kontrola poprawności jest przeprowadzana na
serwerze. Oznacza to, że jeżeli istnieje błąd w danych, użytkownik nie będzie o nim wiedział aż do chwili
Rozdział 3 – Formularze i cookie
50
przesłania danych formularza. Dlatego w trakcie tworzenia aplikacji musisz się zdecydować, w jaki sposób
reagować na błędy.
Istnieje kilka sposobów reagowania na błędy, przytoczymy tutaj dwa z nich. Pierwszą metodą jest
wypisywanie błędów i nakazanie użytkownikowi, aby wrócił do poprzedniej strony i poprawił dane. Według mnie
jest to najmniej pożądany sposób reakcji na błędy, ale jest najprostszy do zrealizowania. Jeżeli do formularza
wpisywane jest bardzo mało danych (jedno lub dwa pola) metoda ta będzie do zaakceptowania. Jeżeli jednak
tworzysz duży formularz nie należy używać tej metody, ponieważ może ona wymagać ponownego wprowadzenia
wszystkich danych. Niektóre przeglądarki nie utrzymują wartości formularza po użyciu przycisku Wstecz.
Drugą metodą obsługi nieprawidłowych danych jest ponowne pokazanie strony formularza z
zainicjowanymi wszystkimi polami i zaznaczonymi nieprawidłowymi pozycjami. Możesz utworzyć taki
formularz przesyłając dane z formularza do tego samego skryptu. Metoda taka wymaga bardziej zaawansowanego
projektowania, ale skutkuje powstaniem solidniejszej i bardziej użytecznej aplikacji, ponieważ ten sam skrypt
może być użyty do pobierania nowych danych, zmiany danych istniejących i kontroli poprawności tych danych.
Na wydruku 3.11 pokazane jest w jaki sposób można użyć jednego skryptu do zbierania i kontroli poprawności
danych na prostym formularzu używanym do wpisywania adresów e-mail i numerów telefonów.
Wydruk 3.11. Inteligentna obsługa nieprawidłowych danych
<?php
error_reporting( 0 );
// na początku przestawiamy skrypt na zbieranie nowych danych.
$aCurPhoneVal = "";
$aCurEmailVal = "";
$aPhoneTextCol = "black";
$aEmailTextCol = "black";
if ( !empty( $Submit ) )
{
/*
Jeżeli zmienna $Submit jest zainicjowana jesteśmy tutaj po
przesłaniu danych do skryptu. Próbujemy sprawdzić wartości
zmiennych formularza.
*/
include( "../include/class.Validator.php3" );
$aValidator = new Validator;
$aValidPhone = $aValidator->is_phone( $Phone );
$aValidEmail = $aValidator->is_email( $Email );
if ( $aValidPhone && $aValidEmail )
{
// Dane są prawidłowe, przechodzimy do odpowiedniej strony
header( "Location:thanks.html\n" );
}
else
{
// Dane nieprawidłowe, wyróżniamy je
$aCurPhoneVal = $Phone;
$aCurEmailVal = $Email;
if ( $aValidPhone == False )
$aPhoneTextCol = "red";
if ( $aValidEmail == False )
$aEmailTextCol = "red";
}
}
?>
<html>
<head>
<title>Inteligentna obsługa nieprawidłowych danych</title>
</head>
<body>
<?php
if ( empty( $Submit ) ) {
?>
Proszę wprowadzić numer telefonu i adres email.
<br>
<?php
} else { // if
?>
We wprowadzonych danych wystąpiły błędy.
Sprawdź dane oznaczone kolorem czerwonym.
<?php
} // end if
?>
<form action="handle_errors.phtml" method="post">
<font color="<?php print( $aPhoneTextCol );?>">
Numer telefonu:</font>
<input type="text" name="Phone"
51
PHP – Kompendium wiedzy
value="<?php echo $aCurPhoneVal;?>">
<br>
<font color="<?php print( $aEmailTextCol );?>">
Adres e-mail:</font>
<input type="text" name="Email"
value="<?php echo $aCurEmailVal;?>">
<br>
<input type="submit" name="Submit" value="Wyślij">
</form>
</body>
</html>
W skrypcie na wydruku 11, gdy strona jest otwierana bezpośrednio, zmienna $Submit jest pusta, więc
formularz jest wyświetlany z pustymi polami. Gdy użytkownik kliknie przycisk Wyślij, strona jest ładowana po
raz drugi, ale tym razem zmienna $Submit nie jest pusta, więc sprawdzana jest poprawność danych. Jeżeli oba
pola mają poprawne dane, wywoływana jest funkcje header(), która powoduje przekierowanie przeglądarki do
nowej strony zawierającej podziękowanie. Jeżeli któreś pole zawiera nieprawidłową wartość, formularz
wywoływany jest ponownie, ale tym razem pola mają wartości wprowadzone poprzednio przez użytkownika.
Dodatkowo, aby zaznaczyć wystąpienie błędu, nieprawidłowe dane są wyświetlane kolorem czerwonym.
Metoda ta pozwala na szybką identyfikację przez użytkownika danych, które wymagają poprawienia i nie
wymaga ponownego wprowadzenia całej zawartości formularza. Jeżeli tworzysz aplikację WWW, która wymaga
od użytkownika wprowadzania danych należy rozważyć użycie podobnej metody do obsługi błędnych danych.
Jeżeli twoja aplikacja będzie niewygodna lub wymagać będzie ponownego wprowadzania danych, na pewno nie
będzie lubiana.
Przedstawione metody nie są jedynymi stosowanymi do obsługi błędnych danych, ale ilustrują one
podstawy tworzenia aplikacji WWW. Wybór metody obsługi błędów może być kluczową decyzją przy
projektowaniu aplikacji.
Obsługa i formatowanie wyświetlanych danych
W zwykłej aplikacji wyświetlanie danych wprowadzonych przez użytkownika nie wymaga zwykle
formatowania lub przetwarzania. Czasami formatowane są liczby, aby wyświetlać wartości walutowe lub dodać
separatory tysięcy, ale zwykle nie ma zbyt dużo kłopotu przy wyświetlaniu danych wprowadzonych przez
użytkownika. W przypadku programowania dla WWW wyświetlanie danych wprowadzonych do formularza w
postaci strony WWW jest sprawą krytyczną. Dzieje się tak, ponieważ przeglądarka interpretuje cały tekst
otrzymany z serwera WWW. Jeżeli dostarczysz użytkownikom formularz a następnie będziesz wyświetlał
wpisane dane, niektórzy użytkownicy będą dodawać znaczniki HTML, aby sprawdzić co się stanie.
Pamiętając o tym pomyśl o formularzu, w którym użytkownicy będą mogli wpisywać swoje uwagi.
Załóżmy, że stworzysz formularz w którym zapisywane będą: nazwa użytkownika, adres e-mail oraz treść uwagi.
Po wprowadzeniu tekstu wyświetlasz komunikat w celu weryfikacji a następnie przetwarzasz ten komunikat.
Pomysłowi lub złośliwi użytkownicy mogą próbować przetestować twój serwer WWW dodając znaczniki HTML
lub kod JavaScript w treści komunikatu. Zwykle nie jest to niebezpieczne, ale na pewno skutkuje różnymi
efektami ubocznymi.
Aby uniknąć tego problemu zawsze należy przetwarzać dane wprowadzone do formularza przed ich
wyświetleniem. PHP posiada kilka funkcji pomagających w tym zadaniu. Są to funkcje strip_tags() i
htmlentities(). Funkcja strip_tags() usuwa wszystkie znaczniki z ciągu oprócz tych, które zostały podane w
dodatkowym opcjonalnym parametrze. Funkcja htmlentities() konwertuje specjalne znaki HTML na
odpowiadające im symbole HTML. Na przykład znaki < i > są zastępowane przez &lt; i &gt;. Formularz i skrypt
na wydruku 3.12 pokazuje obróbkę danych do ponownego wyświetlenia.
Wydruk 3.12. Obróbka danych do wyświetlenia.
<html>
<head>
<title>Pobieranie danych do wyświetlenia</title>
</head>
<body>
<form action="safedisplay.phtml" method="post">
Wprowadź tekst:<br>
<textarea cols="40" rows="6" name="TheText"></textarea>
<br><br>
Wybierz metodę filtrowania:
<select name="FilterType" size="1">
<option value="0">brak</option>
Rozdział 3 – Formularze i cookie
52
<option value="1">strip_tags()</option>
<option value="2">htmlentities()</option>
</select>
<br><br>
<input type="submit" name="Submit" value="Wyślij">
</form>
</body>
</html>
<!-- Skrypt safedisplay2.phtml -->
<?php
error_reporting( 255 );
switch ( $FilterType )
{
case 0 : // brak
$aDisplayText = $TheText;
break;
case 1 : // strip_tags
$aDisplayText = strip_tags( $TheText );
break;
case 2 : // htmlentities
$aDisplayText = htmlentities( $TheText );
break;
}
?>
<html>
<head>
<title>Bezpieczne wyświetlenie danych użytkownika</title>
</head>
<body>
<?php
print( $aDisplayText );
?>
</body>
</html>
Rysunki 3.3. do 3.6. pokazują formularz wejściowy i wyniki działania skryptu. Rysunek 3.3. zawiera
formularz wprowadzania danych. Rysunek 3.4. pokazuje co się dzieje, jeżeli nie ma filtrowania. Rysunki 3.5. i
3.6. pokazują wyniki filtrowania danych z formularza za pomocą funkcji odpowiednio strip_tags() i
htmlentities().
Rysunek 3.3.
Formularz
wprowadzania
danych
53
PHP – Kompendium wiedzy
Rysunek 3.4.
Wyświetlanie bez
filtrowania
Rysunek 3.5.
Wyświetlanie ze
strip_tags()
Rozdział 3 – Formularze i cookie
54
Rysunek 3.6.
Wyświetlanie z
htmlentities()
Jeżeli dokładnie przyjrzysz się tym rysunkom zauważysz, że widać niespodziewane wyniki po
wyświetleniu danych. Na przykład pojedynczy apostrof jest wyświetlany na stronie jako sekwencja \'. Również
znaki końca linii wprowadzone w polu tekstowym nie są uwzględniane w wyświetlanym tekście.
Pierwsze z zakłóceń jest powodowane przez dyrektywę konfiguracji --enable-magic-quotes oraz opcje
pliku php.ini magic_quotes_gpc, magic_quotes_runtime i magic_quotes_sybase. Jeżeli jest ona uaktywniona,
wszystkie apostrofy, cudzysłowy, NUL1 i znaki backslash pochodzące z zewnętrznych źródeł, na przykład
formularzy i bazy danych, są automatycznie poprzedzane ukośnikiem. Jest to szczególnie przydatne, jeżeli dane te
będą zapisywane w bazie danych, ponieważ nie będziesz musiał ręcznie oznaczać tych znaków w ciągu SQL. Aby
wyświetlić taki ciąg, należy wywołać funkcję strip_slashes(), która usuwa te dodatkowe znaki.
Jeżeli chodzi o problem ze znakami nowej linii, należy pamiętać, że HTML nie interpretuje znaku CR ani
LF jako znaku podziału wiersza, chyba, że wystąpi on w bloku <pre></pre>. PHP posiada funkcję nl2br(), która
konwertuje znaki nowej linii na znaczniki <br>.
Na wydruku 13 znajduje się ten sam formularz i skrypt co na wydruku 12, ale z dodatkowymi opcjami
które powodują wywołanie funkcji strip_slashes() i nl2br().
Wydruk 3.13. Ulepszona obróbka danych do wyświetlenia
<html>
<head>
<title>Pobieranie danych do wyświetlenia</title>
</head>
<body>
<form action="safedisplay2.phtml" method="post">
Wprowadź tekst:<br>
<textarea cols="40" rows="6" name="TheText"></textarea>
<br><br>
Wybierz metodę filtrowania:
<select name="FilterType" size="1">
<option value="0">none</option>
<option value="1">strip_tags()</option>
<option value="2">htmlentities()</option>
</select>
<br><br>
<input type="checkbox" name="DoSS"> strip_slashes()<br>
<input type="checkbox" name="DoNB"> nl2br()<br><br>
<input type="submit" name="Submit" value="Wyślij">
</form>
</body>
</html>
<!-- Skrypt safedisplay2.phtml -->
<?php
1
Znak o kodzie zero (przyp. tłum.)
55
PHP – Kompendium wiedzy
error_reporting( 0 );
switch ( $FilterType )
{
case 0 : // brak
$aDisplayText = $TheText;
break;
case 1 : // strip_tags
$aDisplayText = strip_tags( $TheText );
break;
case 2 : // htmlentities
$aDisplayText = htmlentities( $TheText );
break;
}
if ( $DoSS == "on" )
$aDisplayText = stripslashes( $aDisplayText );
if ( $DoNB == "on" )
$aDisplayText = nl2br( $aDisplayText );
?>
<html>
<head>
<title>Bezpieczne wyświetlenie danych użytkownika</title>
</head>
<body>
<?php
print( $aDisplayText );
?>
</body>
</html>
Rysunek 3.7.
Formularz
wprowadzania
danych
Rozdział 3 – Formularze i cookie
56
Rysunek 3.8.
Wyświetlanie
przefiltrowane
przez strip_tags(),
strip_slashes() i
nl2br()
Po wprowadzeniu zmian pokazanych na wydruku 3.13, formularz wprowadzania danych i postać danych
wynikowych jest taka, jak widać na rysunku 3.7. i 3.8.
Jeżeli wcześniej miałeś doświadczenie jedynie ze zwykłymi aplikacjami, musisz pamiętać o tych
pułapkach stosowania przeglądarki jako warstwy prezentacji aplikacji. Oprócz pamiętania o wspomnianych
problemach należy również zwrócić uwagę, że każda przeglądarka działa nieco inaczej. Szczegółowe omówienie
tych problemów znajduje się w rozdziale 9 „Niezależność od przeglądarki”.
Podsumowanie
Rozdział ten zawiera opis podstaw przetwarzania formularzy przy użyciu PHP. Ponieważ PHP został
zaprojektowany jako język programowania dla WWW, upraszcza on znacznie proces interakcji z formularzami
HTML. Ważniejsze od prostego pobierania danych od użytkowników jest prawidłowa obsługa tych danych i
zabezpieczanie serwera i użytkowników przed nieprawidłowymi lub niebezpiecznymi danymi. W rozdziale tym
omówiono niektóre narzędzia umożliwiające obsłużyć nieprawidłowe dane i zabezpieczyć przed szkodliwymi
danymi. W rozdziale tym omówiono również proces zapamiętywania i odczytywanie cookie na komputerze
klienta. Wszystkie te tematy razem stanowią podstawę do tworzenia interaktywnych aplikacji WWW.
57
PHP – Kompendium wiedzy
Rozdział 4. Operacje na plikach
Wstęp
Obsługa plików jest zawarta we wszystkich nowoczesnych językach programowania. Zdolność do
tworzenia, czytania, zapisu i innych operacji na plikach lub innych obiektach systemu plików jest niezbędna do
zrealizowania obsługi sesji i serializacji. Do obsługi plików i innych obiektów systemu plików PHP posiada
funkcje podobne do tych spotykanych w języku C. Tak jak C, w funkcjach służących do odczytu i zapisu, PHP
używa uchwytów plików oraz pozwala na tworzenie uchwytów (pozwalających na operacje innymi typami
strumieni danych, takimi jak gniazda i potoki). Zdolność ta powoduje, że równie łatwo można zapisać dane do
pliku jak również wysłać je poprzez potok do innego programu.
Odczyt i zapis plików
Jedną z głównych różnic przy pisaniu aplikacji opartych o sieć WWW w stosunku do zwykłych aplikacji,
jest sposób utrzymywania stanu aplikacji. W przypadku zwykłego programu, użytkownik uruchamia go,
wykonuje kilka komend i kończy działanie programu. W czasie pracy programu stan aplikacji jest utrzymywany
w pamięci. W aplikacjach opartych o sieć WWW stan musi być utrzymywany przez serwer WWW, ponieważ
klientem jest zwykle prosta przeglądarka WWW. Szczegółowe przedstawienie zarządzania stanem aplikacji
można znaleźć w rozdziale 7 „Sesje i stan aplikacji”. W chwili obecnej wystarczy wiedzieć, że do utrzymywania
stanu aplikacji i tworzenia innych mechanizmów przechowywania danych można użyć plików.
Ważne jest, aby używając plików, pamiętać o zagadnieniach bezpieczeństwa. Ponieważ aplikacja będzie
działać w kontekście serwera WWW, pliki będą miały uprawnienia użytkownika przy pomocy którego
uruchamiany jest serwer WWW. W przypadku Apache domyślnie jest to użytkownik nobody, którego
uprawnienia ograniczają dostęp przez aplikację do obiektów systemu plików. Należy uważać, aby korzystając z
plików nie naruszyć systemu bezpieczeństwa serwera WWW. W większości przypadków użycie bazy danych
zamiast plików jest o wiele bardziej bezpieczne i praktyczne. Oczywiście istnieje wiele sytuacji gdy narzut
czasowy wprowadzany przez bazę danych lub wymagania aplikacji powodują, że pliki są jedynym sensownym
rozwiązaniem.
Na wydruku 4.1 pokazane zostało w jaki sposób można zrealizować liczniki dostępu do stron witryny. Do
tego celu wykorzystane zostały podstawowe operacje na plikach, otwarcie, odczyt, zapis i zamknięcie prostego
pliku śladu. W przykładzie tym nie zostały wykorzystane wszystkie dostępne w PHP funkcje operujące na
plikach. Bardziej szczegółowy opis wszystkich funkcji znajdują się w skorowidzu funkcji na końcu książki.
Wydruk 4.1. Użycie plików do zliczania odwołań do stron witryny
<?php
/*
Plik ten może być dołączany do dowolnego skryptu PHP.
Powoduje to automatyczne zliczanie odwołań do strony.
UŻYCIE: Wystarczy dołączyć ten plik. Tworzy on zmienną
globalną $aPageAccessCount, która zawiera ilość
odwołań do skryptu który dołącza ten plik.
*/
error_reporting( 0 );
$aLogFilePath = "/www/auto_logs/access.log";
$aCountArray = array();
// Sprawdzenie czy plik istnieje
if ( is_file( $aLogFilePath ) == True )
{
// Otwarcie i odczytanie pliku. Format pliku to oddzielone tabulatorami
// pary opisujące kolejne skrypty:
//
ścieżka-do-skryptu
licznik
$aFile = fopen( $aLogFilePath, "r" );
while( !feof( $aFile ) )
{
$aLine = fgets( $aFile, 1024 );
$aTempArray = explode( "\t", $aLine );
if ( count( $aTempArray ) == 2 )
{
$aCountArray[$aTempArray[0]] = $aTempArray[1];
}
}
fclose( $aFile );
}
// Ustawienie globalnego licznika odwołań do strony
// i uaktualnienie tablicy temp
$aPageAccessCount = $aCountArray[$PATH_TRANSLATED] + 1;
$aCountArray[$PATH_TRANSLATED] = $aPageAccessCount;
// Zapis całej tablicy do pliku
$aFile = fopen( $aLogFilePath, "w" );
foreach ( $aCountArray as $aKey => $aValue )
{
fputs( $aFile, "$aKey\t$aValue\n" );
}
fclose( $aFile );
?>
Na wydruku 4.1 pokazujemy użycie jednego pliku do przechowywania liczników odwołań do dowolnej
liczby stron witryny. Nie jest to efektywny sposób, ale pokazuje ideę takiego licznika. W skrypcie tym
sprawdzamy za pomocą funkcji is_file() czy istnieje plik śladu. Jeżeli plik ten istnieje, jego kolejne linie są
odczytywane i analizowane. Każda linia zawiera pełną ścieżkę dostępu do skryptu, znak tabulacji i wartość
licznika. Linia taka jest dzielona przy pomocy funkcji explode() na nazwę skryptu i wartość licznika a następnie
wartości te są zapisywane w tablicy asocjacyjnej. Jeżeli chcesz, możesz użyć tej tablicy do wyświetlenia
liczników dla wszystkich stron witryny a nie tylko bieżącej strony. Po wypełnieniu tablicy uaktualniany jest
licznik odwołań do bieżącej strony (rozpoznawanej przy użyciu zmiennej globalnej PHP $PATH_TRANSLATED) i
wartość ta jest przypisywana do zmiennej $aPageAccessCount. Na koniec cała tablica jest zapisywana do pliku
śladu.
Na wydruku 4.2 pokazane jest strona demonstrująca jak łatwo można użyć tego licznika. Jeżeli szukasz
takiego mechanizmu do twojej witryny, należy pamiętać, że jest to bardzo nieefektywne rozwiązanie. Bardziej
efektywne jest odczytywanie i zapis tylko jednej wartości a nie całego pliku.
Wydruk 4.2. Użycie skryptu z wydruku 4.1
<?php
include( "auto_counter.php" );
?>
<html>
<head>
<title>Strona testowa 1</title>
</head>
<body>
Strona ta była oglądana <b>
<?php
print( $aPageAccessCount );
?>
</b> razy.
</body>
</html>
Użycie gniazd
PHP umożliwia dostęp do surowych gniazd TCP/IP, za pomocą których można komunikować się z innymi
aplikacjami za pomocą dowolnego protokołu. Niektóre z bardziej znanych protokołów TCP/IP, na przykład
HTTP, POP3 i SMTP posiadają swoje implementacje w PHP, więc nie musisz w tych przypadkach używać
surowych gniazd.
Na wydruku 4.3 pokazano sposób dostępu za pomocą gniazd do serwera quotd, który zwraca cytat dnia.
Protokół quotd jest bardzo prosty. Po zestawieniu połączenia serwer wysyła strumień danych tekstowych a
następnie zamyka połączenie. Z perspektywy klienta wystarczy jedynie zestawić połączenie, odczytać dane a
następnie zakończyć połączenie.
59
PHP – Kompendium wiedzy
Wydruk 4.3. Użycie gniazd
<html>
<head>
<title>Przykład wykorzystania serwera QOTD: Użycie gniazd w PHP</title>
</head>
<body>
<?php
// otwarcie gniazda serwera qotd
$aFile = fsockopen( "208.129.36.164", 17 );
// odczytanie wszystkich danych ze strumienia
while ( !feof( $aFile ) )
{
$aLine = fgets( $aFile, 1024 );
print( "$aLine<br>" );
}
fclose( $aFile );
?>
</body>
</html>
Użycie potoków
Tak jak w przypadku gniazd, potoki są traktowane jak kolejny uchwyt pliku. Jedyną różnicą pomiędzy
plikiem i potokiem jest to, że potok jest jednokierunkowym strumieniem danych. Potok może być użyty do
odczytu danych wyjściowych z programu lub skryptu. Na wydruku 4.4 pokazane jest użycie potoku do odczytania
wyniku zapytania do polecenia whois, które jest dostępne w większości systemów Unix. Ten prosty skrypt i
formularz pozwalają na wprowadzenie zapytania dla whois. Skrypt ten ilustruje również częstą praktykę używania
tego samego skryptu do wyświetlenia formularza i przetworzenia jego danych.
Wydruk 4.4. Skrypt przetwarzający zapytanie whois
<?php
/* whois.php */
// ścieżka do programu whois
$whois_prog = '/usr/bin/whois';
if ( !is_file( $whois_prog ) )
{
// nie udało się znaleźć programu
echo "Nie mogę znaleźć $whois_prog!<br>";
exit;
}
?>
<html>
<head>
<title>Whois: Uzycie potoków w PHP</title>
</head>
<body>
<?php
if ( $REQUEST_METHOD == 'POST' )
{
// otwarcie potoku do polecenia whois
if ( $aFile = popen( "$whois_prog $WhoisQuery", "r" ) )
{
// odczytanie wszystkich danych z potoku
while ( !feof( $aFile ) )
{
$aLine = fgets( $aFile, 1024 );
print( "$aLine<br>" );
}
pclose( $aFile );
}
else
{
echo "Nie mogę otworzyć $whois do odczytu!<br>";
}
print( "<hr>" );
}
?>
<form action="<?php echo $PHP_SELF ?>" method="post">
Wprowadź zapytanie <b>whois</b>: <input type="text" name="WhoisQuery">
<input type="submit" name="Submit" value="Submit">
</form>
</body>
</html>
Rozdział 4 – Operacje na plikach
60
Klasa File
W poprzednim rozdziale wspominaliśmy, że do PHP dostępne są świetne narzędzia dodatkowe
pochodzące z różnych źródeł. Klasa File dostępna z WebMasters Net (http://www.theWebMasters.net) jest
przydatnym narzędziem, szczególne wtedy, gdy twoja aplikacja intensywnie wykorzystuje pliki. Klasa ta zawiera
wiele często używanych funkcji PHP operujących na plikach i hermetyzuje kontrolę błędów, dzięki czemu
możesz więcej czasu poświęcić logice aplikacji zamiast zajmować się pisaniem podstawowych konstrukcji
kontroli błędów.
Na wydruku 4.5 pokazany jest skrypt wyświetlający nazwy wszystkich plików w bieżącym katalogu w
postaci łączy. Gdy użytkownik kliknie łącze, skrypt zamieszczony na wydruku 4.6 wyświetla jego zawartość
używając celu klasy File do odczytania jego zawartości.
Wydruk 4.5. Użycie klasy File do wyświetlenia zawartości bieżącego katalogu
<?php
include( "class.File.php3" );
?>
<html>
<head>
<title>Użycie klasy File</title>
</head>
<body>
Poniżej znajduje się lista plików w bieżącym katalogu.<br>
Kliknij nazwę pliku aby zobaczyć ich zawartość.<br><br>
<?php
$aFileClass = new File();
$aDirContents = $aFileClass->get_files( "." );
for ( $nIndex = 0; $nIndex < count( $aDirContents ); $nIndex++ )
{
$aCurFile = $aDirContents[$nIndex];
print( "<a href=\"disp_file.phtml?fn=$aCurFile\">" );
print( "$aCurFile</a><br>" );
}
?>
</body>
</html>
Wydruk 4.6. Wyświetlenie zawartości pliku za pomocą klasy File
<?php
include( "./class.File.php3" );
?>
<html>
<head>
<title>Użycie klsy File</title>
</head>
<body>
<?php
print( "The file <b>$fn</b>:<br><br>" );
$aFileClass = new File();
$aFileCont = $aFileClass->read_file( $fn );
print( "<pre>" );
print( nl2br( htmlentities( $aFileCont ) ) );
print( "</pre>" );
?>
</body>
</html>
Podsumowanie
Zdecydowanie się na użycie plików w aplikacji opartej na WWW jest jedną z krytycznych decyzji w fazie
projektowania aplikacji. Noe wszystkie aplikacje używają plików, ale aby efektywnie korzystać z różnych typów
strumieni danych, na przykład gniazd i potoków, należy poznać sposoby korzystania z uchwytów plików i funkcji
operujących na plikach. Rozdział ten zawiera nie tylko opis podstawowych operacji na plikach i systemie plików,
ale również przedstawia dodatkową klasę ułatwiającą operacje na plikach. Opis operacji na plikach zawarty w
tym rozdziale oraz opis formularzy zamieszczony w rozdziale poprzednim stanowią odpowiednią podstawę do
następnego rozdziału, „Wysyłanie plików przez formularz”.
61
PHP – Kompendium wiedzy
Rozdział 5. Wysyłanie plików przez
formularz
Wstęp
Poprzednie dwa rozdziały omawiały niezbędne podstawy dla tego rozdziału, ponieważ wysyłanie plików
wymaga poznania zarówno formularzy HTML, jak i funkcji systemu plików. Obsługa przesyłania plików w PHP
jest bardzo łatwa. PHP posiada wbudowany mechanizm pozwalający na odebranie pliku wysłanego z przeglądarki
zgodnej z RFC 1867. Większość nowoczesnych przeglądarek jest zgodnych z tym dokumentem, ponieważ został
on włączony do standardu HTML 3.2.
Jeżeli pozwolisz użytkownikom na wysyłanie plików za pomocą formularza, musisz rozważyć
dopuszczalne typy plików oraz ich wielkości. Mechanizm wbudowany w PHP działa świetnie dla małych plików,
ale jeżeli masz zamiar przesyłać duże pliki należy się zastanowić nad zastosowaniem innego mechanizmu, a
przykład anonimowego FTP. Możesz również pomyśleć o stworzeniu dodatkowego mechanizmu przesyłania
plików, jeżeli są one niezbędne do działania aplikacji.
Wysyłanie pojedynczego pliku
Formularz przy pomocy którego można przesyłać pliki różni się kilkoma szczegółami od zwykłego
formularza HTML. Znacznik <FORM> musi posiadać atrybut ENCTYPE ustawiony na multipart/form-data zamiast
domyślnego application/x-www-form-urlencoded. Musisz również umieścić na formularzy znacznik <INPUT> typu
file. Wydruk 5.1. zawiera prosty formularz HTML zawierający jeden znacznik <INPUT>.
Wydruk 5.1. Formularz HTML ze znacznikiem <INPUT>
<html>
<head>
<title>Formularz do przesyłania plików</title>
</head>
<body>
<form action="upload_single.phtml"
method="post" enctype="multipart/form-data">
Wyślij plik: <input type="file" name="thefile"><br><br>
<input type="submit" name="Submit" value="Wyślij">
</form>
</body>
</html>
Po wysłaniu danych formularza z wydruku 5.1, PHP tworzy automatycznie cztery zmienne globalne, które
opisują przesłany plik:
• $thefile — Zmienna zawiera nazwę pliku tymczasowego w którym znajduje się plik przesłany na serwer.
• $thefile_name — Zmienna ta zawiera nazwę pliku na komputerze z którego został wysłany.
• $thefile_size — Zmienna zawiera wielkość przesłanego pliku w bajtach.
• $thefile_type — Zmienna ta zawiera typ MIME przesyłanego pliku (o ile przeglądarka udostępnia taką
informację).
Nazwy tych zmiennych są tworzone w oparciu o nazwę znacznika <INPUT> w formularzu, tak jak jest to
pokazane na Wydruku 5.1. Pisząc skrypt obsługujący przesyłanie pliku należy pamiętać, że PHP automatycznie
usuwa plik tymczasowy po zakończeniu skryptu, więc jeżeli nie skopujesz go, plik zostanie stracony.
Skrypt na wydruku 5.2 zawiera kod obsługi przesyłania pliku poprzez formularz z Wydruku 1 i jeżeli plik
jest rysunkiem (w formacie GIF lub JPEG) mniejszym od 100 kB, jest on wyświetlany. Jeżeli przesłany plik nie
ma właściwego typu lub jest większy, wyświetlany jest komunikat błędu.
Wydruk 5.2. Obsługa przesyłania pliku
<?php
$aErrors = "";
if ( !empty( $thefile_name ) ) // nie wybrano pliku
{
if ( ( $thefile_type == "image/gif" ) ||
( $thefile_type == "image/pjpeg" ) ||
( $thefile_type == "image/jpeg" ) )
{
if ( $thefile_size < ( 1024 * 100 ) )
{
$aCurBasePath = dirname( $PATH_TRANSLATED );
$aNewName = $aCurBasePath . "/uppics/" .
$thefile_name;
copy( $thefile, $aNewName );
}
else
{
$aErrors .= "Za duży plik !!!";
}
}
else
{
$aErrors .= "Plik nie jest typu gif ani jpeg";
}
}
else
{
$aErrors .= "Nie wybrano pliku";
}
?>
<html>
<head>
<title>Wyświetlenie przesłanego pliku</title>
</head>
<body>
<?php
if ( $aErrors != "" )
{
print( "<b>Wystąpił błąd</b>: $aErrors<br>" );
}
else
{
print( "Przesłany plik:<br><br>" );
print( "<img src=\"uppics/$thefile_name\" border=\"0\">" );
}
?>
</body>
</html>
W przykładzie zamieszczonym na wydruku 5.2. nie wzięto pod uwagę, że nie wszystkie przeglądarki
wysyłają typu MIME pliku. Opuszczono również inne zagadnienia kontroli błędów, na przykład kontrolę
poprawności wykonania funkcji copy. Jednak przykład ten miał za zadanie pokazanie jak łatwo można obsłużyć
za pomocą PHP operacje przesyłania pliku.
W przykładzie tym na początku sprawdzane jest, czy został wybrany plik do przesyłania. Jeżeli nie został
wybrany plik, zmienna $thefile_name jest pusta. Następnie sprawdzane jest, czy plik ma odpowiednią wielkość i
typ MIME. Jeżeli obie wartości zostaną zaakceptowane, przy pomocy wyrażenia dirname($PATH_TRANSLATED)
odczytywany jest bieżący katalog na serwerze WWW. Funkcja dirname() zwraca nazwę katalogu z podanej
ścieżki. Zmienna $PATH_TRANSLATED jest zmienną PHP i zawiera pełną ścieżkę do bieżącego skryptu. Dodając
/uppics/ i oryginalną nazwę pliku na komputerze lokalnym, tworzymy nową ścieżkę. Na koniec, przesłany plik
jest kopiowany z katalogu tymczasowego do katalogu określonego przez przed chwilą skonstruowaną ścieżkę.
Należy pamiętać, że aby operacja kopiowania się udała, docelowy katalog musi posiadać odpowiednio ustawione
uprawnienia. Korzystając z Apache w systemie Linux oznacza to, że uprawnienia do katalogu muszą pozwolić na
zapis przez użytkownika nobody.
PHP posiada mechanizm pozwalający na ograniczanie w skrypcie wielkości przesyłanych plików. Jest to
realizowane przez dodanie do formularza ukrytego pola o nazwie MAX_FILE_SIZE. Na wydruku 5.3 pokazany jest
formularz identyczny z tym z wydruku 5.1, ale dodane zostało pole MAX_FILE_SIZE ograniczające wielkość
przesyłanych plików do 100 kB.
Wydruk 5.3. Ograniczenie wielkości przesyłanego pliku za pomocą MAX_FILE_SIZE
<html>
<head>
63
PHP – Kompendium wiedzy
<title>Formularz do przesyłania plików</title>
</head>
<body>
<form action="upload_single.phtml" method="post" enctype="multipart/form-data">
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="102400">
Wyślij plik: <input type="file" name="thefile"><br><br>
<input type="submit" name="Submit" value="Wyślij">
</form>
</body>
</html>
Pułapki
PHP domyślnie ogranicza wielkość plików, jakie można przesyłać używając tego mechanizmu, do 2
megabajtów. Ta wielkość jest ważniejsza od zmiennej formularza MAX_FILE_SIZE. Wartość ta może być zmieniona
przez ustawienie wartości upload_max_filesize w pliku php.ini, lub ustawienie dyrektywy w pliku Apache.conf
(więcej szczegółów znajduje się w rozdziale o opcjach konfiguracji, który znajduje się na końcu książki). Gdy
osiągnięta zostanie graniczna wielkość pliku (zarówno ustawiona w formularzu jak i globalne maksimum), PHP
generuje błąd, przerywa przesyłanie i ustawia nazwę pliku na none.
Mimo tego, że ta graniczna wielkość pliku jest ustawiana w celu chronienia serwera WWW, sieje ona
zniszczenie w twoich aplikacjach. Ponieważ błąd przekroczenia wielkości przesyłanego pliku występuje przed
wykonaniem jakiejkolwiek linii skryptu, nie ma możliwości przechwycenia generowanego ostrzeżenia
generowanego przez mechanizm przesyłania plików. Oznacza to, że jeżeli opcja konfiguracji display_errors ma
wartość On (domyślnie) w przeglądarce będzie się pojawiał komunikat błędu.
Jeżeli nie chcesz aby pojawiał się ten komunikat, musisz ustawić w pliku php.ini opcję konfiguracji
display_errors na Off. Możesz następnie ustawić opcję log_errors na On a error_log na wartość odpowiednią
dla twojego środowiska. Jeżeli używasz Linuksa i Apache, ustawienie error_log na stderr spowoduje, że
wszystkie błędy PHP trafią do dziennika błędów Apache. Aplikacja twoja może sprawdzać zmienne przesyłu
plików i odpowiednio obsługiwać błędy. Jeżeli użytkownikowi nie uda się przesył pliku, zmienna $thefile
będzie miała wartość none, a $thefile_name będzie zawierała odpowiednią wartość.
Innym problemem, nad jakim należy się zastanowić w trakcie pisania skryptu obsługi przesyłania plików
jest to, że zanim rozpocznie się wykonywanie skryptu musi zostać przesłany cały plik lub maksymalna określona
ilość bajtów. Jeżeli więc twoja aplikacja dopuszcza przesyłanie dużych plików, ale akceptuje jedynie niektóre
typy plików, twoi użytkownicy mogą dosyć długo czekać zanim zobaczą komunikat o odrzuceniu przesyłanego
pliku.
Przesyłanie wielu plików
Jeżeli chcesz przesłać kilka plików używając jednego formularza możesz skorzystać z tablicy PHP do
przesłania danych o przychodzących plikach. Poniższy przykład pokazuje użycie tablicy do przesłania czterech
plików.
Wydruk 5.4. Przesyłanie czterech plików
<html>
<head>
<title>Formularz do przesyłania plików</title>
</head>
<body>
Proszę podać cztery pliki rysunków do przesłania:
<form action="upload_multiple.phtml" method="post" enctype="multipart/form-data">
Plik 1: <input type="file" name="thefiles[]"><br><br>
Plik 2: <input type="file" name="thefiles[]"><br><br>
Plik 3: <input type="file" name="thefiles[]"><br><br>
Plik 4: <input type="file" name="thefiles[]"><br><br>
<input type="submit" name="Submit" value="Wyślij">
</form>
</body>
</html>
Wydruk 5.5. Obsługa czterech przesyłanych plików
<?php
$aBasePath = dirname( $PATH_TRANSLATED );
// każdy przesłany plik należy skopiować
Rozdział 5 – Wysyłanie plików przez formularz
64
// i zapamiętać ich nowe ścieżki do późniejszego wykorzystania
for ( $nIndex = 0; $nIndex < count( $thefiles ); $nIndex++ )
{
if ( !empty( $thefiles_name[$nIndex] ) )
{
$aType = $thefiles_type[$nIndex];
if ( ( $aType == "image/gif" ) ||
( $aType == "image/pjpeg" ) ||
( $aType == "image/jpeg" ) )
{
$aNewName = $aBasePath . "/uppics/" .
$thefiles_name[$nIndex];
copy( $thefiles[$nIndex], $aNewName );
$aNewNames[] = $thefiles_name[$nIndex];
}
}
}
?>
<html>
<head>
<title>Wyświetlanie przesłanego rysunku</title>
</head>
<body>
<?php
$aCount = count( $aNewNames );
print( "Przesłano <b>$aCount</b> rysunki:<br><br>" );
foreach( $aNewNames as $aNewName )
{
print("<img src=\"uppics/$aNewName\" border=\"0\"><br><br>");
}
?>
</body>
</html>
Bezpieczeństwo
Jeżeli dopuszcza się dostarczanie jakichkolwiek danych do aplikacji, należy brać pod uwagę każdą
ewentualność. Jeżeli pozwalasz na przesyłanie plików musisz się upewnić, że pliki te zostaną właściwie
obsłużone na serwerze. Na przykład, jeżeli tworzysz witrynę do której programiści mogą przesyłać własne
skrypty nie należy pozwalać na wykonywanie tych skryptów na serwerze. Można je jedynie odebrać i wyświetlić
w postaci czystego tekstu i nie można zakładać, że można je bezpiecznie uruchomić.
Nawet pozwolenie na wyświetlenie przesłanych plików niesie ze sobą potencjalne zagrożenie. Na
wydruku 5.6. pokazany jest prosty przykład w jaki sposób mechanizm wyświetlania plików może spowodować
dziurę w systemie bezpieczeństwa.
Wydruk 5.6. Naruszenie bezpieczeństwa podczas obsługi przesłanych plików
<?php
include( "class.File.php3" );
// skopiowanie przesłanego pliku
$aCurBasePath = dirname( $PATH_TRANSLATED );
$aNewName = $aCurBasePath . "/uploads/" . $thefile_name;
copy( $thefile, $aNewName );
?>
<html>
<head>
<title>Naruszenie bezpieczeństwa przy przesyłaniu pliku</title>
</head>
<body>
<?php
// wyświetlenie zawartości pliku
print( "Plik <b>$aNewName</b>:<br><br>" );
$aFileClass = new File();
$aFileCont = $aFileClass->read_file( $thefile );
print( "<pre>" );
print( nl2br( htmlentities( $aFileCont ) ) );
print( "</pre>" );
?>
</body>
</html>
Jest to oczywiście wymyślony przykład. W przykładzie tym przesłany plik jest kopiowany do nowego
katalogu, ale wyświetlając plik odczytywany i wysyłany do przeglądarki jest plik tymczasowy. W rzeczywistości
65
PHP – Kompendium wiedzy
prawdopodobnie odczytasz i wyświetlisz plik znajdujący się na ścieżce zapamiętanej w $aNewName. Dla potrzeb tej
prezentacji poprzedni plik pokazuje w jaki sposób źle napisany skrypt narusza system bezpieczeństwa.
Aby wykorzystać niedoskonałość skryptu ktoś może wpisać do przeglądarki nazwę skryptu i podać nazwę
dowolnego pliku na serwerze. Na przykład wprowadzenie takiego adresu URL spowoduje wyświetlenie
zawartości pliku /etc/passwd (zakładając, że będzie on wykonywany na systemie Uniksowym):
http://serwer.com/sciezka/upload_flaw.phtml?thefile=/etc/passwd
Można przetestować to na komputerze z Uniksem, że niebezpieczeństwo jest rzeczywiste. Nawet mimo
tego, że serwer WWW pracuje jako użytkownik nobody, plik /etc/passwd musi być możliwy do odczytania przez
wszystkich użytkowników.
W rozdziale o formularzach kładłem nacisk na to, że nie wolno zakładać, że wszyscy użytkownicy
aplikacji będą używali jej zgodnie z twoimi zamiarami. Tak samo jest i teraz. Niektórzy użytkownicy będą chcieli
rozmyślnie wykorzystać słabości aplikacji a inni nieświadomie spowodują jej awarię. Należy dokładnie
przemyśleć wszystkie możliwe skutki uboczne pozwolenia na przesyłanie plików na serwer WWW.
Podsumowanie
W rozdziale tym pokazane zostały sposoby odczytywania i wykorzystania plików przesłanych przez
przeglądarki zgodne z dokumentem RFC 1867. Zostały przytoczone przykłady obsługi jednego pliku jak również
tablicy plików. Na końcu rozdziału znajduje się mała część ilustrująca w jaki sposób źle napisany skrypt może
stworzyć dziurę w systemie bezpieczeństwa serwera.
Dopuszczenie do przesyłania plików do aplikacji może być w wielu przypadkach użyteczne, ale należy
pamiętać, że niektórzy użytkownicy mogą nie posiadać dostatecznie szybkiego łącza aby efektywnie korzystać z
tego mechanizmu, więc dobrym pomysłem jest zapewnienie jeszcze jednego sposobu na dostarczanie plików do
aplikacji.
Rozdział 5 – Wysyłanie plików przez formularz
66
Rozdział 6. Współpraca z bazami danych
Wstęp
Jedną z najważniejszych cech nowoczesnych języków programowania lub narzędzi programistycznych
jest zdolność współpracy z bazą danych. Jest to spowodowane tym, że systemy zarządzania relacyjnymi bazami
danych (SZRBD) posiadają wiele bardzo wydajnych i niezwykle użytecznych mechanizmów zarządzania danymi,
jak na przykład indeksowanie, relacje pomiędzy danymi, obsługa transakcji, kaskadowe operacje wykonywane na
danych i wiele innych. PHP pozwala na dostęp do danych przy użyciu bogatego zestawu funkcji związanych z
bazami danych.
Wprowadzenie
Jak można wywnioskować na podstawie dokumentacji, autorzy PHP uważają obsługę baz danych za jedną
z najważniejszych i najsilniejszych cech PHP. Obsługiwane są między innymi takie bazy danych:
Adabas D
InterBase
Solid
dBase
mSQL
Sybase
Empress
MySQL
Velocis
FilePro
Oracle
Unix dbm
Informix
PostgreSQL
Mictosoft SQL Server
ODBC
Obsługując ODBC, PHP może zostać użyty do prawdopodobnie dowolnej istniejącej bazy danych. Z
powodu ogromnej ilości obsługiwanych baz danych jest niemożliwe szczegółowe omówienie obsługi każdej z
nich w tej książce. Dodatkowo, język SQL jest sam w sobie niezwykle bogatym i wydajnym narzędziem, które
również nie zostanie odpowiednio dokładnie opisane w tej książce. Najlepiej posiłkować się dokumentacją
odmiany SQL zaimplementowanej w używanej przez ciebie bazie danych. Zakładamy w tym rozdziale, że
czytelnicy znają podstawy SQL w stopniu wystarczającym do zrozumienia przykładów zamieszczonych na
wydrukach.
W rozdziale tym skupimy się na przykładach użycia MySQL i ODBC. Wybrałem MySQL ponieważ jest
to wydajna baza danych dostępna na zasadach licencji GNU General Public License (GPL) i jest powszechnie
używana do współpracy z PHP. ODBC wybrałem, ponieważ do większości baz danych dostępne są sterowniki
tego standardu. Przykłady ilustrują zastosowanie języka PHP i nie zawsze pokazują najlepsze zastosowania SQL
oraz działania na bazach danych.
Funkcje baz danych
Każda z obsługiwanych baz danych posiada własny zestaw funkcji PHP. Nazwy funkcji związanych z
MySQL rozpoczynają się od mysql_ i podobna zasada obowiązuje w przypadku innych baz (W skorowidzu
funkcji na końcu książki znajduje się kompletna lista funkcji związanych z bazami danych). Mimo, że każda z baz
danych ma własny zestaw funkcji, istnieje wspólny model dostępu do każdego z typów baz danych. Pseudokod
opisujący pobieranie danych z dowolnego systemu bazy danych przedstawiony jest na wydruku 6.1.
Wydruk 6.1. Pseudokod opisujący pobieranie danych z bazy
<?php
połącz_z_Bazą();
wybierz_bazę();
wyślij_wyrażenie_SQL();
pobierz_wynik();
while ( istnieje_wiersz )
pobierz_wiersz();
zamknij_połączenie();
?>
Następne dwie części zawierają szczegóły konfiguracji i użycia MySQL i ODBC.
MySQL
MySQL jest świetną bazą danych dla większości projektów. Oficjalną witryną MySQL jest
http://www.mysql.com. Na tej witrynie znajduje się najnowsza wersja systemu oraz dokumentacja opisująca
instalację i konfigurację MySQL w różnych środowiskach.
Rozpoczynamy pracę z MySQL
W zależności od twoich potrzeb i typu serwera, możesz albo ściągnąć źródła MySQL, dystrybucję binarną
albo RPM. Najszybszą metodą zainstalowania MySQL na systemie Linux działającym na platformie Intel jest
ściągnięcie pliku RPM i zainstalowanie go. Przy użyciu tej metody instalowane są wszystkie elementy serwera,
więc możesz od razu zaczynać pracę. Jeżeli używasz systemu działającego w oparciu o Win32, najszybszą
metodą pozyskania serwera jest ściągnięcie skompresowanej instalacji binarnej.
PHP4 posiada wbudowaną obsługę MySQL, więc nie musisz ponownie kompilować PHP aby używać
funkcji mysql_. Jednak jeżeli korzystasz z wbudowanej obsługi MySQL, nie można używać innych modułów
odwołujących się do MySQL, na przykład mod_auth_mysql i mod_perl. Jeżeli potrzebujesz modułów używających
MySQL, musisz przekompilować PHP podając opcję konfiguracji --with_mysql=/ścieżka/do/mysql.
Użycie MySQL
Po zainstalowaniu i uruchomieniu MySQL można rozpocząć pisanie skryptów PHP, które korzystają z
danych umieszczonych w bazie danych. Skrypt zamieszczony na wydruku 6.2 pokazuje jak proste jest użycie
MySQL do pobrania danych z bazy. Tabela której będę używał w dwóch kolejnych przykładach została
utworzona za pomocą następującego kodu SQL:
CREATE TABLE employees
(
id tinyint(4) DEFAULT '0' NOT NULL auto_increment,
first varchar(20),
last varchar(20),
adress varchar(255),
position varchar(50),
PRIMARY KEY (id),
UNIQUE id (id)
)
Wydruk 6.2. Pobieranie danych z bazy danych MySQL
<html>
<head>
<title>Pobieranie danych z MySQL</title>
</head>
<body>
<?php
// Ukrywamy komunikaty błędów i sami je obsługujemy
$aDBLink = @mysql_connect( "db.server.com", "user", "pass" );
if ( !empty( $aDBLink ) )
{
// wybór bazy danych MySQL
if ( mysql_select_db( "mydb", $aDBLink ) == True )
{
$aSQL = "select * from employees";
// Wykonanie zapytania SELECT
$aQResult = mysql_query( $aSQL, $aDBLink );
if ( $aQResult == True )
{
// Pobranie wiersza danych i wypisanie dwóch pól
while ( $aRow = mysql_fetch_array( $aQResult ) )
{
$aFName = $aRow["first"];
$aPos
= $aRow["position"];
print( "$aFName, $aPos<br>" );
Rozdział 6 – Współpraca z bazami danych
68
}
mysql_free_result( $aQResult );
}
else
{
print( "Błąd wykonania zapytania<br>" );
}
}
else
{
print( "Błąd wyboru bazy danych<br>" );
}
}
else
{
print( "Błąd przy podłączaniu do bazy danych<br>" );
}
?>
</body>
</html>
Po uruchomieniu skryptu z wydruku 6.2, próbuje się on podłączyć do serwera bazy danych MySQL
działającego na komputerze db.serer.com podając nazwę użytkownika i hasło. Symbol @ umieszczony przed
funkcją mysql_connect() powoduje zablokowanie wypisywania błędów i ostrzeżeń. Podczas testowania możesz
opuścić ten symbol, ale w normalnej pracy należy go używać i stosować własne procedury obsługi błędów.
Następną czynnością wykonywaną przez skrypt jest wybranie odpowiedniej bazy danych, w naszym przypadku
mydb. Jeżeli się to powiodło, przy pomocy funkcji mysql_query() zadawane jest zapytanie do bazy danych. W
naszym przykładzie jest to zapytanie SELECT, które powoduje pobranie rekordów z bazy danych. Może być to
dowolne zapytanie, na przykład: INSERT, UPDATE, ADD TABLE lub dowolne inne zapytanie SQL. Wynik funkcji jest
różny od zero w przypadku powodzenia i zero w przypadku błędu. Dodatkowo, jeżeli zapytanie jest typu SELECT,
wynik funkcji jest identyfikatorem wyniku przekazywanym do funkcji mysql_result(), mysql_fetch_array(),
mysql_fetch_lengths(), mysql_fetch_object(), i mysql_fetch_row(), które są używane do odczytania
wynikowych danych. W naszym przykładzie używamy funkcji mysql_fetch_array() do odczytania wiersza z
wynikowych danych a następnie wyświetlane są dane z odpowiednich pól.
Funkcje mysql_fetch_array() i mysql_fetch_row() są podobne do siebie i zwracają jeden wiersz wyniku
w postaci tablicy. Funkcja mysql_fetch_array() zwraca wynik w postaci tablicy asocjacyjnej indeksowanej
nazwami kolumn. Wywołanie funkcji mysql_fetch_row() zwraca tablicę indeksowaną liczbami. Wywołanie
jednej z tych funkcji zwraca kolejny wiersz danych zwracanych przez zapytanie i przesuwa wewnętrzny wskaźnik
do następnego wiersza. Jeżeli nie ma więcej danych, funkcja zwraca False. Wywołanie funkcji
mysql_fetch_array() nie jest zauważalnie wolniejsze niż wywołanie mysql_fetch_row(), a dostarcza o wiele
więcej danych.
Używając skryptu z wydruku 6.2 jako podstawy, można napisać wszystkie możliwe aplikacje oparte na
bazie danych. Funkcje MySQL posiadają dodatkowo kilka cech, które nie są dostępne dla wszystkich baz
obsługiwanych przez PHP. Dostarczone są specjalizowane funkcje do tworzenia i usuwania baz danych oraz
funkcje umożliwiające odczytanie struktury bazy danych. Na przykład za pomocą funkcji mysql_list_tables()
można uzyskać listę wszystkich tabel w bazie danych.
Jedną z moich ulubionych funkcji dla MySQL jest mysql_insert_id(). Używając pól o atrybucie
auto_increment można po prostu zapisać dane do tabeli a następnie odczytać unikalny identyfikator rekordu za
pomocą funkcji mysql_insert_id(). Na wydruku 6.3 mamy formularz, który pozwala na wprowadzenie danych
nowego pracownika do bazy używanej na wydruku 6.2. Skrypt korzysta z funkcji mysql_insert_id() w celu
zrealizowania potwierdzenia operacji wstawienia danych.
Wydruk 6.3. Wstawianie rekordu do bazy danych MySQL
<?php
/*
Funkcja InsertRecord
Wstawia mowy rekord do tabeli employees.
W przypadku powodzenia operacji zwraca identyfikator nowego rekordu
a w przypadku błędu wartość ujemną wskazującą na przyczynę błędu.
*/
function InsertRecord( $aFirstName, $aLastName, $aAddr, $aPos )
{
// Przygotowanie wyrażenia SQL INSERT
$aSQL = "insert into employees ( first, last, address, ";
$aSQL .= "position ) values ( '$aFirstName', '$aLastName', ";
$aSQL .= "'$aAddr', '$aPos' )";
// Przyłączenie do serwera i wykonanie instrukcji INSERT
69
PHP – Kompendium wiedzy
$aDBLink = @mysql_connect( "db.server.com", "root", "" );
if ( !empty( $aDBLink ) )
{
if ( mysql_select_db( "mydb", $aDBLink ) == True )
{
$aQResult = mysql_query( $aSQL, $aDBLink );
if ( $aQResult == True )
{
$aResult = mysql_insert_id( $aDBLink );
}
else
{
// print( "Błąd wykonania zapytania<br>" );
$aResult = -1;
}
}
else
{
// print( "Błąd wyboru bazy danych<br>" );
$aResult = -2;
}
}
else
{
// print( "Błąd przy podłączaniu do bazy danych<br>" );
$aResult = -3;
}
return $aResult;
}
?>
<html>
<head>
<title>Przykład MySQL: Wstawianie danych do bazy </title>
</head>
<body>
<?php
if ( $REQUEST_METHOD == 'POST' )
{
// Nastąpiło przesłanie danych formularza
$aResult = InsertRecord( $FirstName, $LastName,
$Address, $Position );
if ( $aResult > 0 )
{
print( "Dodano nowy wiersz, ID = $aResult<br>" );
}
else
{
print( "Błąd funkcji InsertRecord. Kod błędu = $aResult<br>" );
}
print( "<hr>" );
}
?>
Proszę wpisać dane nowego pracownika:<br>
<form action="<?php echo $PHP_SELF ?>" method="post">
Imię: <input type="text" name="FirstName" maxlength="20"><br>
Nazwisko: <input type="text" name="LastName" maxlength="20"><br>
Adres: <input type="text" name="Address" maxlength="255"><br>
Stanowisko: <input type="text" name="Position" maxlength="50"><br><br>
<input type="submit" name="Submit" value="Wyślij">
</form>
</body>
</html>
W skrypcie z wydruku 6.3, funkcja IndertRecord() zawiera całą logikę wstawienia nowego rekordu do
bazy danych. Zwraca on identyfikator nowego rekordu (wartość przypisywana przez MySQL do kolumny id) lub
wartość ujemną oznaczającą jedną z trzech obsługiwanych sytuacji błędnych. Realistycznie patrząc, Ten typ
aplikacji powinien zawierać o wiele więcej kodu odpowiedzialnego za obsługę błędów, na przykład sprawdzanie
pustych pól, ale dla naszych potrzeb kod ten nie został rozmyślnie wprowadzony. Ponieważ pole id w tabeli
employees jest polem typu auto_increment, MySQL automatycznie generuje jednoznaczne wartości tego pola
przy każdym wstawieniu rekordu. W naszym przykładzie wartość ta jest odczytywana za pomocą funkcji
mysql_insert_id().
Przykład ten miał na celu pokazanie prostoty korzystania z baz danych w PHP. Więcej przykładów użycia
baz danych w aplikacjach WWW można znaleźć w rozdziale 15 „Witryny oparte o bazę danych”. Znajdują się
tam bardziej złożone przykłady zawierające obsługę błędów i skomplikowane zapytania.
Rozdział 6 – Współpraca z bazami danych
70
MySQL jest wydajną bazą danych posiadającą funkcje wystarczające do tworzenia większości typów
aplikacji WWW. Jest ona szybka, solidna i zawiera większość funkcji dostępnych w komercyjnych bazach
danych. Jednak w czasie pisania tej książki MySQL nie zawierał mechanizmu transakcji. Niedostępne są również
niektóre elementy SQL, na przykład podzapytania. Jeżeli jeszcze nie wybrałeś swojego systemu bazy danych,
spisz swoje wymagania i porównaj ze specyfikacją dostępnych systemów. W przypadku tworzenia aplikacji o
wysokiej jakości koszt bazy nie jest jedynym czynnikiem jaki należy brać pod uwagę. Jeżeli twoja firma posiada
system bazy danych inny niż MySQL, następna część zawiera informacje na temat ODBC, które pomogą
podłączyć się do twoich istniejących danych.
ODBC
Open Database Connectivity (ODBC) to powszechnie stosowany interfejs API (application programming
interface) służący do łączenia się z bazami danych. Jest on oparty na specyfikacji Call Level Interface
pochodzącym z X/Open oraz ISO/IEC i jako języka dostępu do danych używa SQL. Istnieje kilka implementacji
ODBC API dla systemów Uniksowych. W systemie Windows ODBC jest zwykle instalowany razem z systemem.
Podstawy ODBC
PHP może obsługiwać praktycznie każdą implementację ODBC, ale musi być w tym celu odpowiednio
skonfigurowany, ponieważ ODBC nie jest w chwili obecnej domyślną opcją. W PHP istnieją cztery opcje
konfiguracji związane z ODBC: --with-unixODBC, --with-custom-ODBC, --with-iodbc oraz --with-openlink.
Opcje te są lepiej opisane w skorowidzu na końcu książki. W rozdziale tym przykłady korzystają z implementacji
ODBC unixODBC (http://www.unixodbc.org/). Jest on dostępny na zasadach licencji GPL lub LGPL i jest bardzo
łatwy do instalacji i konfigurowania.
ODBC tym różni się od MySQL i innych API baz danych tym, że wszystkie odwołania do bazy danych
wykonuje za pośrednictwem sterownika bazy danych. Oznacza to, że najpierw musisz zainstalować program
zarządzający sterownikami, na przykład unixODBC, a następnie sterownik do twojego systemu bazy danych. Na
rysunku 6.1. pokazane są powiązania pomiędzy komponentami aplikacji PHP opartej o ODBC. Aplikacja
wywołując funkcję, na przykład odbc_connect(), kontaktuje się z zarządcą sterowników. Zarządca ten jest
odpowiedzialny za załadowanie odpowiedniego sterownika bazy danych i przekazanie do niego żądania.
Sterownik bazy danych wywołuje odpowiednią funkcję bazy danych, która realizuje nasze żądanie.
PHP Application - aplikacja PHP
Rysunek 6.1.
Driver Manager - zarządca sterowników
Komponenty
Database Driver - sterownik do bazy danych
aplikacji PHP
DBMS - SZRBD
korzystającej z
PHP
Ponieważ ODBC wymaga zastosowania zarządcy sterowników oraz sterownika odpowiedniej bazy
danych, instalacja i konfiguracja ODBC jest nieco bardziej skomplikowana niż konfiguracja MySQL. Również
każdy z używanych sterowników baz danych musi zostać zainstalowany i skonfigurowany.
W książce tej zostanie opisana instalacja i konfiguracja zarządcy sterowników unixODBC oraz sterownika
ODBC-ODBC Bridge (OOB), który można uzyskać z Easysoft Limited, http://www.easysoft.com/. Sterownik
OOB powoduje wzrost komplikacji struktury, ale posiada tak dużo zalet, że jest wart zainteresowania. Sterownik
ten pozwala na dostęp do baz danych zainstalowanych na różnych platformach za pomocą własnego modelu
klient-serwer. NA rysunku 6.2. zilustrowano sposób użycia sterownika OOB.
PHP Application - aplikacja PHP
Rysunek 6.2.
Driver Manager - zarządca sterowników
Dodajemy
The OOB driver - sterownik OOB
sterownik OOB
OOB Client - klient OOB
Network - sieć
OOB Server - serwer OOB
Driver Manager - zarządca sterowników
Database Driver - sterownik do bazy danych
71
PHP – Kompendium wiedzy
DBMS - SZRBD
Zaletą stosowania sterownika OOB jest to, że możesz dzięki niemu używać ODBC w aplikacjach
działających na serwerze WWW i korzystać z danych z bazy danych działającej na innym komputerze (który
może działać na innym systemie operacyjnym). Dla przykładu w moim testowym systemie zainstalowałem Oracle
8i na serwerze Windows NT i utworzyłem prostą bazę danych. Następnie w moim linuksowym serwerze WWW
dodałem sterownik OOB. Sterownika tego można używać do podłączania się do dowolnej bazy zgodnej z ODBC,
działającej na dowolnej platformie.
Dodatkowym utrudnieniem jest to, że używając OOB należy kolejno zainstalować klienta i serwer OOB
na oddzielnych komputerach. Na szczęście na witrynie Easysoft bardzo łatwo jest odszukać i załadować
odpowiednie programy.
Kolejne trzy części omawiają instalowanie zarządcy sterowników unixODBC, kompilację PHP z obsługą
unixODBC oraz instalowanie sterownika OOB. Części te są przeznaczone dla użytkowników Linuksa i
zakładamy, że potrafisz kompilować programy dla tego systemu oraz, że masz zainstalowane wszystkie
niezbędne kompilatory i narzędzia.
Instalowanie i kompilowanie unixODBC
Po ściągnięciu i rozpakowaniu plików unixODBC, musisz skompilować zarządcę sterowników. W
instalacji unixODBC znajduje się standardowy skrypt służący do konfigurowania środowiska kompilacji. W celu
skompilowania mojej konfiguracji PHP użyłem następujących opcji:
./configure --disable--drivers --disable-threads --prefix=/usr/local/unixODBC --disable-gui
Ponieważ miałem już potrzebny sterownik, nie potrzebowałem aby unixODBC dodał swoje sterowniki
wewnętrzne. Powodem wyłączenia wątków jest to, że moja instalacja PHP jest w postaci dynamicznie
ładowanego modułu (--with-apxs) a Apache nie obsługuje domyślnie wątków. Skompilowanie tego modułu z
obsługa wątków spowodowałoby awarię Apache w trakcie ładowania modułu. Wyłączyłem również obsługę
graficznego interfejsu użytkownika, ponieważ nie mam na moim serwerze zainstalowanego środowiska
XWindows.
Kompilowanie PHP z obsługą unixODBC
Po skompilowaniu i zainstalowaniu zarządcy sterowników unixODBC należy przekompilować PHP z
włączoną obsługą unixODBC. Odpowiednią opcją konfiguracji jest --with-unixODBC=/sciezka/do/unixODBC.
Użyta ścieżka musi być taka sama jak ścieżka użyta w opcji --prefix podczas kompilowania unixODBC. W
moim przypadku jest to /usr/local/unixODBC.
Jeżeli statycznie łączysz PHP z Apache, musisz również przekompilować Apache. Jeżeli korzystasz z
dynamicznego łączenia, wystarczy wyłączyć Apache, zainstalować nowy moduł PHP i powtórnie uruchomić
Apache.
Instalowanie sterownika OOB
W moim przypadku musiałem zainstalować serwer OOB na komputerze z Windows NT i skonfigurować
go tak, aby przyjmował żądania. Wykonałem to uruchamiając program instalacyjny i wykonując wszystkie kroki
w programie instalacyjnym. Wszystko zadziałało bez problemów. Następnie ściągnąłem i zainstalowałem
oprogramowanie klienta na serwerze z systemem Linux. Proces ten był niespodziewanie łatwy, ponieważ
dostępny był program instalacyjny prowadzący użytkownika przez kolejne kroki procedury instalacyjnej. Można
również skorzystać z witryny Easysoft, gdzie na podstawie konkretnej konfiguracji otrzymamy szczegółowy opis
tego jak ściągnąć i zainstalować serwer i klienta OOB.
Konfigurowanie OOB
Po zainstalowaniu całego oprogramowania należy utworzyć nazwy źródeł danych (DSN) zarówno na
kliencie jak i na serwerze. Źródła danych są mechanizmem specyficznym dla ODBC służącym do opisywania
sposobu współpracy z systemem bazy danych. W Windows tworzy się DSN poprzez program Źródła danych
ODBC dostępny w Panelu sterowania. OOB wymaga utworzenia systemowego DSN a nie DSN użytkownika.
Program ten zawiera plik pomocy opisujący sposób tworzenia systemowych DSN.
Rozdział 6 – Współpraca z bazami danych
72
Aby utworzyć DSN na Linuksie należy zmienić przy pomocy graficznego narzędzia unixODBC lub
edytora tekstowego pliki odbcinst.ini i odbc.ini. Plik odbcinst.ini jest używany do opisu nazw sterowników i łączy
nazwy z plikami sterowników. Mój plik wygląda następująco:
[OOB]
Driver = /usr/local/easysoft/oob/client/libesoobclient.so
Setup = /usr/local/easysoft/oob/client/libesoobsetup.so
FileUsage = 1
Plik odbc.ini zawiera opis źródeł danych. Swoje źródło skonfigurowałem następująco (serwer i hasło jest
oczywiście zmyślone):
[localdsn]
Server=satabase.server.com
Driver=OOB
Port=8888
Transport=tcpip
LogonUser=prodplaner
LogonAuth=password
TargetDSN=LocalOracle
TargetUser=prodplaner
TargetAuth=password
Korzystanie z ODBC
Po zainstalowaniu i skonfigurowaniu wszystkich komponentów korzystanie z ODBC w PHP jest bardzo
podobne do korzystania z MySQL. Na wydruku 6.4 znajduje się skrypt, który jest odpowiednikiem ODBC
skryptu umieszczonego na wydruku 6.2. Tabela używana w tym przykładzie jest odpowiednikiem używanej w
poprzednim przykładzie.
Wydruk 6.4. Odczytywanie danych z bazy ODBC
<html>
<head>
<title>Pobioeranie danych z bazy danych ODBC</title>
</head>
<body>
<?php
putenv("ODBCINI=/usr/local/unixODBC/etc/odbc.ini");
// Ukrywamy komunikaty błędów i sami je obsługujemy
$aDBLink = @odbc_connect( "localdsn", "prodplanner", "agdec" );
if ( !empty( $aDBLink ) )
{
$aSQL = "select * from employees";
$aQResult = @odbc_exec( $aDBLink, $aSQL );
if ( $aQResult == True )
{
$aRow = array();
$aRowNum = 1;
while ( odbc_fetch_into( $aQResult, $aRowNum, &$aRow ) )
{
$aFName = $aRow[1];
$aPos
= $aRow[4];
print( "$aFName, $aPos<br>" );
$aRowNum++;
}
odbc_free_result( $aQResult );
}
else
{
print( "Błąd wykonania zapytania<br>" );
}
}
else
{
print( "Błąd podłączenia do bazy danych<br>" );
}
?>
</body>
</html>
Wydruk 6.4 jest właściwie taki sam jak wydruk 6.2. Mimo, że nazwy funkcji są inne, koncepcja jest
nieomal identyczna. Jedyną zauważalną różnicą jest wywołanie putenv() na początku skryptu. Wywołanie to
umieszcza w środowisku programu ścieżkę do pliku inicjalizującego ODBC. Nie jest to potrzebne, jeżeli w ten
sam sposób ustawiłeś środowisko serwera WWW. Dodatkowo, na wydruku 6.4 do pól tabeli odwołujemy się dla
73
PHP – Kompendium wiedzy
uproszczenia za pomocą numer a nie nazwy. Dostępne są funkcje ODBC zapewniające obsługę transakcji,
kursorów i wiele innych. W skorowidzu funkcji na końcu książki znajdują wszystkie funkcje do obsługi ODBC.
Uwaga na temat połączenia do baz danych
W poprzednim przykładzie połączenie do baz danych było realizowane za pomocą podstawowych funkcji xxx_connect(). PHP
posiada również zdolność tworzenia trwałych połączeń za pomocą funkcji pxxx_connect(). Użycie połączenia trwałego poprawia
wydajność aplikacji, ponieważ sam PHP utrzymuje połączenie z bazą danych, więc może być ono wielokrotnie używane. Po
utworzeniu połączenia za pomocą odpowiedniej kombinacji host-użytkownik-hasło, PHP ciągle dostarcza tego samego połączenia do
kolejnych wywołań połączenia. W bazach danych utworzenie połączenia trwa zwykle długo (na przykład w Oracle), więc użycie
trwałych połączeń może mieć ogromny wpływ na ogólną wydajność aplikacji.
PHPLIB
Jak wspomniałem w poprzednich rozdziałach, dostępne są świetne biblioteki do wykorzystania przez
programistów PHP. Jedna z najczęściej używanych bibliotek, PHP Base Library (PHPLIB) jest dostępna pod
adresem http://phplib.netuse.de. Zawiera ona klasy dostęu do baz danych, obsługi sesji, narzędzi autoryzacji i
wiele, wiele innych.
Klasy dostępu do bazy danych w PHPLIB tworzą warstwę abstrakcji dla kilku baz danych obsługiwanych
przez PHP. Warstwa ta zapewnia wspólny interfejs dla bazowych funkcji baz danych, więc programiści mogą
łatwo zmieniać typ bazy danych bez konieczności nauki nowego zestawu funkcji lub wielu zmian w kodzie. W
czasie pisania książki PHPLIB obsługiwał MySQL, PostgreSQL, mSQL, Oracle 7, Oracle 8, Sybase, Microsoft
SQL Sever i bazy ODBC.
Poniższy wydruk ilustruje siłę modułu obsługującego bazy danych z pakietu PHPLIB. W skrypcie
umieszczonym na wydruku 6.5. pokazany został sposób uproszczenia skryptu z wydruku 6.2.
Wydruk 6.5. Użycie PHPLIB do powtórzenia wyników z wydruku 6.2
<?php
include ( "db_mysql.inc" );
// Dziedziczymy po klasie DB_Sql aby użyć jej z
// naszą bazą MySQL
class MySQLDBTest extends DB_Sql
{
var $Host
= "208.129.36.163";
var $Database
= "mydb";
var $User
= "root";
var $Password
= "";
}
// Tworzenie egzemplarza nowej klasy MySQLDBTest
$aDB = new MySQLDBTest;
$aDB->query( "select * from employees" );
while( $aDB->next_record() )
{
$aFName = $aDB->f( "first" );
$aPos
= $aDB->f( "position" );
print( "$aFName, $aPos<br>" );
}
?>
Dostarczona przez PHPLIB klasa DB_Sql ukrywa w sobie szczegóły procesu łączenia i wyboru bazy
danych oraz zawiera kod obsługi błędów. Pozwala to osiągnąć w wyniku kod, który jest łatwiejszy do czytania,
utrzymania i uruchamiania. Klasa DB_Sql nie jest przeznaczona do bezpośredniego używania. Zamiast tego
powinna być tworzona klasa dziedzicząca po niej, w której ustawiane są zmienne specyficzne dla twojego
środowiska pracy. Jeżeli PHP będzie obsługiwał klasy abstrakcyjne, jest to idealny kandydat do takiej właśnie
implementacji. Na wydruku 6.5 definiowana jest klasa pochodna MySQLDBTest, w której zawarte są dane opisujące
połączenie z MySQL. Następnie tworzony jest obiekt tej klasy, na którym wykonywane są operacje.
Największa zaleta korzystania z klas PHPLIB ujawnia się, gdy zachodzi potrzeba wymiany bazy danych.
Poniższy wydruk pokazuje jak łatwo można zamienić skrypt z wydruku 6.5, aby zamiast z MySQL korzystał z
Oracle poprzez sterownik ODBC.
Wydruk 6.6. Skrypt z wydruku 6.5 korzystający z Oracle i ODBC
<?php
putenv("ODBCINI=/usr/local/openlink/odbc.ini");
include( "db_odbc.inc" );
// Dziedziczymy po klasie DB_Sql aby użyć jej z
// bazą danych Oracle poprzez ODBC
Rozdział 6 – Współpraca z bazami danych
74
class OracleDBTest extends DB_Sql
{
var $Database
= "localdsn";
var $User
= "prodplanner";
var $Password
= "agdec";
}
// Tworzenie egzemplarza nowej klasy OracleDBTest
$aDB = new OracleDBTest;
$aDB->query( "select * from employees" );
while( $aDB->next_record() )
{
$aFName = $aDB->f( "first" );
$aPos
= $aDB->f( "position" );
print( "$aFName, $aPos<br>" );
}
?>
Jedyną widoczną zmianą pomiędzy wydrukami 5 i 6 jest funkcja include(), ale znaczenie tej zmiany jest
olbrzymie. Skrypt z wydruku 6.5 korzystał z danych z bazy MySQL działającej na tym samym komputerze co
serwer WWW. Skrypt z wydruku 6.6 pobiera dane z bazy Oracle zainstalowanej na serwerze z Windows NT.
Z powodu prostoty projektu i implementacji PHPLIB może być on użyteczny dla programistów
pracujących w złożonych, heterogenicznych środowiskach, jak również w prostych instalacjach składających się z
jednego serwera. Biblioteka ta zapewnia jednakowy interfejs dostępu do różnych baz danych, co powoduje bardzo
łatwe ponowne użycie istniejącego kodu. Więcej informacji na temat klas zawartych w PHPLIB można odnaleźć
na witrynie http://phplib.netuse.de/.
Przechowywanie danych z formularzy
Omówienie formularzy HTML jest potrzebne w rozdziale dotyczących baz danych, ponieważ formularze
są najczęściej używanym mechanizmem używanym do wprowadzania danych w aplikacjach WWW. Tak jak
opisano w rozdziale 3, „Formularze i cookie”, PHP dostarcza wielu funkcji potrzebnych przy używaniu
formularzy i baz danych.
W przy domyślnych ustawieniach PHP automatycznie oznacza we wszystkich zmiennych GET, POST i
COOKIE apostrofy, cudzysłowy, ukośniki i znaki NUL. Powoduje to, że wartość przekazana z formularza jest od
razu gotowa do użycia w zapytaniu SQL. Jeżeli zablokowałeś tą opcję, musisz użyć funkcji addslashes() zanim
skorzystasz w zapytaniu SQL z ciągu przekazanego z formularza. Dodatkowo, wszystkie wartości, które będą
wyświetlane muszą zostać przed wyświetleniem przetworzone za pomocą funkcji stripslashes().
Tak jak we wszystkich aplikacjach, dane wpisane do formularza HTML muszą być sprawdzone przed ich
zapisaniem do bazy danych. Mechanizmy kontroli poprawności danych były opisane w rozdziale 3. Wynikiem
braku kontroli danych może być niezadowolenie użytkowników z aplikacji a nawet załamanie systemu
bezpieczeństwa serwera. Na przykład, niektóre komunikaty błędów generowane przez bazę danych mogą
zawierać takie informacje na temat używanej bazy danych, których na pewno nie chciałbyś pokazywać
użytkownikom. Należy być przygotowanym na sytuacje, że niektórzy użytkownicy mogą próbować wyszukać
słabe punkty w aplikacji.
Aby zabezpieczyć się przed niektórymi typami ataków należy zawsze używać atrybutu maxlength w
polach tekstowych oraz kontrolować typ i postać danych. Jak wspomniano w rozdziale 3, tam gdzie jest to
możliwe należy zastępować procedury kontroli danych przez takie mechanizmy, które ze swojej natury
ograniczają pomyłki. Pola wyboru, przyciski opcji i inne tego typ elementy pozwalają na dużą elastyczność i
ograniczają możliwość błędu przy wprowadzaniu danych.
Tworząc alternatywne mechanizmy wprowadzania danych należy pamiętać o możliwości korzystania z
bazy danych przy tworzeniu początkowego zestawu danych. Umieszczenie takiego zestawu opcji w bazie danych
skutkuje w dłuższym okresie stworzeniem aplikacji łatwiejszej do zarządzania. Na przykład na wydruku 6.7
pokazane zostało tworzenie listy wyboru zawierającej kraje oraz stany USA. Oczywiście można wybrać stan w
USA a następnie Afrykę południową. Przykład ten pokazuje jedynie koncepcję. W skrypcie tym używane są
tabele us_states oraz world_countries. Każda z tabel zawiera identyfikator oraz nazwę. Identyfikator jest
przekazywany jako wartość formularza.
Wydruk 6.7. Użycie tabel słownikowych do generacji listy opcji
<?php
include ( "./db_mysql.inc" );
class MySQLDBTest extends DB_Sql
75
PHP – Kompendium wiedzy
{
var
var
var
var
$Host
$Database
$User
$Password
=
=
=
=
"208.129.36.163";
"mydb";
"root";
"";
}
function GetGenOpts( $aTableName, $aCurSel = "" )
{
$aResult = "";
$aDB = new MySQLDBTest;
$aSQL = "select ID, Name from $aTableName order by Name";
$aDB->query( $aSQL );
while( $aDB->next_record() )
{
$aName
= $aDB->f( "Name" );
$aID
= $aDB->f( "ID" );
if ( $aID == $aCurSel )
{
$aResult .= "<option value=\"$aID\" selected>$aName</option>";
}
else
{
$aResult .= "<option value=\"$aID\">$aName</option>";
}
}
return $aResult;
}
?>
<html>
<head>
<title>Formularz wyboru stanu USA oraz kraju</title>
</head>
<body>
<form action="some_place.phtml" method="post">
<table>
<tr>
<td>
Wybierz stan USA:
</td>
<td>
<select name="us_state" size="1">
<?php
print( GetGenOpts( "us_states", "ID" ) );
?>
</select>
</td>
</tr>
<tr>
<td>
Wybierz kraj:
</td>
<td>
<select name="world_country" size="1">
<?php
print( GetGenOpts( "world_countries", "ZA" ) );
?>
</select>
</td>
</tr>
</form>
</body>
</html>
Na rysunku 6.3. pokazany jest formularz. Funkcja GetGenOpts() może być użyta do tworzenia listy opcji z
każdej tablicy posiadającej kolumny ID oraz Name. Opcjonalny parametr $aCurSel może zostać użyty do określenia
wybranej pozycji na formularzu, jeżeli formularz jest użyty do edycji danych a nie do wprowadzania nowych
danych. Użycie tabel słownikowych pozwala również na natychmiastowe zmiany w aplikacji o ile zajdzie taka
potrzeba. Jeżeli masz listę akceptowanych przez ciebie kart kredytowych, należy ją przechowywać w bazie
danych zamiast statycznie definiować na stronie HTML, ponieważ w razie zmiany tej listy, nie trzeba przeglądać
wszystkich stron szukając odwołań. Zamiast tego można po prostu zmienić wartości w tabeli bazy danych.
Aplikacja zostanie natychmiast zmieniona się bez modyfikacji jednej linii kodu.
Rozdział 6 – Współpraca z bazami danych
76
Rysunek 6.3.
Dynamicznie
generowany
formularz do
wprowadzania
danych
Kolejny raz musimy powtórzyć, że najlepszym zabezpieczeniem przed nieprawidłowymi danymi jest
dobrze skonstruowany mechanizm wprowadzania danych. Jeżeli umieścisz na formularzu pole tekstowe, zawsze
musisz zweryfikować poprawność danych, zanim trafią one do serwera bazy danych.
Udostępniając aplikację, nie możesz zapomnieć o bezpieczeństwie bazy danych. Zawsze należy
zabezpieczyć bazę danych w taki sposób, aby możliwy był dostęp do niej jedynie za pomocą aplikacji.
Oczywiście, w aplikacji nie powinny znajdować się pola umożliwiające wykonanie dowolnego zapytania SQL.
Należy również przetestować aplikację za pomocą danych, które mogą spowodować błąd. Spróbuj wprowadzić
do pól tekstowych apostrofy oraz znaki backslash. Można również wpisać średnik i po nim wyrażenie SQL.
Na przykład, spójrzmy na przykład aplikacji, która pobiera identyfikator a następnie wykonuje wyrażenie
SQL:
select * from table where ID = wprowadzona_wartosc
Spodziewasz się, że wprowadzona_wartosc będzie jedną wartością, więc można ją wkleić do wyrażenia
SQL. Mimo, że przypadek ten jest dość nieprawdopodobny, ktoś może wpisać do formularza napis „1; drop
database”. Wynikowe wyrażenie SQL będzie następujące:
select * from table where ID = 1; drop database
Mimo, że jest nieprawdopodobne, aby przykład ten spowodował jakiekolwiek szkody, to jednak możesz
odszukać podobne przykłady, które mogą spowodować naruszenie bezpieczeństwa, lub uszkodzenie bazy danych.
W oparciu o typ tworzonej aplikacji, powinieneś określić poziom wymaganego bezpieczeństwa i kontroli
poprawności.
Wykorzystanie możliwości bazy danych
Część ta nie jest związana bezpośrednio z wykorzystaniem baz danych z PHP — jest to dodatek
poświęcony pisaniu aplikacji wykorzystujących bazy danych. Może on znajdować się również w rozdziale
poświęconym inżynierii programowania. Wszyscy, którzy nie pisali zbyt wielu aplikacji w środowisku
wielowarstwowym, powinni dokładnie przeczytać ten fragment i stosować go podczas pisania własnych aplikacji
WWW korzystających z bazy danych.
Zanim zacząłem pisać aplikacje dla WWW, tworzyłem w większości aplikacje Windows wykorzystywane
przez jednego użytkownika. We wszystkich przypadkach bazy danych używał jeden użytkownik i działała na tym
samym komputerze. Środowisko takie jest bardzo wygodne, ponieważ nie trzeba robić żadnych założeń
dotyczących współbieżności a system bazy danych jest zwykle czymś więcej niż pośrednikiem służącym do
odczytu i zapisu danych.
77
PHP – Kompendium wiedzy
W przypadku tworzenia aplikacji dla środowiska wielowarstwowego, baza danych pełni o wiele
ważniejszą rolę. Potrzebna jest zwykle nowoczesna baza danych, która potrafi zarządzać współbieżnością,
uprawnieniami użytkownika, transakcjami i to odbierając wiele równoczesnych żądań w tym samym czasie.
Oprócz wykonywania tych krytycznych funkcji, większość nowoczesnych baz danych posiada ogromną ilość
funkcji, które pomagają w pisaniu aplikacji. Niezależnie od tego, czy serwer bazy danych i serwer WWW
umieszczony jest na tym samym komputerze, czy na osobnych maszynach, powinieneś wszędzie tam gdzie jest to
możliwe wykorzystywać siłę systemu zarządzania bazą danych.
W mojej ostatniej stałej pracy trafiłem na świetny przykład. Zadaniem było powielenie kilku wierszy
danych z tabeli zmieniając w nowych wierszach zawartość kilku pól. Znaleziony przeze mnie kod wyglądał mniej
więcej tak:
wybierz wszystkie wiersze do kopiowania
dla każdego wiersza
inicjuj nowy ciąg zawierający wyrażenie INSERT
wybierz nowy klucz główny w bazie danych
jeżeli te dane powinny być skopiowane bez zmian
skopiuj istniejące dane do wyrażenia INSERT
w przeciwnym wypadku
dodaj nowe wartości do wyrażenia INSERT
wykonaj wyrażenie INSERT z wyrażenia
koniec dla każdego wiersza
Nie mam zamiaru śmiać się z programisty, który pisał ten fragment, ale fragment ten prezentuje styl
kodowania brute-force częsty u młodych lub niedoświadczonych programistów. Fragment ten wymaga 1+
(2*ilość wierszy) odwołań do bazy danych. Pierwsze wywołanie pobiera wszystkie wiersze i następnie dla
każdego z nich jest potrzebne jedno wywołanie do wygenerowania nowego klucza głównego i jedno dla
wykonania instrukcji INSERT. Cały fragment można zredukować do jednego wyrażenia SQL wykonywanego w
całości przez bazę danych:
INSERT INTO tabela SELECT sequence.nextval AS PRIMARY KEY, inne_pola FROM tabela
Wyrażenie to opiera się na generatorze sekwencji do wygenerowania nowego klucza głównego, który to
mechanizm musi posiadać baza danych, ale pokazuje w jaki sposób wykorzystując odpowiednio SQL można
uniknąć pisania sporej ilości kodu oraz poprawić wydajność aplikacji. Jeżeli zdarzy ci się pisać kod formatujący,
filtrujący bądź sortujący dane pobierane z bazy danych, przyjrzyj się dokładniej swojemu zapytaniu SQL. Możesz
skorzystać z wbudowanych funkcji bazy danych lub zastosować bardziej skomplikowany kod SQL do osiągnięcia
oczekiwanych wyników.
W jednym z ostatnich projektów musiałem posortować wiersze opisujące personel w oparciu o różnicę
wieku licząc od określonej daty. Na przykład, musiałem określić pozycję rekordu osoby w oparciu o to, jak
bardzo jej wiek jest zbliżony do 30 lat. Dodatkowo każdej osobie przypisywana była wartość, będącą liczbą od 0
do 10, obliczana w oparciu o to jak blisko wiek osoby jest zbliżony do założonych wymagań wiekowych. Każdy,
którego wiek był oddalony od założonego o więcej niż 10 lat otrzymywał tą samą ocenę. Poniższe wyrażenie
może wyglądać na dosyć skomplikowane, ale otrzymujemy wszystkie potrzebne dane bez potrzeby pisania
dodatkowego kodu manipulującego wynikami:
SELECT concat (firstname, ' ', surneme) as fullname,
ROUND(MAX(0, (10-ABS((30-ROUND(((TO_DAYS(NOW()) - TO_DAYS(birthdate))/365)))))))
AS age_dif FROM persons ORDER BY age_diff DESC
Każdy z wierszy wyniku zawiera imię i nazwisko osoby oraz liczbę oznaczającą żądaną wartość.
Wszystko czego potrzebujemy, to w pętli odczytać wyniki i wyświetlić je na ekranie. Na początku wyniku znajdą
się osoby o wieku najbliższym 30 lat.
Jednym z najważniejszych problemów przypisaniu aplikacji dla WWW jest użycie właściwych narzędzi i
właściwych ludzi do realizacji poszczególnych fragmentów projektu. Następna duża część książki, „Zarządzanie
projektem przy tworzeniu aplikacji WWW” zawiera więcej informacji na temat inżynierii programowania dla
aplikacji WWW.
Podsumowanie
Rozdział ten zawiera opis użycia baz danych razem z PHP. Ponieważ PHP obsługuje wiele typów baz
danych, skupiliśmy się na bazie MySQL oraz dostępowi poprzez ODBC. Zamieszczona została również krótka
dyskusja na temat inżynierii programowania i wykorzystaniu możliwości baz danych. Dalsze informacje na temat
Rozdział 6 – Współpraca z bazami danych
78
użycia baz danych znajdują się w rozdziałach 15, 16 i 17. Najobszerniejsze przykłady znajdują się w rozdziale 15
„Witryny oparte o bazę danych”.
79
PHP – Kompendium wiedzy
Rozdział 7. Sesje i stan aplikacji
Wstęp
W rozdziale 4 „Operacje na plikach” zostało przedstawione wykorzystanie plików do utrzymania stanu
sesji, ale nie zawiera on ogólnego opisu problemu utrzymywania stanu. W standardowych aplikacjach stan jest
automatycznie utrzymywany w zmiennych przechowywanych w pamięci komputera, plikach oraz bazach danych
wykorzystywanych przez program. Stan programu jest zawsze znany, ponieważ cały model działania programu
jest dosyć prosty: użytkownik uruchamia program, wykonuje swoje zadania a następnie zamyka program. Jeżeli
użytkownik chwilowo przełączy zadanie a następnie powróci do niego, stan aplikacji nie zmieni się. Gdy
użytkownik kończy pracę, niezbędne dane są serializowane oraz zapisywane i sesja pracy programu się kończy.
W aplikacjach WWW zarządzanie danymi sesji jest bardziej złożone. Jest to powodowane faktem, że
zarówno przeglądarka jak i serwer WWW nie były projektowane do uruchamiania aplikacji WWW. Ponieważ
aplikacje WWW są ze swojej natury aplikacjami wielodostępnymi, w utrzymanie sesji jest zaangażowany
zarówno serwer jak i klient. Pod pojęciem klienta kryją się tutaj poszczególni użytkownicy. Serwer korzysta z
danych przekazanych mu przez klientów podczas kolejnych odwołań do stron do śledzenia i utrzymywania
danych sesji.
PHP pozwala na stosowanie kilka metod utrzymywania stanu sesji. W PHP4 wbudowano funkcje do
obsługi sesji, ale dostępne są również moduły zewnętrzne realizujące to samo zadanie. Inną metodą jest napisanie
w PHP własnego mechanizmu zarządzania sesjami.
Podstawy mechanizmu sesji
Jak napisałem we wprowadzeniu, obsługa sesji w sieci WWW wymaga współpracy pomiędzy
przeglądarką klienta i serwerem WWW. Gdy sesja zaczyna się, serwer WWW tworzy unikalny identyfikator sesji
(ID) i przekazuje go do klienta. Zwykle identyfikator ten jest przechowywany w cookie na komputerze klienta.
Następnie przeglądarka wysyła ID do serwera razem z każdym żądaniem przesłania strony. Serwer wykorzystuje
ID do odczytania i odtworzenia wszystkich potrzebnych danych aplikacji. Po zakończeniu aplikacji dane są
usuwane z serwera. Na rysunku 7.1. pokazany został schemat komunikacji pomiędzy klientem a serwerem WWW
(w tym przypadku jest to serwer 1U produkowany przez Penguin Computing) w przypadku rozpoczynania sesji
oraz wykorzystywania zmiennych.
Rysunek 7.1.
Rozpoczynanie
sesji oraz użycie
zmiennych sesji
Wbudowany w PHP mechanizm zarządzania sesjami
W wersji 4 do PHP wprowadzono mechanizm zarządzania sesjami. Funkcje obsługi sesji są dokładnie
opisane w skorowidzu funkcji na końcu książki. Wszystkie nazwy funkcji obsługi sesji rozpoczynają się od
sesion_.
Wykorzystując sesje w PHP należy wykonać następujące podstawowe operacje:
1. Rozpoczęcie sesji za pomocą session_start().
2. Zarejestrowanie nazw zmiennych sesji za pomocą session_register().
3. Użycie zmiennych sesji.
System zarządzania sesjami w PHP można w dużym stopniu konfigurować. Można zmienić sposób
przesyłania identyfikatora sesji, miejsce przechowywania zmiennych sesji na serwerze oraz częstotliwość
usuwania przerwanych sesji. Ponieważ dostępne jest wiele opcji konfiguracji, część ta zostanie podzielona na
części o wzrastającym stopniu skomplikowania.
Rozpoczęcie pracy z sesjami w PHP
Wydruki 7.1 i 7.2 pokazują, jak łatwe jest użycie sesji w PHP wykorzystujące domyślne ustawienia. Na
wydruku 7.1 zamieszczony jest skrypt inicjujący wszystkie zmienne sesji używane w aplikacji oraz łącze do
skryptu z wydruku 7.2, który wykorzystuje zmienne sesji ze skryptu na wydruku 7.1.
Wydruk 7.1. Uruchamianie sesji i inicjowanie zmiennych
<?php
session_start();
session_register( "aUser", "aAccount" );
$aUser
= "Cidnie";
$aAccount
= "1016";
?>
<html>
<head>
<title>Podstawy sesji: Strona 1</title>
</head>
<body>
<?php
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );
?>
<br><br>
<a href="listing2.phtml">Przejście do strony 2</a>
</body>
</html>
Wydruk 7.2. Użycie zmiennych sesji z wydruku 7.1
<?php
session_start();
81
PHP – Kompendium wiedzy
?>
<html>
<head>
<title>Podstawy sesji: Strona 2</title>
</head>
<body>
<?php
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );
?>
</body>
</html>
Pierwszym krokiem skryptu z wydruku 7.1 jest uruchomienie sesji poprzez wywołanie funkcji
session_start(). W domyślnej konfiguracji PHP używa cookie do przechowywania identyfikatora sesji. Funkcja
session_start() posiada te same ograniczenia co funkcje set_cookie() i header(). Funkcje te muszą być
wywoływane przed wysłaniem do przeglądarki jakichkolwiek informacji lub musi zostać włączone buforowanie
danych wyjściowych. Chociaż można zmienić sposób przesyłania identyfikatora sesji, najprostszą metodą jest
wykorzystanie domyślnego mechanizmu — cookie. Pozostałe metody zostaną opisane później.
Po rozpoczęciu sesji, zostają zarejestrowane dwie zmienne, aUser oraz aAccount. Gdy użytkownik kliknie
łącze prowadzące do strony 2, przeglądarka samoczynnie wyśle identyfikator sesji do serwera. W skrypcie z
wydruku 7.2 w trakcie wywołania funkcji session_start(), PHP korzysta z identyfikatora sesji do odczytania
wszystkich zmiennych sesji. Na rysunkach 7.2. i 7.3. pokazane są wyniki działania skryptów umieszczonych
odpowiednio na wydrukach 1 i 2.
Rysunek 7.2. Wynik
działania skryptu z
wydruku 7.1
Rysunek 7.3. Wynik
działania skryptu z
wydruku 7.2
Możliwe jest wyświetlenie bieżącego identyfikatora sesji wypisując na ekran zawartość zmiennej
Dodatkowo, w domyślnej konfiguracji na Apache i Linuksa, dane sesji są przechowywane w
katalogu /tmp w plikach o nazwach w postaci sess_$PHPSESSID. Po uruchomieniu poprzedniego przykładu
odszukałem
plik
sess_e66b342b4e76889f8f25105db11820c6,
który
zawierał:
aUser|s:6:"Cidnie";aAccount|s:4:"1016";.
$PHPSESSID.
Rozdział 7 – Sesje i stan aplikacji
82
Domyślne ustawienia PHP dotyczące zarządzania sesjami są łatwe do użycia i wystarczają dla większości
aplikacji WWW. Jednak w niektórych przypadkach cookie mogą nie być pożądaną metodą przesyłania
identyfikatora sesji, a w przypadku niektórych dużych aplikacji WWW użycie plików na serwerze WWW może
utrudniać skalowanie aplikacji. Następne dwie części zawierają omówienie sposobu rozwiązania tych problemów.
Przesyłanie identyfikatora sesji bez użycia cookie
Jeżeli aplikacja absolutnie wymaga zastosowania zmiennych sesji, do przesyłania identyfikatora sesji
możesz użyć innego mechanizmu niż cookie. Należy pamiętać, że niektórzy użytkownicy mają w swoich
przeglądarkach włączoną obsługę cookie. Pierwszą z metod jest ręczne przesyłanie identyfikatora sesji w postaci
zmiennej GET lub POST. Na wydruku 7.3 pokazany jest skrypt, który pokazuje w jaki sposób należy zmienić kod z
wydruku 7.1, aby identyfikator sesji był przesyłany jako zmienna GET.
Wydruk 7.3. Ręczne przesyłanie identyfikatora sesji za pomocą metody GET
<?php
session_start();
session_register( "aUser", "aAccount" );
$aUser
= "Cidnie";
$aAccount
= "1016";
?>
<html>
<head>
<title>Ręczne przesyłanie identyfikatora sesji: Strona 1</title>
</head>
<body>
<?php
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );
?>
<br><br>
<a href="listing2.phtml?<?=SID?>">Przejście do strony 2</a>
</html>
Należy zauważyć, że kod jest taki sam jak na wydruku 7.1, poza łączem w trzecim wierszu od końca. W
tym przypadku do adresu URL została doklejona stała PHP SID. Stała ta jest zdefiniowana jako
SessionName=SessionID, poniższy kod jest semantycznie identyczny z odpowiednią linią z wydruku 7.3:
<a href="listing2.phtml?<?php echo session_name() . "=" . session_id()?>">
Przejście do strony 2</a>
Należy pamiętać, że SID jest stałą a nie zmienną, więc jeżeli będziesz chciał wydrukować $SID zamiast
nie otrzymasz takiego samego wyniku. Na wydruku 7.3 zastosowany został skrót <?=SID?>. Zapis taki jest
równoważny z <?php echo SID;?> zakładając, że w czasie kompilacji PHP użyto opcji --enable-short-tags.
Wydruk 7.3 ilustruje mechanizm ręcznego przesyłania identyfikatora sesji w programie, ale nie pokazuje
jak mechanizm ten wpływa na tworzenie aplikacji. Korzystając z tego mechanizmu, każde łącze i każdy
formularz w aplikacji musi zawierać identyfikator sesji. Jeżeli nie dodasz identyfikatora do jednego łącza, SID
zostanie utracony, a aplikacja będzie źle działać. Na szczęście PHP posiada opcję automatycznego
przekształcania łączy, który to mechanizm rozwiązuje ten problem za ciebie. Jeżeli chcesz przesyłać identyfikator
sesji przy użyciu metod GET i POST, możesz uaktywnić ten mechanizm kompilując PHP z opcją --enable-transsid. Po przebudowaniu PHP kod z wydruku 7.3 może być zmieniony na nieco prostszy, pokazany na wydruku
7.4.
Wydruk 7.4. Przetwarzanie względnych adresów URL przez PHP w celu przekazywania identyfikatora
sesji
SID,
<?php
session_start();
session_register( "aUser", "aAccount" );
$aUser
= "Cidnie";
$aAccount
= "1016";
?>
<html>
<head>
<title>Automatyczne przesyłanie identyfikatora sesji: Page 1</title>
</head>
<body>
<?php
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );
?>
<br><br>
<a href="listing2.phtml">Przejście do strony 2</a>
83
PHP – Kompendium wiedzy
</html>
Różnica pomiędzy wydrukiem 3 i 4 jest taka, że na wydruku 7.4 nie ma odwołania do stałej SID w łączu.
Można również zauważyć, że wydruk 7.4 jest praktycznie identyczny z wydrukiem 7.1, ale wynik jego działania
jest różny z powodu zmiany konfiguracji. Gdy użytkownik kliknie łącze, URL będzie zawierał ciąg
PHPSESSID=xxx, tak samo jak w przypadku skryptu z wydruku 7.3. Kod ten działa, ponieważ PHP szuka na stronie
względnych adresów URL i dodaje do nich potrzebną wartość identyfikatora sesji. Aby to pokazać, następny
skrypt zawiera kilka względnych łączy i kilka bezwzględnych. Pokazujemy również w jaki sposób PHP
przetworzył łącza.
Wydruk 7.5. Przykłady automatycznego uzupełniania łączy przez PHP
<?php
session_start();
session_register( "aUser", "aAccount" );
$aUser
= "Cidnie";
$aAccount
= "1016";
?>
<html>
<head>
<title>Uzupełnianie adresów URL</title>
</head>
<body>
<?php
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );
?>
<br><br>
<a href="listing2.phtml">Łącze 1</a>
<br><br>
<a href="listing2.phtml?MyVar=1234">Łącze 2</a>
<br><br>
<a href="http://www.php.net/">Łącze 3</a>
<br><br>
<a href="http://localhost/listing2.phtml">Łącze 4</a>
<br><br>
<form action="listing2.phtml">
<input type="submit" name="Submit"
value="Przycisk przesłania danych formularza">
</form>
</html>
Po uruchomieniu skryptu, do przeglądarki został wysłany następujący kod HTML:
<html>
<head>
<title>Uzupełnianie adresów URL</title>
</head>
<body>
Użytkownik: Cidnie<br>Konto: 1016<br>
<br><br>
<a href="listing2.phtml?PHPSESSID=9771f86dc94e367cf1c62e0339d02c4b">Łącze 1</a>
<br><br>
<a href="listing2.phtml?MyVar=1234&PHPSESSID=9771f86dc94e367cf1c62e0339d02c4b">
Łącze 2</a>
<br><br>
<a href="http://www.php.net/">Łącze 3</a>
<br><br>
<a href="http://localhost/listing2.phtml">Łącze 4</a>
<br><br>
<form action="listing2.phtml"><INPUT TYPE="HIDDEN" NAME="PHPSESSID"
VALUE="9771f86dc94e367cf1c62e0339d02c4b">
<input type="submit" name="Submit"
value="Przycisk przesłania danych formularza">
</form>
</html>
Ponieważ pierwsze dwa łącza są łączami względnymi, zostały do nich dołączone dane na temat sesji.
Łącze 3 nie jest oczywiście łączem względnym, więc identyfikator sesji nie został dołączony. Działanie takie było
przewidziane. Łącze 4 pokazuje jak ostrożnym należy być używając funkcji automatycznego uzupełniania łączy.
W tym przypadku jest to bezwzględny adres URL, chociaż strona ta znajduje się na tym samym serwerze. PHP
uzupełnia jedynie adresy URL zapisane w postaci łączy względnych.
Do przykładu został dołączony formularz, ponieważ PHP potrafi również uzupełniać formularz tak, aby
zawierał on wartość identyfikatora sesji. Oznacza to, że aplikacja korzystająca z formularzy również będzie
prawidłowo działała. Jedyną wadą tego mechanizmu jest to, że działa on jedynie dla metody POST. Jeżeli będziesz
chciał użyć formularza korzystającego z metody GET, aplikacja nie będzie działała prawidłowo. Mimo, że atrybut
ACTION zostanie prawidłowo zmodyfikowany, przeglądarka nie dodaje zmiennej PHPSESSID do ciągu zapytania
(przetestowane na najnowszych wersjach Netscape i Internet Explorer).
Rozdział 7 – Sesje i stan aplikacji
84
Przesyłanie identyfikatora sesji za pomocą metod GET i POST pozwala uniknąć niektórych problemów z
cookie i jest łatwe do zrealizowania. Jeżeli zamierzasz skorzystać z automatycznego uzupełniania adresów,
powinieneś również się zastanowić, jaki wpływ będzie to miało na wydajność aplikacji. PHP musi przecież
podczas każdego uruchomienia strony odszukać wszystkie łącza na stronie i zmienić URL.
Aby sprawdzić wpływ tego mechanizmu na wydajność stworzyłem przykładową stronę WWW oraz
skrypt, który odczytywał ją z serwera i zapamiętywał czas potrzebny na jej odczytanie. Przykładowa strona
zawierała 14 łączy z których 12 było łączami względnymi, które wymagały przepisania. Strona miała wielkość
9,55 kB. Użyłem skryptu z wydruku 7.6 do odczytania strony kolejno 1000 razy. Skrypt uruchamiałem z aktywną
opcją --enable-trans-sid, oraz bez niej.
Wydruk 7.6. Skrypt do sprawdzania wydajności
<?php
function getmicrotime()
{
$mtime = microtime();
$mtime = explode( " ", $mtime);
$mtime = $mtime[1] + $mtime[0];
return ($mtime);
}
$aStartTime = getmicrotime();
$aFileName = "http://localhost/ch07/listing5.phtml";
for ($nIndx = 0; $nIndex < 1000; $nIndex++)
{
$aData = file( $aFileName );
}
$aEndTime = getmicrotime();
$aTotTime = $aEndTime - aStartTime;
print( "Czas całkowity: $aTotTime\n");
?>
Test był uruchamiany wiele razy, aby obliczyć średnią różnicę czasów wykonania. Zanotowano średnio
9% zysk wydajności w przypadku zablokowania opcji --enable-trans-sid. Mimo, że różnica taka może być w
większości witryn mało znacząca, może ona być ważna w przypadku silnie obciążonych witryn. Zanim
zastosujesz któreś z rozwiązań, powinieneś przeprowadzić własne testy sprawdzające wpływ zastosowanego
mechanizmu na wydajność.
Błąd w PHP
Jak wspominaliśmy w tej części, PHP wersja 4.0.1 poziom poprawek 2, zawierał błąd w mechanizmie automatycznego uzupełniania
adresów URL. Błąd ten poprawiono w wersji 4.0.2. Jeżeli chcesz korzystać z tej funkcji, upewnij się, że masz zainstalowaną właściwą
wersję PHP.
Zapisywanie zmiennych sesji w bazie danych
Po wybraniu mechanizmu przesyłania identyfikatora sesji, należy zdecydować, gdzie będą zapisywane
wartości samych zmiennych sesji. PHP posiada mechanizm zapisywania zmiennych sesji w dowolnie wybrany
sposób. Do napisania dowolnego mechanizmu obsługi sesji wystarczy zdefiniować sześć funkcji i zarejestrować
je w PHP. Funkcje te wraz z ich parametrami są przedstawione poniżej.
• bool open( string save_path, string sess_name ); Funkcja ta jest wywoływana w trakcie inicjalizacji
sesji. Można jej użyć do wstępnej inicjalizacji sesji. Pierwszy argument jest ścieżką podaną w jako
wartość zmiennej konfiguracji session.save_path określonej w pliku php.ini, lub ostatnia wartość
przekazana do funkcji session_save_path(). Drugi argument jest nazwą sesji określoną przez parametr
session.name zdefiniowany w pliku php.ini, lub ostatnią wartościa przekazaną do funkcji session_name().
Wartościami domyślnymi są odpowiednio /tmp i PHPSESSID.
• bool close(); Funkcja jest wywoływana w celu zakończenia sesji.
• mixed read( string sess_id ); Funkcja jest używana do odczytania zawartości sesji. Jeżeli dane sesji nie
są dostępne, powinien zostać zwrócony pusty ciąg (""). Jeżeli wystąpi błąd, powinna zostać zwrócona
wartość False. Jeżeli istnieją dane sesji, powinny zostać zwrócone w postaci serializowanej. Dane te
powinny być dokładnie takie same, jak przekazane przez PHP do funkcji write().
• bool write( string sess_id, string value ); Funkcja jest wywoływana w przypadku konieczności
zapamiętania danych sesji. Dane przekazane do parametru value są danymi sesji w postaci serializowanej.
85
PHP – Kompendium wiedzy
•
Funkcja jest wywoływana podczas wywołania w skrypcie funkcji
session_destroy(). Powinna usunąć wszystkie dane związane z sesją.
• bool gc( int max_lifetime ); Funkcja ta jest wywoływana w czasie rozpoczynania sesji. Jest ona
wywoływana z częstotliwością określoną przez parametr konfiguracji session.gc_probability. Funkcja
jest przeznaczona do usuwania nieużywanych danych sesji. Podczas swojego działania powinna usunąć
wszystkie dane nie używane przez max_lifetime sekund. Usuwanie niepotrzebnych danych sesji jest
omówione w następnej części rozdziału.
Po utworzeniu funkcji obsługi sesji należy zarejestrować je za pomocą funkcji
session_set_save_handler(). Po tej operacji PHP będzie wywoływało wszędzie tam gdzie jest to potrzebne nowe
funkcje. Do zilustrowania tego mechanizmu przygotowany został skrypt na wydruku 7.7, który zawiera 7 funkcji
obsługi zmiennych, które jedynie wypisują swoją nazwę i parametry wywołania. Funkcja read() z tego skryptu
zwraca dla celów testowych wartości dwóch zmiennych sesji.
Wydruk 7.7. Zdefiniowany przez użytkownika mechanizm obsługi sesji: mysession.php
bool destroy( string sess_id );
<?php
function mysess_open( $aSavePath, $aSessionName )
{
print( "mysess_open( $aSavePath, $aSessionName )<br>" );
return True;
}
function mysess_close()
{
print( "mysess_close()<br>" );
return True;
}
function mysess_read( $aKey )
{
print( "mysess_read( $aKey )<br>" );
return "aUser|s:6:\"Cidnie\";aAccount|s:4:\"1016\";";
}
function mysess_write( $aKey, $aVal )
{
print( "Wywołanie mysess_write!\n\nWłaśnie tutaj!\n\n" );
print( "mysess_write( $aKey, $aVal )<br>" );
return True;
}
function mysess_destroy( $aKey )
{
print( "mysess_destroy( $aKey )<br>" );
return True;
}
function mysess_gc( $aMaxLifetime )
{
print( "mysess_gc( $aMaxLifetime )<br>" );
return True;
}
session_set_save_handler( "mysess_open", "mysess_close", "mysess_read",
"mysess_write", "mysess_destroy", "mysess_gc" );
?>
Aby pokazać w jaki sposób PHP wywołuje nowe funkcje, użyjemy skryptu z wydruku 7.8. Dodatkowo
ustawiłem wartość session.gc_probability na 100, więc funkcja czyszczenia pamięci jest wywoływana na
początku każdej sesji.
Wydruk 7.8. Testowanie mysession.php
<?php
include( "./mysession.php" );
session_start();
?>
<html>
<head>
<title>Własny mechanizm obsługi sesji</title>
</head>
<body>
<?php
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );
$aUser = "Katie";
$aAccount = "2026";
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );
?>
</body>
</html>
Rozdział 7 – Sesje i stan aplikacji
86
Rysunek 7.4. Wynik
działania skryptu
mysession.php
Gdy uruchomiłem ten skrypt, wynik nie był taki, jakiego się spodziewałem. W przeglądarce nie było
informacji na temat wywołania funkcji write() i close(). Jak można zauważyć dodałem nawet dodatkową
instrukcję print() aby dokładniej sprawdzić co się stało. Wynik w przeglądarce jednak nadal nie był prawidłowy.
Po dokładniejszym sprawdzeniu odkryłem, że wynik działania obu funkcji znajduje się w pliku error_log serwera
Apache. Oznacza to, że w którymś momencie wyjście zostało tymczasowo przekierowane z stdout na stderr. W
wyniku tego przekierowania nie można wysłać żadnych danych do przeglądarki zarówno w funkcji write(), jak i
close(). Problem ten jednak nie wpływa na właściwy system obsługi sesji. Trzeba powiedzieć, że ten efet może
nie powtórzyć się w przypadku użycia innej platformy i serwera, ponieważ sposób obsługi standardowego
wyjścia danych i błędów może być inny. Na przykład w przypadku serwera Xitami działającego na Windows
widoczne były wszystkie spodziewane dane.
Po poznaniu zasady działania mechanizmu, stworzenie prawdziwego mechanizmu obsługi sesji będzie
dosyć łatwe. Jeżeli chcesz używać zmiennych sesji, powinieneś przechowywać je w bazie danych a nie w pliku.
Idea ta może być z początku mało zrozumiała, ale należy pamiętać, że zapisywanie danych aplikacji na serwerze
WWW może ograniczać skalowalność aplikacji. Jeżeli aplikacja zostanie rozdzielona na kilka serwerów WWW i
zastosowany zostanie mechanizm równoważenia obciążenia pomiędzy serwerami, użycie plików do obsługi sesji
może spowodować załamanie aplikacji. Awaria ta będzie wynikała z tego, że każde żądanie może być kierowane
do innego serwera w klastrze. Jeżeli początkowe dane zostaną zapisane na serwerze pierwszym, a kolejne żądanie
będzie przekazane do serwera dwa, to dane sesji będą nieosiągalne. Jeżeli wszystkie dane sesji będą
przechowywane w bazie danych, zmienne sesji będą dostępne dla wszystkich serwerów WWW w klasterze.
Następny wydruk zawiera prosty przykład użycia bazy danych MySQL do przechowywania danych sesji.
W celu poprawienia czytelności kodu, przykład korzysta z klasy DB_Sql pochodzącej z pakietu PHPLIB
omówionej w rozdziale 6 „Współpraca z bazami danych”. Do przechowywania danych sesji korzystamy z tabeli
zdefiniowanej w następujący sposób:
CREATE TABLE Sessions
(
SessionId
char(32)
not null,
LastUpdated datetime
not null,
DataValue
text,
PRIMARY KEY (SessionID),
INDEX (LastUpdated )
);
Tabela ta zawiera pole do przechowywania identyfikatora sesji, pole data/czas do zapamiętywania czasu
ostatniej zmiany oraz dane w postaci pola tekstowego typu BLOB. Pole LastUpdated posiada indeks w celu
poprawienia wydajności w trakcie odzyskiwania nieużytków. Cały kod funkcji obsługi sesji zamieszczony jest na
wydruku 7.9.
Wydruk 7.9. Obsługa sesji przy użyciu bazy danych MySQL
<?php
include ( "db_mysql.inc" );
// Specjalizacja klasy DB_Sql do wykorzystania na naszym
// serwerem bazy danych MySQL
class MySQLDB extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
87
PHP – Kompendium wiedzy
var $Password
= "root";
}
function mysess_open( $aSavePath, $aSessionName )
{
// nie trzeba nic robić
return True;
}
function mysess_close()
{
// nie trzeba nic robić
return True;
}
function mysess_read( $aKey )
{
$aDB = new MySQLDB;
$aSQL = "select DataValue from Sessions where SessionID='$aKey'";
$aDB->query( $aSQL );
if ( $aDB->num_rows() == 1 )
{
$aDB->next_record();
$aData = $aDB->f( "DataValue" );
return $aData;
}
else
{
// Wstaw wiersz dla bieżącej sesji aby uprościć funkcję write
$aSQL = "insert into Sessions values ( '$aKey', NOW(), '' )";
$aDB->query( $aSQL );
return "";
}
}
function mysess_write( $aKey, $aVal )
{
$aDB = new MySQLDB;
$aData = addslashes( $aVal );
$aSQL = "update Sessions set DataValue='$aData', ";
$aSQL .= "LastUpdated=NOW() where SessionID='$aKey'";
$aDB->query( $aSQL );
return True;
}
function mysess_destroy( $aKey )
{
$aDB = new MySQLDB;
$aSQL = "delete from Sessions where SessionID = '$aKey'";
$aDB->query( $aSQL );
return True;
}
function mysess_gc( $aMaxLifetime )
{
$aDB = new MySQLDB;
$aSQL = "delete from Sessions where UNIX_TIMESTAMP(NOW()) ";
$aSQL .= "- UNIX_TIMESTAMP(LastUpdated) > $aMaxLifetime";
$aDB->query( $aSQL );
return True;
}
session_set_save_handler("mysess_open", "mysess_close", "mysess_read",
"mysess_write", "mysess_destroy", "mysess_gc");
?>
Kod z wydruku jest całkiem prosty jak na tak dużą zmianę mechanizmu obsługi sesji. Funkcje
i mysess_close() nie są w tym przypadku używane, ponieważ nie są potrzebne. Wszystkie dane
sesji są przechowywane w jednej tabeli, więc wartości przekazane do mysess_open() nie są używane, a po
zakończeniu sesji nie trzeba niczego usuwać.
Interesującymi funkcjami są mysess_read(), mysess_write(), mysess_destroy() oraz mysess_gc(). W
funkcji mysess_read() do bazy jest kierowane zapytanie mające za zadanie odczytać dane związane z
identyfikatorem sesji. Jeżeli dane te zostaną odnalezione — są zwracane. Jeżeli nie ma jeszcze rekordu w bazie,
tworzony jest nowy rekord z pustym polem DataValue i zwracany jest pusty ciąg (""). Powodem takiego działania
jest to, że gdy później będą zapisywane dane sesji nie będzie konieczności sprawdzania, czy istnieje już
odpowiedni rekord w bazie danych.
Funkcja mysess_write() za każdym wywołaniem uaktualnia pola DataValue oraz LastUpdated. Funkcja
mysess_destroy() usuwa rekord związany z identyfikatorem sesji. Funkcja mysess_gc() usuwa wszystkie wiersze,
których wartość pola LastUpdated wskazuje że nie rekord nie był uaktualniany przez ostatnie $aMaxLifetime
sekund. Poniższy kod pokazuje sposób wykorzystania mechanizmu sesji partego o bazę danych.
mysess_open()
<?php
Rozdział 7 – Sesje i stan aplikacji
88
include( "./mysql_session.php" );
session_start();
session_register( "aUser", "aAccount" );
$aUser
= "Cidnie";
$aAccount
= "1016";
?>
<html>
<head>
<title>Obsługa sesji z wykorzystaniem MySQL: Strona pierwsza</title>
</head>
<body>
<?php
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );?>
<br><br>
<a href="mysql_session_mgmt2.phtml?<?=SID?>">Przejście do następnej strony</a>
</body>
</html>
Poprzedni przykład pokazuje jak łatwo można utworzyć i używać własny mechanizm przechowywania
danych sesji w PHP. W przykładzie tym można zastosować kilka optymalizacji i usprawnień ulepszających
działanie, ale przykłady mają za zadanie pokazać ogólną ideę. Jeżeli potrzebujesz w swojej aplikacji zastosować
zmienne sesji, PHP zawiera rozwiązania pozwalające na dowolną implementację takiego mechanizmu.
Inne funkcje i opcje dotyczące sesji
PHP posiada jeszcze kilka nie omówionych jeszcze funkcji obsługi sesji. Funkcje session_name(),
session_module_name(), session_save_path() i session_id() mogą być użyte do odczytywania lub ustawiania
odpowiednio, bieżącej nazwy sesji, nazwy modułu, ścieżki zapisu i identyfikatora. Miałem kłopot wymyślić
projekt, w którym byłaby zalecana zmiana tych parametrów w czasie pracy. Jeżeli twoja zmienna posiada tak
dużo zmiennych sesji, ze musisz korzystać z dzielenia ich przy pomocy tych funkcji powinieneś poważnie
rozważyć zastosowanie sugestii zamieszczonych w części „Inżynieria programowania a sesje”, umieszczony w
dalszej części rozdziału.
W pliku php.ini znajdują się następujące opcje konfigurujące mechanizm sesji:
• sessions.save_handler. Opcja ta pozwala na zdefiniowanie nazwy programu obsługi używanego do
zapisywania i odczytywania danych związanych z sesją. Możliwe są wartości files, user i mm. Opcja ta
może być odczytywana lub zmieniana w czasie pracy za pomocą funkcji session_module_name().
Ustawienie jej wartości na files powoduje zapisywanie danych sesji w pliku na serwerze WWW.
Ustawienie na user, oznacza, że aplikacja posiada własny mechanizm obsługi. Wartość mm powoduje
korzystanie z wspólnej pamięci serwera WWW. Jeżeli wywołasz funkcje session_set_save_handler(),
wartość opcji jest niejawnie przestawiana na user. Wartością domyślną jest files.
• session.save_path. Opcja określa argument przekazywany do funkcji obsługi sesji. Jeżeli używasz
wbudowanego mechanizmu przechowywania danych, jest to nazwa katalogu gdzie są tworzone pliki.
Wartością domyślną jest /tmp.
• session.name. Opcja określa nazwę sesji, używaną również jako nazwa cookie. Powinna zawierać jedynie
znaki alfanumeryczne. Wartością domyślną jest PHPSESSID.
• session.auto_start. Opcja określa, czy moduł sesji automatycznie uruchamia sesję na początku strony.
Domyślną wartością jest 0 (wyłączony).
• session.lifetime. Pozwala określić w sekundach czas ważności cookie wysyłanego do przeglądarki.
Wartość 0 oznacza „do zamknięcia przeglądarki”. Wartością domyślną jest 0.
• session.serialize_handler. Opcja pozwala na zdefiniowanie nazwy programu obsługi używanego do
serializacji i deserializacji danych. Dostępny jest wewnętrzny format PHP (o nazwie php) oraz WDDX (o
nazwie wddx). WDDX jest dostępny jedynie po skompilowaniu PHP z obsługą WDDX. Wartością
domyślną jest php.
• session.gc_probability. Opcja określa prawdopodobieństwo w procentach uruchomienia funkcji gc
(usuwania nieużytków) podczas obsługi żądania. Usuwanie nieużytków polega na usuwaniu zmiennych
sesji zapisanych na serwerze WWW. Ponieważ często niemożliwe jest określenie, kiedy sesja się
zakończyła, PHP wywołuje funkcję usuwania nieużytków usuwającą zmienne sesji, które nie były
uaktualniane przez określony czas (patrz session.gc_maxlifetime). Wartością domyślną jest 1, co
oznacza, że 1% uruchomień sesji powoduje wykonanie funkcji usuwania nieużytków. Jeżeli do
PHP – Kompendium wiedzy
89
przesyłania identyfikatora sesji używane są metody GET i POST, należy zwiększyć tą wartość. Powodem
tego jest możliwość zapisania jako zakładki adresu URL, który posiada dołączony identyfikator sesji.
Prawdopodobnie nie chcesz, aby użytkownicy po dłuższym czasie kontynuowali starą sesję.
• session.gc_maxlifetime. Opcja określa ilość sekund, po których dane są uważane za „nieużytki” i
usuwane. Domyślnie jest to 1440 sekund (24minuty). W zależności od aplikacji możesz wydłużać lub
skracać ten czas.
• session.referer_check. Opcja określa, czy identyfikatory sesji odwołujące się do zewnętrznych witryn są
usuwane. Jeżeli identyfikator sesji jest przesyłany w adresie URL, użytkownicy nie zdając sobie sprawy ze
skutków mogą publikować identyfikator sesji. Sytuacja taka może prowadzić do problemów z
bezpieczeństwem serwera, których można uniknąć stosując tą opcję. Domyślnie jest ustawiona na 0.
• session.entropy_file. Opcja pozwala na podanie ścieżki do zewnętrznego źródła (pliku), które będzie
używane jako dodatkowe źródło entropii do generowania identyfikatorów sesji. Mogą to być /dev/random
lub /dev/urandom, dostępne we wielu systemach Unix.
• session.entropy_length. Opcja pozwala określić ilość bajtów, które należy odczytać z pliku określonego
w poprzedniej opcji. Domyślnie jest to 0 (wyłączone).
• session.use_cookies. Opcja pozwala na zdecydowanie czy do przechowywania identyfikatora sesji na
komputerze klienta używane będą cookie. Domyślnie jest to 1 (włączone).
PHP zapewnia ogromną elastyczność przy obsłudze sesji. Projektując aplikację korzystającą ze zmiennych
sesji należy rozważyć wszystkie dostępne opcje. Mimo, że użycie cookie wydaje się najprostszym rozwiązaniem,
może to spowodować poważne problemy, ponieważ użytkownicy mogą wyłączyć obsługę cookie. Inne metody
przesyłania identyfikatora sesji wymagają więcej pracy, ale korzystne jest wcześniejsze planowanie. Polecam
metodę przesyłania identyfikatora sesji w adresie URL, ponieważ metoda ta wymaga podjęcia decyzji na temat
stron, które będą używały mechanizmu sesji. Polecam również użycie projektu witryny opartego na szablonach
(szczegóły w rozdziale 12 „Oddzielanie kodu HTML od PHP”), ponieważ powoduje on, że ręczne przesyłanie
identyfikatora sesji jest o wiele prostsze niż w przypadku projektu pokazanego w tym rozdziale.
Użycie PHPLIB do obsługi sesji
W rozdziale 6 „Współpraca z bazami danych” przedstawialiśmy PHPLIB, jako świetną bibliotekę
zawierającą niektóre zaawansowane funkcje do tworzenia aplikacji opartych o PHP. PHPLIB była jedną z
pierwszych (i prawdopodobnie najbardziej znaną) bibliotek klas zawierających obsługę sesji w PHP.
Koncepcyjnie jest ona podobna do rozwiązania zastosowanego w PHP4. Obsługa sesji w PHPLIB jest oparta w
całości o kod PHP, więc jest możliwa do rozbudowy i konfiguracji poprzez dziedziczenie i rozbudowę klasy
bazowej. Posiada ona również niektóre opcje inicjalizacji, które mogą być bardzo użyteczne w naszych
aplikacjach.
Obsługa sesji w PHPLIB oparta jest o klasę kontenerową zdefiniowaną w PHPLIB. Używana jest jedna z
klas pochodnych po klasach CT_xxx, przeznaczonych do obsługi przechowywania zmiennych sesji. Powoduje to,
że PHPLIB można rozszerzyć w sposób, który pozwala na przechowywanie zmiennych sesji w praktycznie
dowolnym miejscu. PHPLIB wymaga również, aby funkcje obsługi strony sygnalizowały początek i koniec
strony, oraz która z „funkcji” PHPLIB jest używana na stronie.
Wydruk 7.10 zawiera skrypt ilustrujący użycie PHPLIB do zapisu zmiennych sesji w bazie MySQL.
Przykład ten jest identyczny z przedstawionym na wydruku 7.9, oprócz tego, że korzysta on z cookie do
przechowywania identyfikatora sesji na komputerze klienta.
Wydruk 7.10. Obsługa sesji w PHPLIB
<?php
include( "page.inc" );
include( "ct_sql.inc" );
include( "session.inc" );
include( "db_mysql.inc" );
// Specjalizacja klasy DB_Sql do połączenia z
// naszym serwerem MySQL
class MySQLDB extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
Rozdział 7 – Sesje i stan aplikacji
90
var $Password
= "root";
}
class MySQLCt extends CT_Sql
{
var $classname = "MySQLCt";
var $database_table = "active_sessions";
var $database_class = "MySQLDB";
}
class MySqlSession extends Session
{
var $classname = "MySqlSession"; // obsługa przechowywania
var $mode
= "cookie";
var $lifetime = 0;
// użycie cookie sesji
var $that_class = "MySQLCt";
// nazwa używanego kontenera
}
page_open( array( "sess" => "MySqlSession" ) );
$sess->register( "aUser" );
$sess->register( "aAccount" );
$aUser
= "Cidnie";
$aAccount
= "1016";
?>
<html>
<head>
<title>Obsługa sesji w PHPLIB: Pierwsza strona </title>
</head>
<body>
<?php
print( "Użytkownik: $aUser<br>" );
print( "Konto: $aAccount<br>" );
?>
<br><br>
<a href="phplib_session_mgmt2.phtml">Następna strona</a>
</body>
</html>
<?php
page_close();
?>
PHPLIB jest niezmiernie elastycznym narzędziem do zarządzania danymi sesji. Tak jak PHP posiada on
mechanizmy zapewniające zapisywanie danych sesji w liku, pamięci współdzielonej oraz tabeli bazy danych. Kod
z wydruku 7.10 jest nieco bardziej skomplikowany, ale doświadczeni programiści na pewno zauważą, że jest on
bardzo łatwo rozszerzalny poprzez dziedziczenie bazowych klas obsługi sesji. Pierwsza klasa pochodna, MySQLDB
jest klasą niezbędną do nawiązania połączenia z naszym serwerem bazy danych. Kolejna klasa, MySQLCt jest klasą
pochodną po klasie kontenerowej CT_Sql, która jest podstawową klasą kontenerową zapewniającą zapisywanie
danych w bazach danych SQL. Zawiera ona odwołanie do klasy MySQLDB, która jest używana do zrealizowania
dostępu do tabel. Ostatnia klasa, MySQLSession rozszerza bazową klasę Session i ustawia klasę MySQLCt jako klasę
zapisującą wszystkie dane sesji.
Tabela bazy danych wymagana przez mechanizm obsługi sesji w PHPLIB posiada następującą strukturę:
CREATE TABLE active_sessions (
sid
varchar(32) not null,
name
varchar(32) not null,
val
text,
changed varchar(14) not null,
PRIMARY KEY (name, sid),
KEY changed (changed)
);
Po utworzeniu klas pochodnych PHPLIB wykorzystuje funkcję page_open() do dodania „funkcji” sesji do
bieżącej strony. Wywołanie tej funkcji powoduje utworzenie globalnej zmiennej $sess, która jest
wykorzystywana w kolejnych wywołaniach obsługi sesji. Podstawowe funkcje klasy Session w PHPLIB są
praktycznie identyczne z możliwościami wbudowanego mechanizmu PHP. Po utworzeniu klasy rejestrowane i
wykorzystywane są zmienne sesji. Jedynym dodatkowym wymaganiem jest wywołanie w skrypcie funkcji
page_close() do zaznaczenia końca skryptu.
Tak jak we wbudowanym mechanizmie sesji PHP, PHPLIB pozwala na wykorzystanie cookie lub
zmiennych GET i POST do przesyłania identyfikatora sesji. PHPLIB posiada również narzędzia do tworzenia
klas kontenerowych używanych do zapisywania zmiennych sesji na dowolnie wymyślonym serwerze. Dodatkową
funkcja PHPLIB jest możliwość dostarczania pliku inicjalizującego używanego do inicjalizacji zmiennych sesji
na początku każdej sesji. Poniższy kod pokazuje przykład takiego pliku inicjalizującego:
<?php
global $lang;
$lang = "pl";
$sess->register("lang");
91
// język aplikacji
// domyślnie polski
PHP – Kompendium wiedzy
global $cur;
$cur = "PLN";
$sess->register("cur");
global $cart;
$cart = new Shop_Cart;
$sess->register("cart");
// waluta aplikacji
// domyślnie złotówki
// utworzenie obiektu wózka na zakupy
// zdefiniowanego w local.inc
// zarejestrowanie obiektu
?>
Mimo, że PHP posiada wbudowany mechanizm sesji zbliżony do rozwiązania zastosowanego w PHPLIB,
może być przydatny dostęp do całego kodu źródłowego PHP, na przykład aby wykonać niektóre optymalizacje.
Możesz również stosować PHPLIB do realizowania sesji w starszych wersjach PHP, które nie posiadają
wbudowanego mechanizmu sesji.
Tworzenie własnego mechanizmu sesji
W niektórych przypadkach w aplikacji może nie być potrzebny kompletny mechanizm sesji. W wielu
wypadkach jedyną daną, jaką musimy przesyłać pomiędzy stronami, jest klucz główny lub identyfikator. W
takich przypadkach bardziej efektywne będzie przesyłanie identyfikatora pomiędzy stronami aplikacji za pomocą
zmiennych GET i POST. Mając tą wartość możesz odczytać z bazy danych wszystkie potrzebne na stronie dane.
Rozwiązanie to jest proste do zrealizowania i nie wymaga żadnych dodatkowych narzutów
wprowadzanych przez przedstawione w tym rozdziale narzędzia obsługi sesji. Z drugiej strony, przesyłanie
identyfikatora wymaga nieco dokładniejszego projektowania aplikacji. Dodatkowo przesyłanie wartości
identyfikatora otwartym tekstem może powodować naruszenie bezpieczeństwa, więc korzystając z tej metody
zaleca się używanie odpowiedniej mechanizmu szyfrowania.
Tak jak w przypadku wszystkich innych aspektów projektowania aplikacji należy wykona dokładną
analizę potrzeb aplikacji i na jej podstawie wybrać właściwy schemat zarządzania sesjami. Wybór niewłaściwego
narzędzia na początku całego procesu może być kosztowne i prowadzić w dłuższej perspektywie do problemów z
konserwacją i rozwojem aplikacji.
Inżynieria programowania a sesje
Zmienne sesji mogą być niezmiernie istotne we wielu aplikacjach WWW. Są one elastyczne i łatwe do
użycia, ale tak jak wszystkie inne narzędzia programistyczne powinny być używane ostrożnie i według projektu.
Ponieważ zmienne sesji są bardzo łatwe do użycia, często są nadużywane w takim samym stopniu, jak zmienne
globalne przy pisaniu tradycyjnych aplikacji.
Projektując aplikację WWW należy szczegółowo rozważyć wszystkie zastosowania, w których należy
skorzystać ze zmiennych sesji. Decyzja użycia zmiennej sesji powinna być oparta na takich samych przesłankach,
jak decyzja użycia zmiennej globalnej. Steve McConnell, autor książki „Code Complete” (Microsoft Press, 1993)
uważa, że powodem użycia zmiennej globalnej mogą być następujące przypadki:
• Przechowywanie wartości globalnych. Dane globalne, to dane odzwierciedlające stan całej aplikacji, na
przykład tryb pracy (wersja próbna, pełna). Może być to duże zbiory danych używane w całej aplikacji, na
przykład tabele słownikowe.
• Zastępowanie nazwanych stałych. Ponieważ PHP posiada stałe, zastosowanie to nie jest dopuszczalne.
• Uproszczenie użycia bardzo często używanych danych. Czasami niektóre dane są tak często używane w
aplikacji, że występują w liście parametrów każdej procedury.
• Eliminowanie wędrujących danych. Czasami wartości są przekazywane do procedury tylko po to, aby
mogły być przekazane do kolejnej. Gdy procedury w takim łańcuchu nie korzystają z takich danych, są
one nazywany danymi wędrującymi.
Lista ta wskazuje powody rozważane użycia zmiennych globalnych przy programowaniu zwykłych
aplikacji, ale decyzja użycia zmiennej sesji powinna być oparta na tych samych kryteriach.
Bądź ostrożny przy uznawaniu zmiennej za zmienną sesji, ponieważ wydaje się występować w każdej
procedurze i na każdej stronie witryny WWW. Takie podejście najczęściej prowadzi do nadużywania danych
globalnych i zmiennych sesji. Należy pamiętać, że po zdefiniowaniu w aplikacji zmiennych sesji, każda strona
biorąca udział w sesji musi załadować wszystkie zmienne sesji nawet, gdy nie korzysta z żadnej. Należy również
Rozdział 7 – Sesje i stan aplikacji
92
unikać użycia zmiennych sesji jedynie dlatego, że zapewniają one wygodniejszy dostęp do danych związanych z
sesją.
W jednym z moich ostatnich kontraktów natrafiłem na świetny przykład nieprawidłowego użycia
zmiennych sesji. W aplikacji użytkownicy mogli utworzyć zbiór danych i udostępnić je do modyfikacji przez
innego użytkownika. Użytkownicy, którym dane były udostępniane byli doradcami, którym pierwsi użytkownicy
ufali. Gdy użytkownik udostępniał dane doradcy, dane o tym były zapisywane w bazie danych. Tabela uprawnień
zawierała identyfikator pierwotnego użytkownika i doradcy oraz identyfikator danych udostępnianych przez
użytkownika. Gdy doradca logował się do aplikacji, musiał na początku wybrać zbiór danych do oglądania. W
aplikacji były ustawiane zmienne sesji, które zawierały identyfikator konta doradcy, oraz identyfikator
przeglądanych danych klienta.
Jeżeli te identyfikatory byłyby jedynymi zmiennymi sesji, nie było by problemu. Jednak ktoś zdecydował,
aby nie korzystać z bazy danych do sprawdzania uprawnień i w zmiennej sesji przesyłana była lista zleconych
identyfikatorów danych. Za każdym razem, gdy doradca otwierał w programie zbiór danych, lista ta była
uaktualniana (wraz z tabelą uprawnień). Następnie, gdy element danych był pobierany z bazy, jego identyfikator
był poszukiwany w zawartości zmiennej sesji zamiast w bazie danych.
Głównym problemem powodowanym przez takie podejście były kłopoty z synchronizacją danych. Jeżeli
pierwotny użytkownik uaktualnił tabelę uprawnień w czasie, gdy doradca był zalogowany w aplikacji, doradca
miał dostęp tylko do danych zleconych w trakcie rozpoczynania sesji. Dodatkowo, rozwijanie aplikacji według
tego modelu było frustrujące, ponieważ programista nie wiedział czy używać danych z bazy danych czy ze
zmiennych sesji.
Takie niefortunne działanie było spowodowane tym, że pierwszy programista nie zapewnił realizacji
dwóch celów. Po pierwsze, zmienne sesji zostały zastosowane, aby wyeliminować odwołania do baz danych (aby
przyspieszyć ładowanie strony) przy pobieraniu danych o uprawnieniach. Po drugie, zmienne sesji były używane
do uproszczenia sprawdzania uprawnień w kodzie strony.
Pierwszy cel nie został zrealizowany, ponieważ programista nie ładuje jawnie zmiennych sesji, są one
automatycznie odczytywane z trwałego nośnika. Na wszystkich stronach aplikacji dane o uprawnieniach są
ładowane z serwera WWW i po zakończeniu strony ponownie zapisywane. Proces ten powoduje, że nawet strony,
które nie korzystają z uprawnień, są spowolnione przez proces ładowania zmiennych sesji. Ładowanie danych
uprawnień z bazy danych jedynie na stronach, które wymagają tych informacji, jest o wiele bardziej efektywne.
Drugi cel nie został spełniony, ponieważ programista nie korzystał w pełni z wydajności bazy danych. Na
wielu stronach kod wyglądał następująco:
WYIERZ wszystkie potrzebne dane z konta pierwotnego użytkownika
DLA KAŻDEGO WIERSZA
JEŻELI identyfikator tego wiersza znajduje się na liście uprawnień w zmiennej sesji
wyświetl lub wykorzystaj dane
W PRZECIWNYM WYPADKU
ignoruj ten wiersz, ponieważ doradca nie powinien go widzieć
Jak wspominaliśmy w rozdziale 6 „Współpraca z bazami danych”, należy wykorzystywać możliwości
bazy danych do poprawienia wydajności aplikacji. Poprzedni przykład kodu może być zastąpiony zapytaniem, w
którym tabela z danymi jest połączona z tabelą z uprawnieniami. Spowoduje to usunięcie ogromnej ilości kodu i
wyeliminuje konieczność przechowywania listy uprawnień w danych sesji.
Zmienne sesji są niezmiernie potrzebne przy programowaniu aplikacji WWW, ale powinny być używane
rozważnie. W trakcie projektowania należy rozważyć wszystkie alternatywne sposoby uzyskana tego samego
efektu. Większość aplikacji WWW wymaga zastosowania tylko kilku zmiennych sesji. Gdy chcesz zastosować
zmienną sesji, postaw sobie następujące pytania:
• Czy ta zmienna jest używana w całym programie? Jeżeli ta wartość jest używana na każdej stronie
aplikacji, jest to świetny kandydat na zmienną sesji. Na przykład, jeżeli aplikacja korzysta z logowania
użytkowników, dobrze jest przechowywać identyfikator użytkownika w zmiennej sesji.
• Czy zmienna ta jest unikalna dla tej sesji? Jeżeli jest to na pewno dana związana z sesją, zapamiętaj ją w
zmiennej sesji. Na przykład, jeżeli tworzysz wózek na zakupy, musisz prawdopodobnie przechowywać
jego identyfikator w zmiennej sesji. Jednak jeżeli aplikacja korzysta z kilku trwałych wózków na zakupy
w których użytkownik może przechowywać zamówienie w czasie kilku sesji, prawdopodobnie nie
potrzebujesz zmiennej sesji, ale dobrze zaprojektowanej bazy danych.
• Czy dana jest dana kluczową? Pytanie to jest związane z pierwszym. Jeżeli aplikacja korzysta ze
zmiennych sesji do przechowywania identyfikatora użytkownika, unikaj przechowywania innych danych
93
PHP – Kompendium wiedzy
związanych z użytkownikiem w zmiennej sesji. Zamiast tego, w razie potrzeby skorzystaj z identyfikatora
do odczytania potrzebnych danych. Na przykład, jeżeli aplikacja personalizuje strony, nie przechowuj
zmiennych potrzebnych do tego celu w sesji. Przechowuj w sesji identyfikator i wykorzystaj kilka funkcji
odczytujących dane potrzebne do personalizacji. Struktura taka nie tylko eliminuje powtórzenia danych,
ale również pozwala użytkownikowi na zmianę swoich ustawień w jednej sesji i natychmiastowe
odzwierciedlenie tego w drugiej równoległej sesji.
• Czy aplikacja na pewno potrzebuje zmiennych sesji? Pytanie to może wydawać się oczywiste, ale często
jest pomijane z powodu łatwości używania zmiennych sesji. To, że użytkownik przegląda witrynę i
przeprowadza jakieś operacje niekoniecznie oznacza, że potrzebna jest sesja. Zmienne sesji nie powinny
zastępować innych mechanizmów przechowywania danych.
Jeżeli odpowiedź na te pytania nie zgadza się z zasugerowanymi odpowiedziami, należy rozważyć
zastosowanie innych metod przechowywania danych. Sesje są świetnym narzędziem, ale nieprawidłowo używane
mogą doprowadzić do stworzenia aplikacji pełnej błędów i trudnej do utrzymania.
Podsumowanie
W PHP dostępne jest kilka świetnych narzędzi do stworzenia mechanizmu sesji. Należy wybrać
mechanizm, który najlepiej pasuje do potrzeb i którego zastosowanie będzie przynosiło owoce w dłuższym czasie
a nie tylko będzie miał krótkoterminowy wpływ na kodowanie aplikacji. Nieprawidłowe użycie zmiennych sesji
może doprowadzić do stworzenia aplikacji trudnej do rozwijania, która posiada trudne do zidentyfikowania błędy.
Rozdział 7 – Sesje i stan aplikacji
94
Rozdział 8. Uwierzytelnianie
Wstęp
W poprzednim rozdziale „Sesje i stan aplikacji” omówione zostały sposoby śledzenia użytkowników
witryny WWW w celu zapewnienia ciągłości pracy aplikacji. Ten rozdział poświęcony będzie sposobom
upewnienia się, że użytkownicy maja wystarczające uprawnienia do pracy w aplikacji.
Istnieją różne schematy uwierzytelniania przeznaczone do różnych zadań. Większość serwerów WWW
posiada narzędzia przeznaczone do autoryzacji użytkowników w oparciu o uprawnienia i pliki serwera. W tym
rozdziale zajmiemy się uwierzytelnianiem opartym na mechanizmach serwera, ale jedynie w oparciu o serwer
Apache na Linuksie (Windows i IIS również umożliwiają uwierzytelnianie, ale nie zostanie ono tutaj opisane). W
dalszej części rozdziału przedstawiony zostanie również mechanizm niezależny od serwera i platformy.
Podstawowe uwierzytelnianie w Apache
Rozdział ten rozpoczniemy omówieniem podstawowego schematu uwierzytelniania dostępnego w
serwerze WWW Apache oraz problemami związanymi z tą metodą. Osoby znające dyrektywy uwierzytelniania
Apache oraz przeznaczenie plików .htaccess i innych plików konfiguracyjnych serwera Apache nie dowiedzą się
tutaj zbyt wiele nowego. Nawet w prostej witrynie może być potrzebne ograniczenie dostępu do niektórych stron.
Wykorzystanie mechanizmu uwierzytelniania dostarczanego przez serwer WWW jest zwykle szybkim i
efektywnym sposobem zrealizowania takiego mechanizmu. Na przykład może być niezbędne stworzenie zbioru
stron przeznaczonych do administracji witryną, za pomocą których można przeglądać i zmieniać wybrane
elementy witryny. Strony te nie mogą być dostępne dla wszystkich użytkowników, ale administrator musi mieć
do nich dostęp z dowolnej przeglądarki.
Aby zrealizować takie założenia możesz przenieść wszystkie strony administracyjne do osobnego
podkatalogu w drzewie katalogów witryny WWW oraz zmienić konfigurację Apache tak, aby dostęp do stron
znajdujących się w tym katalogu wymagały autoryzacji. Odpowiednie dyrektywy konfiguracji mogą znajdować
się w pliku httpd.conf lub .htaccess w chronionym katalogu. Jeżeli masz dostęp do plików konfiguracyjnych
Apache powinieneś skorzystać z nich zamiast z pliku .htaccess. Korzystanie z pliku .htaccess jest mniej
efektywne od wykorzystania standardowych plików konfiguracyjnych, ponieważ jest on odczytywany za każdym
żądaniem pliku z katalogu zawierającego plik .htaccess. Jednak jeżeli witryna jest umieszczona na
dzierżawionym serwerze, prawdopodobnie nie będziesz mógł zmienić plików konfiguracyjnych i zrestartować
serwera WWW w celu pobrania zmienionej konfiguracji.
Na wydruku 8.1 zamieszczony jest wydruk prostej strony HTML zawierającej łącze do podkatalogu ze
stroną administracyjną. Strona administracyjna znajduje się w katalogu wymagającym uwierzytelniania, więc
kliknięcie tego łącza spowoduje, że przeglądarka wyświetli standardowe okno uwierzytelniania, pokazane na
rysunku 8.1. Wydruk 8.2 zawiera dyrektywy konfiguracji Apache które powodują wyświetlenie okna logowania.
Wydruk 8.1. Prosta strona HTML z łączem do stron administracyjnych
<html>
<head>
<title>Proste uwierzytelnianie Apache</title>
</head>
<body>
<a href="admin/index.phtml">Przejdź do strony administratora</a>
</body>
</html>
Wydruk 8.2. Dyrektywy konfiguracji Apache włączające podstawowe uwierzytelnianie
AuthUserFile /www/auth_users
AuthName Adminstrative
AuthType Basic
<Limit GET>
require valid-user
</Limit>
Rysunek 8.1. Okno
dialogowe
uwierzytelniania w
przeglądarce
Więcej informacji na temat użycia uwierzytelniania Apache można znaleźć w Sieci oraz we wielu
świetnych książkach poświęconych serwerowi Apache. Ten rodzaj uwierzytelniania wymaga współpracy
pomiędzy przeglądarką i serwerem. Mechanizm ten wygląda następująco: gdy użytkownik musi zostać
autoryzowany, serwer WWW wysyła żądanie 401 do przeglądarki a przeglądarka odpytuje użytkownika i odsyła
wprowadzone przez niego dane do serwera. Jeżeli serwer zaakceptuje uwierzytelnianie, chroniony zasób jest
udostępniony użytkownikowi. Przeglądarka wysyła wprowadzone dane do serwera podczas żądania sprowadzenia
wszystkich kolejnych stron aż do zakończenia pracy przeglądarki.
PHP posiada zmienne globalne, których możesz użyć w aplikacji w celu odczytania danych autoryzacji.
Możesz skorzystać ze zmiennych $PHP_AUTH_USER oraz $PHP_AUTH_PW do odczytania nazwy użytkownika i hasła.
Wydruk 8.3 zawiera stronę wyświetlająca dane autoryzacji. Na rysunku 8.2. pokazana jest zawartość tej strony po
przejściu do niej poprzez łącze znajdujące się na stronie z wydruku 8.1.
Wydruk 8.3. Wyświetlanie zawartości zmiennych autoryzacji
<html>
<head>
<title>Strona administratora</title>
</head>
<body>
<h1>Witamy na stronie administratora</h1>
<?php
print( "PHP_AUTH_USER: $PHP_AUTH_USER<br>" );
print( "PHP_AUTH_PW: $PHP_AUTH_PW<br>" );
?>
</body>
</html>
Rysunek 8.2.
Zmienne
autoryzacji w PHP
Schemat autoryzacji Apache zapewnia podstawowy stopień bezpieczeństwa witryny. Jest on szczególnie
użyteczny w sytuacjach, gdy chcesz chronić wszystkie strony i inne zasoby znajdujące się we fragmencie drzewa
Rozdział 8 – Uwierzytelnianie
96
katalogów witryny. Ograniczeniem stosowania tej metody jest konieczność dodawania i usuwania użytkowników
poprzez wykonanie odpowiednich poleceń na serwerze. W następnej części zostanie opisane w jaki sposób można
wykorzystać PHP do aktualizacji pliku haseł, co pozwoli na stworzenie narzędzia WWW do dodawania i
usuwania użytkowników.
Aktualizacja pliku .htaccess przy użyciu PHP
Jeżeli podstawowe uwierzytelnianie serwera WWW jest wystarczające w tworzonej aplikacji, można przy
użyciu PHP stworzyć narzędzie administracyjne upraszczające zarządzanie użytkownikami. Można udostępnić to
narzędzie zaufanym osobom, którzy będą mogli operować użytkownikami bez konieczności udostępniania im
bezpośredniego dostępu do serwera.
Programiści zespołu The Webmasters Net (http://www.theWebmasters.net/) stworzyli dwie klasy służące
do zarządzania użytkownikami i grupami plików dla celów podstawowego uwierzytelniana. Do manipulacji
standardowym plikiem Apache htpasswd można wykorzystać klasę Htpasswd. Na wydruku 8.4 pokazany został
przykład, jak można wykorzystać tę klasę do autoryzacji użytkownika, przy użyciu bardzo małej ilości kodu.
Przykład korzysta z tego samego pliku, który został użyty w poprzednim przykładzie.
Wydruk 8.4. Sprawdzanie poprawności autoryzacji użytkownika za pomocą klasy Htpasswd
<html>
<head>
<title>Szybkie sprawdzenie użytkownika z uzyciem klasy Htpasswd</title>
</head>
<body>
<?php
include( "./class.Htpasswd.php3" );
$aHTPasswd = new Htpasswd("/www/auth_users");
if ( !$aHTPasswd->EXISTS )
{
print( "Błąd autoryzacji<br>" );
}
else
{
if ( $aHTPasswd->verifyuser( "phpbook", "phpbook" ) )
{
print( "phpbook to prawidłowy użytkownik<br>" );
}
else
{
print( "phpbook nie jest prawidłowym użytkownikiem<br>" );
}
}
?>
</body>
</html>
Klasę Htpasswd można również wykorzystać do dodawania nowych użytkowników, usuwania
użytkowników, zmiany hasła, sprawdzania poprawności użytkownika oraz zmiany jego nazwy. Przy pomocy tej
klasy można napisać obszerne narzędzie do administracji użytkownikami, które będzie pomocne przy zarządzaniu
mechanizmem podstawowego uwierzytelniania serwera. Skrypty na wydruku 8.5, 8.6 i 8.7 zawierają skrypty
pokazujące, w jaki sposób można połączyć wszystkie te operacje w jednym formularzu.
Wydruk 8.5 zawiera pierwszą część skryptu. Jest ona używana do inicjalizacji skryptu i określenia czy
strona jest oglądana pierwszy raz, czy została wywołana w wyniku żądania POST. Skrypt ten jest podobny do
wielu przytoczonych do tej pory przykładów, które przesyłają dane do samego siebie i są używane zarówno do
wyświetlania jak i do zmiany danych.
Wydruk 8.5. Użycie klasy Htaccess do zarządzania użytkownikami
<?php
include( "./class.Htpasswd.php3" );
$aHTPasswd = new Htpasswd("/www/auth_users");
if ( !$aHTPasswd->EXISTS )
{
print( "Błąd krytyczny<br>" );
exit;
}
if (
{
$REQUEST_METHOD == 'POST' )
switch ( $acttype )
{
97
PHP – Kompendium wiedzy
case 'none' :
break;
case 'add' :
$aHTPasswd->addUser( $NewUserName, $NewUserPass );
print( "<b>Dodano użytkownika $NewUserName</b><br>" );
break;
case 'delete' :
$aUserName = $aHTPasswd->USERS[$CurUserRow]["user"];
$aHTPasswd->deleteUser( $aUserName );
print( "<b>Usunięto użytkownika $aUserName</b><br>" );
break;
case 'rename' :
$aUserName = $aHTPasswd->USERS[$CurUserRow]["user"];
$aHTPasswd->renameUser( $aUserName, $RenameName );
print( "<b>Nazwa użytkownika zmieniona z $aUserName
na $RenameName</b><br>" );
break;
case 'changepass' :
$aUserName = $aHTPasswd->USERS[$CurUserRow]["user"];
$aHTPasswd->changePass( $aUserName, $ChangePass );
print( "<b>Zmieniono hasło dla użytkownika $aUserName</b><br>" );
break;
}
}
?>
Jeżeli skrypt ten zostanie wywołany w wyniku żądania POST, na podstawie wartości zmiennej formularza
podejmowana jest decyzja co do kolejnej akcji. Zmienna posiada pięć możliwych wartości: none, add,
delete, rename oraz changepass. W zależności od wyboru użytkownika podejmowana jest odpowiednia akcja. W
skrypcie założono, że wszystkie potrzebne dane są prawidłowo wypełnione. Oczywiście, aby program mógł być
normalnie używany niezbędne jest dodanie kodu kontroli poprawności.
W następnej części skryptu ustawiana jest zmienna $acttype. Dla wszystkich przycisków znajdujących się
na formularzu zdefiniowana jest odpowiednia akcja. Do ustawiania ukrytej zmiennej formularza $acttype
wykorzystujemy JavaScript.
Wydruk 8.6. Ustawianie zmiennej $acttype
$acttype
<html>
<head>
<title>Prosty program zarządający użytkownikami</title>
<script language="JavaScript">
<!-function DoSubmit( aType )
{
document.mainform.acttype.value = aType;
document.mainform.submit();
}
//-->
</script>
</head>
Ostatnia część skryptu pokazana na wydruku 8.7 jest po prostu stroną HTML zawierającą formularz. Kod
PHP jest jedynie używany do wstawiania istniejących użytkowników do listy SELECT. Każdy przycisk na
formularzu zawiera atrybut onClick, który powoduje wywołanie przedstawionej funkcji JavaScript, która realizuje
wysłanie danych formularza do odpowiedniej strony.
Wydruk 8.7. Strona z formularzem HTML
<body>
<form action="<?=$PHP_SELF?>" method="post" name="mainform" id="mainform">
<input type="hidden" name="acttype" value="none">
<h1>Prosty program zarządzający użytkownikami</h1>
<h2>Dodanie użytkownika</h2>
Nazwa nowego użytkownika: <input type="text" name="NewUserName"><br>
Hasło: <input type="password" name="NewUserPass"><br>
<input type="button" value="Dodaj" onClick="DoSubmit( 'add' );">
<hr>
<h2>Zmiana użytkownika</h2>
<table>
<tr>
<td>
<select name="CurUserRow" size="10">
<?php
$nIndex = 0;
foreach( $aHTPasswd->USERS as $aUser )
{
print( "<option value=\"$nIndex\">$aUser[user]</option>" );
$nIndex++;
}
?>
Rozdział 8 – Uwierzytelnianie
98
</select>
</td>
<td>
Usunięcie zaznaczonego użytkownika:
<input type="button" value="Usuń" onClick="DoSubmit( 'delete' );">
<br><br>
Zmiana nazwy zaznaczonego użytkownika:
<input type="text" name="RenameName"><input type="button"
value="Zmiana nazwy" onClick="DoSubmit( 'rename' );"><br><br>
Zmiana hasła dla zaznaczonego użytkownika: <input type="password"
name="ChangePass"><input type="button" value="Zmiana hasła"
onClick="DoSubmit( 'changepass' );"><br><br>
</td>
</tr>
</table>
</form>
</body>
</html>
Na rysunku 8.3. pokazana jest strona bezpośrednio o dodaniu użytkownika scott. Jak mówiliśmy
wcześniej, skrypt ten nie jest kompletnym narzędziem zarządzającym użytkownikami, a jedynie pokazuje sposób
wykorzystania klasy Htpasswd. Można również skorzystać z dostarczanej przez The Webmasters Net klasy
Htgroup do tworzenia i zarządzania grupami użytkowników.
Rysunek 8.3.
Program
zarządzający
użytkownikami
w działaniu
Podstawowe uwierzytelnianie za pomocą PHP
Poprzednie dwie części opisywały podstawowe uwierzytelnianie serwera Apache do ochrony fragmentów
witryny WWW (zwykle katalogów). W niektórych przypadkach może być wymagane zabezpieczenie tylko
niektórych stron aplikacji lub nie jest możliwa modyfikacja odpowiednich plików na serwerze WWW. W takim
przypadku możesz wykorzystać PHP do wysyłania odpowiednich nagłówków do serwera i w ten sposób
bezpośrednio żądać autoryzacji.
99
PHP – Kompendium wiedzy
Tak jak w przypadku wysyłania innych danych nagłówka, należy albo wysyłać dane nagłówków przed
wysłaniem jakichkolwiek danych strony, albo korzystać z buforowania wyjścia. Na wydruku 8.8 zamieszczony
jest prosty skrypt żądający autoryzacji. Skrypt ten jest w postaci pliku dołączanego, auth_include.inc, więc będzie
go można łatwo dodawać do wszystkich stron wymagających autoryzacji.
Wydruk 8.8. Skrypt auth_include.php
<?php
$aDoAuth = True;
if ( isset( $PHP_AUTH_USER ) )
{
if ( ( $PHP_AUTH_USER == "ryan" ) &&
( $PHP_AUTH_PW == "dentist" ) )
{
// prawidłowa nazwa użytkownika i hasło
$aDoAuth = False;
}
}
if( $aDoAuth == True )
{
Header( "WWW-Authenticate: Basic realm=\"My Realm\"" );
Header( "HTTP/1.0 401 Unauthorized" );
echo "Nie udało się zalogowanie do systemu.\n";
exit;
}
?>
Skrypt ten na początku pracy sprawdza, czy ustawiona jest zmienna $PHP_AUTH_USER. Jeżeli tak, to
wartości zmiennych $PHP_AUTH_USER i $PHP_AUTH_PW są porównywane z prawidłową nazwą użytkownika i hasłem
aplikacji. Jeżeli sprawdzenie to się powiedzie, nie ma potrzeby wysyłania do przeglądarki nagłówka autoryzacji.
Jeżeli porównanie nie uda się skrypt wysyła do przeglądarki nagłówek HTTP 401, który powoduje wyświetlenie
okna autoryzacji. Proces ten jest powtarzany aż do podania właściwych danych autoryzacji, albo do przerwania
uwierzytelniania przez użytkownika. Dołączenie tego pliku na początku dowolnego skryptu powoduje
konieczność autoryzacji użytkownika skryptu.
Prawdziwy system uwierzytelniania nie powinien mieć zaszytych nazw użytkowników i haseł w samym
skrypcie. Zamiast tego należy wykorzystać bazę danych lub usługę katalogową (na przykład LDAP) lub nawet
pliki zawierające dane uwierzytelniania.
Jedną z zalet takiego podejścia jest możliwość odwołania uwierzytelnienia użytkownika poprzez ponowne
wysłanie nagłówka HTTP 401. Można to wykorzystać do ponownego logowania użytkownika po określonym
czasie bezczynności lub do chronienia różnymi hasłami różnych części aplikacji.
PHP posiada wystarczająco dużo narzędzi i elastyczności aby można było napisać dowolny system
autoryzacji użytkowników. Poprzednia metoda jest oparta o możliwość obsługi przez przeglądarki wywołań
HTTP 401 ale metoda ta posiada wiele ograniczeń. Następna metoda jest bardziej niezależna od platformy i
posiada bardziej elastyczne podejście do uwierzytelniania.
Kompletny system uwierzytelniania oparty o PHP
Wykorzystanie metody autoryzacji opisanej w poprzedniej części jest łatwe i proste. Większość
programistów WWW wykorzystywało już pliki .htaccess do zabezpieczania katalogów, więc sposób ten jest
zwykle dobrze znany. W tej części skupimy się na implementacji, która nie polega na wywołaniach HTTP 401 z
serwera, wymuszających na przeglądarce wyświetlenie okna uwierzytelniania. Głównym powodem użycia tego
typu implementacji jest zwiększenie elastyczności aplikacji.
Poniższa implementacja wykorzystuje klasę Auth z PHPLIB. Jest to ekstremalnie solidna i elastyczna
implementacja, ale przez o wymaga sporo zachodu, zanim można będzie ją wykorzystać. Jednak po jej
zaprogramowaniu jest świetnym zamiennikiem metody opisanej w poprzedniej części. Jeżeli nie korzystamy z
mechanizmów przeglądarki przy wyświetlaniu okna uwierzytelniania, musimy sami tworzyć formularz HTML
służący do pobierania danych niezbędnych dla naszej aplikacji. Dodatkowo, PHPLIB pozwala na stworzenie
autoryzacji opartej na uprawnieniach, więc do każdej strony można przypisać wymagany poziom uprawnień dla
każdego z użytkowników.
Mechanizm uwierzytelniania realizowany przez PHPLIB jest w wielu punktach podobny do mechanizmu
obsługi sesji. Do działania wymaga on sesji PHPLIB. Schemat autoryzacji PHPLIB jest uruchamiany podczas
wywołania funkcji PHPLIB page_open() i zażądanie „własności” sess. Gdy zostanie zażądana ta własność,
Rozdział 8 – Uwierzytelnianie
100
PHPLIB sprawdza zalogowanie użytkownika. Jeżeli użytkownik nie podawał wcześniej danych autoryzacji,
PHPLIB wyświetla zdefiniowaną przez użytkownika stronę. Strona ta pobiera dowolne dane, jakich aplikacja
wymaga do prawidłowej autoryzacji użytkownika. Następnie PHPLIB wywołuje dostarczoną przez użytkownika
funkcję sprawdzającą uprawnienia użytkownika. Jeżeli funkcja ta zaakceptuje użytkownika, PHPLIB wyświetla
stronę a w przeciwnym wypadku następuje ponowne uwierzytelnianie. Na rysunku 8.4. pokazana jest interakcja
pomiędzy klientem, serwerem WWW (i tym razem jest to 1U z Penguin Computing) oraz aplikacją PHP.
Rysunek 8.4.
Interakcja w
schemacie
autoryzacji
PHPLIB
Z powodu elastyczności jaką zapewnia PHPLIB wymagane jest wykonanie kilku niezbędnych kroków
zanim użyjemy naszej klasy autoryzacji. Po pierwsze, na wydruku 8.9 pokazane są klasy zdefiniowane przez
użytkownika niezbędne do stworzenia klasy Auth i klas ją wspomagających (Klasy sesji i bazy danych są
identyczne jak te, których używaliśmy w rozdziale 7). W naszym przypadku dane autoryzacji znajdują się w
tabeli bazy danych MySQL. Tabela użyta do autoryzacji jest zdefiniowana następująco:
CREATE TABLE MyAuth (
FirstName varchar(20)
SurName
varchar(30)
password
varchar(20)
PRIMARY KEY (FirstName,
);
NOT NULL,
NOT NULL,
NOT NULL,
SurName)
Wydruk 8.9. Przygotowanie klas używanych przez klasę PHPLIB Auth
<?php
include( "page.inc" );
include( "ct_sql.inc" );
include( "session.inc" );
include( "db_mysql.inc" );
include( "auth.inc" );
class MySQLDB extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
var $Password
= "root";
}
class MySQLCt extends CT_Sql
{
var $classname = "MySQLCt";
var $database_table = "active_sessions";
var $database_class = "MySQLDB";
}
class MySqlSession extends Session
{
var $classname = "MySqlSession"; // Obsługa przechowywania
var $mode
= "cookie";
var $lifetime = 0;
// użycie cookie sesji
var $that_class = "MySQLCt";
// wybór kontenera
var $allowcache_expire = 0;
}
class Sample_Auth extends Auth
{
var $classname = "Sample_Auth";
var $lifetime = 20; // 20 minut (0 == ciągle)
function auth_loginform()
{
include( "./sample_lform.htinc" );
}
function auth_validatelogin()
{
global $FirstName, $SurName, $Password;
$aDB
= new MySQLDB;
$aSQL = "select * from MyAuth where ( FirstName = ";
$aSQL .= "'$FirstName' ) and ( SurName = '$SurName' )";
101
PHP – Kompendium wiedzy
$aSQL .= "and ( Password = '$Password' )";
$aDB->query( $aSQL );
if ( $aDB->num_rows() > 0 )
{
return $FirstName;
}
else
{
return False;
}
}
}
?>
Klasa Sample_Auth dziedzicząca po klasie bazowej Auth zapewnia działanie specyficzne dla bieżącej
aplikacji. Zdefiniowane są odpowiednie funkcje auth_loginform() i auth_validatelogin(). Funkcja
auth_loginform() jest wywoływana, gdy klasa Auth wymaga uwierzytelnienia użytkownika. Możesz użyć
instrukcji print() do stworzenia formularza HTML potrzebnego do zalogowania, ale zwykle dołączenie pliku jest
łatwiejsze. Na wydruku 8.10 pokazany jest plik użyty w tym przykładzie.
Wydruk 8.10. Przykładowy formularz logowania (sample_lform.htinc)
<?php
global $FirstName;
global $SurName;
$aCurFirstName = "";
$aCurSurName
= "";
if ( !empty( $FirstName ) )
{
$aCurFirstName = $FirstName;
}
if ( !empty( $SurName ) )
{
$aCurSurName = $SurName;
}
?>
<html>
<head>
<title>Formularz autoryzacji dla PHPLIB</title>
</head>
<body>
<form action="<?=$this->url()?>" method="post">
<table>
<tr>
<td>
Imię:
</td>
<td>
<input type="text" name="FirstName" value="<?=$aCurFirstName?>">
</td>
</tr>
<tr>
<td>
Nazwisko:
</td>
<td>
<input type="text" name="SurName" value="<?=$aCurSurName?>">
</td>
</tr>
<tr>
<td>
Hasło:
</td>
<td>
<input type="password" name="Password">
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="Submit" value="Log In">
</td>
</tr>
<?php if ( !empty( $FirstName ) ) { ?>
<tr>
<td colspan="2">
<br><br>
Podane dane są nieprawidłowe, spróbuj jeszcze raz..
</td>
</tr>
<?php } ?>
</table>
Rozdział 8 – Uwierzytelnianie
102
</form>
</body>
</html>
Strona ta jest zaprojektowana jedynie do wyświetlania przez klasę Auth. Na początku sprawdza, czy
zmiene formularza mają jakieś wartości. Może to się zdarzyć, gdy wyświetlamy formularz po nieudanej
autoryzacji użytkownika W tym przypadku klasa Auth ponownie wyświetla formularz logowania. Wartości
zmiennych formularza są przenoszone do pól formularza FirstName i SurName jedynie z grzeczności (ale
użytkownik nie musi ponownie wpisywać tych danych).
Następnie strona wyświetla trzy pola tekstowe do wprowadzenia imienia, nazwiska i hasła użytkownika.
Dane formularza są wysyłane do strony określonej przez $this->url(). W kontekście tej strony zmienna $this
wskazuje na bieżący obiekt klasy pochodnej po Auth. Funkcja url() zwraca stronę, na której był użytkownik
zanim obiekt klasy interweniował i wywołał naszą stronę autoryzacji. Na koniec definiujemy ostrzeżenie jakie
zobaczy użytkownik gdy poda niewłaściwe dane.
Gdy dane formularza zostaną przesłane do oryginalnej strony, Auth sprawdza ponownie dane autoryzacji.
Aby to zrobić wywołuje ona zdefiniowaną przez użytkownika funkcję auth_validatelogin(). Na wydruku 8.11
pokazujemy funkcję użytą w naszym przykładzie.
Wydruk 8.11. Funkcja auth_validatelogin()
function auth_validatelogin()
{
global $FirstName, $SurName, $Password;
$aDB
= new MySQLDB;
$aSQL = "select * from MyAuth where ( FirstName = ";
$aSQL .= "'$FirstName' ) and ( SurName = '$SurName' )";
$aSQL .= "and ( Password = '$Password' )";
$aDB->query( $aSQL );
if ( $aDB->num_rows() > 0 )
{
return $FirstName;
}
else
{
return False;
}
}
Funkcja odwołuje się do zmiennych globalnych $FirstName, $SurName i $Password, zdefiniowanych w
formularzu logowania. Ich wartości są wyszukiwane w tabeli MySQL zawierającej trzy kolumny: FirstName,
SurName i Password. Jeżeli odnaleziony zostanie rekord w tabeli opisujący bieżącego użytkownika, funkcja
auth_validatelogin() zwraca imię użytkownika (oczywiście użycie imienia jako identyfikatora użytkownika nie
było by zbyt dobrym pomysłem). Jeżeli nie ma pasującego rekordu, zwracana jest wartość False.
Na wydruku 8.12 pokazana została typowa strona WWW wykorzystująca o autoryzacji klasę Auth. W
przykładzie wyświetlane są cztery łącza do innych podobnych stron, wymagających autoryzacji. Ostatnia strona z
listy zapewnia wylogowanie użytkownika.
Wydruk 8.12. Prosta strona wykorzystująca klasę Auth
<?php
// bez buforowania (z witryny php.net)
include( "./auth_phplib.php" );
page_open( array( "sess"
=> "MySqlSession",
"auth"
=> "Sample_Auth" ) );
header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header ("Cache-Control: no-cache");
header ("Pragma: no-cache");
?>
<html>
<head>
<title>Przykład użycia klasy PHPLIB Auth</title>
<META HTTP-EQUIV="Expires" CONTENT="-1">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
</head>
<body>
<h2>Strona główna</h2>
Posiadasz uprawnienia do oglądania tej strony!
<ul>
<li><a href="test_auth_phplib.phtml">Strona główna</a></li>
<li><a href="test_auth_phplib2.phtml">Strona druga</a></li>
<li><a href="test_auth_phplib3.phtml">Strona trzecia</a></li>
<li><a href="test_auth_phplib_logout.phtml">Wylogowanie</a></li>
103
PHP – Kompendium wiedzy
</ul>
</body>
</html>
<?php
page_close();
?>
Pierwsza strona dołącza prosty plik uwierzytelniania a następnie wywołuje funkcję PHPLIB page_open(),
która uaktywnia sesję i mechanizm uwierzytelniania. Na końcu strony wywoływana jest funkcja page_close(),
która zapisuje dane sesji. Zmienne uwierzytelniania są przesyłane pomiędzy stronami przy pomocy mechanizmu
sesji. Druga i trzecia strona jest funkcjonalnie identyczna z pierwszą. Strona Wylogowanie, zawiera na dole strony
następujący kod wymuszający wylogowanie użytkownika:
<?php
$auth->logout();
page_close();
?>
Funkcja $auth->logout() może być wywołana w dowolnym momencie, a wymusza ona ponowne
wywołanie autoryzacji użytkownika na następnej stronie.
Kilka wierszy w tym przykładzie nie jest związane z mechanizmem uwierzytelniania. Wywołania funkcji
header() oraz znaczniki <META> zapewniają, że przeglądarka nie będzie przechowywała strony w buforze. Kod ten
jest dosyć ważny, ponieważ buforowane strony mogą mylić użytkowników, którzy nie będą wiedzieli, czy są już
zalogowani. Szczególne kłopoty sprawia Microsoft Internet Explorer, więc podjęto szczególne środki
zapewniające prawidłowe działanie przykładów. Podczas testowania tego przykładu nie stwierdziliśmy żadnych
problemów w IE 5.5, wszystkich wersjach Netscape, WebTV i Opera.
Jak wcześniej wspomnieliśmy, PHPLIB jest niezwykle elastycznym narzędziem, pozwalającym na
stworzenie własnego mechanizmu uwierzytelniania. Można stworzyć skomplikowane lub proste schematy
uwierzytelniania, w zależności od wymagań aplikacji. Zaletą tego podejścia jest możliwość tworzenia własnych
formularzy logowania, porównywanie wpisanych danych z danymi przechowywanymi na dowolnym nośniku
informacji, oraz możliwość łatwego wylogowania użytkownika. Umieszczenie w aplikacji systemu zabezpieczeń
wydaje się bardziej efektywne, szczególnie dla początkujących użytkowników, którzy mogą być zaskoczeni
systemowymi oknami dialogowymi.
Podsumowanie
W tym rozdziale zostało omówionych wiele aspektów uwierzytelniania użytkowników w aplikacjach
PHP. Pierwsze kilka omówionych metod jest mocno zależne od platformy, ale są łatwe do implementacji.
Ostatnia metoda, wymagająca użycia klas PHPLIB jest bardziej złożona, ale o wiele bardziej elastyczna i
całkowicie przenośna pomiędzy serwerami WWW i systemami operacyjnymi.
Jeżeli aplikacja wymaga jakiegoś typu uwierzytelniania użytkowników, powinieneś w fazie projektowania
określić specyficzne wymagania tej aplikacji. Niektóre mechanizmy uwierzytelniania nie posiadają
wystarczającej elastyczności. Inne mogą nie zapewniać dostatecznego poziomu bezpieczeństwa. Przy pomocy
tego rozdziału można skojarzyć twój potrzeby z oferowanymi przez poszczególne metody możliwościami.
Rozdział 8 – Uwierzytelnianie
104
Rozdział 9. Niezależność od przeglądarki
Wstęp
Podczas pisania standardowych aplikacji interfejs użytkownika jest tworzony dla potrzeb aplikacji i
zwykle jest on przeznaczony dla jednej platformy. Nie przewiduje się niespodziewanych zmian tego interfejsu w
czasie działania programu w zależności od użytkownika, który używa aplikacji. W czasie pisania aplikacji dla
WWW, interfejs użytkownika nie jest już tak niezmienny, ponieważ może być on odtwarzany przez różne typy
przeglądarek na różnych platformach. Tworzenie aplikacji niezależnej od przeglądarki wymaga możliwości
wykrywania typu przeglądarka i wykorzystywania jej możliwości.
Mimo, że większość nowoczesnych przeglądarek będzie wyświetlało aplikacje w podobny sposób, zawsze
istnieją różnice. Jeżeli aplikacja wymaga jakiejś własności przeglądarki, należy tak napisać aplikację, aby
sprawdzała typ użytej przeglądarki i odpowiednio reagowała. PHP pozwala na kilka metod wykrywania rodzaju
przeglądarki, rozpoczynając od stworzenia własnego rozwiązania do użycia narzędzi firm trzecich. W rozdziale
tym przedstawimy przykłady wielu metod, z których będziesz mógł wybrać odpowiednią dla twojej aplikacji.
Rozpoczynamy
Na najbardziej podstawowym poziomie, PHP pozwala na odczytanie typu przeglądarki poprzez zmienną
globalną $HTTP_USER_AGENT. Ciąg ten jest wysyłany przez przeglądarkę do serwera wraz z każdym żądaniem.
Jeżeli wystarczy ci proste rozpoznanie typu przeglądarki, można wykorzystać bezpośrednio zmienną
$HTTP_USER_AGENT. Na przykład, sposób wykrycia przeglądarki Internet Explorer przy użyciu porównywania
ciągów zamieszczony jest na wydruku 9.1.
Wydruk 9.1. Wyświetlanie podstawowych danych na temat przeglądarki
<html>
<head>
<title>Szybkie sprawdzenie typu przeglądarki</title>
</head>
<body>
<?php
$aPos = strpos( $HTTP_USER_AGENT, "MSIE" ) ;
if ( $aPos === False )
{
print( "To <b>nie</b> jest MS Internet Explorer!<br>" );
}
else
{
print( "Przeglądarka MS Internet Explorer!<br>" );
}
?>
</body>
</html>
W przykładzie tym sprawdzamy, czy przeglądarka klienta to Internet Explorer. Przykład opiera się na tym,
że zwracana nazwa przeglądarki w większości wersji Internet Explorera zawiera fragment MSIE. Można
wykorzystać tę informację do wyświetlenia odpowiedniego komunikatu, lub przekierować użytkownika do innej
części witryny, która jest zoptymalizowana do wyświetlania stron w określonej przeglądarce. Metoda ta sprawdza
się w niektórych przypadkach, ale jest zbyt prosta, aby obsługiwać ogromną ilość prawidłowych ciągów user
agent. Kilka przeglądarek zmieniło format tego ciągu podczas jednej ze zmiany wersji, więc rozpoznanie
określonej przeglądarki może być problematyczne, jeżeli potrzebujesz dokładnej informacji o przeglądarce. Na
przykład, niektóre wersje Internet Explorera zawierały następujące ciągi user agent:
• Microsoft Internet Explorer/4.40.305beta (Windows 95)[en]
•
•
Mozilla/2.0 (compatible; MSIE 3.02; Update a; AOL 3.0; Windows 95)[en]
Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0)[en]
Różnice w zawartości tego ciągu powodują, że sprawdzanie ich zawartości staje się nieporęczne. Istnieje
tak wiele kombinacji przeglądarek, wersji, platform i języków, że dokładne rozpoznanie choć jednego
przeglądarki staje się problematyczne.
W rzeczywistości znajomość jedynie typu przeglądarki nie jest tak ważne. Zamiast tego lepiej wiedzieć,
czy przeglądarka obsługuje określone możliwości, na przykład JavaScript lub ramki. Te informacje nie są zawarte
w ciągu informacji o przeglądarce. Następna część omawia rozwiązanie tego problemu w oparciu o PHP.
Wewnętrzne funkcje PHP
Rozpoznawanie typu serwera ma zwykle służyć do poznania możliwości przeglądarki. Z powodu
ogromnej ilości kombinacji przeglądarek i platform, trudno jest stworzyć ogólne rozwiązanie tego problemu. Na
szczęście PHP zawiera kilka metod dokładniejszego rozpoznania serwera za pomocą funkcji get_browser().
Dodatkowe informacje na temat Browscap
Aby użyć
funkcji
get_browser()
należy ściągnąć z
W czasie pisania książki podejmowane były dodatkowe ulepszenia do istniejącej w sieci
plik
PHP funkcji get_browser(). Odkryłem, że plik browser.ini dostępny z firmy cyScape
browscap.ini,
(wspomnianej już wcześniej) wymaga kilku zmian aby działał z PHP 4.0 z poprawką 2. który
jest
Pierwszą z nich jest dodanie pustej linii na końcu pliku. Bez dodatkowego znaku końca linii dostępny z wielu
w trakcie uruchamiania PHP generowany jest błąd składni.
witryn w Sieci.
Drugim, o wiele bardziej skomplikowany problem jest związany z samą struktura W czasie pisania
pliku. Typowo, plik browscap.ini jest zwykłym plikiem konfiguracyjnym w którym każda książki plik był
sekcja reprezentuje określoną przeglądarkę. Każda z sekcji odwołuje się do sekcji wyższego dostępny
bez
rzędu, więc zdefiniowana jest pewnego rodzaju struktura. Tym sposobem w sekcji opisującej żadnych opłat z
nową przeglądarkę zdefiniowane są tylko nowe możliwości a istniejące wcześniej znajdują
witryny
cię w opisie starszej przeglądarki. Problem wynika z tego, że w czasie odczytu pliku PHP http://www.cysca
konwertuje jego zawartość na małe litery. Konwersja ta powoduje, że PHP nie potrafi pe.com/browscap
odszukać nadrzędnej sekcji, ponieważ nie wszystkie nazwy zapisane są małymi literami. Aby .
Po
jego
rozwiązać ten problem wykonałem prosty skrypt konwertujący wszystkie linie pliku ściągnięciu
i
browscap.ini na małe litery:
zainstalowaniu w
<?php
serwerze WWW,
$aArray = file( "./browscap.ini" );
$aNewFile = fopen( "./browscap.ini", "w" );
należy zmienić
foreach( $aArray as $aLine )
plik
php.ini.
{
$aNewFile = strtolower( $aLine );
Odszukaj opcję
fputs( $aNewFile, $aNewLine );
konfiguracji
}
fclose ($aNewFile );
browscap i zmień
?>
na
pełną
Skutkiem ubocznym takiej zmiany jest to, że wszystkie wywołania funkcji ją
ścieżkę
do
pliku
get_browser() muszą zawierać wywołanie funkcji strtolower(). Jednak po wprowadzeniu
browscap.ini. Po
takich zmian funkcja get_browser() działa tak, jak się tego spodziewamy.
ponownym
uruchomieniu serwera WWW będzie można korzystać z danych zawartych w pliku. W czasie pisania książki plik
browscap.ini zawierał ponad 2100 różnych przeglądarek.
Wykorzystanie funkcji get_browser() wraz z plikiem browscap.ini upraszcza proces rozpoznawania
możliwości przeglądarki i rozszerza jego zakres. Na wydruku 9.2 pokazany jest przykład użycia funkcji
get_browser(). Tak jak opisane zostało we wskazówce „Dodatkowe informacje na temat Browscap” pierwszym
krokiem powinno być przekonwertowanie zawartości $HTTP_USER_AGENT na małe litery. Następnie, przy użyciu
metody udokumentowanej w http://www.php.net/, ciąg identyfikacyjny przeglądarki jest zmieniany do właściwej
Rozdział 9 – Niezależność od przeglądarki
106
postaci przed wywołaniem funkcji get_browser(). Do zamiany określenia języka (na przykład [en]) na gwiazdkę,
która występuje w pliku browscap.ini, używana jest funkcja eregi_replace().
Wydruk 9.2. Użycie funkcji get_browser()
<?php
function GetMassagedUA()
{
global $HTTP_USER_AGENT;
$aUserAgent = strtolower( $HTTP_USER_AGENT );
$aUserAgent = eregi_replace( "\[[a-z]{2,}\]", "*", $aUserAgent );
if ( strpos( $aUserAgent, '*' ) === False )
{
$aUserAgent .= '*';
}
return $aUserAgent;
}
?>
<html>
<head>
<title>Możliwości przeglądarki</title>
</head>
<body>
<h1>Możliwości przeglądarki</h1>
<?php
$aUserAgent = GetMassagedUA();
print( "<h2>$aUserAgent</h2>" );
$array = (array) get_browser( $aUserAgent );
if ( count( $array ) > 1 )
{
while ( list( $key, $value ) = each ($array) )
{
$aValue = stripslashes( $value );
echo ("<b>$key=</b> $aValue<br>");
}
}
else
{
print( "<i>brak danych przeglądarki</i><br>" );
}
?>
</body>
</html>
Na rysunku 9.2. w przeglądarce Netscape 4.7.
107
PHP – Kompendium wiedzy
Rysunek 9.2. Wynik
działania skryptu z
wydruku 9.1
wykonywanego w
przeglądarce
Netscape 4.7
Lista dostępnych możliwości pokazuje potęgę funkcji get_browser(). W kodzie zamieszczonym na
wydruku 9.2, wszystkie możliwości są wyświetlane poprzez rzutowanie zwracanego obiektu na tablicę i
przeglądanie kolejnych par klucz-wartość. Można również sprawdzić kolejno każdą z możliwości korzystając
bezpośrednio z obiektu i używając zapisu $obiekt->możliwość. Na wydruku 9.3 pokazujemy przykład
sprawdzenia, czy przeglądarka obsługuje ramki.
Wydruk 9.3. Użycie get_browser() do sprawdzenia obsługi ramek
<?php
function GetMassagedUA()
{
global $HTTP_USER_AGENT;
$aUserAgent = strtolower( $HTTP_USER_AGENT );
$aUserAgent = eregi_replace( "\[[a-z]{2,}\]", "*", $aUserAgent );
if ( strpos( $aUserAgent, '*' ) === False )
{
$aUserAgent .= '*';
}
return $aUserAgent;
}
?>
<html>
<head>
<title>Obsługa ramek?</title>
</head>
<body>
<?php
$aUserAgent = GetMassagedUA();
print( "<h2>$aUserAgent</h2>" );
$aBrowsCap = get_browser( $aUserAgent );
if ( $aBrowsCap->frames == 1 )
{
print( "Przeglądarka obsługuje ramki<br>" );
}
else
{
print( "Przeglądarka nie obsługuje ramek<br>" );
Rozdział 9 – Niezależność od przeglądarki
108
}
?>
</body>
</html>
Funkcja get_browser() dostarcza dużo informacji i jest dobra na początek, gdy aplikacja wymaga
rozpoznania typu przeglądarki w czasie pracy. Jednak posiada ona kilka znaczących ograniczeń. Jak
wspomniałem wcześniej, użycie pliku browscap.ini, dostępnego w Internecie, również niesie ze sobą kłopoty.
Pewność działania funkcji wymaga, aby plik browscap.ini był często uaktualniany, aby podążać za zmianami w
najnowszych dostępnych przeglądarkach. Na przykład nasz plik browscap.ini nie pozwalał na prawidłowe
rozpoznanie przeglądarek Internet Explorer 5.5 i Opera 4.02. Problem tkwi w tym, że uaktualnienie i rozesłanie
pliku browscap.ini wymaga sporo czasu. Jeżeli twoja aplikacja wymaga dokładnego wykrywania możliwości
bieżącej przeglądarki, w następnej części opisane zostanie narzędzie jednej z firm, które świetnie spełnia swoje
zadanie.
BrowserHawk
Komponent BrowserHawk®, dostępny z firmy cyScape jest świetnym narzędziem do wykrywania
możliwości serwera. Jest on dostępny w formie obiektu COM, jeżeli wykorzystujesz serwer z Windows, lub jako
Java bean dla innych platform. Obsługa języka Java jest dostępna w PHP4, ale nie jest domyślnie włączona. Aby
wykorzystać Java bean, lub inny kod Java na serwerze, PHP musi być przekompilowane z opcją konfiguracji -with-java. Niezbędne jest również zainstalowanie maszyny wirtualnej Java (JVM) na serwerze. Wiele dystrybucji
Linuksa zawiera JVM i w wielu przypadkach pakiet ten jest instalowany automatycznie.
Dodatkowo komponent BrowserHawk wymaga kilku dodatkowych modułów. Jednym z nich jest Simple
API for XML (SAX) dostępny pod adresem http://www.megginson.com/SAX/. Wymagane moduły servletów
można znaleźć we wielu miejscach, w tym w najnowszych JVM pochodzących od różnych dostawców. Potrzebny
będzie na przykład dostęp do klasy javax.servlet.http.HttpServlet.
Po ściągnięciu i zainstalowaniu wymaganych klas Javy, należy skonfigurować PHP, aby mógł skorzystać
z BrowserHawk. Taj jak w przypadku każdej innej klasy Java należy podać położenie pliku z klasami Javy
korzystając ze zmiennej java.class.path w pliku php.ini. Poniżej znajduje się przykład:
java.class.path=/usr/share/kaffe/Klasses.jar:/homeblake/php4.0.1pl2/ext/java/php_java.jar:/home/blake/bhawk/
lib/bhawk4j.jar:/home/blake/java/sax2.jar:/home/blake/java/servlet.jar:/home/blake/bhawk:
Zapis taki wskazuje, że klasy wymagane przez BrowserHawk są dostępne dla PHP w katalogach
../bhawk4j.jar, ../sax2.jar i ../servlet.jar. Wpisana jest tutaj również ścieżka bez określenia pliku
(/home/blake/bhawk), która określa położenie plików licencyjnych i danych pakietu BrowserHawk. Ścieżka ta
powinna wskazywać na katalog, w którym został zainstalowany BrowserHawk.
Po ustawieniu wszystkich tych elementów konfiguracji i przekompilowaniu PHP z obsługą Javy, należy
sprawdzić konfigurację za pomocą funkcji phpinfo(). Wywołanie funkcji phpinfo() powoduje wyświetlenie
dużej ilości danych w postaci tabel HTML. Na wydruku 9.3. pokazana jest ta część informacji, która wskazuje na
dostępność Javy.
Rysunek 9.3.
Wynik działania
funkcji phpinfo()
pokazujący
dostępność Javy
109
PHP – Kompendium wiedzy
Po skonfigurowaniu obsługi Javy i BrowserHawk w PHP, wykorzystanie komponentów BrowserHawk
jest łatwe. Na wydruku 9.4 znajduje się kod, który pokazuje w jaki sposób stworzyć obiekt BrowserHawk i
wykorzystać go do odczytania kilku podstawowych danych o przeglądarce.
Wydruk 9.4. Przykład wykorzystania BrowserHawk
<html>
<head>
<title>Przykład wykorzystania BrowserHawk</title>
</head>
<body>
<h1>Przykład wykorzystania BrowserHawk</h1>
<?php
print( "<h2>$HTTP_USER_AGENT</h2>" );
$aBrowserHawk = new Java( "com.cyscape.browserhawk.BrowserHawk" );
$aBrowserInfo = $aBrowserHawk->getBrowserInfo( "$HTTP_USER_AGENT" );
// Czy przeglądarka obsługuje ActiveX?
if ( $aBrowserInfo->getActiveXControls() == True )
{
print( "Przeglądarka obsługuje kontrolki ActiveX<br>" );
}
else
{
print( "Przeglądarka nie obsługuje kontrolek ActiveX<br>" );
}
?>
</body>
</html>
Na wydruku 9.4 pokazujemy w jaki sposób można sprawdzić obsługę ActiveX i tak samo łatwo można
sprawdzić każdą z właściwości BrowserHawk. W tabeli 9.1. zamieszczone są metody odczytujące informacje na
temat możliwości przeglądarki dostępne w BrowserHawk.
Typ
Metoda
Zastosowanie
Boolean
getActiveXControls()
Sprawdza, czy przeglądarka obsługuje
kontrolki ActiveX.
Boolean
getAOL()
Sprawdza, czy użytkownik witryny
korzysta z przeglądarki firmowanej przez
America Online (AOL) (na sieci AOL).
double
getAOLVersion()
Zwraca numer wersji przeglądarki
AOL.
int
getAuthenticodeUpdate()
Zwraca numer wersji Authenticode
obsługiwanego przez przeglądarkę.
Boolean
getBackgroundSounds()
Sprawdza, czy przeglądarka potrafi
odgrywać dźwięk w tle.
Boolean
getBeta()
Sprawdza, czy przeglądarka jest w
wersji beta.
java.lang.String
getBrowser()
Zwraca ogólną nazwę przeglądarki, na
przykład Netscape lub IE (Internet Explorer).
Boolean
getCDF()
Sprawdza, czy przegladarka obsługuje
Channel Definition Format (CDF) używany do
prenumerowania
zawartości
WWW
z
możliwością automatycznej aktualizacji.
Boolean
getCompressGZip()
Sprawdza, czy przeglądarka przyjmuje
dane w skompresowanym formacie GZip.
Boolean
getCookies()
Sprawdza, czy przeglądarka obsługuje
cookie.
Boolean
getCrawler()
Sprawdza, czy przeglądarka jest
szperaczem sieciowym lub innym programem
wykorzystywanym
do
indeksowania
zawartości witryny.
Boolean
getDHML()
Sprawdza, czy przeglądarka obsługuje
skrypty DHTML().
java.lang.String
getFileUpload()
Sprawdza, czy przeglądarka obsługuje
Rozdział 9 – Niezależność od przeglądarki
110
111
Boolean
getFontColor()
Boolean
getFontSize()
Boolean
getFrames()
java.lang.String
getFullversion()
Boolean
getGold()
Boolean
getHDML()
java.lang.String
getIPAddr()
Boolean
getJavaApplets()
Boolean
getJavaScript()
double
getJavaScriptVer()
java.lang.String
getLanguage()
int
getMajorver()
double
getMinorver()
java.lang.String
getMinorverlet()
Boolean
getMouseOver()
Boolean
getMSN()
java.lang.String
getOSDetails()
Boolean
getPDA()
java.lang.String
getPlatform()
Boolean
getPNG()
Boolean
getProxy()
Boolean
getSSL()
Boolean
getSSLActive()
java.lang.String
getSSLCipherSuite()
możliwość przesyłania plików do serwera
(przeglądarki zgodne z RFC 1867).
Sprawdza, czy przeglądarka potrafi
wyświetlać kolorowy tekst.
Sprawdza, czy przeglądarka potrafi
wyświetlać różne wielkości tekstu.
Sprawdza, czy przeglądarka obsługuje
ramki.
Zwraca kompletną wersje przeglądarki
zawierającą wyższą i niższą część numeru oraz
litery, o ile występują.
Sprawdza, czy jest to wersja Gold
przeglądarki Netscape Navigator.
Zwraca True, jeżeli obsługuje HDML
(poprzednik WAP).
Zwraca adres IP klienta.
Sprawdza, czy przeglądarka obsługuje
applety Java.
Sprawdza, czy przeglądarka obsługuje
JavaScript.
Zwraca numer wersji JavaScript
obsługiwanego przez przeglądarkę.
Zwraca wybrany przez użytkownika
język.
Zwraca wyższą część numeru wersji
przeglądarki.
Zwraca niższą część numeru wersji
przeglądarki.
Zwraca literę niższej części numeru
przeglądarki, o ile występuje.
Sprawdza, czy przeglądarka obsługuje
efekt JavaScript, mouseover.
Sprawdza, czy użytkownik korzysta z
sieci Microsoft Network (MSN).
Zwraca szczegóły na temat systemu
operacyjnego (OS) systemu użytkownika.
Zwraca True, jeżeli przeglądarką jest
urządzeniem PDA na przykład PalmPilot.
Zwraca bardziej ogólne dane (w
porównaniu do getOSDetails()) na temat
platformy użytkownika.
Sprawdza, czy przeglądarka obsługuje
format rysunków PNG (Potrable Network
Graphics).
Sprawdza, czy użytkownik jest
połączony poprzez serwer Proxy.
Sprawdza, czy przeglądarka obsługuje
protokół SSL (Secure Socket Layer).
Sprawdza, czy użytkownik jest
połączony poprzez aktywne połączenie SSL.
Zwraca zestaw szyfrowania SSL dla
bieżącej sesji. Dostępny jedynie w przypadku
PHP – Kompendium wiedzy
aktywnej sesji SSL.
Sprawdza wielkość klucza SSL
obsługiwaną przez przeglądarkę. Dostępne
jedynie w przypadku aktywnego połączenia
SSL.
Boolean
getStyleSheets()
Sprawdza, czy przeglądarka obsługuje
kaskadowe arkusze stylu (CSS).
Boolean
getTableBGColor()
Sprawdza, czy przeglądarka obsługuje
ustawianie kolorów dla poszczególnych
komórek tabeli HTML.
Boolean
getTableBGImage()
Sprawdza, czy przeglądarka obsługuje
ustawianie rysunków tła dla poszczególnych
komórek tabeli HTML.
Boolean
getTables()
Sprawdza, czy przeglądarka obsługuje
wyświetlanie tabel.
Boolean
getVBScript()
Sprawdza, czy przeglądarka obsługuje
VBScript.
double
getVersion()
Zwraca wersję przeglądarki.
int
getVersionpos()
Zwraca pozycję w numerze wersji
przeglądarki, który jest umieszczony w ciągu
identyfikacyjnym przeglądarki.
Boolean
getWAP()
Zwraca
True
dla
urządzeń
obsługujących WML i WAP (Wireles
Application Protocol), na przykład telefony
komórkowe z WAP.
java.lang.String
getWAPDeviceModel()
Zwraca model urządzenia WAP, o ile
jest znany.
java.lang.String
getWAPGateway()
Zwraca szczegóły bramy UP.Link, o ile
jest wykorzystywana.
int
getWAPMaxDeckSize()
Zawiera przybliżoną maksymalna ilość
bajtów, jaką może obsłużyć urządzenie.
java.lang.String
getWAPSubscriberID()
Automatycznie
ustawiany
na
identyfikator abonenta dla użytkownika WAP.
Boolean
getWin16()
Sprawdza, czy przeglądarka pracuje w
16 bitowym systemie operacyjnym Windows,
jak na przykład Windows 3.1.
Boolean
getXML()
Sprawdza, czy przeglądarka obsługuje
bezpośrednie wyświetlanie plików XML.
Jedyną wadą przy używaniu komponentu BrowserHawk jest to, że jest on zaprojektowany dla
użytkowników JSP, więc niektóre metody mogą nie być bezpośrednio dostępne poprzez PHP. Niektóre
zaawansowane funkcje raportujące nie mogą być wykorzystane, ponieważ opierają się na obiektach
specyficznych dla JSP. Mimo to, standardowe obiekty zwracają wystarczająco dużo danych dla większości
zastosowań i są stale aktualne dla najnowszych przeglądarek.
Przewagą użycia komponentu BrowserHawk nad innymi metodami opisanymi w tym rozdziale jest jego
dokładność i elastyczność. BrowserHawk uaktualnia swoją bazę danych w razie potrzeby. W dokumentacji
znajduje się informacja, że rozpoznaje on około 9 razy więcej przeglądarek, niż można to zrobić korzystając z
browscap. BrowserHawk jest również zaprojektowany, aby sprawdzał o wiele więcej własności przeglądarki, niż
jest to stosowane w innych metodach.
Jeżeli aplikacja opiera się na dostarczaniu danych specyficznych dla przeglądarki lub polega na bardzo
specyficznych własnościach przeglądarki, BrowserHawk zapewnia najlepsze rozpoznawanie przeglądarki.
Aplikacja będzie nadal działała prawidłowo, niezależnie od ciągłych zmian w technologiach przeglądarek.
int
getSSLKeySize()
Rozdział 9 – Niezależność od przeglądarki
112
Wykorzystanie danych o przeglądarce
Pierwszym zadaniem podczas tworzenia aplikacji niezależnej od przeglądarki jest rozpoznanie możliwości
przeglądarki użytkownika. O wiele ważniejszym krokiem jest zadecydowanie w jaki sposób zostaną
wykorzystane te dane. Tak jak w przypadku innych decyzji podejmowanych w czasie projektowania, zależy ona
od wymagań stawianych aplikacji. Niektóre możliwości przeglądarki i własności aplikacji, takie jak animowane
podpowiedzi, lub obsługa kaskadowych arkuszy stylów nie są krytyczne. Brak innych własności może całkowicie
zatrzymać aplikację, na przykład zdolność przeglądarki do nawiązania połączenia szyfrowanego SSL lub obsługa
wysyłania plików.
Projekt aplikacji powinien zawierać listę wymaganych własności przeglądarki i zapewniać elegancką
obsługę sytuacji, gdy nie można skorzystać z którejś z wymaganych własności. Na wydruku 9.5. zamieszczony
został przykład w jaki sposób można zrealizować elegancką obsługę braku wymaganej własności przeglądarki.
Dodatkowo, można spróbować warunkowo dostarczać niektórych elementów w zależności od zdolności
przeglądarki do ich wyświetlania. Na wydruku 9.6 pokazano przykład takiego działania.
Wydruk 9.5. Eleganckie zakończenie aplikacji w przypadku braku obsługi przesyłania plików
<?php
$aBrowserHawk = new Java( "com.cyscape.browserhawk.BrowserHawk" );
$aBrowserInfo = $aBrowserHawk->getBrowserInfo( "$HTTP_USER_AGENT" );
?>
<html>
<head>
<title>Wysyłanie pliku</title>
</head>
<body>
<h1>Wysyłanie pliku</h1>
<form action="someurl.phtml" method="post" enctype="multipart/form-data">
<?php
if ( $aBrowserInfo->getFileUpload() == True ) {
?>
<input type="file" name="File"><br><br>
<input type="submit" name="Submit" value="Wyślij">
<?php
} else {
?>
Przeglądarka nie obsługuje wysyłania plików.<br><br>
proszę przesłać pliki pocztą na adres [email protected].
<?php
}
?>
</form>
</body>
</html>
Jeżeli przeglądarka posiada obsługę wysyłania plików, skrypt ten wyświetla formularz wysyłania pliku.
Jeżeli przeglądarka nie obsługuje tej funkcji, wyświetlany jest napis informujący użytkownika o możliwości
przesłania pliku za pomocą poczty elektronicznej. W rzeczywistości mechanizm taki jest niezbędny, aby
użytkownicy aplikacji uważali ją za przyjazną. Wybierając taki mechanizm należy zwrócić uwagę, aby
użytkownicy mogli zrozumieć dlaczego wykonanie operacji się nie powiodło. Większość ludzi nie chce widzieć
komunikatów typu „Twoja przeglądarka nie obsługuje RFC 1867”. Jeżeli aplikacja może działać pomimo tego, że
operacja się nie udała, nie wyświetlaj ponownie tego komunikatu. Należy po prostu zapewnić możliwie
największą dostępną ilość funkcji.
Wydruk 9.6. Warunkowe dostarczanie treści w zależności od możliwości przeglądarki
<?php
$aBrowserHawk = new Java( "com.cyscape.browserhawk.BrowserHawk" );
$aBrowserInfo = $aBrowserHawk->getBrowserInfo( "$HTTP_USER_AGENT" );
if ( $aBrowserInfo->getPNG() == True )
{
$aImage = "Logo.png";
}
else
{
$aImage = "Logo.gif";
}
?>
<html>
<head>
<title>Nasze logo</title>
</head>
<body>
<h1>Nasze logo</h1>
113
PHP – Kompendium wiedzy
<img src="<?=$aImage?>" width="180" height="70" alt="" border="0">
</body>
</html>
Skrypt ten wyświetla grafikę w formacie PNG jeżeli przeglądarka potrafi wyświetlić ten format, w
przeciwnym wypadku wysyłany jest rysunek w formacie GIF. Przykład ten jest prosty, ale ilustruje podstawową
zasadę działania. Zamiast wykorzystywać zmienne do wysyłania różnych danych, aplikacja może skorzystać z
informacji o możliwościach przeglądarki do wyświetlenia całkowicie innej sekcji witryny. Na przykład można
stworzyć witrynę zoptymalizowaną dla oglądania jej przez przeglądarki WebTV. Systemy takie mają zwykle
ograniczoną wielkość ekranu i zwykle mniej możliwości wyświetlania różnych czcionek. Dlatego trzeba inaczej
projektować taką witrynę aby poprawić widoczność wszystkich elementów. Poniższy kod jest prostym
przykładem sposobu implementacji takiego przypadku. Zakładamy, że jest to główna strona witryny.
<?php
$aBrowserHawk = new Java( "com.cyscape.browserhawk.BrowserHawk" );
$aBrowserInfo = $aBrowserHawk->getBrowserInfo( "$HTTP_USER_AGENT" );
if ( $aBrowserInfo->getBrowser() == "WebTV" )
{
// Przeglądarka WebTV, przekierowanie do stron zoptymalizowanych dla WebTV
header( "Location: http://mysite.com/webtv/\n" );
}
else
{
// To nie jest przeglądarka WebTV, przekierowanie do standardowych stron
header( "Location: http://mysite.com/main/\n" );
}
?>
W przykładzie tym, użytkownicy przeglądarek WebTV są kierowani na odpowiednio zoptymalizowane
strony. Inni użytkownicy są kierowani do zwykłego zestawu stron przeznaczonych dla innych typów
przeglądarek. Przykład ten może być rozszerzony, aby wykrywał przeglądarki działające na komputerach typu
PDA lub inne specyficzne typy przeglądarek.
Wadą takiego rozwiązania jest to, że jeżeli użytkownik wyśle znajomemu łącze do strony przeznaczonej
dla innej przeglądarki niż używa ten znajomy, wygląd strony nie będzie odpowiedni dla bieżącego typu
przeglądarki. Dodatkowo mechanizm ten wymaga, aby każda strona posiadała kilka równoległych stron
przeznaczonych dla odpowiednich typów przeglądarek. Wprowadzenie takiego projektu jest nieporęczne dla
dużych witryn. Lepszym rozwiązaniem przy tworzeniu stron specyficznych dla przeglądarki jest wyłączenie
kluczowych różniących się elementów i umieszczenie ich w osobnych plikach dla każdego typu przeglądarki.
Tego typu mechanizm może być zaimplementowany przy użyciu systemu szablonów, które będą opisane w
rozdziałach 13 i 14. Tam też przytoczymy przykłady implementacji takiego scenariusza.
Podsumowanie
Wykrywanie możliwości przeglądarki może być niezmiernie ważne dla wielu aplikacji WWW. W czasie
projektowania aplikacji należy poznać ograniczenia różnych przeglądarek, zanim zatwierdzimy realizację
specyficznych funkcji. Następnie, w oparciu o wymagania projektu należy wykorzystać narzędzia do wykrywania
przeglądarki i włączania niektórych funkcji. Należy unikać sytuacji, gdy przeglądarka wyświetla niezrozumiały
komunikat błędu w przypadku, gdy funkcja jest niedostępna. Należy dążyć do zapewnienia zestawu funkcji
niezależnych od używanego typu przeglądarki.
Rozdział 9 – Niezależność od przeglądarki
114
Rozdział 10. Uruchamianie
Wstęp
Uruchamianie aplikacji WWW jest równie krytycznym procesem jak uruchamianie innych typów
aplikacji. Problemem jest to, że może być trudno zdalnie uruchamiać program, szczególnie gdy nie masz
odpowiednich uprawnień do administracji serwerem WWW. W tym rozdziale zaprezentowane zostaną porady i
narzędzia, które mogą usprawnić uruchamianie aplikacji. Dodatkowo, niektóre części rozdziału są
przypomnieniem zasad inżynierii programowania, ponieważ można uniknąć ogromnej pracy przy uruchamianiu
aplikacji, jeżeli jej projekt jest odpowiednio przygotowany.
Z powodu ogromnego zainteresowania jakie wzbudziło programowanie aplikacji WWW, powstało wiele
narzędzi (między innymi PHP) do tworzenia takich aplikacji. Narzędzia te zostały stworzone na podstawie
istniejących już narzędzi, na przykład ASP i JSP, inne natomiast zostały stworzone jedynie w celu tworzenia
interaktywnych aplikacji WWW. Niespodziewanie, narzędzia spełniające zasady inżynierii programowania są tu
w mniejszości. Prawdopodobnie brak ten jest spowodowany potrzebą zaistnienia na rynku jako pierwsze
narzędzie lub z faktu, że pierwszymi projektantami nowej technologii nie byli bardziej zaawansowani
programiści. Niezależnie od powodu, do tego nowego środowiska programowania należy zaadaptować wszystkie
istniejące zasady inżynierii programowania. Pierwsza część rozdziału zawiera przypomnienie zasad inżynierii
programowania. Jest ona dołączona do tego rozdziału, ponieważ zbyt dużo czasu spędzonego przy uruchamianiu
jest zwykle powodowane błędami przy tworzeniu projektu.
Inżynieria programowania a uruchamianie
W rozdziale 3 „Formularze i cookie” doszliśmy do wniosku, że można uniknąć sprawdzania poprawności
niektórych danych w przypadku zastosowania lepszego mechanizmu wprowadzania danych. Tak samo, pisanie
lepszego (bardziej defensywnego) kodu powoduje ogromne zmniejszenie czasu straconego w czasie
uruchamiania.
Projekt aplikacji WWW musi być tak samo dokładnie przemyślany, jak projekt każdej innej aplikacji.
Tworzenie świetnej aplikacji wymaga właściwego projektu, zgodności z standardami tworzenia oprogramowania,
sprawdzania oprogramowania, testowania modułów oraz uruchamiania. Uruchamianie jest koniecznie ostatnie na
tej liście, ponieważ zakłada się, że kod przeszedł wszystkie wcześniejsze wymagane kroki. Kolejne części
zawierają przegląd każdego z tych kroków i zakładają, że posiadasz pewną wiedzę inżynierii programowania.
Projekt aplikacji
Identyfikacja wstępnych założeń aplikacji przed napisaniem jakiegokolwiek kodu jest krytyczna w
przypadku każdego projektu. W dużych projektach takie planowanie może zająć tygodnie lub miesiące. W
małych projektach mogą zostać zapisane na skrawku papieru w przeciągu kilku minut. W każdym z tych
przypadków kluczowe jest przemyślenie wymagań aplikacji, oraz wymyślenie możliwie wielu możliwych
rozwiązań przed rozpoczęciem pisania kodu. Dane z firm TRW i IBM wskazują, że wprowadzenie zmian do
aplikacji w początkowym okresie programowania (przed fazą programowania) jest 10 do 200 razy tańsze niż
wprowadzanie tych samych zmian na końcu tego procesu (McConnell, 1993).
W zależności od projektu, identyfikacja wymaganych funkcji aplikacji może wymagać wykonania sporej
pracy. Wstępny podział aplikacji na moduły może uprościć ten proces. W aplikacji WWW modułami takimi
mogą być współpraca z bazą danych, autoryzacja użytkownika, obsługa stanu, id. Po zdefiniowaniu zadań
poszczególnych modułów należy w razie potrzeby podzielić je na mniejsze fragmenty i zapisać przeznaczenie
każdego fragmentu. W małych aplikacjach dobrą strategią jest podział modułów na pliki kodu bądź klasy
obiektowe.
Oprócz zdefiniowania wymagań funkcjonalnych aplikacji, należy rozważyć architekturę systemu. Należy
tu pomyśleć o rodzaju stosowanego systemu zarządzania relacyjną bazą danych (SZRBD) i innych mniej
oczywistych elementach, na przykład jak będą zorganizowane pliki kodu, jak radzić sobie ze zmianami, oraz czy
niektóre moduły należy zakupić, czy też pisać je od początku. Mimo, że PHP może działać na wielu serwerach
WWW i platformach systemowych, każda z takich kombinacji posiada indywidualne cechy. Należy poświęcić
nieco czasu na zdefiniowanie powodów, dla których należy wybrać określony sprzęt i serwer. Ilość funduszy
dostępnych na początku projektu rzadko jest dobrym powodem wyboru platformy. Wybór bazy danych jest
równie istotny, jeżeli aplikacja ma być wysoce dynamiczna. Dodatkowo należy pomyśleć, czy serwer WWW i
baza danych będą pracować na tym samym komputerze, czy osobno. W zależności od wielkości i charakteru
aplikacji, może być to krytyczne zagadnienie.
Następnie, należy zaprojektować organizację kodu. Zdefiniuj konwencję nazywania plików i katalogów,
co uprości identyfikację kodu. Wymyśl alternatywny plan na wypadek, gdy istnieje duże prawdopodobieństwo
zmian. Jeżeli przewidujesz występowanie zmian, napisz aplikację lokalizującą zmiany w kilku modułach a
buforującą resztę. Taki typ projektowania jest istotny szczególnie, gdy korzystasz przy tworzeniu aplikacji z
narzędzi pochodzących z innych źródeł lub oprogramowania w wersji beta. Tworzenie zastępników takiego kodu
jest łatwe do zaimplementowania i w dłuższym okresie czasu umożliwia łatwiejsze utrzymanie aplikacji.
Na koniec należy zadecydować, które moduły aplikacji zostaną stworzone przy pomocy gotowych
narzędzi pochodzących od zewnętrznych dostawców. Decyzja „tworzyć czy kupić” jest dosyć skomplikowana. W
zależności od harmonogramu projektu, możesz nie i mieć wystarczająco dużo czasu, aby dostatecznie
przetestować dostępne narzędzia. Jednak możesz również nie mieć wystarczająco dużo czasu na stworzenie ich
od początku. Aby zmniejszyć wpływ tej decyzji na projekt można stworzyć własne funkcje pośrednie ukrywające
implementację.
Właściwe zaprojektowanie aplikacji wymaga czasu. W przypadku dobrego systemu faza projektowania
zajmuje 20 do 30 procent czasu tworzenia systemu (McConnell, 1993). Trzeba pamiętać, że ten czas jest
zużywany na projektowanie wysokiego poziomu, do projektowania szczegółów implementacji również potrzebny
jest czas.
Definiowanie standardów programowania
Zdefiniowanie standardów programowania ułatwia długoterminowe utrzymanie projektów o dowolnej
wielkości. Nawet małe aplikacje programowane przez jednego programistę mogą korzystać z odpowiednio
stosowanego zbioru standardów programowania. Taki standard obejmuje sposoby nazywania, komentowania oraz
konwencje układu. Niektóre z nich, na przykład układ kodu, są mniej ważne, ponieważ nowoczesne edytory
potrafią przeformatować kod, jednak inne, jak na przykład konwencje nazw plików i katalogów mogą mieć
ogromne znaczenie przy konserwacji kodu2.
Przegląd oprogramowania
Przegląd oprogramowania dostarcza możliwości zrealizowania kilku celów za jednym razem. Na
przykład, przegląd oprogramowania pozwala na sprawdzenie kodu z standardami kodowania. Pozwalają również
mniej doświadczonym programistom na korzystanie z wiedzy bardziej doświadczonych kolegów. Są również
jednym z bardziej efektywnych metod zapewnienia odpowiedniej jakości oprogramowania. Analizy przeglądów
oprogramowania stosowanych przy tworzeniu prawdziwych aplikacji pokazały, że pozwalają na wykrywanie
błędów z prawdopodobieństwem pomiędzy 55 a 60%. Ten wynik należy zestawić z jedynie 25%
prawdopodobieństwem dla testowania modułów, 35% dla testowania funkcji oraz 45% dla testowania
integracyjnego. Dodatkowo, przeglądy takie zwiększają w dużych projektach ogólną wydajność zespołu. W
2
Przypis tłumacza. Z powodu luźnego traktowania typów w PHP szczególnie ważne wydaje się odpowiednie nazywanie zmiennych. Dobrym pomysłem
może być stosowanie tzw. notacji węgierskiej, gdzie nazwa zmiennej zaczyna się od liter określających jej typ, np.: nIlosc to zmienna przechowująca
liczby całkowite, sTytul zawiera ciąg znaków, a bIstnieje to zmienna logiczna.
Rozdział 10 – Uruchamianie
116
niektórych przypadkach powodują one 80 do 90% spadek awarii oraz 10 do 25% wzrostu wydajności
(McConnell, 1993). Przegląd powinien być przeprowadzany zarówno podczas testowania jak i podczas
implementacji. Przegląd projektu pozwala na identyfikację jego wad w momencie, gdy ich usuwanie jest
najprostsze i najtańsze.
Można wykorzystać kilka metod realizacji przeglądu. Niektóre z nich są formalną inspekcją kodu inne
przeglądem ogólnym lub czytaniem kodu. W przypadku formalnej inspekcji kodu, kilku członków zespołu zbiera
się razem w celu odszukania błędów. Prowadzący spotkanie prowadzi je do przodu i pilnuje, aby jedynym
tematem była identyfikacja błędów. Formalna inspekcja kodu nie powinna zawierać dyskusji na temat rozwiązań.
W przypadku przeglądu ogólnego grupa programistów nieformalnie dyskutuje na temat kodu zadając pytania.
Gdy zidentyfikowany zostanie błąd, mogą powstać sugestie na temat sposobu jego usunięcia, ale głównym celem
jest nadal jego identyfikacja. Czytanie kodu poświęcone jest jedynie dla kodu programu, a nie pracy grupowej.
Zwykle część kodu jest przekazywana dwóm lub więcej osobom, które niezależnie pracując identyfikują błędy.
Wynik ich pracy jest przekazywany autorowi kodu.
W zależności od rozmiaru i organizacji projektu użycie jednej z metod ma przewagę nad inną. Na
przykład w przypadku, gdy pracujesz sam lub w małym zespole, możesz skorzystać z zatrudnienia osoby, która
wykona taki przegląd metodą czytania kodu. Niezależnie od wybranej metody, przeprowadzenie przeglądu kodu
jest najbardziej efektywną metodą identyfikacji problemów w projekcie bądź implementacji.
Testowanie
Zwykle testowanie nie jest pomijane, ale często jest przeprowadzane przypadkowymi metodami. Tak jak
w przypadku innych projektów, testowanie aplikacji WWW powinno zawierać testowanie na różnych poziomach:
testowanie funkcji, testowanie modułów oraz testowanie integracyjne. Testowanie każdego modułu powinno być
odpowiednio zaplanowane. Z testami związany jest określony zbiór oczekiwań i wymagań.
W małych projektach testowanie może wymagać jedynie wymyślenia kilku prostych przypadków użycia
aplikacji a następnie sprawdzenie każdego przypadku. Większe projekty mogą zawierać ludzi, którzy zajmują się
jedynie testowaniem, ale każdy z programistów powinien być odpowiedzialny za dostarczenie testerom
dostatecznie dużo danych, aby ich praca była efektywna. Każdy twórca kodu powinien również być
odpowiedzialny za testowanie swoich modułów na poziomie funkcji lub strony.
Uruchamianie
Uruchamianie jest ostatnim etapem w procesie tworzenia aplikacji, ponieważ w momencie, gdy następuje
uruchamianie powinny być ukończone procesy projektowania, programowania i część testowania. Uruchamianie
może być przeprowadzane w trakcie każdej z fazie testowania jako część tego procesu. Wszystkie zmiany
wprowadzone do kodu w trakcie procesu uruchamiania powinny zostać ponownie przetestowane na wszystkich
poziomach testowania, ponieważ zmiany mogły wprowadzić nowe błędy.
Uruchamianie powinno być gruntownym procesem przeznaczonym do identyfikacji źródła problemu. Nie
powinno być prostym łataniem, które naprawi błędne przypadki, ale nie zapewni trwałego rozwiązania. Każdy,
kto bierze udział w testowaniu powinien znać źródło problemu w momencie, gdy stwierdza się usunięcie
problemu. Znalezienie źródła problemu powoduje stworzenie kompletnego rozwiązania zamiast obchodzenia
problemu. W zależności od natury problemu, czasami czasowe rozwiązania mogą być wystarczające, ale muszą
zostać odpowiednio udokumentowane. Rozwiązywanie problemów powinno brać pod uwagę priorytety.
W tej książce prawdopodobnie nie zostanie opisane wszystko na temat prawidłowej inżynierii
programowania. Najważniejsze jest, aby pamiętać, że inżynieria programowania jest równie ważna w aplikacjach
WWW jak w pozostałych aplikacjach oraz o tym, ze właściwe stosowanie zasad inżynierii może ograniczyć
nakład pracy wymagany przy uruchamianiu. Następna część zawiera opis kilku technik i narzędzi specyficznych
dla aplikacji PHP.
117
PHP – Kompendium wiedzy
Programowanie defensywne
Zanim zaczniesz uruchamiać program, powinieneś podjąć kroki, prowadzące do napisania kodu
zawierającego dużo mniej błędów. Taki sposób programowania jest nazywany programowaniem defensywnym.
Takie programowanie polega na odpowiednim komentowaniu błędów, wewnętrznym sprawdzaniu stanu procedur
w trakcie procesu programowania. Sposób komentowania jest indywidualny dla każdego programisty, ale
powinno być zgodne ze standardami. Jako minimum, programiści powinni opisywać przeznaczenie funkcji, klasy
lub dołączanego pliku oraz zawsze komentować niejasne fragmenty kodu.
Do sprawdzania stanu funkcji, PHP, tak jak wiele języków wysokiego poziomu, posiada funkcję assert().
Funkcja assert() oblicza wartość przekazanego parametru i podejmuje określone akcje w przypadku, gdy jego
wartość wynosi False. W PHP do funkcji assert() można przekazać zarówno ciąg jak i wartość Boolean. Jeżeli
przekazany został ciąg, jest on wykonywany jako blok kodu PHP. Opcje asercji w pliku php.ini (assert.active,
assert.warning, assert.bail, assert.callback i assert.quiet_eval) lub opcje przekazane jako parametr
wywołania funkcji assert_options() definiują akcję jaką podejmuje funkcja assert(). W tabeli 10.1
zamieszczone są różne opcje asercji.
Tabela 10.1. Opcje asercji i ich opis
Opis
Opcja
Domyślnie
assert_active
1
Włącza wykonywanie assert().
assert_warning
1
Wyświetla ostrzeżenie PHP przy
każdej nieudanej asercji.
assert_bail
0
Kończy wykonanie w przypadku
nieudanej asercji.
assert_quiet_eval
0
Wyłącza raportowanie błędów w
czasie obliczenia wyrażenia asercji.
assert_callback
(null)
Nazwa
funkcji
użytkownika
wykonywanej w przypadku nieudanej asercji.
Funkcja assert() jest zaprojektowana jedynie do wykorzystywania w czasie tworzenia programu i nie
powinna być używana w czasie normalnej pracy. Aplikacja powinna działać identycznie z wywołaniami funkcji
assert(), jak i bez nich. Na wydruku 10.1 pokazany został przykład użycia funkcji assert() do kontroli
poprawności parametrów wejściowych.
Wydruk 10.1. Użycie funkcji assert() do kontroli poprawności parametrów wejściowych
<?php
function ArrayAverage( $aArray )
{
$aTotal = 0;
// Apostrofy ozanczają ciąg nie interpretowany przez PHP
assert( 'is_array( $aArray )' );
foreach( $aArray as $aElement )
{
assert( 'is_numeric( $aElement )' );
$aTotal += $aElement;
}
return ( $aTotal / count( $aArray ) );
}
?>
Funkcja ArrayAverage() umieszczona na wydruku 10.1 spodziewa się jako parametru tablicy wartości
numerycznych (liczb lub ciągów zawierających liczby) i zwraca średnią z wartości w tablicy. Wyrażenie assert()
jest wykorzystywane do kontroli poprawności parametru przekazanego do funkcji a później do sprawdzania, czy
tablica zawiera wartości numeryczne. Należy zwrócić uwagę, że do assert() można przekazać ciąg, który jest
wykonywany jako kod PHP, więc jeżeli wykorzystywane są zmienne należy zapewnić, że PHP nie podstawi zbyt
wcześnie wartości zmiennej w miejsce jej nazwy. Aby tego uniknąć należy używać ciągów w apostrofach.
Testowy skrypt dla funkcji z wydruku 10.1 jest zamieszczony na wydruku 10.2.
Wydruk 10.2. Użycie funkcji ArrayAverage()
<?php
include( "./arrayfunc.php" );
?>
<html>
<head>
<title>Testowanie asercji</title>
</head>
<body>
Rozdział 10 – Uruchamianie
118
<?php
$aResult = ArrayAverage( array( 1, 2, 3, 4, 5 ) );
print( "ArrayAverage( array( 1, 2, 3, 4, 5 ) ) = $aResult<br>" );
$aResult = ArrayAverage( array( 10.1, "5.5", 3, "4", 5 ) );
print( "ArrayAverage( array( 10.1, \"5.5\", 3, \"4\", 5 ) ) = $aResult<br>" );
$aResult = ArrayAverage( array( 1, 2, "cat", 4, 5 ) );
print( "ArrayAverage( array( 1, 2, \"cat\", 4, 5 ) ) = $aResult<br>" );
$aResult = ArrayAverage( 1, 2 );
print( "ArrayAverage( 1, 2 ) = $aResult<br>" );
?>
</body>
</html>
Testowy skrypt wywołuje funkcję ArrayAverage() cztery razy. Pierwsze dwa razy przekazywane są
właściwe wartości, natomiast ostatnie dwa razy przekazane wartości są nieprawidłowe. Na rysunku 10.1.
pokazany jest wynik działania skryptu. Należy zauważyć, że ponieważ PHP wewnętrznie wymusza typy
zmiennych, powoduje to, że wywołanie ArrayAverage(array(1, 2, "cat", 4, 5)) udaje się bez żadnych
ostrzeżeń (poza generowanymi przez asercje).
Rysunek 10.1.
Testowanie funkcji
ArrayAverage()
Podejmowane przez funkcję assert() działania zależą od ustawień asercji. Poprzedni przykład
wyorzystywał domyślne ustawienia asercji. Przyjemną cechą asercji jest to, że gdy assert.active jest ustawione
na False, przestają one działać. Aby zmienić tą opcję należy albo wywołać funkcję assert_options(
ASSERT_ACTIVE, False) lub ustawić odpowiednio dyrektywę konfiguracji. Wykorzystując opcję konfiguracji
można instalować aplikację w środowisku z wyłączonymi asercjami a pracować na innym, gdzie asercje są
aktywne.
Istnieje jeszcze jedna funkcja pomagająca w programowaniu defensywnym, error_reporting(). Funkcja
ta jako argumentu wymaga liczby całkowitej określającej poziom raportowania błędów. Argument ten jest
traktowany jako maska bitowa, więc można podać zestaw kilku ustawień. PHP posada zestaw stałych używanych
razem z tą funkcją. Są one następujące:
Wartość
Nazwa
E_ERROR
1
E_WARNING
2
E_PARSE
4
E_NOTICE
8
E_CORE_ERROR
16
E_CORE_WARNING
32
E_COMPILE_ERROR
64
E_COMPILE_WARNING
128
E_USER_ERROR
256
E_USER_WARNING
512
119
PHP – Kompendium wiedzy
E_USER_NOTCE
1024
Dodatkowo istnieje również stała E_ALL, która uaktywnia wszystkie informacje o błędach. Tworząc
aplikację powinno się przestawić poziom raportowania błędów na E_ALL, co spowoduje wyświetlanie wszystkich
informacji o błędach w kodzie. Ustawienie to jest również ważne w trakcie dołączania do aplikacji zewnętrznej
biblioteki. Na wydruku 10.3 zamieszczony jest przykład kodu generujący ostrzeżenia w przypadku ustawienia
maksymalnego poziomu raportowania błędów. Przy standardowych ustawieniach skrypt nie powoduje
wyświetlenia żadnego komunikatu.
Wydruk 10.3. Przykład użycia funkcji error_reporting()
<html>
<head>
<title>Poziomy raportowania błędów</title>
</head>
<body>
<?php
$aArray = array( "state" => "Idaho", "county" => "Madison",
"city" => "Rexburg", "country" => "US" );
// standardowy poziom raportowania błędów
print( "aArray[state] = " . $aArray[state] . "<br>" );
error_reporting( E_ALL );
print( "aArray[state] = " . $aArray[state] . "<br>" );
?>
</body>
</html>
Na rysunku 10.2. pokazane są wyniki działania tego przykładu. Jak można zauważyć, ustawienie bardziej
restrykcyjnego poziomu raportowania błędów może spowodować wykrycie błędów w kodzie, które mogą
spowodować różne efekty uboczne w czasie tworzenia aplikacji. W tym przypadku problem może wydawać się
niewinny, ale jeżeli zdefiniujemy stałą o nazwie state reprezentującą stan działania aplikacji, problem przestanie
być niewinny. Na wydruku 10.4 pokazujemy skrypt z taką właśnie stałą. Wyniki jego działania są widoczne na
rysunku 10.3.
Wydruk 10.4. Drugi przykład użycia funkcji error_reporting() oraz stałej
<?php
// Stan działania aplikacji
define( state, 3 );
// Pozostały kod używający stałej state
?>
<html>
<head>
<title>Poziomy raportowania błędów</title>
</head>
<body>
<?php
$aArray = array( "state" => "Idaho", "county" => "Madison",
"city" => "Rexburg", "country" => "US" );
// domyślny poziom raportowania
print( "aArray[state] = " . $aArray[state] . "<br>" );
error_reporting( E_ALL );
print( "aArray[state] = " . $aArray[state] . "<br>" );
?>
</body>
</html>
Rysunek 10.2.
Wynik działania
skryptu
error_reporting()
Rozdział 10 – Uruchamianie
120
Rysunek 10.3.
Wynik działania
drugiego skryptu
error_reporting()
W obu przykładach, gdy poziom raportowania błędów był ustawiony na standardowy poziom, nie były
generowane żadne ostrzeżenia i program wykonywał się nieomal bezbłędnie. Jednak po dodaniu w drugim
przykładzie stałej, świetnie działający nagle przestał działać. Problem taki może być bardzo trudny do
odszukania, jeżeli stała taka byłaby zdefiniowana w dołączanym pliku. Przykład ten pokazuje zalety zastosowania
ustawienia poziomu raportowania błędów na maksimum. Wszystkie wyświetlane ostrzeżenia powinny zostać
zlikwidowane, aby uniknąć występowania błędów w przyszłości.
W zależności od twojego środowiska, możesz ustawić poziom raportowania błędów na maksymalny w
trakcie rozwijania aplikacji i na minimalny na serwerze produkcyjnym. Takie ustawienie powoduje, że w
przeglądarkach użytkowników nie pojawiają się ostrzeżenia i komunikaty błędów. Jednak osobiście uważam, że
najlepiej ustawić na serwerze produkcyjnym poziom raportowania na maksimum, ale skierować strumień błędów
do pliku dziennika. Można to zrealizować ustawiając zmienne konfiguracji display_errors, log_errors i
error_log na odpowiednio Off, On i stderr. Powoduje to, że PHP nie wyświetla błędów w przeglądarce a zamiast
tego kieruje wszystkie błędy do pliku stderr. Jeżeli używasz Apache, plikiem stderr dla Apache jest dziennik
błędów. Jeżeli chcesz, możesz skorzystać z innej lokalizacji dziennika.
Gdy zostanie wykonany skrypt z wydruku 10.3 po skonfigurowaniu PGP w sposób wspomniany powyżej,
na ekranie nie pojawią się ostrzeżenia, a w pliku dziennika błędów Apache znajdą się następujące pozycje:
[06-Dec-2001 20:53:22] PHP Warning: Undefined offset: 3 in c:\helion\php4devguide\site\ch10\error_reporting_2.phtml on line 17
[06-Dec-2001 20:54:03] PHP Warning: Use of undefined constant state - assumed 'state' in c:\helion\php4devguide\site\ch10\error_reporting.phtml on line 12
[06-Dec-2001 20:54:45] PHP Warning: Use of undefined constant state - assumed 'state' in c:\helion\php4devguide\site\ch10\error_reporting.phtml on line 12
[06-Dec-2001 20:54:49] PHP Warning: Undefined offset: 3 in c:\helion\php4devguide\site\ch10\error_reporting_2.phtml on line 17
[06-Dec-2001 20:54:51] PHP Warning: Undefined offset: 3 in c:\helion\php4devguide\site\ch10\error_reporting_2.phtml on line 17
[06-Dec-2001 20:54:53] PHP Warning: Use of undefined constant state - assumed 'state' in c:\helion\php4devguide\site\ch10\error_reporting.phtml on line 12
Następnym krokiem podczas programowania defensywnego może być napisanie własnego mechanizmu
rejestrującego. W dowolnych miejscach aplikacji możesz sprawdzać stan niektórych funkcji lub raportować błędy
wewnętrzne i kontynuować pracę. PHP posiada funkcję error_log() przy pomocy której można dodawać własne
zapisy do pliku śladu aplikacji. Prototyp funkcji error_log() wygląda następująco:
int error_log(string komunikat, int typ [, string cel [, string naglowki]])
Pierwszy parametr, komunikat, zawiera zapisywane dane. Drugi z parametrów określa gdzie zostanie
zapisany komunikat. Lista prawidłowych wartości parametru typ znajduje się w tabeli 10.2.
Tabela 10.2. Wartości parametru typ
Wartość
Opis
0
Parametr komunikat jest wysyłany do systemowego mechanizmu
rejestrowania PHP przy użyciu mechanizmu rejestrowania
zapewnianego przez system operacyjny lub pliku — w zależności od
ustawienia zmiennej konfiguracji error_log.
1
Komunikat jest wysyłany pocztą elektroniczną na adres podany
w parametrze cel. Jedynie ten typ zapisu wykorzystuje parametr
naglowki. Do obsługi tego typu komunikatu wykorzystywana jest ta
sama funkcja wewnętrzna, co w funkcji mail().
PHP – Kompendium wiedzy
121
2
Komunikat jest wysyłany poprzez połączenie PHP używane do
uruchamiania zdalnego. Opcja ta jest dostępna jedynie w przypadku,
gdy włączone jest uruchamianie zdalne. W tym przypadku parametr cel
określa nazwę komputera lub adres IP oraz opcjonalnie numer portu
używanego do odbierania informacji uruchamiania.
3
Komunikat jest dołączany na koniec pliku o nazwie cel.
W czasie pisania książki typ 2 nie był dostępny. Kod źródłowy zawierał komentarz informujący, że zdalne
uruchamianie nie jest jeszcze dostępne. Inne typy komunikatów działają w sposób opisany w tabeli. Na wydruku
10.5 pokazany jest przykład użycia funkcji error_log().
Wydruk 10.5. Użycie funkcji error_log()
<html>
<head>
<title>Rejestrowanie błędów</title>
</head>
<body>
<?php
// Zapisanie błędu do dziennika systemowego
error_log( "MÓJ BŁĄD: wystąpił błąd!", 0 );
// Wysłanie błędu przez e-mail
error_log( "MÓJ BŁĄD: wystąpił błąd!", 1, "[email protected]",
"From: [email protected]\r\n" );
// Zapisanie błędu w pliku śladu aplikacji
error_log( "MÓJ BŁĄD: wystąpił błąd!", 3, "/tmp/error.log" );
?>
Wystąpiły błędy.
</body>
</html>
Pierwsze wywołanie funkcji error_log() zapisuje komunikat błędu w systemowym dzienniku błędów. W
tym przykładzie błąd ten wysyłany do dziennika błędów Apache. Drugie wywołanie skutkuje wysłaniem poczty
elektronicznej do odbiorcy określonego w parametrze cel. Informacje zawarte w dodatkowych nagłówkach są
utworzone przy użyciu tych samych zasad, co w przypadku funkcji mail(). Ostatnie wywołanie powoduje
dodanie komunikatu błędu do pliku, w tym przypadku /tmp/error.log.
Wykorzystanie tego mechanizmu nie jest w dosłownym znaczeniu uruchamianiem, ale jego zastosowanie
może zaoszczędzić czas spędzony przy właściwym uruchamianiu, powodując eliminację niektórych błędów i
przeoczeń już w fazie programowania. Jak wcześniej wspomniałem, unikanie uruchamiania programu poprzez
tworzenie poprawnego kodu jest o wiele cenniejsze od najlepszych narzędzi używanych przy uruchamianiu.
Własna obsługa błędów
Tak jak prawie każdy element PHP mechanizm obsługi błędów możesz dostosować do własnych potrzeb,
aby spełniał wymagania stawiane przez aplikację. Jak pokazane zostało na końcu poprzedniego przykładu,
funkcja error_log() pozwala na skonstruowanie prostego mechanizmu rejestrowania własnych błędów
występujących w aplikacji, ale nie pozwala na obsługę błędów generowanych przez PHP. Nie pozwala również
na przechwytywanie komunikatów generowanych przez funkcje assert(). Na szczęście PHP pozwala w inny
sposób obsługiwać takie przypadki.
Funkcja set_error_handler() pozwala zarejestrować funkcję w PHP, która będzie wywoływana za
każdym razem, gdy wygenerowany zostanie komunikat błędu. Funkcja set_error_handler() wymaga podania
jednego argumentu — nazwy funkcji obsługi błędów. Prototyp takiej funkcji wygląda następująco:
function ErrorCallBack( int nr_bledu, string ciag_bledu, string nazwa_skryptu,
int nr_lini, array kontekst)
Na wydruku 10.6 zamieszczony jest przykład sposobu rejestrowania i użycia funkcji obsługi błędów.
Wydruk 10.6. Wykorzystanie set_error_handler()
<?php
function myErrorHandler( $aErrorNo, $aErrorStr, $aFile, $aLine, $aContext)
{
switch ( $aErrorNo )
{
case E_ERROR:
$aErrorType = "E_ERROR"; // nie powinien wystąpić
break;
case E_WARNING:
$aErrorType = "E_WARNING";
Rozdział 10 – Uruchamianie
122
break;
case E_PARSE:
$aErrorType = "E_PARSE"; // nie powinien wystąpić
break;
case E_NOTICE:
$aErrorType = "E_NOTICE";
break;
case E_CORE_ERROR:
$aErrorType = "E_CORE_ERROR"; // nie powinien wystąpić
break;
case E_CORE_WARNING:
$aErrorType = "E_CORE_WARNING"; // nie powinien wystąpić
break;
case E_COMPILE_ERROR:
$aErrorType = "E_COMPILE_ERROR"; // nie powinien wystąpić
break;
case E_COMPILE_WARNING:
$aErrorType = "E_COMPILE_WARNING"; // nie powinien wystąpić
break;
case E_USER_ERROR:
$aErrorType = "E_USER_ERROR";
break;
case E_USER_WARNING:
$aErrorType = "E_USER_WARNING";
break;
case E_USER_NOTICE:
$aErrorType = "E_USER_NOTICE";
break;
default:
$aErrorType = "UNKNOWN ERROR TYPE";
break;
}
print(
print(
print(
print(
"<table border=\"1\"><tr><td>" );
"<b>$aErrorType</b>: <i>$aErrorStr</i><br>" );
"w pliku $aFile linia $aLine<br>" );
"</td></tr></table>" );
}
set_error_handler( "myErrorHandler" );
error_reporting( E_ALL );
?>
<html>
<head>
<title>Własna obsługa błędów</title>
</head>
<body>
<?php
trigger_error( "Test błędów", E_USER_ERROR );
$aArray = array( "state" => "Idaho", "county" => "Madison",
"city" => "Rexburg", "country" => "US" );
print( "aArray[state] = " . $aArray[state] . "<br>" );
?>
</body>
</html>
W skrypcie na wydruku 10.6 została zdefiniowana funkcja obsługi błędów myErrorHandler(), która
wyświetla komunikaty błędów w obramowanej tabeli zawierającej jedną komórkę, co pomaga w odróżnieniu
komunikatu błędu od reszty kodu HTML. Po zainstalowaniu funkcji obsługi, skrypt powoduje dwa błędy.
Pierwszy jest generowany przy użyciu funkcji PHP trigger_error(). Drugi błąd (ostrzeżenie) jest identyczny jak
błąd pokazany na wydruku 10.3. Na rysunku 10.4. pokazany został wynik działania skryptu.
Rysunek 10.4.
Działanie funkcji
set_error_handler()
123
PHP – Kompendium wiedzy
Używając funkcji set_error_handler() należy pamiętać, że PHP nie przekazuje do funkcji obsługi błędów
typu E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR oraz E_COMPILE_WARNING. Obsługa tego
typu błędów przez użytkownika nie jest bezpieczna. Z tego powodu w kodzie funkcji obsługi błędów z wydruku
10.6. pojawiły się komentarze „nie powinien wystąpić”.
Uwaga na temat set_error_handler()
Funkcja set_error_handler() jest dostępna w PHP od wersji 4.0.1. Dodatkowo, funkcja użyta w tym przykładzie posiada pięć
parametrów, w tym nazwę skryptu, numer linii i dane kontekstu. Parametry te są dostępne dopiero w wersji 4.0.2. Wcześniejsze
wersje miały tylko dwa parametry: typ komunikatu i komunikat.
W skrypcie z wydruku 10.6 nie są wykorzystane dane na temat kontekstu. Będą one opisane w następnej
części rozdziału. Dane te zawierają nazwy i wartości zmiennych istniejących w skrypcie w momencie wystąpienia
błędu.
Również funkcja assert() pozwala na zdefiniowanie wywoływanej funkcji. Aby to zrealizować należy
skorzystać z funkcji assert_options(). Funkcja obsługująca nieudane asercje jest zdefiniowana w następujący
sposób:
function AssertCallback ($NazwaPliku, $NrLinii, $Asercja )
Uwaga na temat assert_options()
W PHP do wersji 4.0.2 włącznie, w funkcji assert_options() występował mały błąd. Występował on w przypadku wywołania
funkcji w postaci assert_options(ASSERT_CALLBACK), w celu odczytania ustawionej funkcji obsługi. Mimo, że w dokumentacji
napisano, że wywołanie takie zwróci jedynie nazwę bieżącej funkcji obsługi, to dodatkowo oprócz zwracania nazwy, bieżące
ustawienie funkcji obsługi było czyszczone. Dlatego jeżeli chcesz użyć funkcji assert() z funkcją obsługi upewnij się, że nie jest
wywoływana później funkcja assert_options() w celu sprawdzenia nazwy zarejestrowanej funkcji. Błąd ten został zauważony i
poprawiony w wersjach PHP powyżej 4.0.2.
Na wydruku 10.7. pokazany został przykład zdefiniowania i użycia funkcji wywoływanej przez assert().
Wydruk 10.7. Wykorzystanie funkcji wywoływanej przez callback()
<?php
error_reporting( E_ALL );
function MyACallback( $aFileName, $aLineNum, $aAssertion )
{
print( "<table border=\"1\"><tr><td>" );
print( "<b>assert()</b> nieudane: <i>$aAssertion</i><br>" );
print( "w pliku $aFileName w linii $aLineNum<br>" );
print( "</td></tr></table>" );
}
// zarejestrowanie funkcji obsługi
assert_options( ASSERT_CALLBACK, "MyACallback" );
// wyłączenie normalnych ostrzeżeń
assert_options( ASSERT_WARNING, 0 );
?>
<html>
<head>
<title>Własna obsługa asercji</title>
</head>
<body>
Nieudana asercja.
<?php
assert( "1 == 2" );
?>
</body>
</html>
Kod z wydruku jest podobny do tego z wydruku 10.6. Wywołanie asercji powoduje wyświetlenie
jednokomórkowej tabeli. Jeżeli nie zostanie opcja ASSERT_WARNING, oprócz informacji zdefiniowanych przez
użytkownika wyświetlony zostanie standardowy komunikat PHP. Na rysunku 10.5. pokazany jest wynik działania
skryptu z wydruku 10.7.
Rozdział 10 – Uruchamianie
124
Rysunek 10.5.
Użycie funkcji
zdefiniowanej dla
assert()
PHP posiada elastyczny mechanizm obsługi błędów. Pozwala on dzięki temu pisać kod łatwiejszy do
uruchamiania i późniejszego utrzymania. W następnej części połączymy wszystkie przedstawione do tej pory
techniki, co w efekcie pozwoli lepiej uruchamiać programy w całym cyklu produkcyjnym.
Zaawansowana obsługa błędów
Po omówieniu technik obsługi błędów możemy rozpocząć tworzenie ogólnego narzędzia do obsługi
błędów. Motywacją do napisania tego fragmentu był brak dostarczanych przez PHP narzędzi, które
automatycznie łączą różne typy danych o błędach. Oprócz tego, PHP 3 posiadał możliwość zdalnego
uruchamiania, która nie została przeniesiona do PHP 4. Pozwalał on przesyłać dane za pomocą protokołu TCP/IP
do innego komputera. Opcja ta prawdopodobnie niedługo się pojawi, ale na razie muszą wystarczyć podstawowe
techniki obsługi błędów opisane w tym rozdziale.
Przykład przytoczony w tej części jest niezwykle długi, więc zostanie omówiony we fragmentach. Moduł
ten znajduje się w jednym pliku, MyDebug.php i będzie on określony jako moduł MyDebug. Jest on tak
utworzony, że może być łatwo dołączony do dowolnego skryptu PHP. Po dołączeniu pliku wykonywany jest kod
pokazany na wydruku 10.8.
Wydruk 10.8. Dołączanie modułu MyDebug
ParseConfig( getenv( "MYDEBUG_CONFIG" ) );
if ( $aMyDebugType & MYDEBUG_DISPLAYFILE )
{
// jeżeli nie można zapisać do pliku sladu
// poinformuj o tym uzytkownika i wyłączyć zapis do pliku
if ( CheckFileSanity( $aMyDebugFile ) == False )
{
error_log( "MyDebug nie udało się otworzyć pliku $aMyDebugFile", 0 );
$aMyDebugType &= ~MYDEBUG_DISPLAYFILE;
}
}
if ( $aMyDebugType & MYDEBUG_DISPLAYFILE )
{
$aFileHandle = fopen( $aMyDebugFile, "a" );
}
if ( $aMyDebugType & MYDEBUG_DISPLAYIP )
{
$aSocketHandle = fsockopen( "udp://$aMyDebugIP", $aMyDebugPort );
}
// Teraz rejestrujemy funkcje obsługi i funkcje porządkujące
set_error_handler( "MyErrHandler" );
assert_options( ASSERT_CALLBACK, "MyAssertHandler" );
assert_options( ASSERT_WARNING, 0 );
register_shutdown_function( "MyDebugShutdown" );
Pierwsza linia z wydruku 10.8. powoduje przetworzenie ciągu konfiguracji MyDebug, który jest
przechowywany w zmiennej środowiska serwera. Na przykład, plik konfiguracyjny Apache może zawierać kod
podobny do następującego:
SetEnv MYDEBUG_CONFIG FILE=/tmp/mydebug.log;
[email protected];IP=myserver.com:5400;
125
PHP – Kompendium wiedzy
Ta opcja konfiguracji jest specyficzna dla modułu MyDebug i nie jest dostępna jako standardowa część
Apache czy PHP. Przykład ten pokazuje, że można ustawiać zmienne środowiska, poprzez pliki konfiguracyjne
serwera WWW i są one dostępne w kodzie PHP. Zmienna MYDEBUG_CONFIG definiuje miejsca, gdzie MyDebug
będzie zapisywał błędy. W tym przypadku moduł będzie zapisywał błędy do pliku (/tmp/mydebug.log), wysyłał
na adres e-mail ([email protected])oraz do gniazda UDP (myserver.com:5400). W normalnej pracy wybiera
się zwykle jedną z metod zapisu błędów, ale moduł MyDebug pozwala na stosowanie wielu jednoczesnych miejsc
zapisu błędów. Funkcja ParseConfg() analizuje ciąg konfiguracji i ustawia odpowiednie zmienne globalne.
Po przeanalizowaniu ciągu konfiguracyjnego sprawdzane są wszystkie pliki używane do zapisu, aby mieć
pewność, że można do nich zapisywać dane. Jeżeli moduł MyDebug nie może zapisać danych do pliku,
zapisywanie do niego jest wyłączane. Następnie otwierane są wszystkie potrzebne pliki i gniazda. Gniazdo jest
otwierane używając UDP, co nie wymaga istnienia procesu nasłuchu. Własność ta jest użyteczna szczególnie
wtedy, gdy zapisywanie jest aktywne na serwerze produkcyjnym, ale nie zawsze jest aktywny proces nasłuchu.
Następnie moduł MyDebug rejestruje funkcje obsługi błędów i asercji. Ostatnią operacją jest
zarejestrowanie funkcji wywoływanej po zakończeniu programu, co pozwala na eleganckie zakończenie działania
modułu. Na wydruku 10.9 pokazana jest funkcja kończąca program.
Wydruk 10.9. Funkcja kończąca program
function MyDebugShutdown( )
{
global $aFileHandle, $aSocketHandle, $aMyDebugType;
if ( $aMyDebugType & MYDEBUG_DISPLAYFILE )
{
fclose( $aFileHandle );
}
if ( $aMyDebugType & MYDEBUG_DISPLAYIP )
{
fclose( $aSocketHandle );
}
}
Funkcja ta zamyka wymagane pliki oraz gniazdo sieciowe. Funkcję kończącą może zarejestrować
dowolny skrypt. PHP pozwala na rejestrowanie wielu funkcji kończących, które są wykonywane w czasie
kończenia pracy skryptu. Choć ten fakt nie jest odnotowany w dokumentacji, funkcje te są wywoływane w tej
samej kolejności, co zostały zarejestrowanie. Ponieważ kolejność ta nie została udokumentowana, skrypty twoje
nie powinny polegać na kolejności wykonywania funkcji kończących lub musisz sam to przetestować. Można
przekazać dodatkowe argumenty do funkcji register_shutdown_function(). PHP przekaże je do funkcji
końcowej. Należy również pamiętać, że w funkcji końcowej nie można wysyłać żadnych danych do przeglądarki.
Po skonfigurowaniu modułu MyDebug, obsługuje on błędy za pomocą funkcji z wydruku 10.10.
Wydruk 10.10. Funkcje obsługi błędów
// Funkcja obsługi ustawiana przez set_error_handler()
function MyErrHandler( $aErrorNo, $aErrorStr, $aFile, $aLine, $aContext)
{
MyDebug( $aErrorStr, $aFile, $aLine, MYDEBUG_ERRCALLBACK,
$aErrorNo, $aContext );
}
// Funkcja obsługi dla funcji assert_options()
function MyAssertHandler( $aFileName, $aLineNum, $aAssertion )
{
MyDebug( "asercja( $aAssertion ) nieudana", $aFileName,
$aLineNum, MYDEBUG_ASSERTCALLBACK );
}
Obie funkcje przekazują parametry do głównej funkcji obsługi błędów, która może również zostać
wywołana bezpośrednio ze skryptu. Główna funkcja obsługi błędów to przedstawiona na wydruku 10.11. funkcja
MyDebug().
Wydruk 10.11. Funkcja MyDebug()
// Funkcja MyDebug jest główną funkcją obsługi
function MyDebug( $aMessage, $aFile, $aLine,
$aCallType = MY_DEBUG_INTERNAL, $aErrType = 0,
$aErrContext = array() )
{
global $aMyDebugType;
for ( $aDisplayType = MYDEBUG_DISPLAYFILE;
$aDisplayType <= MYDEBUG_DISPLAYIP;
$aDisplayType++ )
{
Rozdział 10 – Uruchamianie
126
if ( $aDisplayType & $aMyDebugType )
{
$aType
= FormatType( $aCallType, $aDisplayType );
$aMessage
= FormatMsg ( $aCallType, $aMessage, $aErrType, $aDisplayType );
if ( $aCallType == MYDEBUG_ERRCALLBACK )
{
$aContext = FormatContext( $aErrContext, $aDisplayType );
}
else
{
$aContext = "";
}
MyDebugOutput( $aType, $aMessage, $aFile, $aLine, $aContext, $aDisplayType );
}
}
}
Funkcja MyDebug() formatuje różne parametry w zależności od typu medium zapisu (plik, e-mail lub
TCP/IP). Następnie wywołuje funkcje MyDebugOutput() (wydruk 10.12), która wysyła dane do prawidłowego
miejsca. Funkcje formatujące z wydruku 10.11 zostaną omówione później.
Wydruk 10.12. Funkcja MyDebugOutput()
function MyDebugOutput( $aType, $aMessage, $aFile, $aLine,
$aContext, $aDisplayType )
{
global $aFileHandle, $aSocketHandle, $aMyDebugEmail;
switch( $aDisplayType )
{
case MYDEBUG_DISPLAYFILE:
$aMsg = "$aType: '$aMessage' wystąpił w $aFile w lini $aLine. ";
if ( $aContext != "" )
{
$aMsg .= "Dane kontekstu:\n{$aContext}\n";
}
else
{
$aMsg .= "\n";
}
fputs( $aFileHandle, $aMsg );
break;
case MYDEBUG_DISPLAYEMAIL:
$aMsg = "$aType: '$aMessage' wystąpił w $aFile w linii $aLine. ";
if ( $aContext != "" )
{
$aMsg .= "Dane kontekstu:\n{$aContext}\n";
}
else
{
$aMsg .= "\n";
}
mail($aMyDebugEmail, "Raport MyDebug", $aMsg, "From: [email protected]\r\n");
break;
case MYDEBUG_DISPLAYIP:
$aMsg = "$aType|$aMessage|$aFile|$aLine|$aContext^^";
fputs( $aSocketHandle, $aMsg );
break;
}
}
Funkcja MyDebugOutput() wysyła dane do właściwych miejsc. Jest ona zaskakująco prosta, jeżeli pomyśli
się o efektywności każdej z tych opcji. Każda funkcja formatująca użyta w module MyDebug posiada mechanizm
zamiany wewnętrznego numeru błędu na postać czytelną dla człowieka. Na przykład funkcja FormatType()
przedstawiona na wydruku 10.13 formatuje kod typu błędu.
Wydruk 10.13. Funkcja FormatType()
/*
Funkcja formatuje typ komunikatu w oparciu o to
gdzie będzie wyświetlony */
function FormatType( $aCallType, $aDisplayType )
{
switch( $aDisplayType )
{
case MYDEBUG_DISPLAYFILE:
case MYDEBUG_DISPLAYEMAIL:
switch ( $aCallType )
{
case MYDEBUG_INTERNAL:
return "INTERNAL";
127
PHP – Kompendium wiedzy
break;
case MYDEBUG_ERRCALLBACK:
return "ERROR CALLBACK";
break;
case MYDEBUG_ASSERTCALLBACK:
return "ASSERT CALLBACK";
break;
}
break;
case MYDEBUG_DISPLAYIP:
return $aCallType;
break;
}
}
Jeżeli dane są wysyłane poprzez TCP/IP, nie jest przeprowadzane formatowanie. Sam numer typu jest
wysyłany do zdalnego komputera. W innym wypadku numer typu jest zamieniany na czytelny ciąg. Inne funkcje
konwertujące użyte w MyDebug działają podobnie. Jedyną funkcją formatującą, która jest wyraźnie inna, jest
funkcja formatująca kontekst błędu, FormatContext(). Funkcja ta jest wywoływana jedynie wtedy, gdy błąd
zostanie obsłużony przez funkcję zarejestrowaną za pomocą set_error_handler(). Dane kontekstu udostępniane
przez PHP zawierają wszystkie zmienne będące w zasięgu w momencie wystąpienia błędu. Dane te są przesyłane
w postaci tablicy asocjacyjnej z nazwami zmiennych i ich wartościami. Analiza tych danych wymaga
wykorzystania funkcji rekurencyjnej, ponieważ w kontekście mogą znajdować się tablice. Funkcja zamieszczona
na wydruku 10.14. analizuje dane kontekstu, przekształcając je na postać czytelną dla człowieka.
Wydruk 10.14. Analiza danych kontekstu
/*
Funkcja formatuje typ komunikatu w oparciu o to
gdzie będzie wyświetlony. Funkcja oparta o
funkcję rekurencyjną FormatContextR */
function FormatContext( $aErrContext, $aDisplayType )
{
// od tej pory wszystkie wyświetlane typy
// otrzymują ten sam ciąg kontekstu
$aString = "";
$aDelim = "\n";
FormatContextR( $aErrContext, $aString, $aDelim );
return $aString;
}
function FormatContextR( $aErrContext, &$aString, $aDelim )
{
foreach( $aErrContext as $aVarName => $aVarValue )
{
if ( is_array( $aVarValue ) == True )
{
$aString .= "$aVarName = array( ";
FormatContextR( $aVarValue, $aString, "," );
$aString .= " )$aDelim";
}
else
{
$aString .= "$aVarName = {$aVarValue}{$aDelim}";
}
}
}
Funkcja FormatContext() ustawia kilka parametrów i wywołuje funkcję rekurencyjną FormatContextR().
Funkcja rekurencyjna przegląda tablice zmiennych kontekstu i zapisuje każdą parę nazwa-wartość do
wynikowego ciągu. Jeżeli napotkana zostanie tablica, rekurencyjnie jest wywoływana funkcja FormatContextR().
W zależności od miejsca wystąpienia błędu, kontekst lokalny może zawierać sporo danych. Jeżeli błąd
wystąpi w głównej części skryptu, w zasięgu znajdą się wszystkie zmienne globalne, w tym zmienne środowiska i
zmienne GET i POST. Wszystkie te zmienne znajdą się w danych kontekstu. Jeżeli błąd wystąpi w funkcji, kontekst
będzie zawierał jedynie zmienne lokalne funkcji.
Do skryptu testującego (wydruk 10.15.) dołączyliśmy moduł MyDebug oraz ustawiliśmy zmienną
konfiguracji na zapisywanie do pliku tekstowego. Po jego uruchomieniu na końcu pliku śladu znalazł się ciąg
błędu. Poniższy tekst nie jest całym plikiem, jedynie wynikiem wystąpienia ostatniego błędu w skrypcie:
ERROR CALLBACK: 'Typ błędu PHP: E_USER_ERROR - error in sum'
wystąpił w c:\helion\php4-devguide\site\ch10\test_mydebug.phtml w lini 16. Dane kontekstu:
a = 1
b = 2
aArray = array( 0 = spring,1 = summer,2 = autumn,3 = winter, )
Wydruk 10.15. Skrypt testowy
<?php
Rozdział 10 – Uruchamianie
128
include_once( "./mydebug.php" );
?>
<html>
<head>
<title>Test modułu MyDebug</title>
</head>
<body>
Nieudana asercja.<br><br>
<?php
function sum( $a, $b )
{
$aArray = array( "spring", "summer", "autumn", "winter" );
trigger_error( "error in sum", E_USER_ERROR );
}
assert( "1 == 2" );
trigger_error( "Błąd testowy", E_USER_ERROR );
$aArray = array( "state" => "Idaho", "county" => "Madison",
"city" => "Rexburg", "country" => "US" );
print( "<br><br>aArray[state] = " . $aArray[state] . "<br>" );
sum( 1, 2 );
?>
</body>
</html>
Skrypt testowy przedstawiony na wydruku 10.15. nie robi nic, poza generowaniem błędów. Wynik funkcja
sum() nie jest nigdzie używany, ale jest ona umieszczone w tym skrypcie, aby pokazać jak wywołanie funkcji
wpływa na dane kontekstu przekazywane przez PHP. Linie z opisem błędu zamieszczone bezpośrednio przed
wydrukiem 15 są wygenerowane przy wywołaniu funkcji sum().
Aby pokazać elastyczność tego modułu, napisana została aplikacja Windows, która realizuje proces
nasłuchu portu TCP/IP i wyświetla przychodzące dane. Jest to prosta aplikacja Delphi, która odczytuje pakiety
UDP przychodzące do portu 5400. Po odczytaniu danych formatuje linie i wyświetla je. Na rysunku 10.6.
pokazana została ta aplikacja po odebraniu kilku komunikatów wygenerowanych przez PHP.
Rysunek 10.6.
Aplikacja
nasłuchu dla
MyDebug
Jednym z powodów atrakcyjności języka PHP jest to, że jest on niezwykle rozszerzalny. Moduł MyDebug
jest napisany całkowicie w PHP dodając do niego niezwykle użyteczne funkcje (kompletne źródła modułu
MyDebug są dostępne wraz z wszystkimi przykładami kodu z tej książki). Moduł ten nie jest kompletny i może
być rozwijany na wiele sposobów. Na przykład, wykorzystanie poczty elektronicznej do raportowania błędów jest
niezwykle nieefektywne, ale można wykorzystać pocztę elektroniczną do raportowania jedynie krytycznych
błędów i ostrzeżeń, co pozwoli na wykorzystanie tej opcji w środowisku produkcyjnym. Niezmiernie istotny jest
fakt, że wszystkie te opcje są zrealizowane całkowicie w PHP. Nie wszystkie narzędzia programowania dla
WWW są tak elastyczne.
Podsumowanie
W tym rozdziale przedstawione zostały informacje na temat technik programowania defensywnego, które
pozwalają na uniknięcie możliwie dużo pracy przy uruchamianiu. W chwili obecnej PHP nie posiada programu
do uruchamiania skryptów, podobnego do tych, które są dostępne we wielu nowoczesnych językach
129
PHP – Kompendium wiedzy
programowania. Jednak przy odrobinie pomysłowości i wykorzystując rozszerzalność PHP, można stworzyć
świetne narzędzia do uruchamiania aplikacji. Opisany został jeden z modułów, który zapewnia elastyczną obsługę
błędów i może być modyfikowany i rozszerzany tak, aby spełniał wymagania prawie każdego programisty.
Bibliografia
Steve McConnell. Code Complete. Seattle: Microsoft Press, 1993.
Rozdział 10 – Uruchamianie
130
Rozdział 11. Ponowne wykorzystanie
kodu
Wstęp
Podczas tworzenia dowolnej aplikacji niezmiernie ważne jest wykorzystanie istniejących modułów kodu.
Pierwszym powodem jest to, że używane moduły kodu stanowią podstawę kolejnych aplikacji i w dłuższym
czasie polepszają wydajność zespołu programistów.
Ponieważ PHP pozwala na dołączanie zewnętrznych plików oraz na tworzenie klas, ponowne
wykorzystanie kodu jest dosyć proste. W tym rozdziale ponowne wykorzystanie kodu zostanie krótko omówione
z perspektywy inżynierii programowania, oraz przytoczone zostanie kilka przykładów kodu PHP nadającego się
do powtórnego wykorzystania. W rozdziale tym omówione zostanie wykorzystanie w projektach PHP kodu
napisanego w innych językach programowania. Taka elastyczność pozwala programistom na przenoszenie do
sieci WWW istniejących aplikacji bez konieczności całkowitego przepisywania kodu.
Ponowne wykorzystanie kodu a inżynieria programowania
Ponowne wykorzystanie kodu nie polega jedynie na integracji istniejącego kodu z nowym produktem.
Nowe fragmenty kodu często są tworzone w sposób ułatwiający ich ponowne wykorzystanie. Gdy planowane jest
ponowne wykorzystanie kodu, ważne są efekty długoterminowe, ponieważ tworzenie takiego kodu zajmuje często
dużo więcej czasu i jest bardziej kosztowne w porównaniu do tego samego kodu do jednokrotnego użycia
(McConnell, 1996). Zalety ponownego użycia nie są natychmiast widoczne, ale wiele firm zauważyło około 58%
wzrost wydajności rocznie w przeciągu czterech lat (McConnell, 1996).
Zalety te nie będą wykorzystane, jeżeli nie zostanie zastosowane odpowiednie planowanie. Poniżej
przedstawione zostały niektóre ważne zagadnienia, jakie należy wziąć pod uwagę:
• Zaangażowanie kierownictwa w proces ponownego wykorzystania kodu.
• Upewnienie się, że tworzenie kodu do ponownego wykorzystania jest integralną częścią całego procesu
produkcji oprogramowania i że wszyscy programiści zgadzają się z tą ideą.
• Skupienie się na tworzeniu małych, precyzyjnych modułach kodu.
• Tworzenie kodu do ponownego wykorzystania przy użyciu możliwie najlepszych standardów
programowania i dokumentacji.
Tworząc kod należy mieć na uwadze, że przy pisaniu aplikacji w przyszłości będą potrzebne podobne
fragmenty. Mając to na uwadze, częściej należy dzielić grupy funkcji na oddzielne moduły lub klasy. Jeżeli
wiadomo, że dany fragment kodu będzie wykorzystywany w przyszłości, należy napisać go i udokumentować w
sposób zgodny z najlepszymi zaleceniami stosowanymi w zespole. Należy unikać używania danych lub założeń
specyficznych dla projektu, a zamiast tego tworzyć moduł w sposób, który uprości jego wykorzystanie w
przyszłości.
W PHP kod nadający się do powtórnego wykorzystania można tworzyć przy pomocy kilku metod, na
przykład tworząc oddzielne pliki z kodem źródłowym (pliki dołączane) lub tworząc klasy obiektowe. Wybór
plików dołączanych lub podejścia obiektowego nie wpływa zbytnio na ogólne założenia. Kluczem do sukcesu jest
tworzenie kodu nadającego się do powtórnego użycia, który jest odpowiednio zorganizowany i dobrze
udokumentowany. Użycie hermetyzacji i technik ukrywania danych da w efekcie maksymalne zwiększenie
wydajności i efektywności ponownie wykorzystanego kodu.
Ponowne użycie istniejącego kodu
Z powodu natury projektów internetowych, w firmie może nie istnieć zbyt wiele fragmentów kodu do
wykorzystania. Jednak ponowne wykorzystanie kodu może jedynie wymagać przewidywania przyszłych
projektów. Omówione zostaną teraz niektóre techniki dostępne w PHP, o których należy pamiętać przy
projektowaniu aplikacji.
Jeżeli przenosi się zwykłą aplikację biurową do sieci, lub przepisuje się z innego języka na PHP,
prawdopodobnie istnieje wtedy kod, który można wykorzystać. Ponieważ PHP jest niezwykle rozszerzalny,
istnieje wiele metod użycia obcego kodu w aplikacjach opartych o PHP. Niektóre z tych metod zostaną opisane w
późniejszych częściach.
PHP
PHP zawiera kilka narzędzi ułatwiających ponowne wykorzystanie kodu. Z tego powodu została
przygotowana podstawa do tworzenia narzędzi dla PHP tworzonych przez różne firmy. Niektóre z nich zostały
wspomniane w poprzednich rozdziałach i są wymienione na liście zasobów internetowych, na końcu książki.
Najbardziej oczywistą metodą ponownego wykorzystania kodu PHP jest użycie funkcji include() lub
require() do dołączenia istniejącego kodu. Używane już we wcześniejszych przykładach, funkcje te pozwalają
na dołączanie czystego kodu PHP, HTML lub ich kombinacji. Zaczynając od wersji PHP 4, dostępne są funkcje
include_once() i require_once(), które upraszczają proces dołączania. Funkcje te eliminują problem występujący
przy wielokrotnym dołączaniu do skryptu tego samego pliku. Na wydruku 11.1. i 11.2. przedstawiono przykład
takiego problemu i sposób jego rozwiązania.
Wydruk 11.1. Plik dołączany date_funcs.php
<?php
include_once( "./format_funcs.php" );
// Zwraca ilość dni pomiędzy datami
// jako sformatowany ciąg w postaci mm-dd-rrrr
function GetDateDiff( $aDateStr1, $aDateStr2 )
{
$aDateArray1 = explode( "-", $aDateStr1 );
assert( 'count( $aDateArray1 ) == 3' );
$aDateArray2 = explode( "-", $aDateStr2 );
assert( 'count( $aDateArray2 ) == 3' );
$aTime1 = mktime( 0, 0, 0, $aDateArray1[0], $aDateArray1[1], $aDateArray1[2] );
$aTime2 = mktime( 0, 0, 0, $aDateArray2[0], $aDateArray2[1], $aDateArray2[2] );
$aTimeDiff = abs( $aTime1 - $aTime2 );
return GetFormattedNumber( $aTimeDiff / ( 60 * 60 * 24 ) );
}
?>
Wydruk 11.2. Plik dołączany format_funcs.php
<?php
function GetFormattedNumber( $aNum )
{
return number_format( $aNum, 0, '.', ' ' );
}
?>
Skrypt z wydruku 11.3. wykorzystuje funkcje z obu poprzednich plików dołączanych.
Wydruk 11.3. Skrypt wykorzystujący oba pliki dołączane
<?php
include( "./date_funcs.php" );
include( "./format_funcs.php" );
?>
<html>
<head>
<title>Problem z wielokrotnym dołączaniem plików</title>
</head>
<body>
<?php
$aNumVisitors = 14500;
print( "Witrynę odwiedziło " );
print( GetFormattedNumber( $aNumVisitors ) );
print( " gości " );
print( "w przeciągu ostatnich " );
print( GetDateDiff( "9-21-2000", "8-15-1992" ) );
print( " dni." );
?>
</body>
</html>
Rozdział 11 – Ponowne wykorzystanie kodu
132
Problem występujący w skrypcie z wydruku 11.3 wynika z tego, że plik dołączany date_funcs.php dołącza
również plik format_funcs.php. Po uruchomieniu skryptu generowany jest komunikat błędu:
Fatal error: Cannot redeclare getformattednumber() in ./format_funcs.php on line 2
Na wydruku 11.4. pokazane zostało jak łatwo można rozwiązać ten problem korzystając z funkcji
include_once().
Wydruk 11.4. Skrypt wykorzystujący include_once()
<?php
include_once( "./date_funcs.php" );
include_once( "./format_funcs.php" );
?>
<html>
<head>
<title>Problem z wielokrotnym dołączaniem plików</title>
</head>
<body>
<?php
$aNumVisitors = 14500;
print( "Witrynę odwiedziło " );
print( GetFormattedNumber( $aNumVisitors ) );
print( " gości " );
print( "w przeciągu ostatnich " );
print( GetDateDiff( "9-21-2000", "8-15-1992" ) );
print( " dni." );
?>
</body>
</html>
Funkcje require() i require_once() działają podobnie. Ten mechanizm dołączania plików pozwala na
tworzenie własnych bibliotek często używanych funkcji oraz wykorzystanie kodu od zewnętrznych dostawców.
Dodatkowo PHP obsługuje tworzenie klas obiektowych, które można ponownie wykorzystywać lub rozszerzać.
W poprzednich rozdziałach zostały pokazane przykłady rozszerzania klas pochodzących z od różnych
dostawców. Ponieważ PHP obsługuje dołączanie modułów oraz programowanie obiektowe, naturalnie pozwala
na tworzenie kodu wielokrotnego użycia. Oprócz tego, rozszerzalność PHP pozwala na wykorzystanie innego
istniejącego kodu.
C/C++
PHP jest napisany w C i C++. Z tego powodu możliwa jest integracja istniejącego kodu C/C++
bezpośrednio w PHP. Tak naprawdę wiele z rozszerzeń PHP jest bezpośrednio przeniesiona z C lub C++. Na
przykład CyberCashTM Merchant Control Kit został napisany w C a jego funkcje są dostępne w PHP jako funkcje
cybercash_xxx().
Jeżeli posiadasz istniejący kod projektu w C lub C++, który ma być przeniesiony do środowiska WW,
możesz rozważyć dołączenie tego kodu do twojej instalacji PHP. Należy jednak pamiętać, że wymaga to sporo
pracy i w efekcie może być mniej efektywne, niż proste przepisanie kodu na PHP.
Skupmy się teraz na tworzeniu wbudowanych funkcji PHP opartych o istniejące funkcje w C. Jeżeli
istniejący kod jest napisany w C++, można utworzyć obiekty PHP używające implementacji w C++, ale nie
opiszemy tutaj tego procesu. Można zamiast tego napisać funkcje mapujące dla metod istniejących obiektów
C++.
Załóżmy, że mamy trzy funkcje zamieszczone na wydruku 11.5 i chcemy na ich podstawie utworzyć
wewnętrzne funkcje PHP. Funkcje te są wykorzystywane do obliczania płatności hipotecznych i tworzenia tabel
amortyzacji w USA. Pierwsze dwie funkcje zwracają pojedyncze wartości oznaczające odpowiednio ratę
miesięczną i sumę wszystkich rat. Ostatnia funkcja zwraca tabelę wartości reprezentujących wartość odsetek
miesięcznych w racie. Używając tych danych można wygenerować harmonogram amortyzacji.
Wydruk 11.5. Funkcje w C do konwersji na PHP
/*
_fin_mpmt:
oblicza miesięczną spłatę kredytu w oparciu o
kwotę kredytu (p), oprocentowanie (i) oraz czas (l)
*/
double _fin_mpmt (double p, double i, double l)
{
double j;
double n;
j = i / (12 * 100);
n = l * 12;
133
PHP – Kompendium wiedzy
return ( p* ( j/( 1 - (pow(( 1+j ), (n * -1))))));
}
/*
_fin_total:
oblicza całkowitą kwotę spłat w czasie trwania kredytu
w oparciu o kwotę kredytu (p), oprocentowanie (i) i czas (l)
*/
double _fin_total (double p, double i, double l)
{
return _fin_mpmt( p, i, l) * l * 12;
}
/*
_fin_table:
oblicza miesięczne odsetki używane w planie amortyzacji dla kredytów
w oparciu o kwotę (p), oprocentowanie (i), i czas (l)
*/
void _fin_table ( double p, double i, double l, double *pIntPmt)
{
double n, m, h, q, j, c;
int
nIndex;
j = i / (12 * 100);
n = l * 12;
q = p;
m = _fin_mpmt( p, i, l );
for (nIndex = 0; nIndex < n; nIndex++ )
{
h = q * j;
c = m - h;
q = q - c;
pIntPmt[nIndex] = h;
}
return ;
}
W dystrybucji PHP dostarczany jest program o nazwie build_skel, który służy do tworzenia zbioru
szkieletowych plików konfiguracji dla nowych rozszerzeń PHP. Program ten znajduje się w katalogu ext
dystrybucji PHP zawierającej pliki źródłowe. Aby dodać funkcje finansowe do PHP należy uruchomić build_skel
w następujący sposób:
./build_skel --extname=fin_funcs --proto=/sciezka/do/fin_funcs.proto --assign-params
Parametr extname jest nazwą nowego rozszerzenia PHP, natomiast proto jest nazwą pliku zawierającego
prototypy tworzonych funkcji. Plik prototypów powinien zawierać prototypy funkcji PHP. Dla funkcji
finansowych użyjemy następującej zawartości pliku prototypów:
double fin_mpmt ( double principle, double interest, double length )
double fin_total ( double principle, double interest, double length )
array fin_table ( double principle, double interest, double length )
Parametr assign-params powoduje, że pliki szkieletowe dołączają parametry o prawidłowych typach, co
zostanie opisane później. Inne dostępne parametry pozwalają kontrolować wygląd dokumentacji, i inne
ustawienia generacji kodu. Więcej szczegółów można uzyskać uruchamiając skrypt build_skel bez parametrów.
Po uruchomieniu skryptu w sposób przedstawiony powyżej, tworzony jest nowy katalog ext/fin_funcs, który
zawiera pliki rozszerzeń wymagane przez PHP. Pierwsza zmiana musi zostać wprowadzona do pliku config.4m.
W pliku tym zawarty jest opis omawiający wymagane zmiany. Plik ext/fin_funcs/config.m4 jest pokazany poniżej
(komentarze zostały usunięte):
PHP_ARG_ENABLE(fin_funcs, whether to enable fin_funcs support,
[ --enable-fin_funcs
Enable fin_funcs support])
if test "$PHP_FIN_FUNCS" != "no"; then
AC_DEFINE(HAVE_FIN_FUNCS, 1, [ ])
PHP_EXTENSION(fin_funcs, $ext_shared)
fi
Funkcja build_skel tworzy plik źródłowy w C, który zawiera wymagane funkcje i dołączone pliki
nagłówków, więc natychmiast po uruchomieniu tego narzędzia i poprawieniu pliku config.m4 można
skompilować PHP z obsługą nowych rozszerzeń. Aby upewnić się, że pliki szkieletowe i konfiguracyjne są
prawidłowe, można wykonać następujące czynności:
1. Uruchom skrypt buildconf w głównym katalogu PHP.
2. Uruchom skrypt configure i dodaj obsługę nowego rozszerzenia.
3. Skompiluj PHP.
4. Wykonaj skrypt testowy z katalogu z rozszerzeniem (fin_funcs.php) aby sprawdzić, czy rozszerzenie jest
aktywne w PHP.
Testowy moduł rozszerzenia jest uaktywniany za pomocą dyrektywy konfiguracji --enable-fin_funcs.
Skrypt testowy wykrywający, czy rozszerzenie działa jest podobny do następującego:
Rozdział 11 – Ponowne wykorzystanie kodu
134
<?php
if (extension_loaded( "fin_funcs" ))
{
// Wykonaj jedną z funkcji
}
else
{
print( "moduł fin_funcs niedostępny<BR>" );
}
?>
Po skonfigurowaniu PHP, aby korzystał z nowego rozszerzenia, należy jeszcze uaktualnić plik extension.c,
aby zawierał implementację każdej z funkcji. We wielu przypadkach wymaga to jedynie dołączenia oryginalnych
nagłówków i wywołaniu oryginalnych funkcji. W przykładzie z funkcjami finansowymi, funkcje są zdefiniowane
w sposób pokazany na wydruku 11.6. Należy zauważyć, że skrypt build_skel wygenerował większość kodu w
ciele każdej funkcji. Kod dodany ręcznie zaznaczony jest czcionką pogrubioną.
Wydruk 11.6. Funkcje finansowe dodane do PHP
/* {{{ proto double fin_mpmt(double principle, double interest, double length)
*/
PHP_FUNCTION(fin_mpmt)
{
zval **principle_arg, **interest_arg, **length_arg;
double principle;
double interest;
double length;
double aRetVal;
if (ZEND_NUM_ARGS() != 3 ||
zend_get_parameters_ex(3, &principle_arg, &interest_arg, &length_arg) == FAILURE){
WRONG_PARAM_COUNT;
}
convert_to_double_ex(principle_arg);
principle = Z_DVAL_PP(principle_arg);
convert_to_double_ex(interest_arg);
interest = Z_DVAL_PP(interest_arg);
convert_to_double_ex(length_arg);
length = Z_DVAL_PP(length_arg);
aRetVal = _fin_mpmt( principle, interest, length );
RETVAL_DOUBLE( aRetVal );
}
/* }}} */
/* {{{ proto double fin_total(double principle, double interest, double length)
*/
PHP_FUNCTION(fin_total)
{
zval **principle_arg, **interest_arg, **length_arg;
double principle;
double interest;
double length;
double aRetVal;
if (ZEND_NUM_ARGS() != 3 ||
zend_get_parameters_ex(3, &principle_arg, &interest_arg, &length_arg) == FAILURE){
WRONG_PARAM_COUNT;
}
convert_to_double_ex(principle_arg);
principle = Z_DVAL_PP(principle_arg);
convert_to_double_ex(interest_arg);
interest = Z_DVAL_PP(interest_arg);
convert_to_double_ex(length_arg);
length = Z_DVAL_PP(length_arg);
aRetVal = _fin_total( principle, interest, length );
RETVAL_DOUBLE( aRetVal );
}
/* }}} */
/* {{{ proto array fin_table(double principle, double interest, double length)
*/
PHP_FUNCTION(fin_table)
{
zval **principle_arg, **interest_arg, **length_arg;
double principle;
double interest;
double length;
double *pIntPmts;
int n, nIndex;
135
PHP – Kompendium wiedzy
if (ZEND_NUM_ARGS() != 3 ||
zend_get_parameters_ex(3, &principle_arg, &interest_arg, &length_arg) == FAILURE){
WRONG_PARAM_COUNT;
}
convert_to_double_ex(principle_arg);
principle = Z_DVAL_PP(principle_arg);
convert_to_double_ex(interest_arg);
interest = Z_DVAL_PP(interest_arg);
convert_to_double_ex(length_arg);
length = Z_DVAL_PP(length_arg);
n = (int)length * 12;
pIntPmts = emalloc( sizeof( double ) * n );
_fin_table( principle, interest, length, pIntPmts );
if (array_init(return_value)== FAILURE )
{
php_error( E_ERROR, "fin_table: nie udało się utworzyć tablicy");
}
else
{
for ( nIndex = 0; nindex < n; nIndex++ )
add_next_index_double( return_value, pIntPmts[nIndex]);
}
efree( pIntPmts );
}
/* }}} */
W pierwszych dwóch funkcjach do implementacji rozszerzenia wymagane było napisanie jednie trzech
linii kodu. Pierwsza linia jest deklaracją zmiennej, druga wywołuje wewnętrzną funkcję obliczającą wartość a
trzecia ustawia zwracaną wartość. Ostania funkcja jest utworzona w taki sposób, aby zwracała tablicę PHP.
Wymaga to nieco więcej pracy od dwóch pierwszych funkcji, ale wyniki tej pracy są znaczące.
Implementacja funkcji fin_table() pokazuje kilka technik ważnych dla programowania dla PHP. Po
pierwsze, przydział pamięci jest przeprowadzany za pomocą funkcji emalloc(), natomiast efree() zapewnia, że
PHP wykona normalny proces odzyskiwania nieużytków. W implementacji fin_table() pamięć jest przydzielana
dla tablicy tymczasowej zawierającej wartości wygenerowane przez funkcję C _fin_table(). Po wywołaniu
funkcji wbudowanej, zwracana wartość jest deklarowana przy pomocy wywołania funkcji array_init() jako
tablica PHP. Następnie przy pomocy pętli przebiegającej po kolejnych komórkach tablicy i kolejnych wywołań
funkcji add_next_index_double(), wartości z tablicy C są kopiowane do nowej tablicy PHP. Na koniec
tymczasowa tablica jest niszczona i funkcja się kończy.
Po wbudowaniu tych funkcji w PHP, mogą być one wywoływane identycznie, jak inne wewnętrzne
funkcje PHP. Na wydruku 11.7 pokazujemy przykład użycia nowego rozszerzenia.
Wydruk 11.7. Użycie funkcji finansowych dodanych do PHP
<html>
<head>
<title>Kalkulator kredytowy</title>
</head>
<body>
<?php
if ( $REQUEST_METHOD == 'POST' )
{
print( "Kwota pożyczki: <b>" . number_format( $Amount ) . "</b><br>" );
print( "Oprocentowanie: <b>{$Interest}%</b><br>" );
print( "Czas spłaty: <b>$Term lat</b><br><hr>" );
$aMontlyPayment = fin_mpmt( $Amount, $Interest, $Term );
print("Rata miesięczna: <b>" . number_format( $aMontlyPayment, 2 ) . "</b><br>");
print( "Suma rat: <b>" .
number_format( fin_total( $Amount, $Interest, $Term ), 2 ) . "</b><br><br>" );
$aArray = fin_table( $Amount, $Interest, $Term );
?>
<table border="1">
<tr>
<td>
Rata nr.
</td>
<td>
Podstawa
</td>
<td>
Odsetki
</td>
</tr>
<?php
$nIndex = 1;
Rozdział 11 – Ponowne wykorzystanie kodu
136
foreach( $aArray as $aIntPmt )
{
$aPrinciple = number_format( $aMontlyPayment - $aIntPmt, 2 );
$aIntPmt = number_format( $aIntPmt, 2 );
?>
<tr>
<td>
<?=$nIndex?>
</td>
<td>
<?=$aPrinciple?>
</td>
<td>
<?=$aIntPmt?>
</td>
</tr>
<?php
$nIndex++;
}
?>
</table>
<?php
}
?>
<form action="<?=$PHP_SELF?>" method="post">
<table>
<tr>
<td colspan="2">
To jest prosty kalkulator rat kredytu.
Wprowadź kwotę pożyczki, oprocentowanie i czas spłaty
</td>
</tr>
<tr>
<td>
Kwota:
</td>
<td>
<input type="text" name="Amount">
</td>
</tr>
<tr>
<td>
Oprocentowanie ("7.5" == 7.5%):
</td>
<td>
<input type="text" name="Interest">
</td>
</tr>
<tr>
<td>
Czas spłaty (w latach):
</td>
<td>
<input type="text" name="Term">
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="Submit" value="Wyślij">
</td>
</tr>
</table>
</form>
</body>
</html>
Skrypt ten wyświetla formularz do wprowadzenia danych kredytu, a następnie wysyła je do samego siebie.
Po wywołaniu go poprzez wywołanie HTTP POST, wywoływane są funkcje finansowe i wyświetlane wyniki ich
działania. Na rysunku 11.1. pokazany jest fragment strony będącej wynikiem typowego wykonania programu.
137
PHP – Kompendium wiedzy
Rysunek 11.1.
Wykorzystanie
nowych funkcji
finansowych
Jak wspomniano wcześniej, jeżeli masz dużą bibliotekę kodu C/C++ pochodzącą z istniejących aplikacji i
zamierzasz przenieść je do środowiska WWW, PHP posiada prosty mechanizm integracji istniejącego kodu z
nowymi aplikacjami. Zaletą tego rozwiązania jest możliwość ponownego wykorzystania dobrze przetestowanego
kodu oraz dobra wydajność skompilowanego kodu. Dodatkowo, funkcje napisane w C lub C++ mogą realizować
funkcje, których nie da się napisać wyłącznie w PHP. Na przykład implementacja bezpiecznych gniazd zapewnia
możliwości, które nie mogą być w chwili obecnej zrealizowane przy pomocy funkcji PHP.
Rozważając integrację istniejącego kodu C/C++ z PHP należy wziąć pod uwagę, że koszt integracji może
być wyższy od kosztu przepisania kodu na PHP. Przytoczony wcześniej przykład może być łatwo przepisany na
PHP i zajmie to mniej czasu. Dodatkowo kroki podjęte w czasie integracji muszą być w części powtórzone dla
każdej nowej wersji PHP. Jeżeli zamierzasz zawsze korzystać z najnowszej wersji PHP, powoduje to konieczność
ciągłej konserwacji istniejącej witryny.
Inną możliwością wykorzystania istniejącego kodu C/C++ jest jego skompilowanie i wykonywanie na
serwerze WWW poprzez PHP. Metoda ta zostanie opisana w dalszej części rozdziału.
Java
W rozdziale 9, „Niezależność od przeglądarki” przedstawiony został opis połączenia Javy z PHP.
Możliwość używania klas Javy została wprowadzona w PHP4. Z powodu popularności Javy, dostępne jest wiele
klas i modułów klas Javy, oferowanych przez wielu niezależnych dostawców. Obsługa Javy nie jest włączona
domyślnie do PHP, więc należy przekompilować PHP, aby móc skorzystać z tego potężnego narzędzia.
Dodawanie obsługi Javy w PHP na *niksach
Jeżeli korzystasz z PHP na platformie *nix, musisz przekompilować PHP w celu dodania obsługi Javy. W
podręczniku PHP znajdziemy, że nie można wykorzystać opcji konfiguracji --with-java, jeżeli posiadasz PHP
statycznie włączone w Apache. Opcja ta działa, jeżeli PHP jest uruchamiany jako program CGI lub dynamicznie
włączany moduł Apache. Z powodów bezpieczeństwa nie zaleca się korzystania z PHP w postaci CGI. Jeżeli
serwer Apache nie posiada obsługi dynamicznych modułów, należy go wcześniej przekompilować.
Rozdział 11 – Ponowne wykorzystanie kodu
138
Poniższy skrypt powoduje przekompilowanie Apache tak, aby korzystał z dynamicznie ładowanych
modułów oraz tworzy właściwie skonfigurowany skrypt apxs, który będzie potrzebny do skompilowania PHP. W
skrypcie tym zakładamy, że będzie on uruchomiony z głównego katalogu instalacji Apache.
make clean
./configure --enable-module=so --enable-rule=SHARED_CORE --prefix=/www
make
make install
Po przekompilowaniu Apache można uaktywnić obsługę Javy w PHP za pomocą następującego skryptu.
Zakładamy w nim, że będzie uruchomiony z głównego katalogu instalacji PHP.
make clean
./configure --with-apxs=/www/bin/apxs --with-java ...
make
make install
Opcja --with-java może zawierać ścieżkę oznaczającą katalog instalacji używanej maszyny wirtualnej
Javy. Po zakończeniu kompilacji można sprawdzić konfigurację PHP za pomocą funkcji phpinfo(). Należy
również ustawić kilka opcji konfiguracji Javy w pliku php.ini. Pierwsza jest linia z dołączeniem rozszerzenia
(extension=libphp_java.so). Pozostałe opcje zostaną omówione później.
Dołączanie obsługi Javy w PHP dla Windows
Zamiast kompilowania specjalnej wersji PHP dla Windows, rozszerzenie Javy jest dostępne do pobrania z
www.php.net. Powinieneś sprawdzić która wersja JDK (Java Development Kit) jest zainstalowana na serwerze.
Można to zrobić przy pomocy java -showversion. Należy pobrać odpowiedni plik rozszerzenia i skopiować
php_java.dll do katalogu systemowego. W Windows 95 jest to zwykle \windows\system a Windows NT
\winnt\system32.
Następnie należy uaktualnić plik php.ini. Należy doda linię ładującą rozszerzenie
(extension=php_java.dll). Następnie należy dodać odpowiednio sekcję z opcjami konfiguracji. Są one kluczowe
do prawidłowego działania Javy na każdej platformie.
Opcje konfiguracji Javy
Niezależnie od platformy, jeżeli obsługa Javy jest aktywna w PHP, musisz dodać kilka opcji konfiguracji
do pliku php.ini. W Windows sekcja ta powinna wyglądać podobnie do następującej:
[java]
java.class.path="D:\php4\php_java.jar;D:\PHP4 book\other\RTF2HTML\lib\Scrooge_09b7.jar"
java.home="D:\Program Files\JavaSoft\JRE\1.3"
java.library="D:\Program Files\JavaSoft\JRE\1.3\bin\hotspot\jvm.dll"
W przypadku systemów *nix, sekcja ta jest następująca:
[java]
java.library.path=/usr/lib/kafee:/home/blake/php-4.0.1p12/modules
java.home=/usr/lib/kaffe
java.class.path=/usr/share/kaffe/Klasses.jar:/home/blake/php4.0.1.p12/ext/java/php_java.jar:/home/blake/bhawk/lib/bhawk4j.jar:/home/blake/bhawk:/home/blake/java/num
berspeller.jar:/home/blake/java/sax2.jar:/home/blake/java/servlet.jar:/home/blake/java/scrooge.jar
java.library=/www/libexec/libkaffevm.so
Po skonfigurowaniu obsługi Javy, w pliku php.ini musisz podać lokalizację klas Javy lub plików JAR.
Należy to wykonać dla każdej używanej klasy Javy, której chcesz używać. Jak widać na zamieszczonych opcjach
konfiguracji, java.class.path zawiera pełną ścieżkę do plików implementacji.
Tak jak jest to w przypadku każdego języka umożliwiającego tworzenie komponentów, dla Javy dostępne
jest wiele narzędzi, z których można skorzystać za pomocą języka obsługującego API. Jednym z dostępnych
komercyjnie modułów Javy jest konwerter RTH na HTML Scrooge, który można załadować z witryny
www.betabeans.de. Moduł ten posiada prosty interfejs używany do konwertowania plików RTF na standardowy
HTML. Funkcja ta może być wykorzystywana we wielu aplikacjach, w których użytkownicy mogą wysyłać takie
pliki. Ponieważ RTF obsługuje różne czcionki i układy, wykorzystanie RTF pozwala użytkownikowi na
dostarczanie plików bez niebezpieczeństwa bezpośredniego dodawania kodu HTML do witryny. Moduł Scrooge
zawiera przykładowy plik RTF (pokazany na rysunku 11.2.) którego możemy użyć do sprawdzenia siły i
elastyczności modułu.
139
PHP – Kompendium wiedzy
Rysunek 11.2.
Przykładowy plik
RTF modułu
Scrooge
Użycie modułu Scrooge jest łatwe i proste. Dołączona dokumentacja zawiera nazwę klasy Javy, oraz listę
dostępnych metod i właściwości. W skrypcie z wydruku 11.8 pokazane jest wykorzystanie tego modułu.
Wydruk 11.8. Użycie modułu Javy Scrooge
<HTML>
<HEAD>
<TITLE>Konwersja RTF na HTML</TITLE>
</HEAD>
<BODY>
<?php
if ($REQUEST_METHOD == 'POST' )
{
if ( ( $rtffile_type == "text/richtext" ) ||
( $rtffile_type == "application/rtf" ) )
{
// utworzenie obiektu Scrooge
$aR2H
= new Java ("de.betabeans.scrooge.Scrooge");
$aArray = file ( $rtffile );
$sR2H->setOptWrapHTML( False );
$aOutput = $aR2H->convert( implode( "", $aArray) );
print( $aOutput );
}
else
{
print ("Wybrany plk nie jest plikiem <b>RTF</b>.<BR>");
}
}
?>
<FORM METHOD="POST" ACTION="<?=$PHP_SELF?>" enctype="multipart/form-data">
Przesyłanie pliku: <INPUT TYPE="file" NAME="rtffile"><br><br>
<INPUT TYPE="submit" NAME="submit" value="Wyślij">
</FORM>
</BODY>
</HTML>
Skrypt ten zawiera formularz przesyłania pliku, za pomocą którego użytkownik może przesłać plik RTF.
Po przesłaniu danych formularza sprawdzany jest typ pliku i jeżeli jest prawidłowy tworzony jest obiekt Scrooge.
Rozdział 11 – Ponowne wykorzystanie kodu
140
Przesłany plik jest odczytywany do tablicy za pomocą funkcji file(), a następnie używając funkcji implode(),
tablica jest konwertowana na ciąg, który jest przekazywany do obiektu Scrooge. Zwracaną wartością jest ciąg
zawierający kod HTML utworzony na podstawie przesłanego pliku. Wynikowy kod HTML jest wysyłany do
przeglądarki. Na rysunku 11.3. przedstawiony jest wynik uzyskany z przykładowego pliku RTF.
nie potrafię uruchomić tego przykładu
Rysunek 11.3.
Wynik
przetworzenia
przykładowego
pliku RTF na kod
HTML
Java jest tylko jednym z języków umożliwiających tworzenie komponentów, które można wykorzystać w
środowisku PHP. Następna część opisuje użycie obiektów COM w PHP.
COM
COM jest z natury oparty o Windows, więc dyskusja ta odnosić się będzie do PHP działającego na
serwerze pracującym pod kontrolą systemu Windows. Standardowa instalacja PHP dla Windows posiada obsługę
COM, więc nie jest potrzebna dodatkowa konfiguracja. Implementacja COM w PHP ewoluowała z opartego o
funkcje API w wersji 3, do implementacji obiektowej w PHP 4. Powoduje to, że użycie COM w PHP jest bardzo
naturalne.
W części tej omówimy serwer konwersji walut Cloanto Currency Server, dostępny z witryny
http://cloanto.com. Obiekt ten pozwala na przeliczanie walut pomiędzy sobą i posiada wewnętrzną bazę danych
kursów. Baza ta jest automatycznie uaktualniana, więc można użyć tego modułu w międzynarodowej aplikacji
handlu elektronicznego w celu umożliwienia wyświetlania cen w lokalnej walucie.
Obiekt ten posiada bogaty zestaw metod, ale bardzo łatwo można użyć podstawowych funkcji w
środowisku testowym. Na wydruku 11.9. zamieszczony jest przykład wykorzystania tego obiektu. Rysunki 11.4. i
11.5. pokazują formularz z cenami w dwóch różnych walutach.
Wydruk 11.9. Użycie serwera konwersji walut Cloanto
<html>
<head>
<title>Użycie potoków</title>
</head>
<body>
<?php
$aFreeProg = '/usr/bin/free';
if ( !is_file( $aFreeProg ) )
{
print( "Nie można znaleźć programu na serwerze<br>" );
}
else
{
$aLines = array();
if ( $aProgFile = popen( $aFreeProg . " -t", "r" ) )
{
$nIndex = 0;
$aLines = array();
while ( !feof( $aProgFile ) )
{
$aLine = fgets( $aProgFile, 1024 );
$aLines[$nIndex++] = $aLine;
}
pclose( $aProgFile );
$aCount = count( $aLines );
$aTotal = $aLines[$aCount - 2];
$aArray = split( "[ ]+", $aTotal );
$aTotalK = number_format( $aArray[1] );
$aUsedK = number_format( $aArray[2] );
$aFreeK = number_format( $aArray[3] );
?>
Całkowita ilość dostępnej pamięci <?=$aTotalK?> KB.<br>
Wolna pamięć <?=$aFreeK?> KB.<br>
Użyte <?=$aUsedK?> KB.<br>
<?php
}
else
141
PHP – Kompendium wiedzy
{
print ( "Nie można użyć programu na serwerze<br>" );
}
}
?>
</body>
</html>
Rysunek 11.4.
Przykład użycia
serwera Cloanto,
wyświetlana
waluta: dolary
amerykańskie
Rysunek 11.5.
Przykład użycia
serwera Cloanto,
wyświetlana
waluta: forinty
węgierskie
W skrypcie umieszczonym na wydruku 11.9. utworzona jest prosta tabela cen dla trzech różnych towarów.
Dodatkowo dostępny jest formularz do wyboru lokalnej waluty. Po przesłaniu danych formularza skrypt
wykorzystuje serwer Cloanto do przeliczenia cen na wybraną walutę. Obiekt ten jest używany do uzyskania listy
krajów, współczynników wymiany oraz wykonuje przeliczanie na bieżąco.
Jeżeli tworzona jest aplikacja handlu elektronicznego, przy pomocy tego obiektu można dodać niezwykle
przydatną dla użytkowników funkcję, która eliminuje frustrujące pomyłki w liczeniu cen. Wykorzystując serwer
Cloanto wraz z wykrywaniem typu przeglądarki można przeliczać ceny na lokalną walutę bez potrzeby pytania
użytkownika o jej nazwę.
Rozdział 11 – Ponowne wykorzystanie kodu
142
Z powodu dużej ilości programistów Windows oraz dojrzałości modelu COM, dostępne jest wiele
komponentów dla wszystkich typów projektów. Używając obsługi COM w PHP można z łatwością wykorzystać
istniejący kod we własnych projektach.
Inne metody
Prawdopodobnie posiadasz istniejący kod, którego nie da się wykorzystać przy użyciu żadnej z
przedstawionych metod. Jeżeli tak się stanie, nadal można go wykorzystać w PHP. Jeżeli kod ten jest skryptem
(na przykład skryptem Perla) lub można go skompilować do postaci wykonywalnej, da się go zastosować w
skrypcie.
PHP posiada kilka funkcji służących do uruchamiania programów i skryptów na serwerze. Ponieważ
tematem tego rozdziału jest integracja, najlepszą metodą wykorzystania programów na serwerze będzie
skorzystanie z funkcji popen() do uruchamiania programów i skryptów oraz przechwytywania ich wyników.
Technika ta była przedstawiona w rozdziale 4 „Operacje na plikach”, na przykładzie programu whois, dostępnego
na większości systemów *nix. Na wydruku 11.10. pokazany został przykład odczytywania bieżącej ilości użytej
pamięci w systemach *nix.
Wydruk 11.10. Użycie potoków do integracji PHP z istniejącymi skryptami lub programami
wykonywalnymi
<html>
<head>
<title>Użycie potoków</title>
</head>
<body>
<?php
$aFreeProg = '/usr/bin/free';
if ( !is_file( $aFreeProg ) )
{
print( "Nie można znaleźć programu na serwerze<br>" );
}
else
{
$aLines = array();
if ( $aProgFile = popen( $aFreeProg . " -t", "r" ) )
{
$nIndex = 0;
$aLines = array();
while ( !feof( $aProgFile ) )
{
$aLine = fgets( $aProgFile, 1024 );
$aLines[$nIndex++] = $aLine;
}
pclose( $aProgFile );
$aCount = count( $aLines );
$aTotal = $aLines[$aCount - 2];
$aArray = split( "[ ]+", $aTotal );
$aTotalK = number_format( $aArray[1] );
$aUsedK = number_format( $aArray[2] );
$aFreeK = number_format( $aArray[3] );
?>
Całkowita ilość dostępnej pamięci <?=$aTotalK?> KB.<br>
Wolna pamięć <?=$aFreeK?> KB.<br>
Użyte <?=$aUsedK?> KB.<br>
<?php
}
else
{
print ( "Nie można użyć programu na serwerze<br>" );
}
}
?>
</body>
</html>
Skrypt ten otwiera potok do standardowego programu free. Program zwraca dane na temat ilości
dostępnej pamięci w komputerze. Skrypt otwiera potok, który powoduje uruchomienie programu. Skrypt
odczytuje z potoku kolejne wiersze wyniku i wyświetla je w przeglądarce. W zależności od zwracanych danych
może być niezbędna bardziej zaawansowana analiza, ale podstawowa idea jest ta sama.
Technika ta może być użyta dla każdego programu, który zwraca wyniki na standardowe wyjście. W
przypadku systemów Unix oznacza to, że można w ten sposób użyć nieomal każdej komendy bezpośrednio z
PHP – Kompendium wiedzy
143
PHP. Pozwala to łatwo zrealizować odczytanie statusu systemu, zwracanie danych lub inne operacje. Jeżeli trzeba
przenieść istniejący kod do PHP, pozwala to na szybkie prototypowanie, przed zastosowaniem wcześniej
opisanych metod. Pozwala to na szybsze rozpoczęcie testowania funkcji aplikacji minimalizując ilość
koniecznych prac programistycznych. Należy jednak zaznaczyć, że uruchamianie programów wymaga znacznej
ilości zasobów serwera, co może powodować, że aplikacja będzie powolna i trudna do skalowania.
Podsumowanie
W PHP nie brakuje możliwości ponownego użycia kodu. Planując tworzenie biblioteki kodu w PHP
przeznaczonej do wielokrotnego użytku lub przenosząc istniejący kod do aplikacji WWW, można znaleźć
odpowiednie rozwiązanie. Z powodu olbrzymiej ilości istniejących komponentów (zarówno COM jak i Javy)
może się okazać, że większość projektowanej aplikacji jest już napisana. Używając tych komponentów można
znacznie zmniejszyć czas potrzebny na napisanie programu. Używając ich mądrze, można otrzymać aplikację
łatwiejsza w konserwacji i skalowaniu.
Bibliografia
Steve McConnell, Rapid Development. Seattle: Microsoft Press. 1996.
Rozdział 11 – Ponowne wykorzystanie kodu
144
Rozdział 12. Oddzielanie kodu HTML od
PHP
Wstęp
Przy projektowaniu zwykłych aplikacji zwykle nie bierze się pod uwagę oddzielania tworzenia interfejsu
użytkownika od tworzenia części wykonawczej programu. Jest to spowodowane tym, że standardowe aplikacje
wykorzystują standardowe narzędzia tworzenia interfejsu użytkownika, dostępne dla większości programistów.
Jedynymi fragmentami tworzonymi przez inne osoby są emblematy, rysunki przycisków i podobne elementy
wpływające na graficzny wygląd produktu.
Programowanie dla WWW, pozwala na zastosowanie o wiele bogatszego interfejsu użytkownika i przez to
bardzo często wymaga zatrudnienia projektantów specjalizujących się w tworzeniu strony graficznej aplikacji.
Gdy tworzenie interfejsu i kodu jest rozdzielone pomiędzy zespołami lub osobami, oddzielenie kodu i HTML
staje się naturalne a integracja wyników pracy ważna. Nawet w małych jednoosobowych projektach oddzielenie
HTML od logiki aplikacji powoduje, że konserwacja aplikacji jest prostsza i bardziej efektywna.
Wprowadzenie
Programowanie dla WWW jest często nazywane tworzeniem aplikacji wielowarstwowej, ponieważ
stosowane są tutaj oddzielne logiczne warstwy. Często używanymi nazwami warstw są: warstwa prezentacji,
warstwa aplikacji (biznesowa) oraz warstwa bazy danych. Każda z tych warstw może być fizycznie oddzielona od
drugiej. Najważniejszym zadaniem przy projektowaniu wielowarstwowym jest logiczne oddzielenie warstw a nie
ich fizyczna implementacja.
Głównymi zaletami podejścia wielowarstwowego przy tworzeniu aplikacji WWW są:
• Możliwość przydzielenia zadań osobom najlepiej przygotowanym do ich realizacji. Na przykład: graficy i
projektanci przygotowują stronę graficzną aplikacji, programiści tworzą logikę aplikacji a projektanci baz
danych projektują i uruchamiają infrastrukturę bazy danych.
• Możliwość zmian w warstwie bez potrzeby modyfikacji innych. W praktyce nadal jest to trudne, ale wiele
małych zmian ogranicza się do pojedynczej warstwy.
• Możliwość przeniesienia bądź replikacji określonych warstw na inny sprzęt w celu zapewnienia
skalowania bądź nadmiarowości.
Tak jak w przypadku wszystkich aplikacji, podczas trwania projektu aplikacji dla WWW mogą pojawić
się żądania wprowadzenia zmian. Jeżeli zmiany te są ograniczone do jednej warstwy, możliwe jest, że nie będzie
konieczne ponowne kodowanie. Celem tego rozdziału jest pokazanie sposobów tworzenia aplikacji odpornych na
zmiany w późnych stadiach rozwoju. Dodatkowo oddzielenie interfejsu użytkownika od logiki aplikacji jest jedną
z technik programowania modularnego, które pozwala na łatwiejsze użycie istniejących modułów.
W programowaniu tradycyjnym projekt modularny jest zwykle postrzegany jako tworzenie modułów
kodu, które mogą być używane w dowolnych aplikacjach. W przypadku projektowania dla WWW, moduły mogą
zawierać dane będące częścią interfejsu, np. prawa autorskie lub mogą być modułami kodu.
Modularność więcej wnosi do łatwości utrzymania aplikacji niż strukturalność i jest najważniejszym
czynnikiem zapobiegania konieczności tworzenia poprawek do aplikacji mających za zadanie usuwanie błędów.
Według badań 89% użytkowników kodu zgłaszało poprawienie możliwości utrzymania aplikacji modularnej, a w
rozległych testach programiści osiągali o 15% lepsze wyniki pracując nad programem modularnym niż nad
niemodularnym (McConnell, 1993).
Jak wspomniano w poprzednim rozdziale, tworzenie aplikacji modularnej wymaga dodatkowych prac
projektowych i podjęcia odpowiednich decyzji, ale w efekcie można otrzymać aplikację łatwiejszą do
zrozumienia i konserwacji. W książce A Methodology for Client/Server and Web Application Development Roger
Fournier sugeruje, że wspólne fragmenty lub moduły aplikacji zawsze powinny być najpierw projektowane,
tworzone i testowane a następnie udostępniane dla całej korporacji. Komponenty te powinny zawierać nie tylko
moduły kodu, ale również procedury przechowywane w bazie danych, wyzwalacze i zdalne procedury (Fournier,
1998).
W kolejnych częściach zostanie opisane kilka metod implementacji tych metod. Dodatkowo w tym
rozdziale jak również w rozdziale 14 „Witryny oparte o szablony”, dołączone są kompletne przykłady
zastosowania tych technik. Niektóre przykłady w kolejnych częściach pokazują techniki jakich należy unikać.
Oddzielenie i integracja przy użyciu wbudowanych funkcji
PHP
Ponieważ PHP zawiera bogaty zestaw funkcji i narzędzi, oddzielenie modułów kodu od modułów
interfejsu może być zrealizowane bezpośrednio przy pomocy narzędzi języka. Część ta opisuje kilka sposobów
zrealizowania tego zadania.
Motywacja
Pierwszą motywacją dla oddzielenia elementów HTML od kodu jest umożliwienie ponownego
wykorzystania kodu oraz jego łatwiejszej konserwacji. W wszystkich przykładach umieszczonych do tej pory w
książce, HTML i PHP były wymieszane w celu otrzymania krótkich i prostych przykładów. W przypadku
tworzenia kodu prawdziwego kodu technika ta jest niewygodna i powoduje powstanie trudnych do analizy
skryptów. Dla przykładu, skrypt z wydruku 12.1 zawiera fragment strony WWW ze zintegrowanym kodem PHP i
HTML.
Wydruk 12.1. PHP i HTML w jednym skrypcie
<?php
if ( $aShowForm == True ) {
?>
<p>
<font face="Arial" size="3">
<b>
<?php
print( $aQuestion );
?>
</b>
<form action="response.php3" method="POST">
<?php if (!empty( $UserID )) { ?>
<input type="Hidden" name="UserID" value="<?php print($aUserID );
?>">
<?php } ?>
<?php if ($aQuestionID != -1 ) { ?>
<input type="Hidden" name="QuestionID"
value="<?php print($aQuestionID ); ?>">
<?php } ?>
<ul>
<font face="Arial" size="2">
<!--wyświetl możliwe odpowiedzi-->
<?php
if ( $aQuestionID != -1 )
{
if ($aSortOrd != 0 )
//Sortowanie alfabetyczne
{
$aSQL = "SELECT * FROM Answers WHERE (QuestionID=$aQuestionID)
ORDER BY Text";
}
else
{
$aSQL = "SELECT * FROM Answers WHERE (QuestionID=$aQuestionID)";
}
$aDB->SetSQL( $aSQL );
Rozdział 12 – Oddzielanie kodu HTML od PHP
146
Oprócz tego, że przykład jest niekompletny, Wydruk 12.1 pokazuje jak skomplikowana może stać się
strona HTML z wbudowanym PHP. Nawet pomocą edytorów wyróżniających składnię, zlokalizowanie bloków
kodu może być trudne.
Problemy z utrzymaniem tego typu skryptów wykraczają jednak poza podstawowe problemy z
czytelnością kodu. Równie trudno jest wprowadzać zmiany zarówno do kodu, jak i wyglądu strony bez
wpływania na inne elementy. Na przykład, załóżmy, że projektanci uaktualnią wygląd przycisków nawigacji i
muszą być one umieszczone w witrynie. Odpowiedź na pytanie kto powinien wprowadzić zmiany jest trudna,
ponieważ projektanci mogą nie mieć wystarczająco dużo doświadczenia, aby nie popsuć kodu podczas
wprowadzania zmian, a programiści mogą być zmuszeni uaktualniać fragmenty kodu jedynie w celu zmiany
wyglądu. W obu przypadkach wynikiem są opóźnienia w projekcie. Można tego uniknąć stosując lepsze praktyki
projektowe.
Jeżeli twoja firma zamierza dostarczać wysokiej jakości i łatwe do konserwacji aplikacje WWW,
tworzenie stron za pomocą przedstawionej metody nie powinno być stosowane. Dodatkowo, jeżeli
zainwestowano w projekt interfejsu, nie należy tego marnować tworząc aplikację utrudniającą wprowadzanie
prostych zmian. Teraz zostaną zademonstrowane dostępne w PHP metody integrowania oddzielnych modułów
kodu i projektu.
Implementacja
Najprostsza metodą integracji osobnych modułów jest wykorzystanie funkcji PHP include() lub
Metoda ta wymaga umieszczenia elementów projektu HTML w osobnych plikach, które są używane
przez moduły kodu PHP w czasie ich wykonywania. Na przykład na wydruku 12.2 i 12.3 umieszczone są
fragmenty projektu strony rozdzielonej na nagłówek i stopkę. Na wydruku 12.4 pokazano sposób integracji tych
segmentów z dynamicznie tworzonym fragmentem strony.
Wydruk 12.2. Fragment z nagłówkiem HTML
require().
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Nowe książki wydawnictwa Helion</title>
</head>
<body>
<img src="logo.jpg" width="622" height="106" alt="" border="0">
<h1>Nowości wydawnictwa Helion</h1>
Wydruk 12.3. Fragment ze stopką HTML
<br><br><br>
<hr>
<p>
&copy; 2001 Helion. Wszystkie prawa zastrzeżone.
</p>
</body>
</html>
Wydruk 12.4. Skrypt łączący kod z projektem
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Nowe książki wydawnictwa Helion</title>
</head>
<body>
<img src="logo.jpg" width="250" height="68" alt="" border="0">
<h1>Nowości wydawnictwa Helion</h1>
Mimo, jest to bardzo prosty przykład, pokazuje on w jaki sposób można użyć funkcji include() w celu
integracji HTML i kodu, co ułatwia tworzenie efektywnych i łatwych do modyfikacji aplikacji. Na wydruku 12.1
pokazany jest wygląd wynikowej strony w przeglądarce. Przykład ten pokazuje wartość oddzielenia kodu od
HTML. Jeżeli projekt nagłówka lub stopki ulegnie modyfikacji, należy zmienić jedynie pliki HTML.
147
PHP – Kompendium wiedzy
Rysunek 12.1.
Łączenie
HTML i kodu
PHP przy
użyciu
include()
Zamiast funkcji include() lub reqiure(), można również wykorzystać standardowe funkcje obsługi
plików dostępne w PHP w celu odczytania plików HTML i dołączenia ich do strony. Metoda ta pozwala na
większą kontrolę nad obsługą plików, w tym odszukiwanie plików i obsługę błędów. Użycie własnych funkcji
dołączania plików pozwala na to, aby w plikach HTML nie było żadnego kodu PHP.
Kolejne wydruki zawierają bardziej szczegółowy przykład wykorzystania poprzedniej techniki
wykorzystując funkcje obsługi plików zamiast funkcji include(). Dodatkowo użyte zostały kaskadowe arkusze
stylów (CSS) w celu zapewnienia większych możliwości zmiany wyglądu strony. Na wydruku 12.5. i 12.6.
ponownie jest umieszczony nagłówek i stopka, natomiast na wydruku 12.7 znajduje się warstwa logiczna strony.
Dla celów tej demonstracji utworzone zostały dwa osobne pliki CSS.
Wydruk 12.5. Nagłówek HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Nowe książki wydawnictwa Helion</title>
<link rel="STYLESHEET" type="text/css" href="css1.css">
</head>
<body>
<img src="logo.jpg" width="622" height="106" alt="" border="0">
<h1>Nowości wydawnictwa Helion</h1>
Wydruk 12.6. Stopka HTML
<p class="copyright">
&copy; 2001 Helion. Wszystkie prawa zastrzeżone.
</p>
</body>
</html>
Wydruk 12.7. Skrypt aplikacji PHP
<?php
function MyIncludeFile( $aFileName )
{
if ( !is_file( $aFileName ) )
{
// przekierunkowanie na stronę błędu
exit;
}
$aFileArray = file( $aFileName );
foreach( $aFileArray as $aLine )
{
print( "$aLine" );
Rozdział 12 – Oddzielanie kodu HTML od PHP
148
}
}
MyIncludeFile( "./header_2.html" );
include( "./db_mysql.inc" );
// tworzenie klasy news_db class służące do odczytu wiadomości
class news_db extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
var $Password
= "root";
}
// Tworzenie obiektu klasy news_db i odczytanie wiadomości
$aDB = new news_db;
$aDB->query( "select * from news order by date desc limit 5" );
while( $aDB->next_record() )
{
$aNewsID
= $aDB->f( "news_id" );
$aAuthor
= $aDB->f( "author" );
$aTitle
= $aDB->f( "title" );
$aSynopsis = $aDB->f( "synopsis" );
print(
print(
print(
print(
print(
"<h2>$aTitle</h2>" );
"<h4>autor: $aAuthor</h4>" );
"<p>$aSynopsis</p>" );
"<a href=\"full_story.phtml?news_id=$aNewsID\">pełny tekst...</a>" );
"<br><br><hr>" );
}
MyIncludeFile( "./footer_2.html" );
?>
Aplikacja ta wykorzystuje małą bazę danych do przechowywania tekstów wiadomości. Tak jak w
poprzednich przykładach, w przykładzie tym wykorzystane są klasy obsługi baz danych PHPLIB. Zawartość i
struktura bazy danych nie jest istotna, ponieważ jest to przykład rozdzielania kodu oraz technik jego integracji.
Dodatkowo ważna jest elastyczność rozwiązania wykorzystującego pliki CSS. Mimo, że w tekście strony PHP
znajduje się kilka podstawowych znaczników HTML, ich użycie jest ograniczone a sposób ich interpretacji jest
kontrolowany przez CSS. Wygląd kompletnej strony jest pokazany na rysunkach 12.2. i 12.3.
149
PHP – Kompendium wiedzy
Rysunek
12.2.
Przykłado
wa
aplikacja
z
pierwszym
arkuszem
stylów
Rozdział 12 – Oddzielanie kodu HTML od PHP
150
Rysunek
12.3.
Przykłado
wa
aplikacja
z
pierwszym
arkuszem
stylów
Czego należy unikać
Korzystając z tej metody należy unikać mieszania kodu programu i HTML. Dołączane pliki HTML
powinny zawierać jedynie kod HTML, a dołączane pliki PHP — jedynie kod PHP. Ułatwia to rozdzielenie
odpowiedzialności programistów PHP i projektantów interfejsu. Należy unikać kodu PHP, który generuje kod
HTML. Choć pozwala to na pisanie kodu PHP nie zawierającego znaczników HTML, powoduje to, że za zmiany
projektu witryny odpowiada programista PHP. Utrudnia to również wprowadzanie hurtowych zmian w wyglądzie
całej witryny WWW.
Podsumowanie: Oddzielanie i integracja przy wykorzystaniu funkcji
PHP
Tworząc mechanizm oddzielania kodu PHP od HTML należy pamiętać o najważniejszych celach takiego
działania. Czasami programiści przesadzają w swoim zapale pisania kodu i tworzą mechanizmy, które nie
spełniają prawdziwych potrzeb. Celem oddzielenia HTML od PHP jest uproszczenie aplikacji, podział
odpowiedzialności pomiędzy projektantami i programistami oraz ułatwiają konserwację aplikacji.
Celem oddzielenia HTML od PHP może być całkowite oddzielenie projektu od logiki aplikacji. Używając
przedstawionych technik i wykorzystując przy projektowaniu pliki CSS, cel ten jest nieomal osiągnięty. Jednak
czasami trzeba dynamicznie wygenerować niektóre znaczniki HTML, na przykład może być to generowany
dynamicznie znacznik łącza. Również jeżeli przesyłany jest identyfikator sesji lub inny identyfikator specyficzny
dla aplikacji, trzeba dynamicznie generować wszystkie łącza. W tych przypadkach jeżeli wykorzystywana będzie
opisana technika integracji, niezbędne będzie dołączenie części znaczników HTML do kodu PHP.
151
PHP – Kompendium wiedzy
W następnej części zatytułowanej „Wykorzystanie systemu szablonów” opisuję szczegóły metody
umożliwiającej całkowite oddzielenie kodu PHP od HTML. Jest to zalecana metoda, ponieważ cały HTML może
być pod opieką projektantów.
Wykorzystanie systemu szablonów
System szablonów jest mechanizmem przeznaczonym do całkowitego oddzielenia elementów projektu
HTML od kodu PHP. Oczywistą zaletą wykorzystania szablonów jest umożliwienie doświadczonym
projektantom HTML na całkowite panowanie nad wszystkimi aspektami projektu. Gdy wszystkie znaczniki
HTML zostaną usunięte z kodu, cała warstwa projektu interfejsu aplikacji może być modyfikowana niezależnie
od logiki aplikacji.
Tak jak przy wszystkich dotychczasowych technikach projektowania, aby osiągnąć zamierzony wynik
wykorzystując szablony, wymagane są dodatkowe prace projektowe oraz skuteczne wprowadzenia ich w życie.
Podstawowym założeniem jest podział strony na jeden lub więcej szablonów projektowych, które są łączone z
dynamiczną zawartością generowaną przez kod PHP. W prostych aplikacjach plik szablonu może być
wykorzystywany dla wszystkich stron witryny. W bardziej skomplikowanych, może być użyte bardzo wiele
szablonów.
FastTemplate
Mimo, że każdy może zbudować własny system szablonów, dostępne jest świetne narzędzie o nazwie
FastNet, które można załadować z witryny www.thewebmasters.net. FastTemplate jest łatwy do użycia i istnieje
specjalna dokumentacja dla początkujących. Aby rozpocząć pracę z FastTemplate należy utworzyć plik szablonu,
zwykle z rozszerzeniem tpl. Następnie w kodzie należy wykonać następujące kroki:
1. Utworzenie obiektu klasy FastTemplate.
2. Użycie metody define() do przydzielenia plikom szablonów unikalnych nazw.
3. Użycie metody assign() do skojarzenia wartości do zmiennych szablonu.
4. Uruchomienie metody parse() do przetworzenia pliki szablonu i przypisania wartości do zmiennych.
5. Użycie metod FastPrint() lub fetch() do wypisania lub odczytania przetworzonego pliku szablonu.
W szablonach FastTemplate zmienne są umieszczane w nawiasach klamrowych ({}). Przykładowy plik
szablonu znajduje się na wydruku 12.8.
Wydruk 12.8. Przykładowy szablon FastTemplate
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>{TITLE}</title>
</head>
<body bgcolor="{BODY_COLOR}">
{BODY}
<hr>
<font size="1">
{COPYRIGHT}
</font>
</body>
</html>
Przykładowy szablon pokazany na wydruku 12.8 zawiera cztery zmienne FastTemplate: TITLE,
BODY_COLOR, BODY i COPYRIGHT. W najprostszym przypadku, zmienne te mogą być ustawione bezpośrednio z kodu,
w sposób pokazany na wydruku 12.9.
Wydruk 12.9. Skrypt aplikacji
<?php
include( "class.FastTemplate.php" );
$aTemplate = new FastTemplate( "." );
$aTemplate->define( array( 'basic' => 'sample_1.tpl' ) );
$aBodyText = "Bardzo krótka zawartość strony.
for ( $nIndex = 1; $nIndex <= 10; $nIndex++ )
{
$aBodyText .= "$nIndex ";
}
Rozdział 12 – Oddzielanie kodu HTML od PHP
";
152
$aTemplate->assign( array( 'TITLE' => 'Prosty przykład',
'BODY_COLOR' => 'white',
'BODY'
=> $aBodyText,
'COPYRIGHT' => 'Helion 2001, wszystkie prawa zastrzeżone' ) );
$aTemplate->parse( 'PAGE', 'basic' );
$aTemplate->FastPrint( 'PAGE' );
?>
Pierwszym krokiem jest utworzenie obiektu klasy FastTemplate. Konstruktor wymaga jednego argumentu
— ścieżki do pliku szablonu. W naszym przykładzie został wykorzystany bieżący katalog „.”. Następnie plikowi
umieszczonemu na wydruku 12.8 zostaje nadana nazwa basic. W kilku kolejnych liniach generowany i
zapamiętywany jest również test strony oraz wykorzystując metodę assign(), zmiennym FastTemplate
przypisywane są wartości. Na koniec Szablon jest przetwarzany i zapamiętywany w zmiennej PAGE, a następnie jej
zawartość wysyłana jest do przeglądarki. Wynik pokazany jest na rysunku 12.4.
Rysunek 12.4.
Wynik
przetwarzania
prostego szablonu
Po przetworzeniu szablonu przez obiekt FastTemplate, wynik jest zapisany w zmiennej, która może zostać
wydrukowana lub zachowana dla innych celów, lub zmienna ta może być użyta w kolejnym szablonie. Ostatnia
opcja pozwala na zagnieżdżanie plików szablonów. Nowymi plikami są: plik z danymi o prawach autorskich,
oraz główny plik szablonu zamieszczone odpowiednio na wydrukach 10 i 11.
Wydruk 12.10. Szablon z prawami autorskimi (copyright.tpl)
&copy; {YEARS} Helion.
Wszystkie prawa zastrzeżone. Dodatkowe informacje na temat praw autorskich
mozna znaleźć <a href="legal.phtml">tutaj</a>.
Wydruk 12.11. Główny plik szablonu (body.tpl)
<table width="100%">
<tr>
<th colspan="3">
{PAGE_HEADER}
</th>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td align="center" valign="top">
<!-- Panel nawigacji -->
<a href="index.phtml">początek</a><br><br>
<a href="about.phtml">o nas</a><br><br>
<a href="links.phtml">łącza</a><br><br>
</td>
<td width="90%" valign="top">
<!-- Główna sekcja tekstu -->
{PAGE_CONTENT}
</td>
<td width="125" valign="top">
<!-- Tutaj reklamy i inne -->
</td>
</tr>
</table>
Każdy z dodatkowych plików szablonów, które zostały do tej pory pokazane, zawierają swoje zmienne
FastTemplate i aby szablony działały prawidłowo, muszą im zostać przypisane wartości. Jeżeli nie zostanie
przypisana zmienna FastTemplate, wygenerowane zostaną następujące ostrzeżenia:
[Wed Sep 12 19:42:38 2001] [error] [FastTemplate] Warning: no value found for variable: {PAGE_HEADER}
[Wed Sep 12 19:42:38 2001] [error] [FastTemplate] Warning: no value found for variable: {PAGE_CONTENT}
[Wed Sep 12 19:42:38 2001] [error] [FastTemplate] Warning: no value found for variable: {YEARS}
153
PHP – Kompendium wiedzy
Dodając nowe pliki szablonów należy również zmienić główny plik PHP. Na wydruku 12.12 pokazany
jest nowy skrypt PHP używający zagnieżdżonych szablonów.
Wydruk 12.12. Zagnieżdżone pliki szablonów
<?php
include( "class.FastTemplate.php" );
function GetCurrentYear( )
{
$aNow
= getdate();
$aNowYear
= $aNow["year"];
return $aNowYear;
}
$aTemplate = new FastTemplate( "." );
$aTemplate->define( array( 'basic'
'copyright'
'body'
=> 'sample_1.tpl',
=> 'copyright.tpl',
=> 'body.tpl' ) );
$aBodyText = "Bardzo krótka zawartość strony. ";
for ( $nIndex = 1; $nIndex <= 10; $nIndex++ )
{
$aBodyText .= "$nIndex ";
}
$aStartYear
= 1997;
$aCurrentYear = GetCurrentYear();
$aYears = "$aStartYear";
for ( $nIndex = $aStartYear + 1; $nIndex <= $aCurrentYear; $nIndex++ )
{
$aYears .= ", $nIndex";
}
$aTemplate->assign( array( 'TITLE'
'BODY_COLOR'
'YEARS'
'PAGE_HEADER'
'PAGE_CONTENT'
) );
=>
=>
=>
=>
=>
'Lepszy przykład',
'white',
$aYears,
'Lepszy przykład',
$aBodyText
$aTemplate->parse( 'BODY', 'body' );
$aTemplate->parse( 'COPYRIGHT', 'copyright' );
$aTemplate->parse( 'PAGE', 'basic' );
$aTemplate->FastPrint( 'PAGE' );
?>
W przykładzie tym zdefiniowano dwa dodatkowe pliki szablonów nadając im nazwy copyright i body.
Ponieważ te pliki szablonów zawierają własne zmienne FastTemplate, zmiennym tym należy przypisać wartości.
Wartość zmiennej YEARS jest generowana automatycznie, więc dane o prawach autorskich są zawsze aktualne.
Zmienna $aBodyText posiada identyczną wartość jak w poprzednim przykładzie. Należy zauważyć, że w tym
rozdziale zmienne BODY i COPYRIGHT nie są ustawiane w metodzie assign(). Zamiast tego zmienne te otrzymują
wartości przy wywołaniu metody parse() na końcu tego skryptu. Wynik działania tego skryptu jest pokazany na
rysunku 12.5.
Rozdział 12 – Oddzielanie kodu HTML od PHP
154
Rysunek 12.5.
Wynik działania
zagnieżdżonych
szablonów
FastTemplate
Klasa FastTemplate jest potężnym narzędziem, za pomocą którego można tworzyć bogate i złożone
projekty interfejsu. Aby lepiej zilustrować tą technikę w kolejnym przykładzie wrócimy do przykładu aplikacji
dostarczającej najnowszych wiadomości. Zamiast wykorzystywać do tego celu pliki dołączane, w kodzie tym
wykorzystana zostanie siła klasy FastTemplate.
Na wydrukach 12.13, 12.14 i 12.15 umieszczony jest kod HTML szablonów tworzących podstawowy
układ strony, treść i element wiadomości. W przykładzie tym użyty jest szablon zawierający prawa autorskie,
wykorzystany w poprzednim przykładzie.
Wydruk 12.13. Podstawowy szablon dla aplikacji dostarczającej wiadomości (ft_news_base.tpl)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>{TITLE}</title>
<link rel="STYLESHEET" type="text/css" href="css2.css">
</head>
{NEWS_BODY}
</html>
Wydruk 12.14. Szablon treści w aplikacji wiadomości (ft_news_body.tpl)
<body>
<table width="640" border="0" align="center">
<tr>
<td>
<img src="logo.jpg" width="250" height="68" alt="" border="0">
<h1>Nowości wydawnictwa Helion</h1>
</td>
</tr>
<tr>
<td>
<br><br>
{NEWS_ITEMS}
</td>
</tr>
<tr>
<td>
<br>
<p class="copyright">
{COPYRIGHT}
</p>
</td>
</tr>
</table>
</body>
Wydruk 12.15. Szablon elementu wiadomości (ft_news_item.tpl)
<h2>{NEWS_TITLE}</h2>
<h4>autor: {NEWS_AUTHOR}</h4>
<p>{NEWS_SYNOPSIS}</p>
<a href="{FULL_STORY_URL}">więcej...</a>
<br><br><hr>
Na wydruku 12.16. zamieszczony jest skrypt generujący stronę z nowościami. Skrypt ten jest bardziej
skomplikowany niż w poprzednim przykładzie, ale większość kodu pochodzi z poprzednich przykładów.
155
PHP – Kompendium wiedzy
Wydruk 12.16. Główny skrypt aplikacji
<?php
include( "class.FastTemplate.php" );
include( "./db_mysql.inc" );
error_reporting( E_ALL & ~E_NOTICE );
function GetCurrentYear( )
{
$aNow = getdate();
$aNowYear = $aNow["year"];
return $aNowYear;
}
// Tworzenie klasy news_db do pobrania wiadomości
class news_db extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
var $Password
= "root";
}
$aTemplate = new FastTemplate( "." );
$aTemplate->define( array( "base"
"body"
"item"
"copyright"
=>
=>
=>
=>
"ft_news_base.tpl",
"ft_news_body.tpl",
"ft_news_item.tpl",
"copyright.tpl" ) );
// generowanie roku dla treści praw autorskich
$aStartYear
= 1997;
$aCurrentYear = GetCurrentYear();
$aYears = "$aStartYear";
for ( $nIndex = $aStartYear + 1; $nIndex <= $aCurrentYear; $nIndex++ )
{
$aYears .= ", $nIndex";
}
$aTemplate->assign( array( "YEARS"
"TITLE"
=> $aYears,
=> "Nowości wydawnictwa Helion" ) );
// Tworzenie obiektu klasy news_db i generowanie elementów wiadomości
$aDB = new news_db;
$aDB->query( "select * from news order by date desc limit 5" );
while( $aDB->next_record() )
{
$aNewsID
= $aDB->f( "news_id" );
$aAuthor
= $aDB->f( "author" );
$aTitle
= $aDB->f( "title" );
$aSynopsis = $aDB->f( "synopsis" );
$aURL = "full_story.phtml?news_id=$aNewsID";
$aTemplate->assign( array( "NEWS_TITLE"
"NEWS_AUTHOR"
"NEWS_SYNOPSIS"
"FULL_STORY_URL"
=>
=>
=>
=>
$aTitle,
$aAuthor,
$aSynopsis,
$aURL ) );
$aTemplate->parse( "NEWS_ITEMS", ".item" );
}
$aTemplate->parse( "COPYRIGHT", "copyright" );
$aTemplate->parse( "NEWS_BODY", "body" );
$aTemplate->parse( "BASE", "base" );
$aTemplate->FastPrint( "BASE" );
?>
W przykładzie tym funkcja generująca rok dla tekstu o prawach autorskich pochodzi z poprzednich
przykładów, a obsługa bazy danych z poprzedniej realizacji aplikacji wiadomości. Zauważmy, że na początku
skryptu wyłączone zostały ostrzeżenia PHP, ponieważ ostrzeżenie generowane przez FastTemplate zostaną
omówione później.
W skrypcie tym zdefiniowane zostały cztery pliki szablonów. Na początku skryptu inicjowane są dwie
główne zmienne FastTemplate, YEARS i TITLE reprezentujące odpowiednio rok praw autorskich i tytuł strony.
Kolejną główną funkcją skryptu jest dynamiczne dodawanie kolejnych wiadomości. Zostało to
zrealizowane przez pobranie pięciu najnowszych wiadomości z bazy danych i wypisanie ich przy pomocy pętli.
W każdym przebiegu pętli przetwarzany jest szablon item i dodawany do zmiennej FastTemplate NEWS_ITEMS.
Rozdział 12 – Oddzielanie kodu HTML od PHP
156
Dodawanie to jest zrealizowane poprzez dodanie kropki (.) przed nazwą szablonu. Dlatego właśnie w pierwszym
przebiegu pętli FastTemplate generuje ostrzeżenie wskazujące, że zmienna NEWS_ITEMS nie jest zainicjowana. Po
ustawieniu w pętli wartości zmiennej NEWS_ITEMS przetwarzana jest reszta szablonów a następnie drukowana
strona.
Poprzedni przykład pokazuje w jaki sposób można wykorzystać klasę FastTemplate do generowania
powtarzających się elementów, takich jak treść kolejnych wiadomości. Podobna konstrukcja może być
wykorzystana do tworzenia wierszy tablicy lub listy łączy. Po poznaniu podstawowych założeń używanie
FastTemplate staje się niezwykle naturalne.
Oczywistą zaletą klasy FastTemplate jak również innych systemów szablonów jest to, że elementy
projektu strony mogą być tworzone i zmieniane niezależnie od kodu aplikacji. Mimo, że wykorzystanie systemu
szablonów wymaga nieco innego myślenia w trakcie projektowania, jest ono warte zainteresowania.
Zaawansowane techniki użycia FastTemplate
W poprzednich rozdziałach dwa zagadnienia były z rozmysłem odsuwane aż do tego rozdziału. Pierwsze
zostało wspomniane w rozdziale 7. „Sesje i stan aplikacji”, w którym mówiono o lepszych sposobach
przenoszenia identyfikatora sesji w aplikacji. Drugie znalazło się w rozdziale 9. „Niezależność od przeglądarki”,
gdzie znalazła się sugestia, że system szablonów może być alternatywną metodą dostarczania zawartości zależnej
od typu przeglądarki. W tej części skupimy się na tych dwóch zagadnieniach.
Pierwsze zagadnienie, przesyłanie identyfikatora sesji, powinno być w tym momencie dosyć oczywiste.
Wykorzystując szablony projekt może zawierać dynamiczne łącza URL generowane w kodzie PHP. Podstawowy
przykład szablonu nawigacyjnego zamieszczony jest na wydruku 12.17.
Wydruk 12.17. Szablon nawigacji (navi.tpl)
<a href="{HREF_INDEX}">początek</a>
<a href="{HREF_NEWS}">nowości</a>
<a href="{HREF_LINKS}">łącza</a>
Właściwe adresy URL dla łączy mogą być tak generowane, aby zawierały identyfikator sesji, lub inny
specyficzny dla aplikacji. Inną zaletą wykorzystania takich adresów jest łatwa modyfikacja położenia stron w
czasie pracy aplikacji. Na wydruku 12.18 zamieszczony jest skrypt generujący dynamiczne adresy URL dla
poprzedniego szablonu.
Wydruk 12.18. Szablon nawigacji
<?php
include( "class.FastTemplate.php" );
session_start();
function MyGenURL( $aLinkName )
{
switch( $aLinkName )
{
case 'HREF_INDEX' :
$aBaseURL = 'index.phtml';
break;
case 'HREF_NEWS' :
$aBaseURL = 'news.phtml';
break;
case 'HREF_LINKS' :
$aBaseURL = 'links.phtml';
break;
default :
$aBaseURL = 'badlink.phtml';
break;
}
return $aBaseURL . session_name() . "=" . session_id();
}
$aTemplate = new FastTemplate( "." );
$aTemplate->define( array( 'navi' => 'navi.tpl' ) );
$aTemplate->assign( array( 'HREF_INDEX' => MyGenURL( 'HREF_INDEX' ),
'HREF_NEWS' => MyGenURL( 'HREF_NEWS' ),
'HREF_LINKS' => MyGenURL( 'HREF_LINKS' ) ) );
$aTemplate->parse( 'NAVI', 'navi' );
$aTemplate->FastPrint( 'NAVI' );
?>
157
PHP – Kompendium wiedzy
Funkcja MyGenURL() jest głównym elementem skryptu. Pobiera ona symboliczną nazwę łącza i zwraca
prawdziwą lokalizację strony wraz z dołączonymi danymi sesji. Funkcja taka ma dodatkową możliwość obsługi
nieznanych nazw łączy. Pozwala to unikać brzydkich komunikatów „HTTP 404: Page Not Found” spotykanych
we wielu aplikacjach WWW.
Wykorzystanie szablonów do dostarczania treści zależnych od przeglądarki również jest korzystne. W
rozdziale 9. zasugerowane były metody warunkowego dołączania plików lub przekierowania użytkownika do
katalogu odpowiadającego używanej przeglądarce. Używając szablonów preferowana jest pierwsza metoda.
Problemem z przekierowaniem jest to, że użytkownik może wysłać łącze do strony do osoby używającej innej
przeglądarki. Przykład umieszczony na wydrukach 19., 20., 21. i 22. pokazuje w jaki sposób można zintegrować
treści zależne od typu przeglądarki z szablonami. Na wydruku 12.19. pokazany jest główny szablon strony.
Wydruk 12.20. i 12.21. to strony zależne od możliwości przeglądarki, natomiast wydruk 12.22 zawiera skrypt
PHP.
Wydruk 12.19. Podstawowy szablon strony (base_basic.tpl)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>{TITLE}</title>
</head>
<body>
{NAVI}
</body>
</html>
Wydruk 12.20. Menu oparte o Flash (flash_menu.tpl)
<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0"
WIDTH=320 HEIGHT=240>
<PARAM NAME=movie VALUE="flash_menu.swf"> <PARAM NAME=quality VALUE=high> <PARAM NAME=bgcolor
VALUE=#FFFFFF> <EMBED src="Track As Menu.swf" quality=high bgcolor=#FFFFFF WIDTH=320 HEIGHT=240
TYPE="application/x-shockwave-flash"
PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></EMBED>
Wydruk 12.21. Menu HTML (html_menu.tpl)
<a href="index.phtml">początek</a>
<a href="news.phtml">wiadomości</a>
<a href="links.phtml">łącza</a>
Wydruk 12.22. Skrypt
<?php
include( "class.FastTemplate.php" );
// zakładamy, że zmienna $aHasFlash jest ustawiana przez
// prawdziwą funkcję wykrywania Flash-a
$aHasFlash = False;
if ( $aHasFlash == True )
{
$aNaviFile = "flash_menu.tpl";
}
else
{
$aNaviFile = "html_menu.tpl";
}
$aTemplate = new FastTemplate( "." );
$aTemplate->define( array( "navi" => $aNaviFile,
"base" => "base_basic.tpl" ) );
$aTemplate->assign(array("TITLE" => "Przykład działania zależnego od przeglądarki"));
$aTemplate->parse( "NAVI", "navi" );
$aTemplate->parse( "BASE", "base" );
$aTemplate->FastPrint( "BASE" );
?>
Przykład ten pokazuje, w jaki sposób można umieszczać na stronie menu zrealizowane w programie
Macromedia FlashTM, gdy używana przeglądarka potrafi je wyświetlić i zwykłe menu HTML w przypadku
korzystania z innych przeglądarek. Oczywiście powinna zostać wykorzystana prawdziwa funkcja wykrywająca,
podobna do tej zamieszczonej na witrynie firmy Macromedia.
W oparciu o specyficzne potrzeby witryny można pomysłowo rozdzielać wiele aspektów projektu w
zależności od możliwości używanej przeglądarki i wykorzystać system szablonów do dostarczenia najlepszej
zawartości dla każdej z przeglądarek.
Rozdział 12 – Oddzielanie kodu HTML od PHP
158
Podsumowanie
Oddzielanie elementów projektu aplikacji WWW od jej logiki powoduje promowanie projektowania
modularnego i dzięki temu zwiększenie możliwości ponownego wykorzystania kodu oraz jego łatwiejszej
konserwacji. Z powodu elastyczności PHP cel modularnego tworzenia witryn WWW może być osiągnięty
wieloma sposobami. Zalecaną w tym rozdziale metodą jest wykorzystanie systemu szablonów, który pozwala na
pełne oddzielenie wszystkich elementów projektu od kodu.
Tak zupełnie na marginesie, rozdział ten ma podłoże czysto osobiste. Jakiś czas temu zdałem sobie
sprawę, że nigdy nie będę projektantem graficznym ani artystą, więc w mojej firmie poświęciłem sporo czasu na
znalezienie sposobu na dołączenie projektów profesjonalnych projektantów z moimi aplikacjami. Pozwala to
osiągnąć ogólną poprawę witryny, ponieważ warstwa prezentacji jest odpowiedniej jakości a ja nie muszę jej
tworzyć ani zmieniać samemu. Wykorzystuję klasę FastTemplate w nieomal wszystkich moich obecnych
projektach. Pozwala ona moim projektantom łatwo stworzyć pliki szablonów stron wykorzystując nawiasy
klamrowe do zaznaczenia elementów i pozwala mi na projektowanie w pełni funkcjonalne oraz szybkie zmiany w
logice aplikacji.
Bibliografia
Roger Fournier. A Mehodology for Client/Server and Web Application Development. New Jersey:
Prentice Hall PTR. 1998.
Steve McConnell. Code Complete. Seattle: Microsoft Press. 1993.
159
PHP – Kompendium wiedzy
Rozdział 13. Fajny PHP
Wstęp
W przypadku języka tak potężnego i rozszerzalnego jak PHP, trudno jest poszufladkować wszystkie fajne
rzeczy, jakie można zrobić przy jego pomocy. Rozdział ten zawiera opis niektórych z nich. Tematy tu omawiane
są albo zagadnieniami, które musiałem kiedyś zaprogramować, albo odpowiedziami na pytania często
pojawiające się na listach dyskusyjnych poświęconym PHP. Rozdział ten nie opisuje oczywiście wszystkich
rozszerzeń i własności PHP, ale opisuje niektóre z nich, które nie zostały opisane w innych częściach książki.
Wysyłanie do przeglądarki plików innych niż HTML
Ogólnie mówiąc, PHP jest wykorzystywany do wysyłania plików HTML do przeglądarki, ale może być
on również użyty do automatyzacji ściągania plików, lub dostarczania innych typów plików do przeglądarki. Na
przykład można umożliwić użytkownikom na zapisanie fragmentu zawartości bazy danych w formacie
tekstowym, na przykład takim jak CSV. Przykład ten ilustruje sposób, w jaki można umożliwić użytkownikom
zapisanie fragmentu tabeli bazy danych. Na wydruku 13.1. umieszczono skrypt pobierający dane z bazy danych,
formatujący je oraz wysyłający je do przeglądarki.
Wydruk 13.1. Wysyłanie CSV do przeglądarki
<?php
include_once( "db_mysql.php" );
// Tworzenie klasy pochodnej po DB_Sql służącej do pobrania danych pracownika
class employee_db extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
var $Password
= "root";
}
$aSQL
= "select * from employees ";
$aDB = new employee_db;
$aDB->query( $aSQL );
/* metoda metadata() bardzo zależy od wersji MySQL
przykład ten może nie działać dobrze na wszystkich wersjach MySQL */
$aMetaData = $aDB->metadata();
$aData = "";
$aNumFields = count( $aMetaData );
for ( $nIndex = 0; $nIndex < $aNumFields; $nIndex++ )
{
$aData .= "\"" . $aMetaData[$nIndex]["name"] . "\",";
}
// usunięcie ostatniego znaku w ciągu (,) i znaku końca linii (\n)
$aData = substr( $aData, 0, strlen( $aData ) - 1 ) . "\n";
while ( $aDB->next_record() )
{
$aLine = "";
for ( $nIndex = 0; $nIndex < $aNumFields; $nIndex++ )
{
$aLine .= "\"" . $aDB->f( $nIndex ) . "\",";
}
// usunięcie ostatniego znaku w ciągu (,) i znaku końca linii (\n)
$aLine = substr( $aLine, 0, strlen( $aLine ) - 1 );
$aLine .= "\n";
$aData .= $aLine;
}
header( "Content-length: " . strlen( $aData ) );
header( "Content-type: application/octetstream" );
header( "Content-disposition: inline; filename=\"employees.csv\"" );
print( $aData );
?>
Pierwszą czynnością realizowaną przez skrypt jest zdefiniowanie klasy pochodnej po klasie DB_Sql
pochodzącej z PHPLIB, która jest używana do uruchomienia zapytania na bazie danych. Więcej informacji na ten
temat znajduje się w rozdziale 6. „Współpraca z bazami danych”. Następnie wykonywane jest zapytanie i
pobierane z niego są metadane. Metadane zawierają ilość pól oraz nazwę każdego ze zwracanych pól. Dane te są
potrzebne do skonstruowania pierwszej linii pliku CSV. Zwykle CSV zawiera wiersz nagłówka zawierający
nazwy pól, a następnie umieszczone są wiersze danych. Każde pole w CSV jest umieszczone w cudzysłowach i
oddzielona są od siebie przecinkami. Każdy wiersz kończy się znakiem nowej linii.
Po dodaniu wiesza nagłówka, skrypt przebiega po kolejnych rekordach wyniku i konstruuje z nich
sformatowane wiersze CSV. Następnie do przeglądarki wysyłane są trzy wiersze nagłówka HTML. Pierwszy
zawiera wielkość wysyłanego pliku, Następna zawiera typ zawartości pliku. Jest ona ważna, ponieważ
przeglądarka wykorzystuje te dane do rozpoznania, w jaki sposób powinna traktować przesyłane dane. Jeżeli linia
ta zawierała by text/html, przeglądarka próbowała by wyświetlić przychodzące dane w postaci HTML. Ponieważ
typem tym jest w tym przypadku application/octetstream, przeglądarka nie próbuje wyświetlić tych danych, a
zamiast tego pozwala zapisać je na dysku. Ostatni wiersz wskazuje przeglądarce, że dane są wysyłane razem z
nagłówkami oraz sugeruje nazwę dla zapisywanego pliku. Na rysunku 13.1. pokazane jest okno dialogowe
wyświetlane przez Internet Explorer po uruchomieniu tego skryptu.
Pierwsze dwie linie tego pliku umieszczone są na wydruku 13.2., natomiast na rysunku 13.2. widać
wygląd tego pliku w programie Microsoft Excel.
Rysunek 13.1.
Okno dialogowe
Zapisz jako
161
PHP – Kompendium wiedzy
Rysunek 13.2. Plik
CSV w Excelu
Wydruk 13.2. Surowy plik CSV
"id","first","last","address","position"
"1","Bob","Smith","Poziomkowa 16, Miastko","Szef marketingu"
Innym częstym zastosowaniem przesyłania zawartości innej niż HTML do przeglądarki, jest wysyłanie
plików graficznych. Na przykład możesz mieć aplikację, która zapisuje małe rysunki w bazie danych. Następnie
można przy pomocy PHP zapisywać je oraz pobierać i wyświetlać. Poniższy wydruk pokazuje w jaki sposób
można pobierać rysunki poprzez formularz HTML, zapisywać je w bazie danych, a następnie wyświetlać je na
innej stronie. Na wydruku 13.3. znajduje się formularz HTML używany do przesyłania rysunków, natomiast
wydruk 13.4. zawiera skrypt zapisujący rysunki do bazy danych. Tabela MySQL używana do przechowywania
rysunków zdefiniowana jest następująco:
CREATE TABLE pictures (
picture_id int(11) DEFAULT '0' NOT NULL,
name varchar(30) NOT NULL,
date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
pic_data mediumblob NOT NULL,
pic_size int(11) DEFAULT '0' NOT NULL,
pic_type varchar(30) NOT NULL,
PRIMARY KEY (picture_id)
);
Wydruk 13.3. Formularz przesyłania plików
<html>
<head>
<title>Przesyłanie rysunków</title>
</head>
<body>
<form action="upload_pic.phtml" method="post" enctype="multipart/form-data">
<table>
<tr>
<td colspan="2">
Proszę wybrać plik z rysunkiem (jpeg lub gif)
do przesłania, oraz podać jego nazwę.
</td>
</tr>
<tr>
<td>
Plik rysunku:
</td>
<td>
<input type="file" name="PicFile">
</td>
</tr>
<tr>
<td>
Nazwa rysunku:
</td>
<td>
<input type="text" name="PicName" maxlength="30">
Rozdział 13 – Fajny PHP
162
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="Submit" value="Wyślij">
</td>
</tr>
</table>
</form>
</body>
</html>
Wydruk 13.4. Zapisywanie przesłanego pliku w bazie danych
<?php
include_once( "db_mysql.php" );
// Utworzenie podklasy DB_Sql do zapisywania i odczytu rysunków
class pictures_db extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
var $Password
= "root";
}
$aErrors = False;
if ( !empty( $PicFile_name ) ) // nie wybrano pliku
{
if ( ( $PicFile_type == "image/gif" ) ||
( $PicFile_type == "image/pjpeg" ) ||
( $PicFile_type == "image/jpeg" ) )
{
$aFile = fopen( $PicFile, "rb" );
$aFileContents = addslashes( fread( $aFile, filesize( $PicFile ) ) );
fclose( $aFile );
$aDB = new pictures_db();
$aSQL = "select ( max( picture_id ) + 1 ) as new_id from pictures";
$aDB->query( $aSQL );
if ( $aDB->next_record() )
{
$aNewID = $aDB->f( "new_id" );
}
if ( empty( $aNewID ) == True )
{
$aNewID = 1;
}
$aSQL = "insert into pictures ( picture_id, name, date, pic_data, ";
$aSQL .= "pic_size, pic_type ) values ( $aNewID, '$PicName', ";
$aSQL .= "NOW(), '$aFileContents', '$PicFile_size', '$PicFile_type' )";
print( $aSQL );
$aDB->query( $aSQL );
if ( $aDB->Errno != 0 )
{
$aErrors = True;
}
}
else
{
$aErrors = True;
}
}
else
{
$aErrors = True;
}
if ( $aErrors == False )
{
header( "Location: upload_ok.html\n" );
}
else
{
header( "Location: upload_failed.html\n" );
}
?>
Skrypt ten ponownie wykorzystuje klasę PHPLIB do obsługi odwołań do bazy danych. Na początku
sprawdzane jest, czy plik jest właściwego typu. Następnie plik jest umieszczony w zmiennej i przygotowany do
163
PHP – Kompendium wiedzy
umieszczenia w bazie danych poprzez użycie funkcji addslashes(). Następnie z tabeli pobierany jest nowy
identyfikator i dane są umieszczane w bazie danych. Na końcu skryptu przeglądarka jest kierowana do
odpowiedniego pliku w zależności od tego, czy operacja się powiodła czy nie.
Aby wyświetlić rysunek, wykorzystujemy kod z wydruków 5. i 6. Na wydruku 13.5. umieszczona jest
prosta strona HTML powodująca wyświetlenie jednego, określonego rysunku. Wydruk 13.6. zawiera skrypt
wyświetlający rysunki.
Wydruk 13.5. Strona HTML powodująca wyświetlenie rysunku z bazy danych
<html>
<head>
<title>Wyświetlenie rysunku</title>
</head>
<body>
<img src="show_pic.phtml?ID=1" border="0" alt="">
</body>
</html>
Wydruk 13.6. Skrypt wyświetlający rysunki
<?php
include_once( "db_mysql.php" );
// Utworzenie podklasy DB_Sql do zapisywania i odczytu rysunków
class pictures_db extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
var $Password
= "root";
}
$aDB = new pictures_db();
$aSQL = "select * from pictures where ( picture_id = $ID )";
$aDB->query( $aSQL );
if ( $aDB->next_record() )
{
header( "Content-length: " . $aDB->f( "pic_size" ) );
header( "Content-type: " . $aDB->f( "pic_type" ) );
print( $aDB->f( "pic_data" ) );
}
else
{
// Nie znaleziony rysunek, obsługa błędu!
Header( "HTTP/1.0 404 Not Found" );
}
?>
Mimo, że dziwny wydaje się znacznik <IMG> wskazujący na skrypt PHP, nie ma jednak żadnej różnicy.
Ważny kod znajduje się w skrypcie PHP, gdzie ustawiany jest właściwy typ zawartości dla rysunku z bazy
danych. Skrypt powoduje pobranie odpowiedniego rysunku z bazy danych i przesłanie danych. Jeżeli
identyfikator rysunku ($ID) nie zostanie odnaleziony w bazie danych, skrypt zwraca standardowy kod błędu
HTTP 404.
Ponieważ PHP pozwala na wysłanie dowolnych nagłówków HTTP, można w ten sposób przesyłać
dowolną zawartość. Elastyczność ta pozwala na łatwe tworzenie aplikacji o dużych możliwościach.
Skrypty automatyzujące
PHP nie jest jedynie językiem programowania dla WWW, który do działania wymaga serwera WWW, ale
jest on językiem skryptowym, który może zostać do dowolnych zadań programowych. Ponieważ jest on tak
bogaty w funkcje, może być wykorzystany do automatyzacji zadań, które mogą być trudne do zrealizowania w
standardowych językach programowania powłoki lub plikach wsadowych. Dodatkowo, ponieważ PHP jest
dostępny na wielu platformach, te same skrypty mogą być użyte na wielu platformach.
Wykorzystanie PHP jako osobnego narzędzia skryptowego wymaga skompilowania wersji CGI PHP. Jest
to opsane w rozdziale 1., „Kompilacja i instalowanie PHP 4”. Mając dostępną wersję CGI można uruchomić
dowolny skrypt PHP z linii poleceń. Poniższy przykład pokazuje wykorzystanie PHP do generowania plików stref
DNS co jest przydatne w przypadku obsługi wielu stref.
Rozdział 13 – Fajny PHP
164
Wydruk 13.7. Baza do obsługi DNS
CREATE TABLE Domains (
domain_id int(11) NOT NULL,
name varchar(250) NOT NULL,
soa_server_id int(11) DEFAULT '1' NOT NULL,
cname_list varchar(250) NOT NULL,
mail_server_id int(11) DEFAULT '1' NOT NULL,
ip_address_id int(11) DEFAULT '1' NOT NULL,
incl_zone_file tinyint(4) DEFAULT '1' NOT NULL,
created_date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
PRIMARY KEY (domain_id),
KEY name (name),
UNIQUE name_2 (name),
KEY created_date (created_date)
);
CREATE TABLE IPAddressess (
ip_address_id int(11) NOT NULL,
value carchar(15) NOT NULL,
PRIMARY KEY (ip_address_id),
KEY value (value)
);
CREATE TABLE MailServers (
mail_server_id int(11) NOT NULL,
name varchar(250) NOT NULL,
PRIMARY KEY (mail_server_id),
KEY name(name)
);
CREATE TABLE NameServers (
name_server_id int(11) NOT NULL,
name varchar(250) NOT NULL,
PRIMARY KEY (name_server_id),
KEY name(name)
);
CREATE TABLE SOAServers (
soa_server_id int(11) NOT NULL,
name varchar(250) NOT NULL,
PRIMARY KEY (soa_server_id),
KEY name(name)
);
Baza danych jest wykorzystywana do przechowywania danych niezbędnych do utworzenia plików strefy
oraz innych plików konfiguracyjnych niezbędnych do działania serwera DNS. Poniżej pokazany jest jeden rekord
z tabeli Domains:
INSERT INTO Domains VALUES( '4', 'intechra.net', '1', 'www, secure, mail', '1', '1', '1', '2000-08-25
13:29:37');
Wiersz ten zawiera dane DNS na temat domeny intechra.net. Chociaż rekord ten nie jest sam szczególnie
użyteczny, to jednak połączony z innymi powiązanymi tabelami pozwala uzyskać informacje na temat adresów
IP, serwerów pocztowych oraz serwerów SOA. Używając wszystkich tych danych oraz skryptu PHP można
niezmiernie uprościć proces uaktualniania serwera DNS. Poniższe siedem wydruków zawiera elementy głównego
skryptu. Wydruki 8. do 13. są plikami szablonów używanych do generowania plików wynikowych. Przykład ten
korzysta z klasy FastTemplate opisanej w rozdziale 12. „Oddzielanie kodu HTML od PHP”.
Wydruk 13.8. Główny szablon dla pliku strefy DNS (dns_primary.tpl)
$TTL 86400
{DOMAIN}. IN SOA
{SOA_SERVER}. {ADMINISTRATOR}. (
{SERIAL}
; nr seryjny
10800
; odswieżanie
3600
; ponowna próba
604800
; wygaśnięcie
86400
; domyślny TTL
)
{NAMESERVERS}
{DOMAIN}. IN A
{IPADDRESS}
{CNAME_RECORDS}
{DOMAIN}. IN MX 10
{MAIL_SERVER}.
{DOMAIN}. LOC 43 49 57.551 N 111 46 38.071 W 1480.7m
Wydruk 13.9. Szablon nazw hostów DNS (zastępuje CNAME_RECORDS z wydruku 13.8.)
(dns_secondary.tpl)
{CNAME} IN
CNAME
{DOMAIN}.{CRLF}
Wydruk 13.10. Szablon serwerów nazw DNS (zastępuje NAMESERVERS z wydruku 13.8.)
(dns_nservers.tpl)
{DOMAIN}.
IN NS
{NAMESERVER}.{CRLF}
Wydruk 13.11. Główny szablon dla pliku named.conf (named_primary.tpl)
165
PHP – Kompendium wiedzy
acl trustedslaves { ns1.nameserver.com;ns2.nameserver.com; };
options {
directory "/var/named";
recursion yes;
fetch-glue no;
allow-query { any; };
};
zone "." { type hint; file "cache.db"; };
{ZONES}
Wydruk 13.12. Pomocniczy szablon dla pliku named.conf (zastępuje ZONES z wydruku 13.11.)
(named_secondary.tpl)
zone "{DOMAIN}" { type master; file "{DOMAIN_FILE}"; notify yes;
allow-transfer { trustedslaves; }; };
Wydruk 13.13. Szablon dla pliku podrzędnych DNS (named_slaves.tpl)
zone "{DOMAIN}" { type slave; file "{DOMAIN_FILE}"; masters {
master.com; }; };
Szablony te tworzą szkielet niezbędny do utworzenia wszystkich plików konfiguracyjnych dla serwera
nazw BIND. Pierwsze trzy generują osobne pliki stref, które mogą posiadać różną liczbę serwerów nazw i
definicji nazw komputerów. Pozostałe są używane do utworzenia pliku named.conf oraz pliku podrzędnego,
wykorzystywanego w podrzędnym serwerze nazw.
Skrypt pokazany na wydruku 13.14 odczytuje z bazy danych dane DNS i generuje wszystkie pliki
konfiguracyjne.
Wydruk 13.14, Skrypt DNS
<?php
include( "./class.FastTemplate.php" );
include( "./db_mysql.php" ); // db_mysql.inc o zmienionej nazwie
// tworzenie klasy obsługi bazy danych dla aplikacji
class genapps_db extends DB_Sql
{
var $Host
= "localhost";
var $Database = "mydb";
var $User
= "root";
var $Password = "root";
}
// katalog dla plików wynikowych
$aPath = "./dns_output";
$tpl = new FastTemplate( "." );
$tpl->define( array( named_main
=> "named_primary.tpl",
named_zones
=> "named_secondary.tpl",
named_slaves => "named_slaves.tpl",
dns_main
=> "dns_primary.tpl",
dns_cnames
=> "dns_secondary.tpl",
dns_nservers => "dns_nservers.tpl" ));
// pobierz listę serwerów nazw i zapamiętaj do późniejszego wykorzystania
$aNSDB = new genapps_db();
$aSQL = "select * from NameServers";
$aNSDB->query( $aSQL ); // pobierz wszystkie dane strefy
$aDB = new genapps_db();
$aSQL = "select A.name, A.cname_list, A.incl_zone_file, B.name as soa_server,
C.name as ";
$aSQL .= "mail_server, D.value as ip_address from Domains A, SOAServers B, ";
$aSQL .= "MailServers C, IPAddressess D where ( A.soa_server_id = B.soa_server_id)";
$aSQL .= "and ( A.mail_server_id = C.mail_server_id ) and ";
$aSQL .= "( A.ip_address_id = D.ip_address_id )";
$aDB->query( $aSQL );
while ( $aDB->next_record() )
{
$aDomainName
= strtolower( $aDB->f( "name" ) );
$aCNames
= $aDB->f( "cname_list" );
$aSoaServer
= $aDB->f( "soa_server" ) ;
$aMailServer
= $aDB->f( "mail_server" );
$aIPAddress
= $aDB->f( "ip_address" );
$aInclZoneFile = $aDB->f( "incl_zone_file" );
$tpl->assign( array( DOMAIN
=> $aDomainName,
ADMINISTRATOR => "admin." . $aSoaServer,
SERIAL
=> date( "Ymd" ) . "00",
MAIL_SERVER
=> $aMailServer,
SOA_SERVER
=> $aSoaServer,
IPADDRESS
=> $aIPAddress,
CRLF
=> "\n" ) );
/* nazwy hostów (rekordy CNAME) są przechowywane w liście
rozdzielanej przecinkami w bazie danyche. Dzielenie listy
i tworzenie linii dla każdego elementu */
$tpl->clear( CNAME_RECORDS );
Rozdział 13 – Fajny PHP
166
$aCNameList
= explode( ",", $aCNames );
foreach( $aCNameList as $aCName )
{
$aCName = trim( $aCName );
$tpl->assign( array( CNAME => $aCName ) );
$tpl->parse( CNAME_RECORDS, ".dns_cnames");
}
// dodanie linii serwerów nazw do pliku strefy
$tpl->clear( NAMESERVERS );
$aNSDB->seek( 0 ) ;
while ( $aNSDB->next_record() )
{
$tpl->assign( array( NAMESERVER => $aNSDB->f( "name" )) );
$tpl->parse( NAMESERVERS, ".dns_nservers" );
}
$aDomainFile = $aDomainName . ".db";
/* plik strefy jest tworzony tylko wtedy, gdy pole 'incl_zone_file'
w bazie danych ma wartość '!'
*/
if ( $aInclZoneFile == "1" )
{
$tpl->parse( DNS_MAIN, "dns_main");
$aFile = fopen( "$aPath/$aDomainFile", "w" );
fwrite( $aFile, $tpl->fetch( DNS_MAIN ) );
fclose( $aFile );
print ("Plik domeny '$aDomainFile' został utworzony\n" );
}
/* dodanie biżącej nazwy domeny do głównego i pomocniczego pliku
konfiguracyjnego */
$tpl->assign( array( DOMAIN_FILE => $aDomainFile ) );
$tpl->parse( ZONES, '.named_zones' );
$tpl->parse( SLAVES, '.named_slaves' );
}
$tpl->parse( NAMED_CONF, 'named_main' );
$aFile = fopen( "$aPath/named.conf", "w" );
fwrite( $aFile, $tpl->fetch( NAMED_CONF ) );
fclose( $aFile );
print( "Główny plik 'named.conf' utworzony\n" );
$aFile = fopen( "$aPath/named.slave", "w" );
fwrite( $aFile, $tpl->fetch( SLAVES ) );
fclose( $aFile );
print( "Plik domeny 'named.slave' utworzony\n" );
?>
Skrypt ten odczytuje kolejne pozycje w tabeli Domains i tworzy plik strefy. Jest on utworzony za pomocą
szablonów z wydruków 8., 9. i 10. Przykładowy plik strefy pokazany jest na rysunku 13.4.
167
PHP – Kompendium wiedzy
Rysunek 13.4.
Przykładowy plik
strefy DNS
Dodatkowo tworzony jest odpowiednio sformatowany plik named.conf. W celu stworzenia tych plików do
odczytania zapamiętanego tekstu wykorzystana została metoda FastTemplate fetch().
Aby uruchomić ten skrypt pod Windows lub na systemach Unix należy użyć polecenia php
create_dns.php. Postęp wykonywania skryptu jest pokazywany na standardowym wyjściu, a pliki wynikowe są
tworzone w katalogu określonym na początku skryptu.
Ponieważ PHP jest kompletnym językiem skryptowym, przy jego pomocy można napisać dowolne
narzędzia automatyzujące złożone zadania. Użyty z mechanizmami automatycznego uruchamiania programów, na
przykład cron, PHP może być wykorzystany do wykonania wielu złożonych zadań. Tworzenie plików
konfiguracyjnych dla dowolnych programów może być bardzo łatwo wykonane przy użyciu systemu szablonów,
na przykład pakietu FastTemplate. Ponieważ PHP jest niezwykle elastyczny, może być on użyty do napisania
skryptów do takich zadań jak: wysyłanie masowej poczty, składowanie i uaktualnianie bazy danych,
monitorowanie sieci lub aplikacji i wiele innych.
WDDX
WDDX (Web Distributed Data Exchange) to bezpłatna, oparta na XML technologia pozwalająca
aplikacjom WWW działających na dowolnych platformach, łatwo wymieniać pomiędzy sobą dane. Obsługa
WDDX może być uaktywniona w PHP poprzez podanie opcji konfiguracji --enable-wddx i ponowne
skompilowanie PHP. Celem WDDX jest zapewnienie spójnego interfejsu danych dla informacji przekazywanych
pomiędzy aplikacjami sieciowymi. Dla przykładu, można wykorzystać WDDX do współdzielenia przez
partnerów danych z bazy danych.
SDK dla WDDX można ściągnąć z witryny www.wddx.org. Pakiet ten zawiera dokumentację i przykłady
użycia WDDX. Patrząc na najbardziej podstawowym poziomie, kompilując PHP z obsługą WDDX umożliwia się
serializację danych w postaci pakietów WDDX oraz deserializację pakietów danych WDDX do struktur danych
Rozdział 13 – Fajny PHP
168
PHP. Aby to zilustrować, skrypt z wydruku 13.15. tworzy kilka zmiennych i serializuje je w pakiet danych
WDDX, oraz wypisuje zawartość pakietu. Wynik serializacji pokazany jest na wydruku 13.16.
Wydruk 13.15. Wykorzystanie WDDX
<html>
<head>
<title>Przykład użycia WDDX</title>
</head>
<body>
<?php
$aFirstName = "Arian";
$aAge
= 25;
$aArray
= array( "red", "green", "blue" );
$aPacketID
= wddx_packet_start( "products" );
wddx_add_vars( $aPacketID, "aFirstName" );
wddx_add_vars( $aPacketID, "aAge" );
wddx_add_vars( $aPacketID, "aArray" );
$aWDDXPacket = wddx_packet_end( $aPacketID );
print( $aWDDXPacket );
?>
</body>
</html>
Wydruk 13.16. Pakiet WDDX
<wddxPacket version='1.0'><header><comment>products</comment></header><data><struct><var
name='aFirstName'><string>Arian</string></var><var name='aAge'><number>25</number></var><var
name='aArray'><array
length='3'><string>red</string><string>green</string><string>blue</string></array></var></struct></data></wd
dxPacket>
W przedstawionym przykładzie funkcja wddx_packet_start() tworzy nowy pakiet WDDX. Następnie do
tego pakietu dodawane są trzy zmienne PHP i pakiet jest zamykany. Pakiet danych WDDX zawiera wszystkie
dane niezbędne do odtworzenia zmiennych za pomocą funkcji wddx_deserialize().
Aby pokazać jak można wykorzystać WDDX w systemie używającym kilku języków programowania, w
kolejnym przykładzie pakiet WDDX jest wysyłany do strony WWW, gdzie jest używany przez JavaScript. Dane
WDDX reprezentują informacje o towarach: nazwę, cenę i wagę. Gdy użytkownik wybierze z listy nazwę
produktu, w polach tekstowych tylko do odczytu uaktualniana jest cena i waga wybranego produktu. Przykład ten
pokazuje w jaki sposób można manipulować danymi na kliencie przy pomocy JavaScript. Na wydruku 13.17.
pokazany jest szablon HTML, natomiast wydruk 13.18. zawiera skrypt PHP wykorzystujący ten szablon.
Wydruk 13.17 Użycie WDDX do manipulacji danymi na kliencie
<html>
<head>
<title>{TITLE}</title>
<link rel="STYLESHEET" type="text/css" href="css2.css">
<!--- Dołączenie obsługi WDDX / Javascript --->
<SCRIPT SRC="wddx.js" LANGUAGE="JavaScript"></SCRIPT>
<!--- Dołączenie obsługi obiektu WddxDeserializer --->
<SCRIPT SRC="wddxDes.js" LANGUAGE="JavaScript"></SCRIPT>
<script language="JavaScript">
<!-function show_props(obj, obj_name)
{
var result = "";
for (var i in obj)
{
result += obj_name + "." + i + " = " + obj[i] + "\n";
}
return result;
}
function SetupProductsList()
{
MyDeser
= new WddxDeserializer;
aProducts = MyDeser.deserialize( '{PRODUCTS_WDDX}' );
}
function Initialize()
{
SetupProductsList();
aNumProds = aProducts.ARECORDS.length;
// Czyszczenie listy produktów
// dodanie produktu do listy
for ( var nIndex = 0; nIndex < aNumProds; nIndex++ )
{
aValue = aProducts.ARECORDS[nIndex].PRODUCT_ID;
aName = aProducts.ARECORDS[nIndex].DESCRIPTION;
169
PHP – Kompendium wiedzy
// tworzenie nowej opcji
NewOpt = new Option( aName, aValue, false, true );
// Dodanie nowego obiektu do listy SELECT
document.MainForm.Product_List.options[nIndex] = NewOpt;
}
SetInfo();
}
function SetInfo()
{
// ustawienie ceny i wagi zaznaczonego produktu
var RowNum = document.MainForm.Product_List.selectedIndex;
if ( RowNum > -1 )
{
document.MainForm.Price.value = aProducts.ARECORDS[RowNum].PRICE;
document.MainForm.Weight.value = aProducts.ARECORDS[RowNum].WEIGHT;
}
}
//-->
</script>
</head>
<body onload="Initialize()">
<form action="" name="MainForm" id="MainForm">
<table>
<tr>
<td colspan="3">
Wybierz towar z listy, aby zobaczyć jego cenę i wagę.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<th>
Towar
</th>
<th>
Cena
</th>
<th>
Waga
</th>
</tr>
<tr>
<td>
<select name="Product_List" size="1" onChange="SetInfo();">
<option></option>
<option></option>
</select>
</td>
<td>
<input type="text" name="Price" readonly>
</td>
<td>
<input type="text" name="Weight" readonly>
</td>
</tr>
</table>
</form>
</body>
</html>
Szablon ten intensywnie wykorzystuje JavaScript. Pierwsza funkcja, show_props() jest jedynie funkcją
testującą używaną przy wyświetlaniu właściwości obiektu. Funkcja SetupProductsList() deserializuje dane
towarów, które zostały odczytane z bazy danych przez PHP. Funkcja korzysta z obiektu WddxDeserializer
dostępnego w SDK dla WDDX. Po deserializacji pakietu danych WDDX obiekt JavaScript aProducts zawiera
wszystkie dane produktów.
Funkcja Initialize() inicjuje stronę i jest wywoływana automatycznie przez zdarzenie strony onLoad. Ta
funkcja z kolei wywołuje funkcję SetupProductsList() a następnie dodaje nazwy i identyfikatory produktów do
listy rozwijalnej. Funkcja SetInfo() jest wywoływana po zmianie przez użytkownika wybranego elementu w
liście rozwijalnej. Uaktualnia ona wartości wyświetlane w polach tekstowych cena i waga.
Wydruk 13.18. Przygotowanie pakietu danych WDDX
<?php
Rozdział 13 – Fajny PHP
170
include( "class.FastTemplate.php" );
include( "db_mysql.inc" );
error_reporting( E_ALL & ~E_NOTICE );
class products_db extends DB_Sql
{
var $Host
= "localhost";
var $Database
= "mydb";
var $User
= "root";
var $Password
= "root";
}
$aTemplate = new FastTemplate( "." );
$aTemplate->define( array( "base"
=> "products_wddx.tpl" ) );
$aTemplate->assign( array( "TITLE"
=> "Products Page" ) );
$aPacketID = wddx_packet_start( "products" );
$aRecords = array();
$nIndex
= 0;
$aDB = new products_db;
$aDB->query( "select * from Products" );
while( $aDB->next_record() )
{
$aRecord = $aDB->Record;
foreach( $aRecord as $aName => $aValue )
{
if ( !is_numeric( $aName ) )
{
$aRecords[$nIndex][$aName] = $aValue;
}
}
$nIndex++;
}
wddx_add_vars( $aPacketID, "aRecords" );
$aWDDXPacket = wddx_packet_end( $aPacketID );
$aTemplate->assign( array( "PRODUCTS_WDDX" => addslashes( $aWDDXPacket ) ) );
$aTemplate->parse( "BASE", "base" );
$aTemplate->FastPrint( "BASE" );
?>
Główny skrypt PHP wykorzystuje klasę FastTemplate w celu utworzenia kompletnej strony HTML.
Głównym działaniem skryptu jest odczytanie zawartości tabeli Products i utworzenie pakietu WDDX
zawierającego odpowiednie dane, Jest to realizowane w pętli przebiegającej przez rekordy wyniku, dodając dane
do nowej tablicy, $aRecords. Jest to tablica dwuwymiarowa, gdzie pierwszy wymiar jest numeryczną
reprezentacją numeru wiersza. Drugi wymiar to tablica asocjacyjna z nazwami kolumn i ich wartościami.
Jeszcze jeden fragment tego kodu wymaga skomentowania. Linia z funkcją is_numeric() jest używana do
usuwania nadmiarowych informacji zwracanej przez niejawnie wykonywaną funkcję mysql_fetch_array().
Funkcja mysql_fetch_array() zwraca wiersz z wyniku w postaci tablicy. Dane pochodzące z wyniku są
przechowywane pod indeksami numerycznymi, jak również pod indeksami asocjacyjnymi gdzie jako klucze są
wykorzystywane nazwy pól. Sprawdzenie to usuwa dane indeksowane liczbami, pozostawiając jedynie dane
asocjacyjne.
Na rysunku 13.5. pokazana jest wynikowa strona w przeglądarce. Zawsze po wybraniu nowego towaru
automatycznie jest uaktualniana cena i waga.
171
PHP – Kompendium wiedzy
Rysunek 13.5.
Przykład
wykorzystania
danych WDDX na
kliencie
Choć przykład ten pokazuje w wykorzystanie WDDX do dostarczenia danych dla klienta, może być
używany na wiele sposobów. Może być używany do przesyłania firmowych danych pomiędzy serwerami, oraz
łatwego współdzielenia danych pomiędzy różnymi platformami i językami. Jeżeli planujesz współdzielenie
danych, WDDX zawiera narzędzia do szybkiego dostarczania treści w postaci neutralnej dla platformy i języka.
Monitorowanie sieci
Ponieważ PHP wewnętrznie obsługuje gniazda i protokoły sieciowe, tworzenie narzędzi monitorujących
sieć jest łatwe. Poniższy przykład wykorzystuje potoki i gniazda do zrealizowania prostych funkcji
monitorujących sieć. Można rozszerzyć ten przykład o sprawdzanie stanu serwera nazw, serwera pocztowego itd.
Przykład ten może być szkieletem, który można rozszerzać o nowe funkcje.
Na wydruku 13.19. zamieszczone są trzy funkcje, phpPing(), phpTrace() i phpPageCheck(). Pierwsze dwie
wykorzystują komendy systemowe do wykonania operacji ping i traceroute. Ostatnia wykorzystuje gniazda do
wysłania żądania HTTP HEAD do strony w celu sprawdzenia dostępności serwera i samej strony.
Wydruk 13.19. Funkcje sieciowe
<?php
$aPingCmd = '/bin/ping -c 4';
$aTraceCmd = '/usr/sbin/traceroute -n';
// *nix
// *nix
// zwraca średni czas wykonania komendy ping
function phpPing( $aAddress )
{
global $aPingCmd;
$aTotalTime = 0.0;
$aPingCount = 0;
if ( $aFile = popen( "$aPingCmd $aAddress", "r" ) )
{
// odczytanie danych z potoku
while ( !feof( $aFile ) )
{
$aLine = fgets ( $aFile, 1024 );
// odszukanie danych o czasie
$aPos = strpos( $aLine, "time=" );
if ( $aPos > 0 )
{
// wykorzystanie zmienności typów zmiennych PHP
// do konwersji czasu na liczbę
$aTime = substr( $aLine, $aPos + 5 ) * 1.0;
$aTotalTime += $aTime;
$aPingCount++;
}
}
pclose( $aFile );
}
return $aTotalTime / $aPingCount;
}
Rozdział 13 – Fajny PHP
172
function phpTrace( $aAddress )
{
global $aTraceCmd;
$aTraceResults = "";
if ( $aFile = popen( "$aTraceCmd $aAddress", "r" ) )
{
// odczytanie wszystkich danych z potoku
while ( !feof( $aFile ) )
{
$aLine = fgets ( $aFile, 1024 );
$aTraceResults .= $aLine . "<br>";
}
pclose( $aFile );
}
return $aTraceResults;
}
function phpPageCheck( $aWebPage )
{
$aURL = parse_url( $aWebPage );
$aResult = False;
if ( $aURL["scheme"] == "http" )
{
$aRequest = "HEAD {$aURL['path']} HTTP/1.0\r\n\r\n";
$aSocket = fsockopen( $aURL["host"], 80 );
if ( $aSocket )
{
fputs( $aSocket, $aRequest );
while( !feof( $aSocket ) )
{
$aLine = fgets( $aSocket, 1024 );
if ( substr( $aLine, 0, 4 ) == "HTTP" )
{
$aArray = explode( " ", $aLine );
if ( ( $aArray[1] >= 200 ) && ( $aArray[1] < 300 ) )
{
$aResult = True;
}
}
}
}
}
return $aResult;
}
?>
Funkcje te mogą być wykorzystane w skrypcie automatyzującym do okresowego zapisywania wyników
do bazy danych lub do pliku, albo mogą być użyte bezpośrednio ze strony WWW. Skrypt z wydruku 13.20.
pokazuje w jaki sposób używa się tych funkcji.
Wydruk 13.20. Wykorzystanie funkcji sieciowych
<?php
include( "./net_funcs.php" );
?>
<html>
<head>
<title>Test funkcji sieciowych</title>
</head>
<body>
<?php
print(
print(
print(
print(
print(
?>
"phpPing: " . phpPing ( 'www.php.net' ) . "<br><br>" );
"phpTrace: <ul>" . phptrace( 'www.php.net' ) . "</ul><br>" );
"phpPageCheck: " );
phpPageCheck( 'http://www.php.net/' ) ? "OK" : "NOT OK" );
"<br>" );
</body>
</html>
Przykład ten pokazuje jak łatwo można wykorzystać PHP do wykonania podstawowego monitorowania
sieci. PHP obsługuje również inne protokoły sieciowe, takie jak IMAP, SNMP, NNTP i POP3, co pozwala
rozszerzać przytoczony przykład o sprawdzenie dostępności wszystkich rodzajów serwerów i komponentów
sieciowych.
173
PHP – Kompendium wiedzy
Podsumowanie
Rozdział ten opisywał różne zagadnienia pokazujące siłę i elastyczność PHP. Istnieją również rozszerzenia
do tworzenia rysunków, analizy XML, tworzenia plików PDF i wielu innych zadań. Ponieważ PHP jest tak
rozszerzalny i rozwijany przez ogromną grupę programistów, należy spodziewać się dalszego zwiększania
elastyczności i funkcjonalności.
Rozdział 13 – Fajny PHP
174
Rozdział 14. Witryny oparte o szablony
W rozdziale 12., „Oddzielanie HTML od PHP” zostało opisane użycie systemu szablonów. W tym
rozdziale zostanie szczegółowo opisane wykorzystanie szablonów do tworzenia witryn. Użycie szablonów do
projektowania aplikacji umożliwia o wiele więcej, niż jedynie oddzielanie logiki aplikacji od projektu
graficznego. Szablony umożliwiają zastosowanie zapożyczania fragmentów witryn, personalizacji, niezależności
od przeglądarki oraz obsługi wielu języków. Przykłady przytoczone w tym rozdziale wykorzystują klasę
FastTemplate dostępną z witryny http://www.thewebmasters.net/. Istnieją również inne systemy szablonów, ale ta
implementacja jest wydajna, elastyczna i łatwa do nauki.
Podstawy wykorzystania szablonów
Tworzenie witryn WWW korzystających z systemu szablonów wymaga nieco dokładniejszego
projektowania interfejsu użytkownika, niż tworzenie tej samej aplikacji bez szablonów. Jednak korzyści
wykorzystania dobrze zaprojektowanego zaczną się ujawniać bardzo szybko. Na rysunku 14.1. pokazana jest
typowa strona WWW, która może być podzielona na kilka osobnych plików szablonów.
Rysunek 14.1.
Page header - nagłówek strony
Strona WWW
navigation - panel nawigacji
składająca się z
footer - stopka
kilku plików
HTML base page - Podstawowa strona HTML
szablonów
Main body - Główny obszar strony
information, links, contacts, news - Informacje, łącza,
kontakty, nowości
Na rysunku 14.1. pokazana jest strona składająca się z jednego lub więcej szablonów, które składają się na
stronę HTML z różnymi logicznymi sekcjami strony. Na niektórych witrynach WWW może być wykorzystany
tylko jeden szablon dla wszystkich stron witryny. W innych, każda strona może być tworzona na podstawie kilku
szablonów. Aby zaprojektować witrynę korzystającą z szablonów, należy ocenić potrzeby witryny i
zinwentaryzować elementy znajdujące się na stronach.
Przykładem będzie witryna pełniąca funkcję sieciowego katalogu towarów. Katalog ten jest podzielony na
kategorie produktów, takie jak: ubrania, prezenty, zabawki itd. Każda strona musi zawierać wspólne elementy
nawigacyjne oraz logo całej witryny. Przeglądając wybraną kategorię produktów, powinien być wyświetlany
element graficzny oznaczający tą kategorię. Każda strona produktu powinna zawierać dane o towarze, takie jak
cena, waga, dostępne kolory itd. Aby stworzyć system szablonów dla takiej witryny zdefiniowano następujące
szablony:
1. merch_base.tpl: Podstawowy plik zawierający ogólny układ HTML.
2. merch_header.tpl: Nagłówek wspólny dla wszystkich stron witryny.
3. merch_catXXX_header.tpl: Nagłówek określonej kategorii (XXX zastąpione przez nazwę kategorii).
4. merch_navi.tpl: Panel nawigacyjny katalogu.
5. merch_body.tpl: Treść każdej strony.
6. merch_footer.tpl: Stopka każdej strony.
Aby pokazać jak zostały stworzone te pliki, przedstawiona zostaną teraz zawartość każdego z nich.
Wydruki od 1. do 6 zawierają kolejne pliki wymienione powyżej. Na wydruku 14.3 pokazany został plik
merch_catubrania_header.tpl, właściwy dla kategorii produktów ubrania. Pliki dla pozostałych kategorii nie
zostały pokazane, ponieważ są one właściwie takie same.
Wydruk 14.1. merch_base.tpl
<html>
<head>
<title>{TITLE}</title>
</head>
<body bgcolor="White">
<table width="630" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td colspan="2">{PAGE_HEADER}</td>
</tr>
<tr>
<td colspan="2" align="center">{CAT_HEADER}</td>
</tr>
<tr>
<td valign="top">{LEFT_NAVI}</td>
<td valign="top">
{BODY}
</td>
</tr>
<tr>
<td colspan="2">
{PAGE_FOOTER}
</td>
</tr>
</table>
</body>
</html>
Wydruk 14.2. merch_header.tpl
<img src="merch_layout_r1_c1.gif" width="630" height="61" border="0">
Wydruk 14.3. merch_catubrania_header.tpl
<img name="merch_layout_r2_c1" src="merch_layout_r2_c1.gif" width="630" height="37" border="0"><br>
<div align="center"><p>{CATEGORY_SPECIALS}</p></div>
Wydruk 14.4. merch_navi.tpl
<img src="merch_layout_r3_c1.gif" width="104" height="382" border="0" usemap="#merch_layout_r3_c1">
<map name="merch_layout_r3_c1">
<area shape="rect" coords="5,180,97,221" href="{HREF_COMPANY_INFO}" >
<area shape="rect" coords="7,143,86,166" href="{HREF_CONTACT}" >
<area shape="rect" coords="12,90,84,132" href="{HREF_CART}" >
<area shape="rect" coords="18,56,73,80" href="{HREF_HOME}" >
</map>
Wydruk 14.5. merch_body.tpl
<p>
&nbsp;
</p>
<h3>
{PRODUCT_NAME}
</h3>
<p>
{PRODUCT_DESCRIPTION}
</p>
<p>
{PRODUCT_PRICE}
</p>
Wydruk 14.6. merch_footer.tpl
<hr>
<p>
&copy {COPYRIGHT_YEARS} Intechra LLC. Wszystkie prawa zastrzeżone.
</p>
Pliki te pokazują jak niewiele potrzeba do stworzenia dosyć skomplikowanej witryny korzystającej z
szablonów. Niektóre z tych plików, na przykład nagłówek zawiera jedynie rysunek. Inne, jak na przykład szablon
panelu nawigacyjnego zawiera zarówno rysunek, jak i mapę obrazu. Należy zwrócić uwagę, że szablon
nawigacyjny nie zawiera aktualnych adresów URL, a jedynie zmienne szablonu Pozwala to na stworzenie
właściwych adresów łączy, na przykład zawierających identyfikator sesji. Skrypt PHP pokazany na wydruku
14.7. pokazuje w jaki sposób można połączyć pliki szablonów w jedną całość.
Wydruk 14.7. Łączenie szablonów
<?php
include( "class.FastTemplate.php" );
// zakładamy, że wybraną kategorią są ubrania
$aCategoryHeader = 'merch_catubrania_header.tpl';
$aTPL = new FastTemplate( "." );
$aTPL->define( array( 'base'
'header'
'navi'
'footer'
'cat_header'
'body'
Rozdział 14 – Witryny oparte o szablony
=>
=>
=>
=>
=>
=>
'merch_base2.tpl',
'merch_header.tpl',
'merch_navi.tpl',
'merch_footer.tpl',
$aCategoryHeader,
'merch_body.tpl'
176
) );
$aTPL->assign( array( 'TITLE'
'CATEGORY_SPECIALS'
'PRODUCT_NAME'
'PRODUCT_DESCRIPTION'
'PRODUCT_PRICE'
'COPYRIGHT_YEARS'
'HREF_HOME'
'HREF_CART'
'HREF_CONTACT'
'HREF_COMPANY_INFO'
) );
$aTPL->parse( 'PAGE_HEADER',
$aTPL->parse( 'CAT_HEADER',
$aTPL->parse( 'LEFT_NAVI',
$aTPL->parse( 'BODY',
$aTPL->parse( 'PAGE_FOOTER',
$aTPL->parse( 'BASE',
$aTPL->FastPrint( 'BASE' );
=>
=>
=>
=>
=>
=>
=>
=>
=>
=> 'Katalog towarów: Ubrania',
'Sprzedajemy koszulki Intechra!',
'Koszulka Intechra',
'Świetna koszulka z logo Intechra LLC!',
'14.95 zł',
'2001',
'index.phtml',
'cart.phtml',
'contact.phtml',
'company.phtml'
'header' );
'cat_header' );
'navi' );
'body' );
'footer' );
'base' );
?>
Skrypt ten wykorzystuje klasę FastTemplate do analizy i połączenia wszystkich plików szablonów
tworzących katalog produktów. W przykładzie tym wszystkie wartości zostały na stałe zaszyte w skrypcie w celu
uproszczenia opisu. W prawdziwej aplikacji dane na temat kategorii produktu oraz wyświetlanego produktu
powinny być dostarczone poprzez formularz lub inną metodę dynamicznego dostarczania danych. Skrypt ten po
prostu przypisuje wartości do wszystkich zmiennych potrzebnych we wszystkich plikach szablonów.
Aby zrozumieć w jaki sposób FastTemplate analizuje stronę należy wiedzieć, że niektóre zmienne
FastTemplate są ustawiane przy użyciu metody assign(). Na przykład zmienna COPYRIGHT_YEARS
wykorzystywana w szablonie merch_footer.tpl jest inicjowana wartością 2000 przy użyciu metody assign().
Dodatkowo niektóre zmienne FastTemplate są ustawiane za pomocą metody parse(). Dla przykładu zmienna
PAGE_HEADER jest ustawiana poprzez analizę strony o nazwie header. Powoduje to, że wartość PAGE_HEADER jest już
dostępna w czasie analizy pliku merch_base.tpl, który w naszym przykładzie został nazwany base. Należy
pamiętać, że w przypadku zagłębiania szablonów należy zainicjować wszystkie wymagane zmienne szablonu
przed jego analizą. Dodatkowo należy analizować szablony we właściwej kolejności. Dla przykładu, jeżeli w
powyższym przykładzie strona base była by analizowana na początku, większość wymaganych zmiennych (takich
jak PAGE_HEADER i BODY) nie było by dostępnych.
Siłą zastosowania szablonów jest możliwość łatwego wprowadzania zmian w projekcie graficznym
witryny. Na rysunku 14.2. pokazany został wygląd strony wygenerowanej przez skrypt z wydruku 14.6.
Zmieniając szablon o nazwie base, z zamieszczonego na wydruku 14.1. na ten z wydruku 14.8, wygląd strony
ulega całkowitej zmianie. Efekt zmiany szablonu base pokazany jest na rysunku 14.3.
177
PHP – Kompendium wiedzy
Rysunek 14.2.
Strona
wygenerowana
przez skrypt z
wydruku 14.7.
Wydruk 14.8. Nowy plik szablonu „base”
<html>
<head>
<title>{TITLE}</title>
<link rel="STYLESHEET" type="text/css" href="new_base.css">
</head>
<body bgcolor="White">
<table width="630" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td colspan="2">{PAGE_HEADER}</td>
</tr>
<tr>
<td colspan="2" align="center">{CAT_HEADER}</td>
</tr>
<tr>
<td width="526" valign="top">
{BODY}
</td>
<td valign="top">{LEFT_NAVI}</td>
</tr>
<tr>
<td colspan="2">
{PAGE_FOOTER}
</td>
</tr>
</table>
</body>
</html>
Rozdział 14 – Witryny oparte o szablony
178
Rysunek 14.3.
Strona
wygenerowana
przy użyciu
nowego szablonu
„base”
Siła systemu szablonów nie może być przeceniana. Tak jak to zostało pokazane, zmieniając zawartość
szablonu base, znacznie zmieniony został wygląd strony, natomiast nie zostały wprowadzone żadne zmiany po
stronie PHP. Elastyczność ta pozwala projektantom na tworzenie i konserwację bogatego interfejsu użytkownika,
natomiast programiści aplikacji równolegle tworzą i konserwują część logiczną. Oczywiści zachodzi niezbędna
interakcja pomiędzy programistami i projektantami interfejsu, ale po zdefiniowaniu zestawu plików szablonów i
zmiennych szablonów praca obu grup może pracować równolegle. Dodatkowo, wykorzystanie szablonów
pozwala programistom na wykorzystywanie zestawu prototypowych plików interfejsu, do czasu aż projektanci
dostarczą im ostateczne wersje.
W poprzednim przykładzie jedyną znacząca zmianą wprowadzoną w szablonie base było dołączenie pliku
CSS. CSS jest wartościowym dodatkiem do większości zastosowań WWW, ponieważ stanowi on system
szablonów dla HTML. Wykorzystując CSS, można zmienić atrybuty wszystkich elementów HTML. Na przykład
można tak zdefiniować znacznik <h3>, aby w kontekście tej witryny wyglądał w określony sposób. Na wydrukach
14.4. i 14.5. pokazany jest wygląd komercyjnego edytora CSS o nazwie TopStyle z firmy Bradbury Software
LLC (http://www.bradsoft.com/). Edytor ten upraszcza proces tworzenia plików CSS oraz pozwala na podgląd
zmienionych stylów.
179
PHP – Kompendium wiedzy
Rysunek 14.4.
Arkusz stylu
pokazujący
możliwość
modyfikacji
znaczników
<body>, <td> i
<h3>
Rysunek 14.5.
Inny arkusz stylu
pokazujący
możliwość
modyfikacji
znaczników
<body>, <td> i
<h3>
Użycie CSS wraz z systemem szablonów zwiększa możliwość wprowadzania zmian do wyglądu witryny
minimalizując konieczność wprowadzania zmian do kodu aplikacji. Pliki CSS mogą być nawet dołączane
dynamicznie, w postaci zmiennej szablonu. Mimo, że nie jest to optymalne rozwiązanie dla wszystkich typów
witryn, pozwala zrealizować kolejny poziom konfiguracji wyglądu tworzonej aplikacji.
Rozdział 14 – Witryny oparte o szablony
180
Poprzedni przykład stanowi podstawowy szkielet dla tworzenia aplikacji WWW opartej o szablony.
Jednak nie zostały tu pokazane przykłady tworzenia powtarzających się elementów. Często zachodzi potrzeba
stworzenia tabeli zawierającej wszystkie towary, lub listę kategorii zapisanych w bazie danych.
Kolejny przykład pokazuje, w jaki sposób można dołączyć powtarzające się elementy, korzystając z klasy
FastTemplate. Wydruk 14.9. zawiera główny plik szablonu. Wydruk 14.10. to zawartość szablonu items,
natomiast wydruk 14.11. szablon pojedynczego elementu. Na wydruku 14.12 znajduje się skrypt łączący te
szablony w całość.
Wydruk 14.9. Główny szablon kategorii
<html>
<head>
<title>{TITLE}</title>
</head>
<body>
{ITEMS}
</body>
</html>
Wydruk 14.10. Szablon kategorii ‘items’
Do wyboru są następujące kategorie produktów:
<ul>
{ITEM_LIST}
</ul>
Wydruk 14.11. Szablon dla pojedynczej kategorii
<li><a href="show_category.phtml?cat_id={CAT_ID}">{CAT_NAME}</a></li>
Wydruk 14.12. Skrypt generujący stronę z listą kategorii
<?php
include( "class.FastTemplate.php" );
$aTPL = new FastTemplate( "." );
$aTPL->define( array( 'base'
=> 'cat_base.tpl',
'items' => 'cat_items.tpl',
'item'
=> 'cat_item.tpl' ) );
$aCategories = array( "ubrania", "prezenty", "zabawki", "książki" );
foreach( $aCategories as $aID => $aName )
{
$aTPL->assign( array( 'CAT_ID'
=> $aID,
'CAT_NAME' => $aName ) );
// analiza elementu i jego dołączenie do zmiennej szablonu
// ITEM_LIST
$aTPL->parse( 'ITEM_LIST', '.item' );
}
$aTPL->assign( array( 'TITLE'
=> 'Lista kategorii' ) );
$aTPL->parse( 'ITEMS', 'items' );
$aTPL->parse( 'BASE', 'base' );
$aTPL->FastPrint( 'BASE' );
?>
Rysunek 14.6. Lista
kategorii
Przedstawiony przykład zawiera wbudowaną listę kategorii w celu wygenerowania strony z listą kategorii.
Wynik działania skryptu przedstawiony jest na rysunku 14.6. Po raz kolejny załóżmy, że dział projektowy
zdecydował się na zmianę formatu listy kategorii z listy wypunktowanej na tabelę. Zmiany są ograniczone jedynie
do plików items i item. Wykorzystując poprzedni przykład zmienione szablony przedstawione są na wydrukach
13. i 14. Efekt końcowy pokazany jest na rysunku 14.7.
PHP – Kompendium wiedzy
181
Wydruk 14.13. Nowy szablon „items”
Do wyboru są następujące kategorie produktów:
<br><br>
<table border="1">
{ITEM_LIST}
</table>
Wydruk 14.14. Nowy szablon „item”
<tr>
<td>
Kategoria nr. {CAT_ID}
</td>
<td>
<a href="show_category.phtml?cat_id={CAT_ID}">{CAT_NAME}</a>
</td>
</tr>
Rysunek 14.7. Lista
kategorii w postaci
tabeli
Przedstawiony przykład pokazuje podstawowe kroki potrzebne do generowania listy powtarzających się
elementów przy użyciu FastTemplate. Istnieje również w FastTemplate inny mechanizm pozwalający na
wyeliminowanie dodatkowych plików zawierających szablon pojedynczego elementu. Aby użyć tego
mechanizmu zmienimy szablon items, oraz główny skrypt PHP. Na wydrukach 15. i 16. zamieszczone są
zmienione pliki. Wynik działania tego skryptu jest taki, jak pokazany na rysunku 14.7.
Wydruk 14.15. Nowy szablon „items” korzystający z dynamicznych bloków
Do wyboru są następujące kategorie produktów:
<br><br>
<table border="1">
<!-- BEGIN DYNAMIC BLOCK: item -->
<tr>
<td>
Kategoria nr. {CAT_ID}
</td>
<td>
<a href="show_category.phtml?cat_id={CAT_ID}">{CAT_NAME}</a>
</td>
</tr>
<!-- END DYNAMIC BLOCK: item -->
</table>
W szablonie tym został zdefiniowany podszablon — blok dynamiczny o nazwie item. Jest to dokładnie to
samo, co stworzenie osobnego pliku zawierającego szablon item. Zaletą takiego rozwiązania jest utrzymanie
oryginalnej struktury pliku HTML oraz ograniczenie ilości niezbędnych plików szablonów. Użycie szablonów
wymaga również kilku zmian w skrypcie używającym klasy FastTemplate. Zostały one zamieszczone na wydruku
14.16.
Wydruk 14.16. Nowy skrypt PHP
<?php
include( "class.FastTemplate.php" );
$aTPL = new FastTemplate( "." );
$aTPL->define( array( 'base'
=> 'cat_base.tpl',
'items' => 'cat_items_dyn.tpl') );
Rozdział 14 – Witryny oparte o szablony
182
$aTPL->define_dynamic( 'item', 'items' );
$aCategories = array( "ubrania", "prezenty", "zabawki", "książki" );
foreach( $aCategories as $aID => $aName )
{
$aTPL->assign( array( 'CAT_ID'
=> $aID,
'CAT_NAME' => $aName ) );
// analiza elementu i jego dołączenie do zmiennej szablonu
// ITEM_LIST
$aTPL->parse( 'ITEM_LIST', '.item' );
}
$aTPL->assign( array( 'TITLE'
=> 'Lista kategorii' ) );
$aTPL->parse( 'ITEMS', 'items' );
$aTPL->parse( 'BASE', 'base' );
$aTPL->FastPrint( 'BASE' );
?>
W skrypcie tym widoczne są dwie wyraźne zmiany w stosunku do wydruku 14.12. Po pierwsze, w nowym
skrypcie brakuje jednego wywołania metody define(). Po drugie, wykorzystana jest metoda FastTemplate
define_dynamic(), która wskazuje systemowi FastTemplate, że w szablonie items istnieje blok dynamiczny o
nazwie item. Od tej chwili FastTemplate traktuje blok dynamiczny identycznie, jak byłby to osobny plik.
Korzystając z tego mechanizmu, niezmiernie ważne jest, aby blok dynamiczny był poprawny składniowo.
Składnia linii BEGIN i END musi być poprawna i wymagane jest zachowanie odpowiedniej wielkości liter. Blok
kodu zaczyna się od nowej linii tekstu przeznaczonej jedynie dla tej dyrektywy. W linii zawierającej wyrażenia
BEGIN i END nie powinno być żadnego innego tekstu, można jedynie umieszczać tam dowolną ilość znaków
odstępu. Dyrektywa musi być napisana dokładnie w takiej postaci, jak poniższa linia kodu. Linia ta musi być
dokładnie taka, jak przedstawiona, z dokładnością do odstępów pomiędzy znakami. To samo obowiązuje dla
dyrektywy END. Linie BEGIN i END nie mogą rozciągać się na większa ilość linii.
<!-- BEGIN DYNAMIC BLOCK: nazwa_bloku -->
Wszystkie te przykłady tworzą szkielet aplikacji WWW korzystających z szablonów. Następna część tego
rozdziału zawiera kilka przykładów scenariuszy stosowanych w prawdziwych aplikacjach.
Zapożyczanie
Zapożyczanie jest bardzo łatwo realizowalne za pomocą witryny opartej o szablony. Zapożyczanie
witryny to wykorzystanie projektu witryny partnerskiej jako podstawy własnej aplikacji. Dla przedstawianego
wcześniej przykładu katalogu produktów, jest możliwe aby kilka witryn dystrybutorów korzystających z
własnego projektu graficznego używało katalogu jako jednej z dostępnych usług. Istnieje kilka sposobów
zrealizowania takiego scenariusza w PHP, ale wykorzystując szablony można zrobić to bardzo szybko.
Tworzenie zapożyczonej witryn jest w zasadzie identyczne, jak tworzenie innych witryn opartych o
szablony. Ponieważ aplikacja opiera się na interfejsie z innej firmy, integracja i testowanie musi być
przeprowadzone przez obie strony, aby upewnić się, że wszystkie funkcje działają tak, jak to zostało
zaplanowane. Tworząc aplikację, która może być zapożyczana, należy zdecydować na ile konfigurowalna
powinna być taka witryna. W niektórych przypadkach partnerzy mogą umieścić dodatkowe informacje o prawach
autorskich, żądać zmian w terminologii itd. W prostych przypadkach możesz dodać jedynie kilka znaków
firmowych.
Aby zilustrować to zagadnienie, poniższe pliki szablonów są wykorzystywane w aplikacji przedstawionej
w poprzedniej części. W tym scenariuszu zmienione zostały jedynie dane o prawach autorskich oraz szablon
bazowy. Wydruki 17. i 18. zawierają stopkę z prawami autorskimi oraz plik bazowy.
Wydruk 14.17. Szablon partnera z opisem prawa autorskich
<hr>
<p>
Niektóre fragmenty witryny pochodzą z firmy Keen Partner Company. &copy 2000
&copy {COPYRIGHT_YEARS} Intechra LLC. Wszystkie prawa zastrzeżone.
</p>
Wydruk 14.18. Bazowy szablon partnera
<html>
<head>
<title>{TITLE}</title>
<link rel="STYLESHEET" type="text/css" href="new_base.css">
183
PHP – Kompendium wiedzy
</head>
<body bgcolor="White">
<table width="630" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
Firma Keen Partner Company wykorzystuje katalog produktów firmy Intechra LLC.
<td colspan="2">{PAGE_HEADER}</td>
</tr>
<tr>
<td colspan="2" align="center">{CAT_HEADER}</td>
</tr>
<tr>
<td width="526" valign="top">
{BODY}
</td>
<td valign="top">{LEFT_NAVI}</td>
</tr>
<tr>
<td colspan="2">
{PAGE_FOOTER}
</td>
</tr>
</table>
</body>
</html>
Zmodyfikowany został również główny skrypt łączący szablony a skrypt tworzący stronę wynikową jest
również tak zmieniony, aby rozpoznał właściwy wygląd witryny na podstawie nazwy partnera. Na przykład
główna witryna jest dostępna poprzez adres http://www.katalog.com/, natomiast witryna partnera poprzez
http://cobrand.katalog.com/. Nazwy te są oczywiście używane jedynie do testowania i nie muszą być to docelowe
nazwy witryny. Po uruchomieniu głównego skryptu sprawdzana jest nazwa witryny i wyświetlana jest
odpowiednia strona. Na wydruku 14.19. pokazany jest taki skrypt.
Wydruk 14.19. Główny skrypt realizujący zapożyczanie
<?php
include( "class.FastTemplate.php" );
$aHostArray = explode( ".", $HTTP_HOST );
$aPartner = $aHostArray[0];
switch ( $aPartner )
{
case "cobrand" :
$aPartnerBase
= "partner_base.tpl";
$aPartnerFooter = "partner_footer.tpl";
break;
default :
$aPartnerBase
= "merch_base2.tpl";
$aPartnerFooter = "merch_footer.tpl";
break;
}
// Zakładamy, że wybraną kategorią są ubrania
$aCategoryHeader = 'merch_catubrania_header.tpl';
$aTPL = new FastTemplate( "." );
$aTPL->define( array( 'base'
'header'
'navi'
'footer'
'cat_header'
'body'
) );
$aTPL->assign( array( 'TITLE'
'CATEGORY_SPECIALS'
'PRODUCT_NAME'
'PRODUCT_DESCRIPTION'
'PRODUCT_PRICE'
'COPYRIGHT_YEARS'
'HREF_HOME'
'HREF_CART'
'HREF_CONTACT'
'HREF_COMPANY_INFO'
) );
$aTPL->parse(
$aTPL->parse(
$aTPL->parse(
$aTPL->parse(
$aTPL->parse(
$aTPL->parse(
'PAGE_HEADER',
'CAT_HEADER',
'LEFT_NAVI',
'BODY',
'PAGE_FOOTER',
'BASE',
Rozdział 14 – Witryny oparte o szablony
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
$aPartnerBase,
'merch_header.tpl',
'merch_navi.tpl',
$aPartnerFooter,
$aCategoryHeader,
'merch_body.tpl'
=> 'Katalog produktów: Ubrania',
'Sprzedanemy koszulki Intechra!',
'Koszulka Intechra',
'Świetna koszulka z logo Intechra LLC!',
'14.95 zł',
'2000',
'index.phtml',
'cart.phtml',
'contact.phtml',
'company.phtml'
'header' );
'cat_header' );
'navi' );
'body' );
'footer' );
'base' );
184
$aTPL->FastPrint( 'BASE' );
?>
Po uruchamianiu tego skryptu analizowana jest zmienna $HTTP_HOST, aby sprawdzić, która witryna została
wywołana. Jeżeli nazwa zawiera cobrand, używane są szablony partnera, natomiast w pozostałych przypadkach
używane są standardowe szablony. Gdy strona ta zostanie wywołana poprzez adres http://www.katalog.com,
wynik jest identyczny jak na rysunku 14.3. Rysunek 14.8. przedstawia wygląd strony po wywołaniu strony
poprzez adres zapożyczonej witryny.
Rysunek 14.8.
Zapożyczenie
katalogu
produktów
Personalizacja witryny
Personalizacja wydaje się ostatnio najpopularniejszym elementem przy projektowaniu witryn. Każdy
portal i wiele dużych witryn pozwalają na personalizowanie witryny tak, aby spełniała potrzeby użytkownika. We
wielu przypadkach personalizacja jest ograniczona do typu wyświetlanych informacji i niektórych podstawowych
kolorów. Wykorzystując szablony możliwa jest o wiele bardziej zaawansowana modyfikacja wyglądu witryny.
Zamiast tworzyć przykłady dla tej części książki, chciałbym odwołać się do witryny, którą wykonałem. Nie jest
moim celem reklamować ten serwis, ale jedynie pokazać jak bardzo można modyfikować wygląd witryny
korzystając z dobrego systemu szablonów.
Tą witryną jest http://www.HopeToAdopt.com/ i jest to sieciowy serwis dla rodzin adoptujących dzieci.
Witryna pozwala na tworzenie własnych profili poprzez odpowiedź na kilka prostych pytań oraz wybranie
odpowiednich opcji. Najlepszą cechą witryny jest możliwość wybrania własnego tematu używanego w stronach
informacyjnych. Każdy z dostępnych tematów jest przedstawiony w postaci ikony na stronie.
Gdy Użytkownik kliknie ikonę tematu, w bazie danych zapisywany jest wybrany identyfikator tematu i
jest on używany później przy wyświetlaniu. Na rysunku 14.10.pokazany jest wygląd witryny po wybraniu tematu
kolejowego.
Do stworzenia tematu potrzebne są cztery pliki: {temat}_navi.jpg, {temat}_header.jpg, {temat}_map.tpl
oraz {temat}_vars.php. Pierwsze dwie są rysunkami używanymi w nagłówku oraz panelu nawigacyjnym. Trzeci
jest mapą obrazu dla panelu nawigacyjnego. Ostatni plik jest zbiorem zmiennych specyficznych dla szablonu,
które są dołączane do pliku skryptu PHP korzystającego z danych tematu. Przykład takiego pliku jest pokazany na
wydruku 14.20.
PHP – Kompendium wiedzy
185
Wydruk 14.20. Plik dołączany specyficzny dla tematu
<?php
function AddTemplateVars( &$tpl, $aCurTemplate )
{
$tpl->assign( array( BODYBGCOLOR
=> "#FFFFFF",
MAINWIDTH
=> 584,
TOPIMGWIDTH
=> 584,
TOPIMGHEIGHT
=> 128,
LEFTIMGWIDTH
=> 137,
LEFTIMGHEIGHT
=> 312,
FILLWIDTH
=> 584,
TABLECOLOR
=> "#ffadad"));
}
function GetTemplteValue( $aValName )
{
switch ( $aValName )
{
case "NavSide": return "left";
case "HasOvr" : return False;
}
}
?>
Rysunek 14.10.
Profil
użytkownika z
tematem
kolejowym
Plik ten zawiera dane na temat kolorów wykorzystywanych w temacie, oraz wysokość i szerokość różnych
rysunków używanych w temacie. Dodatkowo dostępna jest funkcja zwracająca do głównego skryptu dane na
temat tematu.
Przykład ten jest specyficzny dla aplikacji HopeToAdopt.com, ale może służyć jako ilustracja
elastyczności systemu szablonów. Witryna HopeToAdopt.com jest używana jako działający przykład pokazujący
siłę systemu szablonów — zamiast tworzenia kolejnego trywialnego przykładu. Pełny kod tej witryny nie może
być tutaj zamieszczony, ale poprzednie przykłady zawierają wystarczająco dużo informacji, aby stworzyć tego
typu witrynę.
Rozdział 14 – Witryny oparte o szablony
186
Obsługa wielu języków
Coraz częstsze jest tworzenie witryn działających w kilku językach. Wykorzystując system szablonów do
obsługi tej funkcji pozwala na tworzenie aplikacji w jednym języku, a następnie w łatwy sposób dodać później
kolejne języki. I tym razem tworzenie tak skomplikowanej aplikacji wymaga uważnego projektowania przed
rozpoczęciem prac programowych, ale efekt jest wart tej pracy. Jedną z pierwszych decyzji jest zadecydowanie, w
jaki sposób będą dzielone i identyfikowane elementy właściwe dla języka. Jedną z metod jest stworzenie
oddzielnych katalogów dla poszczególnych języków. Drugą jest umieszczenie identyfikatorów języka w nazwach
i plikach szablonów. Metoda ta zostanie zastosowana w przykładzie.
W przykładzie tym, dla każdego języka wymagane są cztery pliki: rysunek nagłówka, rysunek panelu
nawigacyjnego, mapa rysunku, oraz główny plik. Nie będziemy tu zamieszczać wszystkich plików, pokażemy
jedynie główny skrypt i wynik działania. Na wydruku 14.21. zamieszczony jest główny skrypt, który generuje
jedną stronę międzynarodowej witryny opartej o szablony.
Wydruk 14.21. Główny skrypt międzynarodowej witryny
<?php
include( "class.FastTemplate.php" );
$aTPL = new FastTemplate( "." );
if ( empty( $Lang ) )
{
$Lang = 'enu';
}
$aHeaderImg
$aNaviImg
$aNaviMap
$aBodyTpl
=
=
=
=
"intl_head_{$Lang}.gif";
"intl_nav_{$Lang}.gif";
"intl_map_{$Lang}.tpl";
"body_{$Lang}.tpl";
$aTPL->define( array( 'base'
=> 'intl_base.tpl',
'body'
=> $aBodyTpl,
'navimap' => $aNaviMap ) );
$aTPL->assign( array( 'HREF_HOME'
'HREF_LINKS'
'HREF_ABOUT'
'HREF_CONTACT'
'HEADER_IMG'
'NAV_IMG'
'HREF_ENU'
'HREF_POL'
'HREF_DEU'
=>
=>
=>
=>
=>
=>
=>
=>
=>
"intl.phtml?Lang=$Lang",
"links.phtml?Lang=$Lang",
"about.phtml?Lang=$Lang",
"contact.phtml?Lang=$Lang",
$aHeaderImg,
$aNaviImg,
$PHP_SELF . "?Lang=enu",
$PHP_SELF . "?Lang=pol",
$PHP_SELF . "?Lang=deu" ) );
$aTPL->parse( 'NAV_MAP', 'navimap' );
$aTPL->parse( 'BODY', 'body' );
$aTPL->parse( 'BASE', 'base' );
$aTPL->FastPrint( 'BASE' );
?>
Jedyną widoczną różnicą w tym skrypcie, w porównaniu z innymi przedstawionymi w tym rozdziale jest
część na początku ustalająca bieżący język i korzystająca z tej informacji w celu dołączenia właściwego pliku. W
przykładzie tym identyfikator języka jest przesyłany poprzez adres URL, więc każde łącze w witrynie musi
przesyłać tą daną do kolejnej strony. W dużych aplikacjach przedstawiona metoda definiowania wszystkich
możliwych łączy staje się nieporęczna. W praktyce kod generujący łącza prawdopodobnie będzie umieszczony w
oddzielnym pliku dołączanym. Niezależnie od prostoty przedstawionego przykładu, elastyczność i siła tego
rozwiązania jest ogromna. Na rysunkach 14.12, 14.13 i 14.14 pokazana jest strona główna w języku odpowiednio:
angielskim, polskim i niemieckim.
187
PHP – Kompendium wiedzy
Rysunek 14.12.
Witryna
międzynarodowa
w języku
angielskim
Rysunek 14.13.
Witryna
międzynarodowa
w języku polskim
Rozdział 14 – Witryny oparte o szablony
188
Rysunek 14.14.
Witryna
międzynarodowa
w języku
niemieckim
Podsumowanie
W rozdziale tym pokazano jak zastosowanie systemu szablonów polepsza elastyczność i łatwość
utrzymania aplikacji WWW. Dostarczone przykłady pokazują, w jaki sposób można użyć szablonów do obsługi
zapożyczania, personalizacji i obsługi języków.
Używanym systemem szablonów jest FastTemplate, który można uzyskać pod adresem
http://www.thewebmasters.net/. Niezależnie od rodzaju używanego systemu szablonów jest zalecane zapoznanie
się z tym sposobem tworzenia aplikacji WWW.
189
PHP – Kompendium wiedzy
Rozdział 15. Witryny oparte o bazę
danych
Wstęp
W rozdziale 6. „Współpraca z bazami danych” opisane zostały narzędzia PHP pozwalające na dostęp do
baz danych. W ostatnim rozdziale dokładnie opisane jest wykorzystanie systemu szablonów do oddzielenia
interfejsu aplikacji od kodu aplikacji. Rozdziały te stanowią podstawę dla tego rozdziału. W rozdziale tym
opisane są szczegóły projektu i implementacji na wysokim poziomie, więc nie będą opisane niskopoziomowe
funkcje obsługi baz danych. Więcej na ten temat można przeczytać w rozdziale 6. oraz w skorowidzu funkcji na
końcu tej książki.
Projekt bazy danych
W każdym aspekcie tworzenia oprogramowania wynikiem dobrego projektu jest dobry produkt.
Nieprawidłowy projekt bazy danych zwykle prowadzi do problemów z integracją, utrzymaniem i tworzeniem
aplikacji. Prawidłowe projektowanie baz danych jest tematem wielu wspaniałych książek i jest to temat zbyt
obszerny i skomplikowany, aby go tutaj przedstawić, więc opisane zostaną niektóre podstawowe informacje.
Pierwszą decyzją jaką należy podjąć jest wybór systemu zarządzania bazą danych (SZRBD). Ponieważ
PHP obsługuje wiele popularnych systemów baz danych, przy podejmowaniu tej decyzji powinniśmy wziąć pod
uwagę koszty, funkcjonalność, skalowalność oraz inne kluczowe aspekty bazy danych, a nie obsługa języka.
Dla wielu aplikacji PHP świetnym systemem bazy danych jest MySQL, ponieważ PHP posiada domyślnie
wbudowaną obsługę MySQL. MySQL jest dostępny na zasadach licencji GNU General Public License (GPL).
Posiada on obsługę dużego podzbioru SQL oraz bogate API. Informacje na temat instalacji i korzystania z
MySQL znajdują się w rozdziale 6. Przykłady w tym rozdziale są napisane w oparciu o bazę danych MySQL.
Dostępne są również inne bazy danych, które także mają swoje silne strony. Jeżeli masz zamiar stworzyć
aplikację, która obsługiwać będzie dużą liczbę użytkowników lub potrzebujesz obsługi transakcji, powinieneś
rozważyć zastosowanie Oracle lub Microsoft SQL Server. Wybór właściwej bazy danych dla aplikacji wymaga
wyboru pomiędzy ceną, dostępnością obsługi technicznej, skalowalnością i dostępnymi funkcjami. Wybór
niewłaściwego systemu bazy danych może spowodować, że w przypadku dużego obciążenia aplikacja będzie
miała niską wydajność lub odmówi posłuszeństwa. Jeżeli przypuszczasz, że po stworzeniu aplikacji system bazy
danych może być zmieniony na inny, należy skorzystać z pośredniego API stanowiącego bufor pomiędzy
aplikacją a funkcjami specyficznymi dla określonej bazy danych, oraz korzystać ze standardowego języka SQL.
Dodatkowo należy pamiętać o różnicach w obsłudze standardu SQL w różnych systemach baz danych. Dla
przykładu w Oracle można korzystać z następujących podzapytań:
SELECT * FROM tabela1 WHERE id IN (SELECT id FROM tabela2)
W czasie pisania tej książki MySQL nie potrafił obsługiwać takiej konstrukcji. Tworzenie kodu SQL
niezależnego od systemu bazy danych jest wyzwaniem samym w sobie, więc zmiana systemu bazy danych na
inny może być niepraktyczna nawet dla małych aplikacji.
Po wybraniu systemu bazy danych kolejnym krokiem jest stworzenie i dokładne przetestowanie modelu
danych. Jako przykładu użyjemy sieciowego katalogu towarów, przeznaczonego dla wielu sprzedawców lub
sklepów. W tym rozdziale opisany zostanie proces projektowania i implementacji bazy danych, która będzie
wykorzystywana w dwóch kolejnych rozdziałach. Celem jest stworzenie sieciowego katalogu, obsługującego w
jednej bazie danych fragmenty danych przypisane do różnych sprzedawców, a każdy z tych sprzedawców może
mieć wiele kategorii produktów. Ogólny schemat tej bazy danych jest pokazany na rysunku 15.1.
Rysunek 15.1.
Podstawowy model
danych katalogu
towarów
Rozwijając model z rysunku 15.1, każdy sprzedawca może mieć jedną lub więcej kategorii produktów, a
każda z kategorii może zawierać jeden lub więcej produktów. Na tym poziomie szczegółowości można stworzyć
kompletny model danych. Na rysunku 15.2 pokazany jest kompletny model danych katalogu produktów. Jego
implementacja w SQL zamieszczona jest na wydruku 15.1.
Rysunek 15.2.
Pełny model
danych katalogu
towarów
Wydruk 15.1. Implementacja modelu danych katalogu produktów
CREATE TABLE mcMerchants
(
merchant_id
int
name
varchar(50)
created_date
datetime
internal_status int
addtl_handling float
mgr_email
varchar(25)
mgr_username
varchar(30)
mgr_password
varchar(30)
mgr_name
varchar(50)
not
not
not
not
default 0.0 not
not
not
not
not
null,
null,
null,
null,
null,
null,
null,
null,
null,
primary key ( merchant_id ),
index( name ),
index( mgr_username )
);
CREATE TABLE mcCategories
(
merchant_id
int
category_id
int
name
varchar(50)
191
not null,
not null,
not null,
PHP – Kompendium wiedzy
created_date
deleted
datetime
tinyint
default 0
not null,
not null,
primary key ( merchant_id, category_id ),
index( name )
);
CREATE TABLE mcProducts
(
merchant_id
int
product_id
int
category_id
int
name
varchar(200)
descr
text
has_image_file tinyint
default 0
external_id
varchar(100)
ship_weight
float
price
float
created_date
datetime
deleted
tinyint
default 0
not
not
not
not
not
not
not
not
not
not
not
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
primary key ( merchant_id, product_id ),
index( name )
);
CREATE TABLE mcProductsToCategories
(
merchant_id
int
category_id
int
product_id
int
not null,
not null,
not null,
primary key ( merchant_id, category_id, product_id )
);
CREATE TABLE mcProductsOptions
(
merchant_id
int
product_id
int
option_id
int
name
varchar(100)
sort_type
tinyint
default 0
not
not
not
not
not
null,
null,
null,
null,
null,
primary key ( merchant_id, product_id, option_id ),
index( name )
);
CREATE TABLE mcProductsOptionsValues
(
merchant_id
int
product_id
int
option_id
int
value_id
int
name
varchar(100)
not
not
not
not
not
null,
null,
null,
null,
null,
primary key ( merchant_id, product_id, option_id, value_id ),
index( name )
);
Po zaprojektowaniu i sprawdzeniu modelu danych można rozpocząć prace nad aplikacją. Podstawowymi
założeniami aplikacji katalogu produktów są:
• Wyświetlanie danych o produktach w logicznym i łatwym do użycia formacie.
• Umożliwienie sprzedawcom uaktualniania danych o produktach w dowolnym momencie z dowolnego
komputera przyłączonego do sieci Internet.
• Umożliwienie sprzedawcom zarządzanie kategoriami produktów i przypisywanie produktów do kategorii
w dowolnym momencie z dowolnego komputera przyłączonego do sieci Internet.
Mówiąc prościej, celem jest dostarczenie metody na dodawanie, zmianę i wyświetlanie dowolnej danej
zawartej w katalogu produktów, wykorzystując do tego celu Internet. W następnej sekcji opisane zostanie
zarządzanie tymi danymi.
Zarządzanie danymi aplikacji
Po zaprojektowaniu i stworzeniu bazy danych można rozpocząć tworzenie aplikacji zarządzającej
rekordami w bazie danych. Podstawowymi operacjami jakie można przeprowadzać na dowolnych danych jest
Rozdział 15 – Witryny oparte o bazę danych
192
dodawanie, zmiana i usuwanie. W tej aplikacji niezbędne będzie również zarządzanie hierarchią danych. Aby
spełnić to wymaganie, spełniona musi być zasada, że przed dodaniem jakiegokolwiek produktów, musi istnieć co
najmniej jedna kategoria produktów dla sprzedawcy.
Mając na uwadze tą zasadę, logicznym punktem startowym jest strona z możliwością zarządzania
kategoriami produktów. W aplikacji tej zakładamy, ze sprzedawca może się zalogować do fragmentu witryny w
celu zarządzania danymi. W aplikacji będziemy korzystać z omówionego wcześniej systemu szablonów
FastTemplate. Do podstawowego zarządzania danymi aplikacji użyte zostaną szablony przedstawione na
wydrukach od 2. do 4.
Wydruk 15.2. Podstawowy szablon zarządzania danymi aplikacji (mgmt_app_base.tpl)
<html>
<head>
<title>{TITLE}</title>
<link rel="STYLESHEET" type="text/css" href="mgmt.css">
</head>
<body bgcolor="White">
{BODY}
</body>
</html>
Wydruk 15.3. Szablon zarządzania danymi aplikacji (mgmt_body.tpl)
<table width="630" align="center">
<tr>
<td align="center" class="title">
{MERCHANT_NAME}
</td>
</tr>
<tr>
<td>
{PAGE_BODY}
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
</tr>
<tr>
<td>
{FOOTER}
</td>
</tr>
</table>
Wydruk 15.4. Szablon zarządzania danymi aplikacji — stopka (mgmt_footer.tpl)
<hr>
<p class="footer">
&copy; 2000 Intechra LLC. Wszystkie prawa zastrzeżone.
</p>
Szablony przedstawione na wydrukach od 2. do 4. stanowią podstawowy szablon aplikacji zarządzania
danymi. Szablony używane do stworzenia strony zarządzania konkretną kategorią umieszczone są na wydrukach
od 5. do 7. Na wydruku 15.8. znajduje się skrypt łączący te szablony i wyświetlający dane z bazy danych.
Wydruk 15.5. Szablon zarządzania danymi aplikacji — główny szablon kategorii (mgmt_cats_ovr.tpl)
<h1>
Zarządzanie kategoriami produktów
</h1>
<p>
Proszę użyć poniższych narzędzi do dodaniam edycji i usunięcia
kategorii produktów.
</p>
<p>
<a href="mgmt_cat_add.phtml">Kliknij tutaj</a> aby dodać kategorię.
</p>
{EXISTING_CATEGORIES}
Wydruk 15.6. Szablon zarządzania danymi aplikacji — tabela kategorii (mgmt_cats_table.tpl)
<h2>
Istniejące kategorie produktów:
</h2>
<table cellspacing="0" cellpadding="0">
<tr>
<th>
&nbsp;&nbsp;Identyfikator kategorii&nbsp;&nbsp;
</th>
<th>
&nbsp;&nbsp;Nazwa kategorii&nbsp;&nbsp;
</th>
193
PHP – Kompendium wiedzy
<th>
&nbsp;&nbsp;Operacje&nbsp;&nbsp;
</th>
</tr>
{CATEGORY_LIST}
</table>
Wydruk 15.7. Szablon zarządzania danymi aplikacji — bieżąca kategoria (mgmt_cats_item.tpl)
<tr>
<td>
{CAT_ID}
</td>
<td>
{CAT_NAME}
</td>
<td class="small">
<a href="mgmt_cat_edit.phtml?cat_id={CAT_ID}">ZMIEŃ</a>
<a href="mgmt_cat_del.phtml?cat_id={CAT_ID}">USUŃ</a>
</td>
</tr>
Wydruk 15.8. Aplikacja zarządzająca danymi — zarządzanie kategoriami (mgmt_cats.phtml)
<?php
error_reporting( E_ALL & ~E_NOTICE );
session_start(); // niejawne ustawienie zmiennej sesji $aMerchantID
if ( empty( $aMerchantID ) == True )
{
header( "Location: login.phtml?retpage=" . urlencode( $REQUEST_URI ) . "\n" );
exit;
}
include( "class.FastTemplate.php" );
include( "./mgmt_db.php" );
include( "./mgmt_funcs.php" );
$aTPL = new FastTemplate( "." );
$aDB = new mgmt_db();
$aTPL->define( array(
"base"
"body"
"footer"
"page_body"
"cat_table"
"cat_item"
=>
=>
=>
=>
=>
=>
"mgmt_app_base.tpl",
"mgmt_body.tpl",
"mgmt_footer.tpl",
"mgmt_cats_ovr.tpl",
"mgmt_cats_table.tpl",
"mgmt_cats_item.tpl" ) );
$aSQL = "select category_id, name from mcCategories
where ( merchant_id = $aMerchantID )";
$aDB->query( $aSQL );
if ( $aDB->num_rows() > 0 )
{
while ( $aDB->next_record() )
{
$aCatID
= $aDB->f( "category_id" );
$aCatName = $aDB->f( "name" );
$aTPL->assign( array( "CAT_ID"
=> $aCatID,
"CAT_NAME"
=> $aCatName ) );
$aTPL->parse( "CATEGORY_LIST", ".cat_item" );
}
$aTPL->parse( "EXISTING_CATEGORIES", "cat_table" );
}
else
{
$aTPL->assign( array(
}
$aTPL->assign( array(
"EXISTING_CATEGORIES" =>
"TITLE"
=>
"MERCHANT_NAME" =>
) );
"" ) );
"Zarządzanie katalogiem towarów",
GetMerchantName( $aDB, $aMerchantID )
$aTPL->parse( "PAGE_BODY", "page_body" );
$aTPL->parse( "FOOTER", "footer" );
$aTPL->parse( "BODY", "body" );
$aTPL->parse( "PAGE", "base" );
$aTPL->FastPrint( "PAGE" );
?>
Pierwszą operacją jaką wykonuje skrypt jest rozpoczęcie sesji i sprawdzenie identyfikatora sprzedawcy,
$aMerchantID. Jeżeli nie jest on ustawiony, użytkownik jest kierowany na stronę logowania. Na stronie logowania
sprawdzane są dane użytkownika i jeżeli zostanie on rozpoznany, ta zmienna sesji jest inicjowana identyfikatorem
Rozdział 15 – Witryny oparte o bazę danych
194
sprzedawcy. Następnie używając identyfikatora jako filtru, skrypt ten pobiera kategorie z bazy danych. Jeżeli
istnieje co najmniej jedna kategoria, skrypt pobiera te dane i generuje tabelę istniejących kategorii. Na rysunku
15.3. pokazana jest strona z dwiema kategoriami testowego sprzedawcy.
Rysunek
15.3.
Strona
zarządza
nia
kategoria
mi
katalogu
produktó
w
Dodawanie kategorii jest zrealizowane za pomocą kliknięcia w łącze. Jeżeli istnieją kategorie, każda z
nich posiada własne łącza ZMIEŃ i USUŃ, na rysunku 15.3. szablony dodawania kategorii oraz skrypt
umieszczone są na wydrukach 9. i 10.
Wydruk 15.9. Szablon zarządzania danymi aplikacji — dodawanie kategorii (mgmt_cat_add.tpl)
<h1>
Dodawanie kategorii produktu
</h1>
<form action="{FORM_ACTION}" method="post">
<table>
<tr>
<td colspan="2">
{ERRORS}
</td>
</tr>
<tr>
<td>
Nazwa kategorii:
</td>
<td>
<input type="text" name="CategoryName">
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="Submit" value="Wyślij">
</td>
</tr>
</table>
</form>
Wydruk 15.10. Aplikacja zarządzająca danymi — dodawanie kategorii (mgmt_cat_add.phtml)
<?php
session_start(); // niejawne ustawienie zmiennej sesji $aMerchantID
if ( empty( $aMerchantID ) == True )
{
header( "Location: login.phtml?retpage=" .
urlencode( $REQUEST_URI ) . "\n" );
exit;
}
include( "class.FastTemplate.php" );
195
PHP – Kompendium wiedzy
include( "./mgmt_db.php" );
include( "./mgmt_funcs.php" );
$aTPL = new FastTemplate( "." );
$aDB = new mgmt_db();
$aErrors = "";
if ( $REQUEST_METHOD == 'POST' ) // Tutaj wchodzimy po wysłaniu danych z formularza
{
if ( IsValidCategory( $aDB, $aMerchantID, $CategoryName ) == True )
{
SaveCategory( $aDB, $aMerchantID, $CategoryName );
header( "Location: mgmt_cats.phtml\n" );
exit;
}
else
{
$aErrors = "Nazwa kategorii została już użyta. ";
$aErrors .= "Proszę wybrać inną nazwę kategorii.";
}
}
$aTPL->define( array(
$aTPL->assign( array(
"base"
"body"
"footer"
"page_body"
=>
=>
=>
=>
"TITLE"
"MERCHANT_NAME"
"FORM_ACTION"
"ERRORS"
) );
"mgmt_app_base.tpl",
"mgmt_body.tpl",
"mgmt_footer.tpl",
"mgmt_cat_add.tpl" ) );
=>
=>
=>
=>
"Zarządzanie katalogiem produktów",
GetMerchantName( $aDB, $aMerchantID ),
$PHP_SELF,
$aErrors
$aTPL->parse( "PAGE_BODY", "page_body" );
$aTPL->parse( "FOOTER", "footer" );
$aTPL->parse( "BODY", "body" );
$aTPL->parse( "PAGE", "base" );
$aTPL->FastPrint( "PAGE" );
?>
Skrypt przedstawiony na wydruku 15.10. jest podobny do wielu innych skryptów zbierających i
kontrolujących dane, które były opisane w tej książce. Jest on używany do wyświetlenia formularza oraz kontroli
poprawności wprowadzonych danych. W tym przypadku cała logika kontroli poprawności oraz zapamiętywania
nowych kategorii jest umieszczona w funkcjach IsValidCategory() i SaveCategory(). Te funkcje pomocnicze
zostaną zamieszczone w dalszej części rozdziału na wydruku pliku mgmt_funcs.php. Funkcja sprawdzająca
poprawność szuka jedynie kategorii o takiej samej nazwie.
Funkcje edycji i usuwania kategorii są bardzo podobne do innych skryptów zamieszczonych już w tej
książce. Przyglądając się wydrukowi 8. można zauważyć, że łącza do usuwania i zmiany kategorii zawierają
identyfikator kategorii. Dla przykładu pełny adres URL do usuwania kategorii Ubrania to
http://server.com/ch15/mgmt_cat_del.phtml?cat_id=1. Do skryptu jest przekazany identyfikator kategorii, więc
można na jego podstawie skonstruować proste wyrażenie SQL DELETE. W przypadku edycji, ten sam mechanizm
umożliwia wczytanie nazwy kategorii do pola tekstowego. Kod źródłowy tych stron nie został tu zamieszczony,
ponieważ jest on bardzo podobny do kodu z wydruków 9. i 10. Funkcje usuwające i zmieniające kategorie
pokazane są na wydruku pliku mgmt_funcs.php (wydruk 15.12.).
Podczas tworzenia kategorii należy pamiętać, że nazwa nowej kategorii nie może znajdować się w bazie
danych. W przypadku usuwania kategorii należy sprawdzić, czy nie istnieje produkt należący do tej kategorii.
Jeżeli do kategorii należą jakieś produkty usunięcie kategorii spowodowałoby powstanie osieroconych rekordów
produktów i potencjalnie błędów aplikacji. Tworząc aplikacje WWW działające w oparciu o bazę danych,
spełnienie wszystkich zasad biznesowych w kodzie jest krytyczne do dobrego działania aplikacji. Niektóre z
zasad mogą być realizowane przez funkcje bazy danych, na przykład wymuszanie więzów integralności lub
kaskadowe operacje na danych. Inne zasady mogą być realizowane w bazie danych za pomocą wyzwalaczy lub
procedur przechowywanych. Pozostałe zasady biznesowe muszą być realizowane w kodzie aplikacji.
Tworząc kod obsługi zasad biznesowych dobrą praktyką jest tworzenie funkcji obsługi wszystkich zasad.
Dla przykładu należy użyć funkcji DeleteEntity() zamiast wplatać w kod wyrażenia DELETE. Funkcja
DeleteEntity() może zawierać w sobie całą logikę wymaganą do kontroli więzów integralności oraz zasad
biznesowych i zwracać różne wartości kodu powrotu w zależności od różnych błędów, jakie mogą wystąpić. W
Rozdział 15 – Witryny oparte o bazę danych
196
ten sposób poprawia się możliwość późniejszego użycia kodu oraz ułatwia wprowadzanie do aplikacji zmian w
logice.
Wracając do katalogu produktów, kolejnym krokiem jest utworzenie stron obsługi aktualnego zestawu
produktów. Strony te są logicznie identyczne ze stronami obsługi kategorii. Na rysunku 15.4 pokazana jest strona
zarządzania produktami, natomiast na wydruku 15.11. znajduje się skrypt generujący tą stronę.
Rysunek
15.4.
Ekran
zarządza
nia
produkta
mi
Wydruk 15.11. Aplikacja zarządzania danymi — zarządzanie produktami (mgmt_prods.phtml)
<?php
error_reporting( E_ALL & ~E_NOTICE );
session_start(); // niejawne ustawianie zmiennej sesji $aMerchantID
if ( empty( $aMerchantID ) == True )
{
header( "Location: login.phtml?retpage=" . urlencode( $REQUEST_URI )."\n" );
exit;
}
include( "class.FastTemplate.php" );
include( "./mgmt_db.php" );
include( "./mgmt_funcs.php" );
$aTPL = new FastTemplate( "." );
$aDB = new mgmt_db();
$aTPL->define( array(
"base"
"body"
"footer"
"page_body"
"prod_table"
"prod_item"
=>
=>
=>
=>
=>
=>
"mgmt_app_base.tpl",
"mgmt_body.tpl",
"mgmt_footer.tpl",
"mgmt_prods_ovr.tpl",
"mgmt_prods_table.tpl",
"mgmt_prods_item.tpl" ) );
$aSQL = "select a.category_id, a.product_id, a.name, a.external_id, a.price,";
$aSQL .= "b.name as cat_name from mcProducts a, mcCategories b where (a.merchant_id";
$aSQL .= "= $aMerchantID) and (a.category_id = b.category_id)";
$aDB->query( $aSQL );
if ( $aDB->num_rows() > 0 )
{
while ( $aDB->next_record() )
{
$aCatID
= $aDB->f( "category_id" );
$aCatName
= $aDB->f( "cat_name" );
$aProdID
= $aDB->f( "product_id" );
$aProdName = $aDB->f( "name" );
$aProdEID
= $aDB->f( "external_id" );
$aProdPrice = $aDB->f( "price" );
$aTPL->assign( array( "PROD_ID"
197
=>
$aProdID,
PHP – Kompendium wiedzy
"PROD_EID"
=> $aProdEID,
"PROD_NAME"
=> $aProdName,
"PROD_CAT"
=> $aCatName,
"PROD_PRICE" => '$' .
number_format( $aProdPrice, 2 ) ) );
$aTPL->parse( "PRODUCT_LIST", ".prod_item" );
}
$aTPL->parse( "EXISTING_PRODUCTS", "prod_table" );
}
else
{
$aTPL->assign( array(
"EXISTING_PRODUCTS" =>
"" ) );
}
$aTPL->assign( array(
"TITLE"
=>
"MERCHANT_NAME" =>
) );
"Zarządzanie katalogiem produktów",
GetMerchantName( $aDB, $aMerchantID )
$aTPL->parse( "PAGE_BODY", "page_body" );
$aTPL->parse( "FOOTER", "footer" );
$aTPL->parse( "BODY", "body" );
$aTPL->parse( "PAGE", "base" );
$aTPL->FastPrint( "PAGE" );
?>
Strony umożliwiające dodawanie, usuwanie i zmianę produktów nie zostały tutaj szczegółowo
przedstawione, ale są dostępne na stronie WWW wymienionej w zasobach sieci na końcu książki. Zasady
biznesowe obowiązujące przy dodawaniu nowych produktów są następujące:
• Produkt musi zostać przypisany do jednej kategorii.
• Nazwy produktów w kategorii muszą być unikalne.
• Cena produktu musi wynosić co najmniej zero.
• Waga towaru również musi wynosić co najmniej zero.
W chwili obecnej nie ma ograniczeń na kasowanie produktów. Po zmianie danych produktu muszą być
spełnione te same zasady biznesowe co przy dodawaniu nowego produktu. Na wydruku 15.12 zamieszczony
został fragment pliku mgmt_funcs.php zawierający niektóre funkcje dostępu do bazy danych oraz funkcje zasad
biznesowych używanych w aplikacji.
Wydruk 15.12. Aplikacja zarządzająca danymi — funkcje użytkowe (mgmt_funcs.php)
<?php
function GetMerchantName( $aDB, $aMerchantID )
{
$aResult = "";
$aSQL
= "select name from mcMerchants where ";
$aSQL
.= "( merchant_id = $aMerchantID )";
$aDB->query( $aSQL );
if ( $aDB->next_record() == True )
{
$aResult = $aDB->f( "name" );
}
return $aResult;
}
function NewCategoryID( $aDB, $aMerchantID )
{
$aSQL = "select ( max( category_id ) + 1 ) as new_id ";
$aSQL .= "from mcCategories where ( merchant_id = $aMerchantID )";
$aDB->query( $aSQL );
if ( $aDB->next_record() )
{
$aResult = $aDB->f( "new_id" );
}
if ( empty( $aResult ) == True )
{
$aResult = 1;
}
return $aResult;
}
function IsValidCategory( $aDB, $aMerchantID, $aCategoryName )
{
$aSQL = "select category_id from mcCategories where ";
$aSQL .= "( merchant_id = $aMerchantID ) and ";
$aSQL .= "( upper( name ) = upper( '$aCategoryName' ) )";
$aDB->query( $aSQL );
// Jeżeli istnieje rekord z tą samą nazwą kategorii,
Rozdział 15 – Witryny oparte o bazę danych
198
// zwróć false
return ( $aDB->num_rows() == 0 );
}
function SaveCategory( $aDB, $aMerchantID, $aCategoryName )
{
$aNewID = NewCategoryID( $aDB, $aMerchantID );
$aSQL
= "insert into mcCategories ( merchant_id, ";
$aSQL .= "category_id, name, created_date ) values ";
$aSQL .= "( $aMerchantID, $aNewID, '$aCategoryName', ";
$aSQL .= " NOW() )";
$aDB->query( $aSQL );
return ( $aDB->Errno == 0 );
}
function DeleteCategory( $aDB, $aMerchantID, $aCategoryID )
{
$aSQL = "delete from mcCategories where ( merchant_id = ";
$aSQL .= "$aMerchantID ) and ( category_id = $aCategoryID )";
$aDB->query( $aSQL );
return ( $aDB->Errno == 0 );
}
function UpdateCategory( $aDB, $aMerchantID, $aCategoryID, $aCategoryName )
{
$aSQL = "update mcCategories set name='$aCategoryName' ";
$aSQL .= "where ( merchant_id = $aMerchantID ) and ";
$aSQL .= "( category_id = $aCategoryID )";
$aDB->query( $aSQL );
return ( $aDB->Errno == 0 );
}
// i inne funkcje
?>
Aplikacja zarządzająca danymi jest jedynie małym fragmentem całego katalogu produktów. Zapewnia ona
interfejs WWW do zarządzania elementami katalogu. Inną ważną funkcją katalogu jest możliwość wyświetlania
produktów, szukania produktów oraz odczytywania szczegółowych danych o produktach w katalogu. Następna
część tego rozdziału traktuje właśnie o tych zagadnieniach.
Wyświetlanie danych
Aplikacja wyświetlająca dane produktów z bazy pozwala na wyświetlanie produktów określonej kategorii,
wyświetlanie alfabetycznej listy produktów oraz zapewnia mechanizm przeszukiwania, pozwalający na
znalezienie określonego produktu. Aby odszukać produkty i kategorie bieżącego sprzedawcy wykorzystywany
jest identyfikator sprzedawcy, przekazywany w postaci zmiennej sesji. Zmienna ta jest ustawiana jeszcze zanim
użytkownik wejdzie na stronę, na której wyświetlane są informacje o produktach.
Na rysunku 15.5. znajduje się główna strona katalogu produktów. Strona ta pozwala na natychmiastowy
dostęp do danych podzielonych na kategorie oraz na przeszukiwanie katalogu. Jeżeli nie ma zarejestrowanych
żadnych kategorii (co oznacza brak towarów), wyświetlana jest informacja, że dla ten sprzedawca nie ma
zarejestrowanych produktów. Na wydruku 15.13. zamieszczony jest skrypt generujący tą stronę.
199
PHP – Kompendium wiedzy
Rysunek
15.5.
Główna
strona
katalogu
produktó
w
Wydruk 15.13. Aplikacja zarządzająca danymi — wyświetlanie produktów (mgmt_main.phtml)
<?php
error_reporting( E_ALL & ~E_NOTICE );
session_start(); // niejawne ustawianie zmiennej sesji $aMerchantID
if ( empty( $aMerchantID ) == True )
{
print( "Błąd wewnętrzny aplikacji. Brak identyfikatora sprzedawcy." );
exit;
}
include( "class.FastTemplate.php" );
include( "./mgmt_db.php" );
include( "./mgmt_funcs.php" );
$aTPL = new FastTemplate( "." );
$aDB = new mgmt_db();
$aTPL->define( array(
"base"
"body"
"footer"
"page_body"
"cat_body"
"cat_item"
=>
=>
=>
=>
=>
=>
"mgmt_app_base.tpl",
"mgmt_body.tpl",
"mgmt_footer.tpl",
"mgmt_main.tpl",
"mgmt_main_body.tpl",
"mgmt_main_cat_item.tpl" ) );
$aSQL = "select category_id, name from mcCategories
where ( merchant_id = $aMerchantID )";
$aDB->query( $aSQL );
if ( $aDB->num_rows() > 0 )
{
while ( $aDB->next_record() )
{
$aCatID
= $aDB->f( "category_id" );
$aCatName = $aDB->f( "name" );
$aTPL->assign( array( "CAT_HREF"
=> GetCategoryHREF( $aCatID ),
"CAT_NAME"
=> $aCatName ) );
$aTPL->parse( "CATEGORY_LIST", ".cat_item" );
}
$aTPL->parse( "CATALOG_MAIN_BODY", "cat_body" );
}
else
{
$aTPL->assign( array("CATALOG_MAIN_BODY" =>
Rozdział 15 – Witryny oparte o bazę danych
"Brak dostępnych produktów." ) );
200
}
$aTPL->assign( array("TITLE"
=>
"MERCHANT_NAME" =>
) );
"Zarządzanie katalogiem produktów",
GetMerchantName( $aDB, $aMerchantID )
$aTPL->parse( "PAGE_BODY", "page_body" );
$aTPL->parse( "FOOTER", "footer" );
$aTPL->parse( "BODY", "body" );
$aTPL->parse( "PAGE", "base" );
$aTPL->FastPrint( "PAGE" );
?>
Pliki szablonów użyte do wygenerowania tej strony są bardzo podobne do tych, które były używane w
skrypcie zarządzającym kategoriami, zamieszczonym na poprzednim wydruku. W skrypcie pokazanym na
poprzednim wydruku, do generowania adresów URL dla poszczególnych nazw kategorii, została wykorzystana
funkcja GetCategoryHREF(). Funkcja ta wchodzi w skład pliku mgmt_funcs.php i jest przedstawiona na wydruku
15.14. Funkcja ta pozwala na wygenerowanie przez ten skrypt serii statycznych stron na podstawie dynamicznych
danych. Metoda ta zostanie opisane szczegółowo w następnym rozdziale.
Wydruk 15.14. Funkcja GetCategoryHREF()
function GetCategoryHREF( $aCatID, $aDynamic = True )
{
if ( $aDynamic == True )
{
return "mgmt_prod_list.phtml?cat_id=$aCatID";
}
else
{
return "mgmt_cat_{$aCatID}.html";
}
}
Na wydruku 15.15. zamieszczony został skrypt wyświetlający produkty. Jest on używany do wyświetlania
listy podzielonej na kategorie, listy alfabetycznej oraz wyników wyszukiwania.
Wydruk 15.15. Przykład skryptu wyświetlającego produkty
<?php
error_reporting( E_ALL & ~E_NOTICE );
session_start(); // niejawne ustawianie zmiennej sesji $aMerchantID
if ( empty( $aMerchantID ) == True )
{
print( "Błąd wewnętrzny aplikacji. Brak identyfikatora sprzedawcy." );
exit;
}
include_once( "class.FastTemplate.php" );
include_once( "mgmt_db.php" );
include_once( "mgmt_funcs.php" );
$aMerchantID = 1;
if ( $REQUEST_METHOD == 'POST' ) // Tutaj wchodzimy po wysłaniu danych z formularza
{
$aSQL = "select a.category_id, a.product_id, a.name, a.external_id, a.price, ";
$aSQL .= "a.ship_weight, a.has_image_file, a.descr, b.name as cat_name from ";
$aSQL .= "mcProducts a, mcCategories b where ( a.merchant_id = $aMerchantID) ";
$aSQL .= "and ( a.category_id = b.category_id ) and ( ( upper( a.name ) like ";
$aSQL .= "upper( '%{$SearchTerms}%' ) ) or ( upper( a.descr ) like ";
$aSQL .= "upper( '%{$SearchTerms}%' ) ) ) order by a.name";
}
else
{
if ( empty( $cat_id ) == False ) // lista według kategorii
{
$aSQL = "select a.category_id, a.product_id, a.name, a.external_id, ";
$aSQL .= "a.price, a.ship_weight, a.has_image_file, a.descr, b.name as ";
$aSQL .= "cat_name from mcProducts a, mcCategories b where ";
$aSQL .= "(a.merchant_id = $aMerchantID) and (a.category_id = b.category_id) ";
$aSQL .= "and ( a.category_id = $cat_id ) order by a.name";
}
else // lista alfabetyczna
{
$aSQL = "select a.category_id, a.product_id, a.name, a.external_id, a.price, ";
$aSQL .= "a.ship_weight, a.has_image_file, a.descr, b.name as cat_name from ";
$aSQL .= "mcProducts a, mcCategories b where (a.merchant_id = $aMerchantID) ";
$aSQL .= "and (a.category_id = b.category_id) order by a.name";
}
}
201
PHP – Kompendium wiedzy
$aTPL = new FastTemplate( "." );
$aDB = new mgmt_db();
$aTPL->define( array(
"base"
"body"
"footer"
"page_body"
"prod_item"
=>
=>
=>
=>
=>
"mgmt_app_base.tpl",
"mgmt_body.tpl",
"mgmt_footer.tpl",
"mgmt_prod_main.tpl",
"mgmt_prod_item.tpl" ) );
$aDB->query( $aSQL );
if ( $aDB->num_rows() > 0 )
{
while ( $aDB->next_record() )
{
$aProdName
= $aDB->f( "name" );
$aProdEID
= $aDB->f( "external_id" );
$aProdPrice
= $aDB->f( "price" );
$aProdWeight
= $aDB->f( "ship_weight" );
$aHasImage
= $aDB->f( "has_image_file" );
$aProdDescr
= $aDB->f( "descr" );
$aCatName
= $aDB->f( "cat_name" );
$aCatID
= $aDB->f( "category_id" );
$aProdID
= $aDB->f( "product_id" );
$aImageFile = "images/default.jpg";
if ( $aHasImage == True )
{
$aImageFile = "images/{$aMerchID}_{$aCatID}_{$aProdID}.jpg";
}
$aTPL->assign( array( "PROD_NAME"
"CAT_NAME"
"PROD_EID"
"PROD_PRICE"
"PROD_DESCR"
"IMAGE_FILE"
) );
$aTPL->parse( "ITEM_LIST", ".prod_item"
=>
=>
=>
=>
=>
=>
$aProdName,
$aCatName,
$aProdEID,
number_format( $aProdPrice, 2 ).'zł',
$aProdDescr,
$aImageFile
);
}
}
else
{
$aTPL->assign( array("ITEM_LIST" => "Nie ma produktów dla wybranego kryterium."));
}
$aTPL->assign( array(
"TITLE"
=>
"MERCHANT_NAME" =>
) );
"Zarządzanie katalogiem produktów",
GetMerchantName( $aDB, $aMerchantID )
$aTPL->parse( "PAGE_BODY", "page_body" );
$aTPL->parse( "FOOTER", "footer" );
$aTPL->parse( "BODY", "body" );
$aTPL->parse( "PAGE", "base" );
$aTPL->FastPrint( "PAGE" );
?>
Pierwszą operacją podejmowaną przez skrypt jest sprawdzenie, jaki zbiór danych powinien zostać
wybrany. Jeżeli jest on uruchomiony poprzez wywołanie POST, oznacza to, że użytkownik chciał wyszukiwać
dane. W przeciwnym przypadku należy wygenerować listę alfabetyczną, lub tylko dla jednej kategorii. Jeżeli
ustawiona została zmienna $cat_id, potrzebna jest lista dla określonej kategorii. W oparciu o te informacje,
generowane jest odpowiednie zapytanie SQL. W zależności od wyniku zapytania wynikowa strona zawiera listę
produktów albo komunikat, który informuje użytkownika o braku produktów dla wybranej przez niego kryteriów.
Dla każdego rekordu sprawdzany jest znacznik has_image_file. Jeżeli jest on ustawiony, generowana i
wykorzystywana jest standardowa nazwa pliku, natomiast w przeciwnym wypadku wyświetlany jest domyślny
rysunek.
Na rysunkach 15.6., 15.7., i 15.8. pokazane są odpowiednio: lista dla pojedynczej kategorii, lista
alfabetyczna oraz lista wyników wyszukiwania. Szukaną frazą było „pol”.
Rozdział 15 – Witryny oparte o bazę danych
202
Rysunek
15.6.
Lista
dla
kategori
i
(katego
ria
ubrania
)
Rysunek
15.7.
Alfabetycz
na lista
produktów
203
PHP – Kompendium wiedzy
Rysunek
15.8. Lista
wyników
wyszukiwa
nia
(szukanie
„pol”)
W sekcji tej skupiliśmy się na wyświetlaniu danych w witrynie WWW. Zwykle wyświetlanie danych z
bazy danych jest dużo łatwiejsze od manipulowania danymi, ponieważ występuje tu mniej problemów i mniej
możliwości wystąpienia błędu. Następne dwa rozdziały są zbudowane w oparciu o dane i przykłady tu
zaprezentowane.
Podsumowanie
Tworzenie aplikacji WWW korzystających z bazy danych wymaga dokładnego projektowania i
programowania, ale wynik jest wart zachodu. Po stworzeniu systemu administracyjnego aplikacja może być w
uaktualniania dowolnym momencie i z dowolnego miejsca świata, co skutkuje powstaniem dynamicznej witryny
WWW, która jest bardzo łatwa do zarządzania. Najważniejszym krokiem jest dokładne zaprojektowanie bazy
danych, oraz zlokalizowanie wszystkich reguł biznesowych. Jeżeli te elementy zostaną odpowiednio
zaprojektowane i zaprojektowane, konserwacja i utrzymanie aplikacji zostanie niezwykle uproszczone.
Rozdział 15 – Witryny oparte o bazę danych
204
Rozdział 16. Generowanie statycznych
stron HTML w oparciu o dynamiczne
dane
Wstęp
Podstawowym zastosowaniem PHP jest tworzenie stron WWW z dynamicznie zmieniającą się zawartością. Zawartością tą może być
najprostszy licznik odwiedzin, aż do personalizowanych stron korzystających z bazy danych. W niektórych jednak przypadkach w pełni
dynamiczna zawartość strony nie jest konieczna lub zbytnio obniża wydajność witryny. We wielu przypadkach zawartość witryn nie jest
w pełni dynamiczna.
Dla przykładu, katalog produktów z poprzedniego rozdziału jest dynamiczny jedynie w tym sensie, że można zmieniać produkty, ale
każdy użytkownik powinien zobaczyć te same produkty i kategorie. W takich sytuacjach bardziej efektywne jest jednokrotne
generowanie statycznych stron HTML (po zmianie danych źródłowych) i ich wyświetlanie w odpowiedzi na żądania użytkowników. Na
szczęście, przy pomocy PHP można z łatwością wygenerować takie strony, więc nie będą potrzebne żadne dodatkowe narzędzia do
zamiany dynamicznej witryny na częściowo dynamiczną.
Koncepcja
Jednym z pomysłów na stworzenie statycznych stron jest wysyłanie kodu HTML do pliku zamiast do przeglądarki. Można to łatwo
zrealizować korzystając ze standardowych funkcji obsługi plików w PHP. Metoda ta wymaga jednak przepisania każdej ze stron tak, aby
cały kod HTML był włączony w kod PHP. Dla większości witryn jest to niepraktyczne. Istnieje lepsza metoda, działająca z wszystkimi
istniejącymi skryptami i stronami, wymagająca wprowadzenia jedynie minimalnych zmian. Pomysł ten został opisany w części
„Generowanie stron statycznych”.
Innym sposobem na poprawianie wydajności serwera jest buforowanie stron, co powoduje, że skrypt nie uruchamia się przy każdym
wywołaniu. Ten sposób opisany jest w części pod tytułem „Techniki buforowania”.
Generowanie stron statycznych
Ponieważ PHP jest niezwykle elastyczny, istnieją co najmniej dwa sposoby generowania statycznych stron z istniejących skryptów PHP,
przy minimalnej ilości zmian. Pierwszym sposobem jest wykorzystanie funkcji buforujących, drugim jest wykorzystanie klasy
FastTemplate opisanej w poprzednich rozdziałach.
Użycie buforowania
Jeżeli rozmiar witryny nie jest zbyt duży, można zastosować funkcje PHP pozwalające kontrolować mechanizm buforowania do
przechwycenia wynikowego kodu HTML i zapisania go do pliku. Skrypt z wydruku 16.1. Jest logicznie identyczny ze skryptem z
wydruku7 z rozdziału 6. „Współpraca z bazami danych”. Skrypt ten generuje kod strony na której można wybrać stan USA oraz kraj.
Listy te są pobierane z bazy danych. Jest to dobry kandydat do stworzenia strony statycznej, ponieważ lista stanów USA oraz krajów nie
zmienia się często. Jeżeli trzeba poprawić wydajność aplikacji, można zrezygnować z pobierania tych elementów z bazy danych za
każdym razem, gdy użytkownik zażąda tej strony. Działanie takie ma jednak sens jedynie wtedy, gdy po zmianie wartości w bazie
danych trzeba powtórnie wygenerować stronę.
Wydruk 16.1. Wykorzystanie buforowania do tworzenia statycznych stron HTML z PHP
<?php
ob_start();
include ( "db_mysql.php" );
class MySQLDBTest extends DB_Sql
{
var
var
var
var
$Host
$Database
$User
$Password
=
=
=
=
"localhost";
"mydb";
"root";
"root";
}
function GetGenOpts( $aTableName, $aCurSel = "" )
{
$aResult = "";
$aDB = new MySQLDBTest;
$aSQL = "select ID, Name from $aTableName order by Name";
$aDB->query( $aSQL );
while( $aDB->next_record() )
{
$aName
= $aDB->f( "Name" );
$aID
= $aDB->f( "ID" );
if ( $aID == $aCurSel )
{
$aResult .= "<option value=\"$aID\" selected>$aName</option>";
}
else
{
$aResult .= "<option value=\"$aID\">$aName</option>";
}
}
return $aResult;
}
?>
<html>
<head>
<title>Formularz wyboru krajów i stanów USA</title>
</head>
<body>
<form action="some_place.phtml" method="post">
<table>
<tr>
<td>
Wybierz stan USA:
</td>
<td>
<select name="us_state" size="1">
<?php
print( GetGenOpts( "us_states", "ID" ) );
?>
</select>
</td>
</tr>
<tr>
<td>
Wybierz kraj:
</td>
<td>
<select name="world_country" size="1">
<?php
print( GetGenOpts( "world_countries", "ZA" ) );
?>
</select>
</td>
</tr>
</form>
</body>
</html>
<?php
$aFileName = ereg_replace( 'phtml', 'html', $PATH_TRANSLATED );
$aFile = fopen( $aFileName, "w" );
fwrite( $aFile, ob_get_contents() );
fclose( $aFile );
ob_end_clean();
print( "Plik <i>$aFileName</i> utworzony<br>" );
?>
Pierwszą czynnością wykonywaną przez skrypt jest uaktywnienie buforowania przy pomocy wywołania funkcji ob_start(). Po
uaktywnieniu buforowania, dane nie są przesyłane do przeglądarki a tylko są zbierane w wewnętrznym buforze. Na końcu skryptu
generowana jest nowa nazwa pliku i zamieniane jest rozszerzenie pliku z phtml na html. Po utworzeniu pliku bufor jest czyszczony, a do
przeglądarki wysyłany jest komunikat informacyjny. Do nowego pliku można sięgnąć za pomocą przeglądarki zmieniając rozszerzenie
żądanego pliku z phtml na html.
Rozdział 16. Generowanie statycznych stron HTML w oparciu o dynamiczne dane
206
Metoda ta działa świetnie dla wielu typów stron. W praktyce skrypty generujące strony powinny być umieszczone w obszarze serwera
WWW chronionym hasłem i jedynie niektórzy użytkownicy powinni mieć do nich dostęp. Możliwe jest również stworzenie stron za
pomocą których można zarządzać danymi dynamicznymi i za pomocą takiego interfejsu WWW generować statyczne strony.
Użycie FastTemplate
W ostatnim rozdziale tematem przykładów był katalog produktów. Jest to kolejny przykład witryny, gdzie aktualne dane strony nie
zmieniają się zbyt często. Kategorie i produkty oferowane przez firmę mogą zmieniać się raz w miesiącu lub raz w tygodniu. Katalog
jednak może być przeglądany codziennie i zawsze musi zawierać aktualne dane. Klasa FastTemplate była używana w poprzednim
rozdziale do stworzenia witryny katalogu. W tym rozdziale zostaną omówione zmiany, jakie należy wprowadzić do skryptów tak, aby
była możliwość tworzenia stron statycznych.
Po pierwsze, musi zostać zdefiniowana struktura katalogu. Dla stron kategorii każda ze stron jest nazywana korzystając z szablonu
mgmt_cat_{$aCatID}.html. Na wydruku 16.2 znajduje się skrypt, który tworzy listę kategorii produktów dla wszystkich kategorii. Jest
on podobny do skryptu z wydruku 16.15. z rozdziału 15. „Witryny oparte o bazę danych”. W tym przypadku tworzy on listę wszystkich
kategorii i zapisuje kolejne strony do osobnych plików, według wspomnianego szablonu nazw.
Wydruk 16.2. Wykorzystanie klasy FastTemplate do tworzenia statycznych stron HTML z PHP
<?php
error_reporting( E_ALL & ~E_NOTICE );
session_start(); // Niejawnie ustawia zmienną sesji $aMerchantID
if ( empty( $aMerchantID ) == True )
{
print( "Błąd wewnętrzny. Brak identyfikatora sprzedawcy." );
exit;
}
include( "class.FastTemplate.php" );
include( "./mgmt_db.php" );
include( "./mgmt_funcs.php" );
$aTPL
= new
$aDB
= new
$aCatDB = new
$aTPL->define(
FastTemplate( "." );
mgmt_db();
mgmt_db();
array(
"base"
=> "mgmt_app_base.tpl",
"body"
=> "mgmt_body.tpl",
"footer"
=> "mgmt_footer.tpl",
"page_body" => "mgmt_prod_main.tpl",
"prod_item" => "mgmt_prod_item.tpl" ) );
$aSQL = "select category_id from mcCategories";
$aCatDB->query( $aSQL );
while( $aCatDB->next_record() )
{
$cat_id = $aCatDB->f( "category_id" );
//print( "$cat_id<br>" );
$aSQL = "select a.category_id, a.product_id, a.name, a.external_id, ";
$aSQL .= "a.price, a.ship_weight, a.has_image_file, a.descr, b.name as ";
$aSQL .= "cat_name from mcProducts a, mcCategories b where ";
$aSQL .= "(a.merchant_id = $aMerchantID) and (a.category_id = b.category_id)";
$aSQL .= "and ( a.category_id = $cat_id ) order by a.name";
$aDB->query( $aSQL );
if ( $aDB->num_rows() > 0 )
{
while ( $aDB->next_record() )
{
$aProdName
= $aDB->f( "name" );
$aProdEID
= $aDB->f( "external_id" );
$aProdPrice
= $aDB->f( "price" );
$aProdWeight
= $aDB->f( "ship_weight" );
$aHasImage
= $aDB->f( "has_image_file" );
$aProdDescr
= $aDB->f( "descr" );
$aCatName
= $aDB->f( "cat_name" );
$aCatID
= $aDB->f( "category_id" );
$aProdID
= $aDB->f( "product_id" );
$aImageFile = "images/default.jpg";
if ( $aHasImage == True )
{
$aImageFile = "images/{$aMerchID}_{$aCatID}_{$aProdID}.jpg";
}
$aTPL->assign( array( "PROD_NAME"
"CAT_NAME"
"PROD_EID"
"PROD_PRICE"
"PROD_DESCR"
"IMAGE_FILE"
207
=>
=>
=>
=>
=>
=>
$aProdName,
$aCatName,
$aProdEID,
'$' . number_format( $aProdPrice, 2 ),
$aProdDescr,
$aImageFile
PHP – Kompendium wiedzy
) );
$aTPL->parse( "ITEM_LIST", ".prod_item" );
}
}
else
{
$aTPL->assign( array(
}
"ITEM_LIST" =>
"Brak produktów dla kategorii <i>$aCatName</i>." ) );
$aTPL->assign( array(
"TITLE" => "Zarządzanie
katalogiem towarów: Kategoria $aCatName",
"MERCHANT_NAME" => GetMerchantName( $aDB, $aMerchantID )
) );
$aTPL->parse( "PAGE_BODY", "page_body" );
$aTPL->parse( "FOOTER", "footer" );
$aTPL->parse( "BODY", "body" );
$aTPL->parse( "PAGE", "base" );
$aFileName = "mgmt_cat_{$aCatID}.html";
$aFile = fopen( $aFileName, "w" );
fwrite( $aFile, $aTPL->fetch( "PAGE" ) );
fclose( $aFile );
print("Kategoria, <i>$aCatName</i>, zapisana do pliku: <b>$aFileName</b><br>");
$aTPL->Clear();
}
?>
W skrypcie tym zakładamy, że w zmiennej sesji przekazany został identyfikator sprzedawcy. Podczas wykonywania swoich zadań klasa
FastTemplate zapisuje całą zawartość strony w wewnętrznych buforach. Aby zapisać te dane w dowolnej zmiennej można skorzystać z
metody fetch(). W poprzednim przykładzie metoda fetch() jest wykorzystywana do pobrania wartości zmiennej FastTemplate
PAGE, która reprezentuje całą stronę HTML. Wartość ta jest zapisywana do pliku wyjściowego, a do przeglądarki wysyłany jest
komunikat potwierdzający prawidłowe wykonanie operacji. Metoda Clear() powoduje skasowanie wszystkich buforów i zmiennych
FastTemplate, co umożliwia wykonanie następnego przebiegu pętli.
W poprzednim rozdziale przytoczona została specyficzna funkcja, GetCategoryHREF(), która była używana w aplikacji zarządzającej
katalogiem. Jest ona zamieszczona ponownie na wydruku 16.3. Jest ona używana do tworzenia łącza do strony zadanej kategorii. W
trybie domyślnym zwraca ona adres strony dynamicznej, ale gdy znacznik $aDynamic zostanie ustawiony na False, zwróci adres
strony statycznej.
Wydruk 16.3. Funkcja GetCategoryHREF()
function GetCategoryHREF( $aCatID, $aDynamic = True )
{
if ( $aDynamic == True )
{
return "mgmt_prod_list.phtml?cat_id=$aCatID";
}
else
{
return "mgmt_cat_{$aCatID}.html";
}
}
Stosując tą metodę, w trakcie edycji danych można przeglądać strony dynamiczne a później generować zbiór stron statycznych.
Dla wielu typów witryn generowanie statycznych stron z danych dynamicznych jest stosunkowo praktyczne i powoduje wzrost
wydajności serwera. Jeżeli dane wykorzystywane w aplikacji nie zmieniają się zbyt często, powinno się rozważyć generowanie
statycznych stron. W przypadku mocno obciążonych witryn wzrost wydajności może z łatwością przeważyć dodatkowe komplikacje
związane z tworzeniem skryptów generujących strony. Do generowania stron w regularnych odstępach czasu można wykorzystać
odpowiednie oprogramowanie systemowe, na przykład cron.
Techniki buforowania
Generowanie stron statycznych jest efektywne w przypadku wielu rodzajów witryn, ale aby było efektywne, wymaga dokładnego
projektowania i programowania. W przypadku wielu aplikacji wystarczająca powinna być pośrednia technika buforowania stron.
Koncepcyjnie buforowanie jest bardzo podobne do generowania stron statycznych i nadal wymaga ingerencji w tekst każdego ze
skryptów. Gdy użytkownik wysyła żądanie pobrania skryptu, na początku sprawdzane jest czy istnieje aktualna strona w buforze. Jeżeli
tak, zawartość tej strony jest wysyłana do przeglądarki. Jeżeli nie ma tej strony, jest ona generowana, umieszczana w buforze do
wykorzystania przez kolejne wywołanie.
To czy strona jest aktualna, zależy od typu strony. Na przykład w witrynie może istnieć strona powitalna z bieżącą datą. Jeżeli na tej
stronie nie ma więcej elementów dynamicznych, musi być ona generowana raz w ciągu dnia i jest aktualna przez 24 godziny. Inną stroną
może być strona z wiadomościami uaktualnianymi co godzinę. W tym przypadku strona jest aktualna przez godzinę.
Rozdział 16. Generowanie statycznych stron HTML w oparciu o dynamiczne dane
208
Implementacja stron buforowanych jest bardzo prosta. Można do tego celu wykorzystać buforowanie wyjścia lub szablony. Na
wydrukach 4. i 5. zamieszczony jest przykład z zastosowaniem buforowania wyjścia. Na wydruku 16.4. znajdują się funkcje realizujące
buforowanie, więc mogą zostać łatwo dołączone do każdej strony. Wydruk 16.5. zawiera główną stronę, która wyświetla bieżące dane o
pogodzie wykorzystując skrypt o nazwie MWeather. Skrypt ten jest dostępny na stronie http://sourceforge.net/prjects/mweather/.
Wydruk 16.4. Funkcje buforujące (cache.php)
<?php
function GetCacheFileName( $aFileName )
{
return $aFileName . ".cache";
}
function DumpCacheFile( $aFileName, $aExpire = 3600 )
{
$aCacheFile = GetCacheFileName( $aFileName );
if ( is_file( $aCacheFile ) == True )
{
$aModTime = filemtime( $aCacheFile );
$aCurTime = time();
if ( ( $aCurTime - $aModTime ) > $aExpire )
{
return False;
}
else
{
readfile( $aCacheFile );
return True;
}
}
}
function SaveCacheFile( $aFileName, $aContents )
{
$aCacheFile = GetCacheFileName( $aFileName );
$aFile = fopen( $aCacheFile, "w" );
fwrite( $aFile, $aContents );
fclose( $aFile );
}
?>
Wydruk 16.5. Wykorzystanie funkcji buforujących
<?php
error_reporting( E_ALL & ~E_NOTICE );
include( "./cache.php" );
if ( $aResult = DumpCacheFile( $PATH_TRANSLATED, 60 * 60 ) )
{
// aktualny plik w buforze, koniec skryptu
exit;
}
ob_start();
// dane strony
$aOldIncludePath = ini_get( 'include_path' );
ini_set( 'include_path', $aOldIncludePath . ":./mweather" );
include( "mweather.php" );
ini_restore( 'include_path' );
SaveCacheFile( $PATH_TRANSLATED, ob_get_contents() );
?>
Skrypt z wydruku 16.5. korzysta z funkcji buforujących umieszczonych na wydruku 16.4. w celu
zrealizowania cogodzinnego buforowania strony z prognozą pogody. Funkcja DumpCacheFile() realizuje kilka
ważnych operacji. Po pierwsze, sprawdzana jest data ostatniej modyfikacji pliku w buforze i jest ona
porównywana z bieżącą datą. Jeżeli różnica pomiędzy tymi datami jest większa od wartości expire, funkcja
zwraca False. Jeżeli tak nie jest, funkcja odczytuje plik z bufora, wyświetla go i zwraca wartość True. Po
powrocie do skryptu sprawdzana jest zwracana wartość. Jeżeli jest ona True, główny skrypt się kończy, ponieważ
plik z bufora jest aktualny i został on już wysłany do przeglądarki. Jeżeli wartość ta wynosi False, skrypt jest
wykonywany i za pomocą funkcji buforowania wydruku jego wynik jest zapamiętywany. Na końcu skryptu
wywoływana jest funkcja SaveCacheFile(), która zapisuje zawartość strony.
W przykładzie tym strona jest generowana przez dołączany skrypt mweather.php. Jedynym zadaniem
głównego skryptu jest modyfikacja zmiennej PHP include_path. Jest to wymagane przez skrypt MWeather i nie
ma nic wspólnego z buforowaniem.
209
PHP – Kompendium wiedzy
Plik cache.php może być używany z dowolnym skryptem PHP, w którym należy zrealizować funkcje
buforowania na żądanie. Bardzo ważne jest jednak, aby zdawać sobie sprawę, jakie skrypty mogą działać z tym
typem buforowania. Metoda ta sprawdza się jedynie dla stron, które nie są wynikiem żądań HTTP GET lub POST.
Inaczej mówiąc, buforowanie jest niepraktyczne w przypadku stron zależnych od wartości wprowadzonych przez
użytkownika. Poprzedni przykład pokazuje pogodę w Rexburg w stanie Idaho, niezależnie kto ogląda stronę.
Jeżeli skrypt wyświetlałby pogodę w miejscu określonym przez użytkownika, buforowanie nie może być już
zastosowane. Wyobraźmy sobie, że strona została by umieszczona w buforze przez użytkownika z Londynu, a
kolejne wywołanie pochodziło by z Cape Town. Otrzymana strona była by oczywiście nieprawidłowa dla
użytkownika z Cape Town.
Przedstawiony typ buforowania jest użyteczny, ale nie może być używany dla wszystkich przypadków.
Jeżeli aplikacja zawiera strony z informacjami zmieniającymi się co określony odcinek czasu i niezależne od
danych użytkownika, ten typ buforowania jest bardzo użyteczny i wyraźnie poprawia wydajność witryny. W
przedstawionym przykładzie do pobrania danych o aktualnej pogodzie potrzebny jest czas około dwóch sekund.
Po zbuforowaniu, strona pojawia się natychmiast.
Podsumowanie
Mimo, że PHP jest najczęściej używany do dynamicznego tworzenia stron WWW, ważne jest, aby
odnaleźć sytuacje, gdy nie są potrzebne w pełni dynamiczne strony. Generując statyczne strony lub buforując je,
można wyraźnie poprawić wydajność witryny. Projektanci witryny powinni w ten sposób zrównoważyć szybkość
ładowania się statycznych stron z elastycznością stron dynamicznych, aby aplikacja miała dostateczną szybkość i
była użyteczna dla użytkowników.
Rozdział 16. Generowanie statycznych stron HTML w oparciu o dynamiczne dane
210
Rozdział 17. Witryny handlu
elektronicznego
Wstęp
Handel elektroniczny jest dla większości firm najważniejszym zadaniem, jakie ma spełniać firmowa
witryna WWW. Z tego powodu niezmiernie ważne jest poznanie sposobu zrealizowania za pomocą PHP
wszystkich aspektów tworzenia aplikacji handlu elektronicznego. Duża część tego rozdziału jest poświęcona
koncepcjom i założeniom projektowania tego typu aplikacji. Samo programowanie i korzystanie z istniejących
narzędzi przeznaczonych dla e-handlu jest trywialne. Prawdziwym wyzwaniem jest stworzenie bezpiecznej,
stabilnej i skalowalnej aplikacji handlu elektronicznego.
Bezpieczeństwo
Pierwszorzędną kwestią przy tworzeniu aplikacji przeznaczonych do handlu elektronicznego jest
zagadnienie bezpieczeństwa. Już w czasie projektowania aplikacji należy mieć na uwadze ochronę danych o
klientach. Należy wykonać kilka kroków w celu zapewnienia możliwie najwyższego poziomu bezpieczeństwa.
Nie należy tego traktować jako propozycji, są to zazwyczaj wymagania większości centrów rozliczających karty
kredytowe.
Zastosowanie SSL
Pierwszym krokiem powinno być wyodrębnienie fragmentów witryny, które wymagają zastosowania
bezpiecznego połączenia za pomocą mechanizmu secure socket layer (SSL). Większość aplikacji posiada dwa
obszary działania. Pierwszy jest obszarem zawierającym opisy dostępnych produktów i usług oferowanych na
witrynie. W części tej zawierają się zwykle strony zawierające dane o firmie, regulaminy i inne dane nie związane
bezpośrednio z handlem. Drugi fragment zawiera aplikację handlową. W części tej zbierane są prywatne dane,
takie jak dane niezbędne do identyfikacji klienta lub numery kart kredytowych. Większość tego rozdziału jest
poświęcona temu właśnie fragmentowi witryny.
Użycie PHP z SSL nie różni się niczym do używania PHP na serwerze nie obsługującym SSL. Istnieje
kilka
dostępnych
bezpiecznych
serwerów
WWW.
Jednym
z
nich
jest
Stronghold
(http://www.c2.net/products/sh3/). W dystrybucji RedHat (http://www.redhat.com/) istnieje również serwer
zawierający OpenSSL. Można go użyć do skompilowania bezpiecznego serwera Apache. Po zainstalowaniu
bezpiecznego serwera WWW opartego o Apache, można użyć jednej z metod opisanych w rozdziale 1.
„Kompilacja i instalowanie PHP” w celu dodania PHP w postaci współdzielonego modułu. Można również
przekompilować bezpieczny serwer Apache ze statycznie dołączonym modułem PHP.
Certyfikaty
Kolejnym krokiem wymaganym do stworzenia bezpiecznej aplikacji jest zainstalowanie certyfikatu
bezpieczeństwa. Certyfikat to plik na serwerze, który jest przesyłany do przeglądarki razem ze stronami WWW.
Certyfikaty są wystawiane przez kilka firm, które są rozpoznawane przez większość nowoczesnych przeglądarek
jako bezpieczne. Jedną z takich firm jest Thawte Consulting (http://www.thawte.com/). Witryna firmy Thawte
zawiera wszystkie dane niezbędne do wypróbowania i wykupienia certyfikatu bezpieczeństwa. Aby otrzymać
certyfikat należy dostarczyć kilka dokumentów:
1. Dokument potwierdzający istnienie firmy, na przykład akt założycielski spółki.
2. Dokument potwierdzający prawo do nazwy domeny.
Jeżeli nazwa widniejąca na dokumentach przedstawionych w punkcie 1. zgadza się z danymi uzyskanymi
przez zapytanie whois do domeny dla której instalowany jest certyfikat, nie trzeba dostarczać dokumentów
wymienionych w punkcie 2.
Z witryny firmy Thawte można pobrać i zainstalować certyfikat testowy. Jeżeli wykorzystujemy taki
certyfikat przeglądarka generuje ostrzeżenia, ale można przetestować aplikację bez konieczności kupienia
certyfikatu.
Jeżeli używanym serwerem jest Apache, aby zaczął on korzystać z certyfikatu należy zainstalować
certyfikat i zmodyfikować plik httpd.conf. Na wydruku 17.1. pokazana jest przykładowa konfiguracja wirtualnego
systemu hostingowego.
Wydruk 17.1. Plik httpd.conf z dyrektywami dotyczącymi certyfikatów
SSLCertificateFile /apache/conf/ssl.crt/server.crt
SSLCertificateKeyFile /apache/conf/ssl.key/server.key
NameVirtualHost 19.129.1.1:443
<VirtualHost 129.129.1.1:443>
SSLEnable
ServerAdmin [email protected]
DocumentRoot /home/server/secure
ServerName secure.server.com
DirectoryIndex index.phtml index.html
</VirtualHost>
Na witrynie firmy Thawte dostępne są wszystkie informacje potrzebne do wygenerowania i
zainstalowania certyfikatu. Jeżeli potrzebne jest więcej informacji na temat instalowania certyfikatu w
konkretnym serwerze WWW, należy ich szukać w dokumentacji serwera. Jeżeli korzystasz z dystrybucji RedHat,
to informacje te są bardzo jasno napisane i łatwe do odszukania.
Bezpieczeństwo bazy danych
Jednym z odkryć jakie zawdzięczamy ostatnio internetowym złodziejom numerów kart kredytowych jest
to, że we wielu przypadkach witryny przechowują dane w niezaszyfrowanej bazie danych dostępnej bezpośrednio
z Internetu. Nawet witryny używające kodowania SSL do zbierania danych, przechowują dane prywatne w mało
bezpieczny sposób. Ostatnio jednak, niektóre umowy pomiędzy sprzedawcami a centrami rozliczeniowymi
zawierają klauzulę o przechowywaniu danych w postaci zaszyfrowanej, umieszczeniu bazy danych za firewallem,
albo o zastosowaniu obu tych rozwiązań. Zaczyna być to powszechnie stosowaną praktyką. Aplikacja powinna
kodować zarówno transmisję jak również przechowywane dane prywatne.
Wiele nowoczesnych systemów baz danych zawiera funkcje szyfrujące dane. Na przykład SZBD MySQL
zawiera funkcje ENCODE() oraz DECODE() jako integralną część języka. Funkcje te nie są jednak wystarczająco
dobre do szyfrowania krytycznych danych. Użycie tych lub podobnych funkcji poprawia jednak poziom ochrony
przechowywanych danych. Ostatecznie to ty i twoja firma jesteście odpowiedzialni za dziury w systemie
bezpieczeństwa, które spowodują ujawnienie krytycznych danych.
Przetwarzanie płatności
Po skompilowaniu i przetestowaniu bezpiecznego serwera WWW należy wybrać metodę obsługi
płatności. PHP zawiera własne interfejsy do kilku systemów przetwarzania płatności, np.: CyberCash, VeriSign i
CCVS. Na rysunku 17.1. przedstawiony został obieg informacji pomiędzy użytkownikiem, bezpiecznym
serwerem WWW i narzędziami obsługi płatności.
Rozdział 17. Witryny handlu elektronicznego
212
Rysunek 17.1.
Zależności w
aplikacji handlu
elektronicznego
Na rysunku 17.1. zostały pokazane cztery podstawowe jednostki biorące udział w obsłudze płatności:
użytkownik, serwer, system przetwarzania i instytucja finansowa. Klient i serwer komunikują się ze sobą za
pomocą protokołu SSL, który zapewnia dwukierunkową szyfrowaną transmisję. Serwer komunikuje się z
systemem obsługi płatności za pomocą protokołu narzuconego przez system. Sam system przetwarzania
komunikuje się z instytucją finansową w celu sprawdzenia czy może przyjąć płatność za pomocą karty
kredytowej (lub innej metody płatności). Jeżeli korzystamy z systemu CCVS możliwe jest ominięcie systemu
przetwarzania i bezpośrednia komunikacja z finansowym centrum rozliczeniowym.
Jednym z powodów wyboru systemu obsługi płatności CyberCash jest to, że protokół komunikacyjny
używany do przesyłania informacji pomiędzy serwerem a systemem obsługi transakcji, jest wbudowany w
interfejs programistyczny do CyberCash. Inne systemy transakcji wymagają użycia przez aplikację bezpiecznych
gniazd, w celu zrealizowania komunikacji z nimi. Należy pamiętać, że mimo użycia bezpiecznego serwera
wykorzystującego protokół SSL, sam PHP nie posiada implementacji SSL. Inaczej mówiąc, jeżeli skrypt otworzy
port, to nie zostanie automatycznie użyty protokół SSL, pomimo że serwer WWW używa SSL. Dopóki PHP nie
będzie posiadał bezpośredniej obsługi gniazd SSL, wykorzystanie niektórych możliwości systemów
transakcyjnych nie będzie możliwe. CyberCash używa do zapewnienia bezpiecznej transmisji pomiędzy
serwerem WWW a centrum przetwarzania, własnego algorytmu Triple DES (potrójny DES). W pozostałej części
rozdziału będziemy wykorzystywać CyberCash jako system przetwarzania płatności.
CyberCash (http://www.cybercash.com/) jest firmą oferującą interfejsy programistyczne (API) dla C i C++
oraz Javy. Wersja API dla C i C++ może zostać wbudowana w PHP za pomocą opcji konfiguracji --withcybercash. Najpierw należy ściągnąć z witryny CyberCash pakiet Merchant Connection Kit (MCK). Oprócz tego
należy upewnić się, że twoje konto sprzedawcy może być używane w systemie CyberCash. Jeżeli nie masz
jeszcze konta sprzedawcy, należy je zarejestrować u jednego z partnerów firmy CyberCash. Proces ten wymaga
podania wielu szczegółowych informacji finansowych, ale może być przeprowadzony w ciągu 24 godzin. Główne
kroki wymagane do zainstalowania MCK są następujące:
1. Nawiązanie współpracy z przedstawicielem finansowym firmy CyberCash (konto sprzedawcy).
2. Zarejestrowanie się na witrynie http://amps.cybercash.com/ jako sprzedawca CyberCash.
3. Ściągnięcie MCK.
4. Dekompresja i zainstalowanie MCK.
5. Kompilacja PHP z obsługą CyberCash (--with-cybercash).
Na witrynie WWW firmy CyberCash znajduje się dokładny opis instalacji MCK. Pakiet ten może być
zainstalowany na systemach Unix lub pod Windows. Procedura instalacji dla systemów Unix jest bardzo prosta.
Podstawowe kroki są następujące:
1. Dekompresja instalatora: uncompress install-mck-3.2.0.6-<system_operacyjny>.Z.
213
PHP – Kompendium wiedzy
2. Zmiana uprawnień do pliku instalatora w taki sposób, aby można było go uruchomić: chmod +x installmck-3.2.0.6-<system_operacyjny>.
3. Uruchomienie programu instalacyjnego: ./install-mck-3.2.0.6-<system_operacyjny>.
4. Uruchomienie programu konfiguracyjnego: ./configure.
W punktach 3. i 4. zostaną zadane pytania na temat firmy, sklepu sieciowego i innych informacji tego
typu. Po wykonaniu tych kroków można przekompilować PHP podając opcję konfiguracji --withcybercash=/ścieżka/do/MCK. Należy podać pełną ścieżkę do katalogu gdzie został zainstalowany MCK. Po
utworzeniu PHP z obsługą CyberCash można przeprowadzić testowe transakcje.
Jedną z miłych cech użycie MCK wraz z PHP jest możliwość opuszczenia większości opcji konfiguracji
(jak sugeruje to podręcznik). Użycie PHP do komunikacji z CyberCash jest bardzo proste i wymaga jedynie
dołączenia jednego skryptu. Skrypt pokazujacy sposób użycia CyberCash znajduje się w dystrybucji PHP
zawierającej pełny kod źródłowy w katalogu <php>/ext/cybercash. Na wydruku 17.2. zamieszczony jest ten
właśnie skrypt testowy.
Wydruk 17.2. Test.php (skrypt testowy CyberCash)
<?php
require "cyberlib.php";
$merchant=""; /* Tutaj należy umieścić idnetyfikator sprzedawcy. */
$merchant_key=""; /* Tutaj należy umieścić klucz sprzedawcy. */
$payment_url="http://cr.cybercash.com/cgi-bin/";
$auth_type="mauthonly";
$response=SendCC2_1Server($merchant,$merchant_key,$payment_url,
$auth_type,array("Order-ID" => "2342322",
"Amount" => "usd 11.50",
"Card-Number" => "4111111111111111",
"Card-Address" => "1600 Pennsylvania Avenue",
"Card-City" => "Washington",
"Card-State" => "DC",
"Card-Zip" => "20500",
"Card-Country" => "USA",
"Card-Exp" => "12/99",
"Card-Name" => "Bill Clinton"));
while(list($key,$val)=each($response))
{
echo $key."=".$val."<br>";
}
?>
Jak widać przetwarzanie płatności przy pomocy PHP i CyberCash jest bardzo proste. Zmienne $merchant
oraz $merchant_key muszą zawierać identyfikator sprzedawcy oraz jego klucz nadany przez CyberCash.
Następnie po ustawieniu w tablicy asocjacyjnej danych wymaganych przez CyberCash płatność jest
przekazywana do obsługi przy pomocy wywołania funkcji SendCC2_1Server() zdefiniowanej w dołączonym pliku
cyberlib.php. Nie potrzeba nawet wywoływać żadnej z funkcji cybercash_xxx() dostępnych w PHP. Funkcja
SendCC2_1Server() hermetyzuje w sobie wszystkie niezbędne funkcje, jak również obsługuje komunikację za
pomocą gniazd z serwerem CyberCash.
Dane niezbędne do działania z Cyberash są przekazywane za pomocą tablicy asocjacyjnej będącej
ostatnim parametrem funkcji SendCC2_1Server(). Zawartość tej tablicy jest określana przez wartość zmiennej
$auth_type. Zmienna ta określa rodzaj wykonywanej operacji lub typ komunikatu przesyłanego do CyberCash.
Komunikaty obsługiwane przez CyberCash zawarte są w tablicy 17.1.
Tabela 17.1. Komunikaty dostępne w CyberCash oraz zadania przez nie realizowane
Komunikat
Realizowane zadanie
batch-commit
Potwierdza transakcje zebrane w grupę.
batch-prep
Powoduje wysłanie transakcji oznaczonych jako
gotowe do przetworzenia w postaci grupy.
batch-query
Pytanie o grupę.
batch-retry
Ponawia próbę przetworzenia oczekującej grupy.
batch-unroll
Zapytanie o transakcję wysłaną w postaci grupy.
card-query
Odczytuje dane karty kredytowej dla podanego
zamówienia.
checkauth
Sprawdza
i
autoryzuje
płatność
czekiem
Rozdział 17. Witryny handlu elektronicznego
214
checkreturn
mauthcapture
mauthonly
postauth
query
retry
return
void
merchant-checkpayment
check-query
check-update-status
check-query-orderstatus
zainicjowaną przez sprzedawcę. Komunikat ten jest
obsługiwany jedynie przez procesor Paymentech
(wykorzystując opcję Electronic Check Payment — ECP).
Zwraca pieniądze na konto czekowe klienta.
Autoryzuje i przechwytuje rozpoczętą przez
sprzedawcę transakcję za pomocą karty kredytowej. Jest
używany
jedynie
dla
głównych
procesorów
przechwytujących.
Autoryzuje rozpoczętą przez sprzedawcę sprzedaż za
pomocą karty kredytowej. Jest używany dla końcowych
procesorów przechwytujących.
Przechwytuje
płatność
kartą
kredytową
autoryzowaną za pomocą mauthonly lub checkauth.
Odpytuje bazę transakcji.
Ponawia oczekującą transakcję dla podanego
zamówienia.
Zwraca pieniądze na kartę kredytową klienta.
Unieważnia transakcję.
Sprawdza i autoryzuje zainicjowaną przez
sprzedawcę płatność w systemie PayNow.
Odszukuje w bazie danych PayNow danych na temat
określonych rachunków.
Uaktualnia serwer rachunków za pomocą zmian
przeprowadzonych w bramce.
Sprawdza bieżący status zamówień.
Dokumentacja CyberCash zawiera dokładny opis każdego z komunikatów oraz jego przeznaczenia. W
większości przypadków pierwszym obsługiwanym komunikatem (i często jedynym) jest komunikat mauthonly.
Jest on używany do autoryzacji płatności dokonywanej kartą kredytową. W zależności od rodzaju sprzedawanego
produktu lub usługi, można tak skonfigurować CyberCash, aby automatycznie zaznaczał i realizował wszystkie
poprawnie autoryzowane transakcje.
W tabeli 17.2. zebrane są wszystkie pola używane do obsługi komunikatu mauthonly. W tabeli zaznaczone
są wszystkie pola, które należy obowiązkowo umieścić w komunikacie.
Tabela 17.2. Pola komunikatu mauthonly i ich opis
Pole
Opis
Wy
magane
order
Unikalny identyfikator transakcji.
id
amount
cardnumber
cardexp
cardname
cardaddress
cardcity
215
Kwota do autoryzacji (to znaczy kwota płatności) w tej
transakcji. Należy używać notacji waluta złote.grosze (na
przykład: usd 12.50).
Numer karty kredytowej obciążanej tą transakcją.
Data ważności karty kredytowej obciążanej tą
transakcją. Należy użyć formatu mm/rr (na przykład: 02/01 dla
lutego 2001).
Nazwa właściciela karty kredytowej.
Adres zamieszkania właściciela karty kredytowej.
UWAGA: pole jest wymagane w przypadku kart AVS i
Discover.
Miejscowość w której mieszka właściciel karty.
UWAGA: pole jest wymagane w przypadku kart AVS i
Discover.
PHP – Kompendium wiedzy
cardzip
cardstate
cardcountry
Kod pocztowy miejscowości, w której mieszka
właściciel karty. Prawidłowymi zapisami są „22091”, „201911448,”, „NW3 5RJ” i „113 192”. UWAGA: pole jest
wymagane w przypadku kart AVS i Discover.
Stan w którym mieszka właściciel karty. UWAGA:
pole jest wymagane w przypadku kart AVS i Discover.
Kraj w którym mieszka właściciel karty.
Funkcja SendCC2_1Server() zwraca wartości również w postaci tablicy asocjacyjnej, która zawiera dane
na temat transakcji przesłane przez CyberCash. W tabeli 17.3. znajdują się pola znajdujące się w odpowiedzi na
komunikat mauthonly.
Tabela 17.3. Pola odpowiedzi na komunikat mauthonly i ich opis
Pole
Opis
MStatus
Zwracany kod statusu wykonanej operacji Pole to zawsze istnieje.
Może przyjmować jedną z następujących wartości:
• success — transakcja udana.
• success-duplicate — wynik poprzedniej udanej transakcji.
• partial success — grupa zawiera nieudane transakcje.
• failure-hard — nieudana transakcja, jej powtórzenie nie uda się.
• failure-q-or-cancel, failure-q-or-discard — nieudane transakcje
z powodu problemów z transmisją, mogą być powtórzone.
• failure-swversion — transakcja nieudana z powodu użycia starego
lub nieistniejącego (nieistniejący numer wersji) oprogramowania.
• failure-bad-money — transakcja nieudana z powodu problemu z
obciążeniem przez instytucję finansową.
MErrLoc
Miejsce wystąpienia błędu w transakcji. Pole to pojawia się jedynie w
przypadku nieudanej transakcji (czyli MStatus jest różny od success).
Zwracane są następujące wartości:
• smps — wystąpił błąd w CashRegister.
• ccsp — wystąpił błąd w bramce.
• financial institution — błąd wystąpił w instytucji finansowej
• CCMckDirectLib3_2 — błąd wystąpił w MCK
MErrMsg
Tekst komunikatu błędu zwracanego przez transakcję. Pole to
występuje jedynie w przypadku nieudanej transakcji.
MErrCod
Numer błędu odpowiadający komunikat błędu przekazanego w
e
MErrMsg.
merchNumer używany przez bramkę do identyfikacji przeprowadzanej
txn
transakcji. Pole to występuje zawsze.
orderIdentyfikator zamówienia do którego należy przetwarzana transakcja.
id
Pole to występuje zawsze.
custNumer transakcji używany przez portfel CyberCash do identyfikacji
txn
transakcji. Dla transakcji nie posiadających portfela jest on taki sam jak
merch-txn.
aux-msg
Komunikat bramki sprzedawcy zawierający dodatkowy opis z bramki
lub serwera płatności.
MSWErrM
Komunikat błędu przy użyciu nieaktualnej wersji portfela lub serwera
sg
płatności. Pole to nie zawsze występuje.
addnlDodatkowe dane transakcji zwracane przez bramkę. UWAGA: Jeżeli
response-data
brak jest takich danych pole to jest puste.
Na wydruku 17.3. znajduje się przykład użycia CyberCash, pochodzący z działającej witryny. Przykład
ten zawiera obsługę błędów oraz wysyła informacje zwrotne do klienta. Elementy te nie były zawarte w
przykładowym skrypcie z wydruku 17.2.
Rozdział 17. Witryny handlu elektronicznego
216
Wydruk 17.3. Użycie CyberCash
<?php
include "cyberlib.php"; // Funkcje obsługi CyberCash
include "dbclass.php"; // Klasa bazy danych dla tej aplikacji
include "class.FastTemplate.php"; // FastTemplate
// funkcja zamieniająca tablicę asocjacyjną
// w jeden ciąg rozdzielany średnikami
function ArrayCrunch( $aArray )
{
$aResult = "";
foreach( $aArray as $aKey => $aValue )
{
$aResult .= "$aKey=$aValue;";
}
return $aResult;
}
$tpl = new FastTemplate( "." );
// pobranie identyfikatora pliku z zaszyfrowanego pola formularza
$aCustomerID
= UnhideID( $ID );
$merchant
$merchant_key
$payment_url
$auth_type
=
=
=
=
""; /* tutaj identyfikator sprzedawcy. */
""; /* tutaj klucz sprzedawcy. */
"http://cr.cybercash.com/cgi-bin/";
"mauthonly";
$aDB = new dbAccess;
$aDB->Init();
// kontrola czy klient ten nie zapłacił wcześniej
$aSQL = "select ISPAID from orders where ( ID = $aCustomerID )";
$aDB->SetSQL( $aSQL );
if ( $aDB->RecordCount() == 1 )
{
$aRow
= $aDB->GetData( 0 );
$aIsPaid
= $aRow["ISPAID"];
}
else
{
$aIsPaid
= 0;
}
// Jeżeli klient już zapłacił, pokaż informację i zakończ skrypt
if ( $aIsPaid == 1 )
{
mail( "[email protected]", "Ponowna próba płatności ($aCustomerID)",
"Czy chcesz jeszcze raz zapłacić??", "From: [email protected]\r\n" );
$tpl->define( array( base
footer
body
) );
=> "a_base.tpl",
=> "c_footer.tpl",
=> "s_paid_already.tpl"
$tpl->assign( array( TITLE
URL
THEDATE
ORDERID
HIDDENID
) );
=>
=>
=>
=>
=>
"Płatność Intechra.Net",
$aInternalURL,
date( "l, j F Y" ),
$aOrderID,
$ID
AddSiteVars( $tpl, $aHiddenID );
$tpl->parse( FOOTER, "footer" );
$tpl->parse( BODY, "body" );
$tpl->parse( PAGE, "base" );
$tpl->FastPrint( PAGE );
exit;
}
// pobierz nowy MCK_ID dla tego klienta
$aSQL = "select MAX( MCK_ID ) as MAX_ID from customers_to_mcks
where ( ID = $aCustomerID )";
$aDB->SetSQL( $aSQL );
if ( $aDB->RecordCount() == 1 )
{
$aRow
= $aDB->GetData( 1 );
217
PHP – Kompendium wiedzy
$aMaxID
}
else
{
$aMaxID
}
$aCurID
$aOrderID
= $aRow["MAX_ID"];
= 0;
= $aMaxID + 1;
= "INT-" . date( "Ymd" ) . "-" . sprintf( "%06d", $aFamilyID ) .
"-" . sprintf( "%04d", $aCurID );
$aOrderDetails = array( "Order-ID"
"Amount"
"Card-Number"
"Card-Address"
"Card-City"
"Card-State"
"Card-Zip"
"Card-Exp"
"Card-Name"
=>
=>
=>
=>
=>
=>
=>
=>
=>
$aOrderID,
"usd 39.00",
$CCNum,
$CCAddr,
$CCCity,
$CCState,
$CCZip,
$CCExpDate,
$CCName );
$response = SendCC2_1Server( $merchant, $merchant_key, $payment_url,
$auth_type, $aOrderDetails );
$aRawRequest = ArrayCrunch( $aOrderDetails );
$aRawResponse = ArrayCrunch( $response );
$aSQL = "insert into customers_to_mcks
values ( $aCustomerID, $aCurID, 0, NOW(), ENCODE( \"$aRawRequest\",
\"good_password\" ), ENCODE( \"$aRawResponse\",
\"good_password\" ) )";
$aDB->SetSQL( $aSQL );
if ( $response["MStatus"] == "success" )
{
mail( "[email protected]",
"Płatność dla Intechra.net zrealizowana ($aCustomerID)",
"Płatność zakończona sukcesem", "From: [email protected]\r\n" );
$aSQL = "update orders set ISPAID = 1 where ( ID = $aCustomerID )";
$aDB->SetSQL( $aSQL );
$tpl->define( array(
base
footer
body
) );
=> "a_base.tpl",
=> "c_footer.tpl",
=> "s_paid_ok.tpl"
$tpl->assign( array(
TITLE
URL
THEDATE
ORDERID
HIDDENID
) );
=>
=>
=>
=>
=>
"Płatności Intechra.net",
$aInternalURL,
date( "l, j F Y" ),
$aOrderID,
$ID
AddSiteVars( $tpl, $aHiddenID );
$tpl->parse( FOOTER, "footer" );
$tpl->parse( BODY, "body" );
$tpl->parse( PAGE, "base" );
$tpl->FastPrint( PAGE );
}
else
{
mail( "[email protected]",
"Płatność dla Intechra.net nieudana ($ ($aCustomerID)",
"Płatność nieudana", "From: [email protected]\r\n" );
$tpl->define( array(
base
footer
body
) );
=> "a_base.tpl",
=> "c_footer.tpl",
=> "s_paid_fail.tpl"
$tpl->assign( array(
TITLE
HIDDENID
) );
=> "Płatności Intechra.net",
=> $ID
$tpl->parse( FOOTER, "footer" );
$tpl->parse( BODY, "body" );
$tpl->parse( PAGE, "base" );
$tpl->FastPrint( PAGE );
Rozdział 17. Witryny handlu elektronicznego
218
}
?>
Skrypt z wydruku 17.2. pokazuje w jaki sposób na podstawie skryptu z wydruku 17.1. można stworzyć
prawdziwy system obsługi płatności. Skrypt ten jest używany do przetwarzania danych formularza, w którym
użytkownik podaje dane karty kredytowej. Na początku skrypt pobiera identyfikator klienta z pola formularza.
Następnie inicjuje zmienne CyberCash, w tym ustawiając typ komunikatu na mauthonly. Następnie w bazie
danych sprawdzane jest, czy użytkownik nie zapłacił już wcześniej. W tej aplikacji każdy użytkownik dokonuje
jednej płatności za usługę. Jeżeli użytkownik już zapłacił skrypt wysyła do administratora pocztę zawierającą
komunikat informujący o tym fakcie, oraz wyświetla stronę informującą użytkownika, że dokonał już wcześniej
płatności. Na tym skrypt się kończy.
Jeżeli płatność nie była jeszcze dokonana, z bazy danych pobierany jest nowy niepowtarzalny
identyfikator. Dokumentacja CyberCash nakazuje, aby identyfikator ten był co najwyżej 25 znakowy i musi być
unikalny. Można używać w nim liter, liczb, kropek, daszków i podkreśleń. Skrypt ten generuje identyfikatory w
postaci RRRRMMDD-CCCCCC-OOOO, gdzie YYYYMMDD jest bieżącą datą, CCCCCC to identyfikator klienta a OOOO jest
identyfikatorem pobieranym z bazy danych.
W tablicy $aOrderDetails umieszczane są dane płatności i wywoływana jest funkcja SendCC2_3Server().
Żądanie i odpowiedź są zapisywane do bazy danych w postaci zaszyfrowanej. Następnie sprawdzany jest status
odpowiedzi. Jeżeli transakcja zakończyła się powodzeniem, wyświetlany jest komunikat o prawidłowym
przetworzeniu transakcji i uaktualniane są dane klienta na temat płatności. Jeżeli operacja się nie powiedzie,
klient jest o tym informowany. W każdym z przypadków do administratora wysyłany jest informujący e-mail.
Przeglądając ten przykład można stwierdzić, że użycie API CyberCash w PHP jest proste, ale stworzenie
bezpiecznej i stabilnej aplikacji handlu elektronicznego wymaga sporej ilości przemyśleń i planowania. Po
systemie obsługującym prawdziwe pieniądze klienci oczekują najlepszej jakości usług. Jeżeli aplikacja pozwoli
na przypadkowe wielokrotne płatności lub nie dostarczy odpowiednich informacji, klienci nie będą zadowoleni.
Należy poświęcić nieco czasu na przestudiowanie dokumentacji procesora transakcji. Dostępne jest mnóstwo
informacji i ty jesteś odpowiedzialny za ich zrozumienie i właściwą implementację.
Dostarczanie produktów
Innym aspektem aplikacji handlu elektronicznego, który wymaga planowania jest kwestia dostarczania
towarów do klientów. Jeżeli twój towar musi być wysłany do klienta, wymagane jest kilku dodatkowych kroków
oprócz wymienionych poprzednio. Powodem jest to, że wielu wystawców kart kredytowych żąda, aby karta była
obciążana dopiero po dostarczeniu towaru do klienta. Można żądać autoryzacji przed dostarczeniem towaru, ale
obciążenie nie będzie zrealizowane do czasu dostarczenia towaru. Ważne jest również podawanie rzeczywistego
kosztu przesyłki.
Jeżeli wysyłasz towary, aplikacja przetwarzania płatności staje się o wiele bardziej skomplikowana od
pokazanej w tym rozdziale. Jednak wiele wymaganych czynności może być zrealizowane za pomocą PHP.
Zalecanym scenariuszem jest stworzenie osobnej aplikacji zapisującej stan przesyłek i po dostarczeniu przesyłki
kończona jest płatność kartą i do klienta wysyłany jest komunikat.
Dostępne jest kilka możliwości śledzenia na bieżąco przesyłek i kosztów. Zarówno UPS
(http://www.ups.com/) jak i Federal Express (http://www.fedex.com/) dostarczają narzędzia do integracji modułu
przesyłek we własnej aplikacji WWW. Narzędzia UPS są bardzo elastyczne i wydajne i łatwo mogą być
umieszczone w aplikacji PHP korzystając z niewielkiej ilości kodu. Niestety nie otrzymałem pozwolenia na
dokumentację żadnego z tych systemów przed zakończeniem tego rozdziału. Jeżeli otrzymam pozwolenie,
umieszczę odpowiednie informacje na witrynie WWW wymienionej w zasobach sieci w dodatkach. Można
jedynie powiedzieć, że wykorzystując narzędzia sieciowe UPS można skorzystać z mechanizmów obliczających
dokładne koszta przesyłek da dowolnych miejsc na ziemi przy użyciu dowolnego poziomu usługi. Dane są
pobierane z witryny UPS — aplikacja odpytuje ich serwery pobierając dane prawidłowe w momencie sprzedaży.
219
PHP – Kompendium wiedzy
Podsumowanie
Tworzenie aplikacji handlu elektronicznego nie jest zbytnim wyzwaniem patrząc jedynie od strony kodu.
Wyzwaniem staje się stworzenie aplikacji, która jest jednocześnie bezpieczna i prosta w użyciu, oraz integruje w
sobie wszystkie niezbędne technologie. Tworząc aplikacje handlowe należy poświęcić nieco czasu na poznanie
wszystkich komponentów oraz na gruntowne testowanie systemu. Należy również szyfrować przechowywane
dane oraz całą transmisję pomiędzy klientem i serwerem realizować za pomocą SSL.
Rozdział 17. Witryny handlu elektronicznego
220
Dodatek A. Funkcje
function_exists
Szuka w liście zdefiniowanych funkcji nazwy przekazanej w
znaleziono podaną nazwę funkcji, w przeciwnym wypadku zwraca False.
$function_name.
Zwraca
True,
jeżeli
int function_exists( string nazwa_funkcji )
func_get_arg
Zwraca argument numer $arg_num z listy argumentów funkcji. Argumenty są numerowane od 0.
Func_get_arg() generuje ostrzeżenie jeżeli jest wywołana poza funkcją. Jeżeli wartość $arg_num jest większa niż
ilość przekazanych argumentów, generowane jest ostrzeżenie a funkcja func_get_arg() zwraca False.
mixed func_get_arg( int arg_num )
<?php
function foo()
{
$numargs = func_num_args();
echo "Ilość argumentów: $numargs<br>\n";
if ($numargs >= 2)
echo "Drugi argument: " . func_get_arg(1) . "<br>\n";
}
foo (1, 2, 3);
?>
Funkcja func_get_arg() może być używana wraz z func_num_args() i
funkcji ze zmienna liczbą argumentów. Funkcja została dodana w PHP 4.
func_get_args()
do zrealizowania
func_get_args
Zwraca tablicę, w której każdy element zawiera odpowiedni argument z listy argumentów funkcji. Funkcja
generuje ostrzeżenie w wypadku wywołania jej spoza definicji funkcji.
func_get_args()
array func_get_args( void )
<?php
function foo()
{
$numargs = func_num_args();
echo "Ilość argumentów: $numargs<br>\n";
if ($numargs >= 2)
echo "Drugi argument: " . func_get_arg(1) . "<br>\n";
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++)
echo "Argument $i = " . $arg_list[$i] . "<br>\n";
}
foo (1, 2, 3);
?>
Funkcja func_get_args() może być używana wraz z func_num_args() i
funkcji ze zmienna liczbą argumentów. Funkcja została dodana w PHP 4.
func_get_arg()
do zrealizowania
func_num_args
Zwraca liczbę argumentów przekazanych do bieżącej funkcji. Funkcja
ostrzeżenie w przypadku wywołania jej z poza funkcji.
int func_num_args( void )
func_num_args()
generuje
<?php
function foo()
{
$numargs = func_num_args();
echo "Ilość argumentów: $numargs<br>\n";
}
foo (1, 2, 3);
?>
Funkcja func_num_args() może być używana wraz z func_get_args() i
funkcji ze zmienna liczbą argumentów. Funkcja została dodana w PHP 4.
func_get_arg()
do zrealizowania
fwrite
Zapisuje zawartość $string do pliku wskazywanym przez $fp. Jeżeli podany został argument $length,
zapisywanie jest przerywane po zapisaniu $length bajtów lub całej zawartości $string. Jeżeli podany został
argument $length, ignorowana jest opcja konfiguracji magic_quotes_runtime i z $string nie będą usuwane
ukośniki. Patrz również fread(), fopen(), fsockopen(), popen() i fputs().
int fwrite( int fp, string [, int length])
getallheaders
Zwraca tablicę asocjacyjną z wszystkimi nagłówkami HTTP wysłanymi wraz z bieżącym żądaniem.
Wskazówka
Można również odczytać wartości zmiennych współdzielonych CGI ze środowiska. Można to zrealizować gdy PHP pracuje jako moduł
Apache lub jako CGI. Aby odczytać wszystkie zmienne środowiska zdefiniowane w ten sposób należy użyć funkcji phpinfo().
array geallheaders( void )
Przykład: getallheaders()
$headers = getallheaders();
while (list ($header, $value) = each($headers))
{
echo "$header: $value<br>\n";
}
Przykład ten wyświetla wszystkie nagłówki bieżącego żądania HTTP. Funkcja
jedynie, gdy PHP pracuje jako moduł Apache.
getallheaders()
działa
getcwd
Zwraca bieżący katalog.
string getcwd( void )
getdate
Zwraca tablicę asocjacyjną zawierającą informacje o dacie odczytane na podstawie parametru $timestamp.
Tablica zawiera następujące elementy:
• seconds — sekundy
• minutes — minuty
• hours — godziny
• mday — dzień miesiąca
• wday — dzień tygodnia jako numer
• mon — miesiąc jako numer
• year — rok jako numer
• yday — dzień w roku jako numer, na przykład 299
• weekday — dzień tygodnia jako tekst, na przykład Friday
• month — miesiąc jako tekst, na przykład January
Dodatek A - Funkcje
222
array getdate( int timetamp )
getenv
Zwraca wartość zmiennej środowiska o nazwie $varname, lub w przypadku wystąpienia błędu False.
string getenv( string varname )
$ip = getenv( "REMOTE_ADDR" ); // odczytuje numer IP użytkownika
Listę zmiennych środowiska można uzyskać za pomocą funkcji phpinfo(). Znaczenie wielu z nich opisane
jest w specyfikacji CGI (http://hoohoo.ncsa.uiuc.edu/cgi/) na stronie poświęconej zmiennym środowiska
(http://hoohoo.ncsa.uiuc.edu/cgi/env.html).
Uwaga
Funkcja ta nie działa w trybie ISAPI.
gethostbyaddr
Zwraca nazwę komputera o adresie przekazanym w argumencie
błędu funkcja zwraca $ip_address. Patrz również: gethostbyname().
$ip_address.
W przypadku wystąpienia
string gethostbyaddr( string ip_address )
gethostbyname
Zwraca adres IP komputera o nazwie przekazanej w $hostname. Patrz również: gethostbyaddr().
string gethostbyname( string hostname )
gethostbynamel
Zwraca listę adresów IP skojarzonych z nazwą
oraz man named(8).
$hostname.
Patrz również:
gethostbyname(),
gethostbyaddr(), checkdnserr(), getmxrr()
string gethostbynamel( string hostname )
GetImageSize
Odczytuje wielkość rysunku GIF, JPG, PNG lub SWF i zwraca wymiary, typ pliku oraz ciąg tekstu z
szerokością i wysokością w postaci fragmentu znacznika IMG. Funkcja zwraca tablicę z 4 elementami. Pod
indeksem 0 znajduje się szerokość rysunku w pikselach, pod indeksem 1 znajduje się wysokość rysunku. Indeks 2
zawiera znacznik określający typ rysunku, 1 = GIF, 2 = JPG, 3 = PNG, 4 = SWF. Pod indeksem 3 znajduje się
ciąg zawierający tekst height=xxx width=xxx, który może być użyty bezpośrednio w znaczniku IMG.
array GetImageSize( string filename [, array imgeinfo])
Przykład: GetImageSize()
<?php $size = GetImageSize ("img/flag.jpg"); ?>
<IMG SRC="img/flag.jpg" <?php echo $size[3]; ?>
Opcjonalny parametr $imageinfo pozwala na odczytanie dodatkowych danych z pliku rysunku. W chwili
obecnej zwracane są różne znaczniki APP pliku JPG w postaci tablicy asocjacyjnej. Niektóre programy
wykorzystują znaczniki APP do umieszczenia w rysunku informacji tekstowej. Częstym zastosowaniem jest
umieszczanie danych IPTC http://www.xe.net/iptc/ w znaczniku APP13. Do zamiany binarnego znacznika APP13
na postać czytelną dla człowieka można użyć funkcji iptcparse().
Przykład: GetImageSize() zwracający IPTC
<?php
$size = GetImageSize ("testimg.jpg", &$info);
if (isset(($info["APP13"]))
{
$iptc = iptcparse( $info["APP13"]);
var_dump( $iptc);
}
?>
Uwaga
223
PHP – Kompendium wiedzy
Funkcja ta nie wymaga biblioteki GD
getlastmod
Zwraca czas ostatniej zmiany bieżącej strony. Zwracana wartość jest znacznikiem czasu Uniksa. W
przypadku błędu zwraca False.
int getlastmod( void )
Przykład: getlastmod()
<?php
// zwraca ciąg w postaci 'Ostatnia modyfikacja: March 04 1998 20:43:59.'
echo "Ostatnia modyfikacja: ". date ("F d Y H:i:s.", getlastmod());
?>
Patrz również: date(), getmyuid(), get_current_user(), getmyinode() oraz getmypid().
getmxrr
Szuka w DNS rekordu MX skojarzonego z $hostname. Zwraca True, jeżeli znalezione zostały jakieś
rekordy, w przypadku wystąpienia błędu lub braku rekordów zwracana jest wartość False. Lista znalezionych
rekordów MX jest umieszczana w tablicy $mxhosts. Jeżeli zostanie podana tablica $weight, zostanie wypełniona
wagami odnalezionych rekordów. Patrz również: checkdnsrr(), gethostbyname(), gethostbynamel(),
gethostbyaddr() oraz man named(8).
int getxrr( string hostname, array mxhosts [, array weight])
getmyinode
Zwraca bieżący inode pliku ze skryptem lub False w przypadku wystąpienia błędu. Patrz również:
getmyuid(), get_current_user(), getmypid() i getlastmod().
Uwaga
Funkcja ta nie działa w Windows
int getmyinode( void )
getmypid
Zwraca identyfikator procesu PHP lub False w przypadku wystąpienia błędu.
Uwaga
Jeżeli PHP działa jako moduł serwera, w kolejnych wywołaniach skryptu nie jest gwarantowane, że identyfikatory procesów będą
różne. Patrz również: getmyuid(), get_current_user(), getmyinode() oraz getlastmod().
int getmypid( void )
getmyuid
Zwraca identyfikator użytkownika uruchamiającego bieżący skrypt, lub False w przypadku wystąpienia
błędu. Patrz również: getmypid(), get_current_user(), getmyinode() oraz getlastmod().
int getmyuid( void )
getprotobyname
Zwraca numer protokołu skojarzonego z protokołem
getprotobynumber().
$name
według pliku /etc/protocols. Patrz również:
int getprotobyname( string name )
Dodatek A - Funkcje
224
getprotobynumber
Zwraca nazwę protokołu skojarzonego z protokołem
getprotobyname().
$number
według pliku /etc/protocols. Patrz również:
int getprotobynumber( string name )
getrandmax
Zwraca maksymalną wartość, jaka może być zwrócona przez funkcję
oraz mt_getrandmax().
rand().
Patrz również:
rand(),
srand(), mt_rand(), mt_srand()
int getrandmax( void )
getrusage
Jest to interfejs do getrusage(2). Zwraca tablicę asocjacyjną zawierającą dane zwrócone przez wywołanie
systemowe. Jeżeli $who jest równe 1, getrusage zostanie wywołane z RUSAGE_CHILDREN.
array getrusage( [int who] )
Przykład: getrusage()
$dat
echo
echo
echo
echo
= getrusage();
$dat["ru_nswap"];
$dat["ru_majflt"];
$dat["ru_utime.tv_sec"];
$dat["ru_utime.tv_usec"];
#
#
#
#
Więcej szczegółów na temat
getrusage(2).
ilość
ilość
użyty
użyty
stronicowań
błędów strony
czas użytkownika (sekundy)
czas użytkownika (mikrosekundy)
getrusage
można znaleźć w podręczniku systemowym pod hasłem
getservbyname
Zwraca numer portu używanego przez usługę $service dla protokołu $protocol, według definicji w
/etc/services. $protocol może być TCP lub UDP. Patrz również: getservbyport().
int getservbyname( string service, string protocol)
gettext
Funkcja szuka tłumaczenia ciągu w jednej z tablic tłumaczeń. Zwraca przetłumaczony ciąg lub oryginalny
ciąg, jeżeli tłumaczenie nie zostanie znalezione. Jako Znaków zastępczych można używać podkreślenia.
string gettext( string message )
Przykład: gettext()
<?php
// Ustaw język na niemiecki
putenv( "LANG=de");
// Określ połozenie tablic tłumaczeń
bindtextdomain( "myPHPApp", "./locale");
// wybierz domenę
textdomain( "myPHPApp");
// wypisz komunikat testowy
print (gettext( "Welcome to My PHP Application"));
?>
gettimeofday
Jest to interfejs do gettimeofday(2). Zwraca tablicę asocjacyjną zawierającą dane zwracane przez
wywołanie systemowe.
• sec — sekundy
• usec — mikrosekundy
• minuteswest — przesunięcie w minutach na zachód od Greenwich
• dsttime — typ poprawki dst
array gettimeofday( void )
225
PHP – Kompendium wiedzy
gettype
Zwraca typ zmiennej PHP $var. Możliwe zwracane wartości zamieszczone są poniżej:
boolean
array
unknown type
integer
object
double
resource
string
user function
string gettype( mixed var )
Patrz również: settype().
get_browser
Odczytuje możliwości przeglądarki użytkownika. Jest to realizowane przez odszukanie danych na temat
przeglądarki w pliku browscap.ini. Domyślnie używana jest wartość zmiennej $HTTP_USER_AGENT, ale można
przekazać dowolną dowolny parametr $user_agent (na przykład, aby odczytać możliwości innej przeglądarki).
Zwracany jest obiekt zawierający dane opisujące, na przykład numer wersji, identyfikator, wartości True lub
False dla takich własności jak, obsługa ramek, JavaScript, cookie itd. Mimo, że plik browscap.ini zawiera dane o
wielu przeglądarkach, to jednak użytkownik musi dbać o jego aktualność. Format pliku jest bardzo prosty.
Poniższy przykład pokazuje przykładowe dane zwracane dla przeglądarki użytkownika.
object get_browser( [string user_agent])
Przykład: get_browser()
<?php
function list_array ($array)
{
while (list ($key, $value) = each($array))
$str .= "<b>$key:</b> $value<br>\n";
return $str;
}
echo "$HTTP_USER_AGENT<hr>\n";
$browser = get_browser();
echo list_array( (array) $browser);
?>
Wynik działania tego skryptu może wyglądać następująco
Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)<hr>
<b>browser_name_pattern:</b> Mozilla/4\.0 (compatible; MSIE 5\.5; Windows NT 5\.0)<br>
<b>parent:</b> IE 5.0<br>
<b>version:</b> 5.5<br>
<b>minorver:</b> 5<br>
<b>platform:</b> Win2000<br>
<b>beta:</b> <br>
<b>browser:</b> IE<br>
<b>majorver:</b> 5<br>
<b>frames:</b> 1<br>
<b>tables:</b> 1<br>
<b>cookies:</b> 1<br>
<b>backgroundsounds:</b> 1<br>
<b>vbscript:</b> 1<br>
<b>javascript:</b> 1<br>
<b>javaapplets:</b> 1<br>
<b>activexcontrols:</b> 1<br>
<b>win16:</b> <br>
<b>ak:</b> <br>
<b>sk:</b> <br>
<b>aol:</b> <br>
<b>crawler:</b> <br>
<b>msn:</b> <br>
<b>cdf:</b> 1<br>
<b>dhtml:</b> 1<br>
<b>xml:</b> 1<br>
Aby skrypt ten mógł działać należy tak ustawić zmienną konfiguracji browscap, aby wskazywała na
katalog z plikiem browscap.ini. Więcej informacji (w tym adresy skąd można ściągnąć plik browscap.ini) można
znaleźć w FAQ do PHP pod adresem http://www.php.net/FAQ.php.
get_cfg_var
Zwraca wartość zmiennej konfiguracji PHP określonej przez $varname, lub False w przypadku
wystąpienia błędu. Funkcja ta nie zwraca danych konfiguracji ustawionych przy kompilacji PHP lub poprzez pliki
konfiguracyjne Apache (przy użyciu dyrektywy php3_configuration_option). Aby sprawdzić, czy system
Dodatek A - Funkcje
226
korzysta z pliku konfiguracji, należy spróbować odczytać wartość zmiennej konfiguracji
jest to możliwe, oznacza to, że jest używany plik konfiguracji.
cfg_file_path.
Jeżeli
string get_cfg_var( string varname )
get_class
Zwraca nazwę klasy przekazanego obiektu $obj. Patrz również: get_parent_class(), is_subclass_of().
string get_class( object obj )
get_class_methods
Zwraca tablicę z nazwami metod zdefiniowanych w klasie określonej przez
get_class_vars(), get_object_vars().
$class_name.
Patrz również:
array get_class_methods( string class_name )
get_class_vars
Zwraca tablicę z nazwami właściwości zdefiniowanych w klasie określonej przez
również: get_class_methods(), get_object_vars().
$class_name.
Patrz
array get_class_vars( string class_name )
get_current_user
Zwraca nazwę właściciela bieżącego skryptu PHP. Patrz również
oraz getlastmod().
getmyuid(), getmypid(), getmyinode()
string get_current_user( void )
get_declared_classes
Zwraca tablicę nazw klas zadeklarowanych w bieżącym skrypcie. W PHP 4.0.1pl2 na początku tablicy
zwracane były trzy dodatkowe klasy: stdClass (zdefiniowana w Zend/zend.c), OverloadedTestClass
(zdefiniowana w ext/standard/basic_functions.h) oraz Directory (zdefiniowana w ext/standard/dir.c).
array get_declared_classes( void )
get_extension_funcs
Zwraca nazwy wszystkich funkcji zdefiniowanych w module $module_name.
array get_extension_funcs( string module_name )
Przykład: get_extension_funcs()
print_r (get_extension_funcs( "xml"));
print_r (get_extension_funcs( "gd"));
Wykonanie tych linii spowoduje wypisanie listy funkcji umieszczonych w modułach xml i gd. Patrz
również: get_loaded_extensions().
get_html_translation_table
Zwraca tablicę translacji używaną wewnętrznie w funkcjach htmlspecialchars() i htmlentities().
Możliwe jest określenie potrzebnej w danym momencie tabeli (HTML_ENTITIES i HTML_SPECIALCHARS). Tak samo
jak w przypadku funkcji htmlspecialchars() i htmlentities() można opcjonalnie określić rodzaj ukośników
$quote_style. Domyślnym ustawieniem jest tryb ENT_COMPAT. Opis trybów znajduje się w opisie funkcji
htmlspecialchars().
string get_html_translation_table( int table [, int quote_style])
Przykład: Tablica translacji
$trans = get_html_translation_table( HTML_ENTITIES );
$str = "To firma & <PRO> & spółka";
$encoded = strtr( $str, $trans);
227
PHP – Kompendium wiedzy
Zmienna $encoded zawiera teraz ciąg To firma &amp; &lt;PRO&gt; &amp; sp&oacute;&sup3;ka.
Ciekawym zastosowaniem jest użycie funkcji array_flip() w celu zmiany kierunku translacji.
$trans = array_flip( $trans );
$original = strtr ($str, $trans);
Teraz w zmiennej $original będzie znajdował się ciąg: To firma & <PRO> & spółka.
Uwaga
Funkcja ta została dodana w PHP 4.0
Patrz również htmlspecialchars(), htmlentities(), strtr() i array_flip().
get_included_files
Funkcja zwraca tablicę asocjacyjną z nazwami wszystkich plików dołączonych do skryptu za pomocą
funkcji include_once(). Indeksami tej tablicy są nazwy plików użytych w include_once() bez rozszerzenia .php.
W PHP 4.0.1pl2 funkcja zakładała, że pliki dołączane poprzez include_once() mają rozszerzenia .php i inne
rozszerzenia nie działają. Patrz również: require_once(), include_once(), get_required_files().
array get_included_files( void )
get_loaded_extesions
Zwraca nazwy wszystkich modułów wkompilowanych i załadowanych przez interpreter PHP.
array get_loaded_extensions( void )
Przykład get_loaded_extensions()
print_r (get_loaded_extensions());
Spowoduje to wypisanie listy podobnej do następującej:
Array
(
[0] => standard
[1] => bcmath
[2] => Calendar
[3] => com
[4] => variant
[5] => ftp
[6] => mysql
[7] => odbc
[8] => pcre
[9] => session
[10] => xml
[11] => wddx
[12] => apache
)
Patrz również: get_extension_funcs().
get_magic_quotes_gpc
Zwraca stan ustawienia magic_quotes_gpc (0 — wyłaczone, 1 — włączone). Patrz również:
get_magic_quotes_runtime(), set_magic_quotes_runtime().
long get_magic_quotes_gpc( void )
get_magic_quotes_runtime
Zwraca stan ustawienia magic_quotes_runtime (0 — wyłaczone, 1 — włączone). Patrz również:
get_magic_quotes_gpc(), set_magic_quotes_runtime().
long get_magic_quotes_runtime( void )
get_meta_tags
Otwiera plik $filename i analizuje go szukając znaczników meta.
array get_meta_tags( string filename [, int use_include_path])
Przykład: Znaczniki <META>
Dodatek A - Funkcje
228
<meta name="author" content="name">
<meta name="tags" content="php3 documentation">
</head> <!-- tutaj zatzymuje się analiza -->
Uwaga
Uwaga na końce linii — PHP wykorzystuje własną funkcję analizującą plik wejściowy, więc pliki z MacIntosha mogą nie działać na
Uniksie.
Nazwa właściwości staje się kluczem, natomiast zawartość umieszczana jest w tablicy jako wartość
elementu. Dzięki temu można wykorzystać standardowe funkcje przeglądające tablice. Znaki specjalne są
zastępowane znakiem podkreślenia, natomiast pozostały tekst jest konwertowany do małych liter. Ustawienie
use_include_path na 1 spowoduje, że PHP będzie próbował otworzyć plik znajdujący się na standardowej ścieżce
dołączania.
get_object_vars
Zwraca tablicę asocjacyjną właściwości zdefiniowanych w obiekcie określonym przez $obj. Jeżeli
zmienna zdefiniowana w klasie nie ma przypisanej wartości, nie znajdzie się ona w tablicy asocjacyjnej.
array get_object_vars( object obj)
Przykład: użycie get_object_vars()
<?php
class Point2D
{
var $x, $y;
var $label;
function Point2D( $x, $y)
{
$this->x = $x;
$this->y = $y;
}
function setLabel( $label)
{
$this->label = $label;
}
function getPoint()
{
return array( "x" => $this->x,
"y" => $this->y,
"label" => $this->label);
}
}
$p1 = new Point2D( 1.233, 3.445);
print_r(get_object_vars($p1));
// Właściwość $Label jest zdefiniowana, ale nie zainicjowana
// Array
// (
//
[x] => 1.233
//
[y] => 3.445
// )
$p1->setLabel("point #1");
print_r(get_object_vars($p1));
// Array
// (
//
[x] => 1.233
//
[y] => 3.445
//
[label] => point #1
// )
?>
Patrz również: get_class_methods(), get_class_vars().
get_parent_class
Zwraca nazwę klasy bazowej dla klasy, której instancją jest obiekt
is_subclass_of().
$obj.
Patrz również:
get_class(),
string get_parent_class( object obj )
229
PHP – Kompendium wiedzy
get_required_files
Zwraca tablicę asocjacyjną z nazwami wszystkich plików załadowanych do skryptu poprzez funkcję
require_once().
array get_required_files( void )
Przykład: Wypisywanie plików dołączanych za pomocą require i include.
<?php
require_once( "local.php" );
require_once( "../inc/global.php" );
for ($i=1; $i<5; $i++)
include "util". $i . ".php";
echo "Pliki dołączane przez require_once\n";
print_r (get_required_files());
echo "Pliki dołączane przez include_once\n";
print_r (get_included_files());
?>
Wykonanie tego skryptu spowoduje wygenerowanie następnego wyniku:
Pliki dołączane przez require_once
Array
(
[0] => C:\helion\php4-devguide\site\doda\local.php
[1] => C:\helion\php4-devguide\site\inc\global.php
[2] => C:\helion\php4-devguide\site\doda\util1.php
[3] => C:\helion\php4-devguide\site\doda\util2.php
[4] => C:\helion\php4-devguide\site\doda\util3.php
[5] => C:\helion\php4-devguide\site\doda\util4.php
)
Pliki dołączane przez include_once
Array
(
[0] => C:\helion\php4-devguide\site\doda\local.php
[1] => C:\helion\php4-devguide\site\inc\global.php
[2] => C:\helion\php4-devguide\site\doda\util1.php
[3] => C:\helion\php4-devguide\site\doda\util2.php
[4] => C:\helion\php4-devguide\site\doda\util3.php
[5] => C:\helion\php4-devguide\site\doda\util4.php
)
Uwaga
W PHP 4.0.1pl2 funkcja zakładała, że pliki dołączane poprzez include_once() mają rozszerzenia .php i inne rozszerzenia nie
działają.
Patrz również: require_once(), include_once(), get_included_files().
gmdate
Funkcja ta jest identyczna z date(), poza tym, że zwracany czas jest czasem Greenwich (GMT). Jeżeli
przykłąd zostanie uruchomiony w Polsce (GMT +0100), pierwsza linia przykładu zwróci Jan 01 1998 00:00:00,
natomiast druga Dec 31 1997 23:00:00.
string gmdate( string format, int timestamp )
Przykład: gmdate()
echo date("M d Y H:i:s", mktime( 0,0,0,1,1,1998));
echo gmdate("M d Y H:i:s", mktime( 0,0,0,1,1,1998));
Patrz również: date(), mktime() i gmmktime().
gmmktime
Funkcja identyczna jak mktime(), poza tym, że przekazane parametry reprezentują czas GMT.
int gmmktime( int hour, int minute, int second, int month,
int day, int year [, int is_dst])
gmstrftime
Zachowuje się tak samo jako jak funkcja strftime(), ale zwracany czas jest czasem GMT. Na przykład,
jeżeli będzie użyta w strefie czasowej GMT -0500, pierwsze wywołanie z przykładu wypisze ciąg Dec 31 1998
20:00:00, natomiast drugie: Jan 01 1999 01:00:00.
Dodatek A - Funkcje
230
string gmstrftime( string format, int timestamp )
Przykład: gmstrftime()
setlocale( 'LC_TIME', 'en_US');
echo strftime("%b %d %Y %H:%M:$S", mktime( 20,0,0,12,31,98));
echo gmstrftime("%b %d %Y %H:%M:$S", mktime( 20,0,0,12,31,98));
Patrz również: strftime().
GregorianToJD
Prawidłowy zakres dat kalendarza gregoriańskiego to 4714 p.n.e. do 9999 n.e. Chociaż można stosować
tak szeroki zakres dat, nie ma to jednak sensu. Kalendarz gregoriański został ustanowiony 15 października 1582
roku (lub 5 października 1582 roku według kalendarza juliańskiego). Niektóre kraje jeszcze długo nie
wprowadziły tego kaledarza. Na przykład Anglia przyjęła go w 1752 roku, Rosja w 1918 a Grecja w 1923 roku.
Większość krajów europejskich przed kalendarzem gregoriańskim używała kalendarza juliańskiego.
int GregorianToJD( int month, int day, int year)
Przykład: Funkcje kalendarza
<?php
$jd = GregorianToJD( 10, 11, 1970);
echo "$jd\n";
$gregorian = JDToGregorian( $jd );
echo "$gregorian\n";
?>
gzclose
Funkcja zamyka plik gz wskazywany przez $zp. W przypadku powodzenia zwraca True, a w przypadku
błędu, False. Wskaźnik pliku gz musi być prawidłowym wskaźnikiem wskazującym na plik otwarty przez funkcję
gzopen().
int gzclose( int zp )
gzcompress
Zwraca dane wejściowe przekazane w $data skompresowane gzipem, lub False w przypadku wystąpienia
błędu. Opcjonalny parametr $level może przyjmować wartości od 0 dla braku kompresji, do 9 dla maksymalnej
kompresji. Patrz również: gzuncompress().
string gzcompress( string data [, int level])
gzeof
Zwraca True, jeżeli wskaźnik pliku gz znajduje się na końcu pliku lub wystąpił błąd. W przeciwnym
przypadku zwraca False. Wskaźnik pliku gz musi być prawidłowym wskaźnikiem wskazującym na plik otwarty
przez funkcję gzopen().
int gzeof( int zp )
gzfile
Funkcja identyczna z readgzfile(), poza tym, że gzfile() zwraca zawartość pliku w tablicy. Można
ustawić parametr opcjonalny na 1, co spowoduje szukanie pliku również na ścieżce ustawionej w include_path.
Patrz również: readgzfile(), gzopen().
array gzfile( string filename [, int use_include_path])
gzgetc
Zwraca ciąg zawierający jeden znak (nieskompresowany) odczytany z pliku na który wskazuje $zp.
Zwraca False na końcu pliku (tak samo jak gzeof()).Wskaźnik pliku gz musi być prawidłowym wskaźnikiem
wskazującym na plik otwarty przez funkcję gzopen(). Patrz również: gzopen() i gzgets().
string gzgetc( int zp )
231
PHP – Kompendium wiedzy
gzgets
Zwraca ciąg znaków (nieskompresowany) o maksymalnej długości $length-1 odczytany z pliku na który
wskazuje $zp. Czytanie kończy się po odczytaniu $length-1 znaków, znaku nowej linii lub znaku EOF. Zwraca
False w przypadku wystąpienia błędu. Wskaźnik pliku gz musi być prawidłowym wskaźnikiem
wskazującym na plik otwarty przez funkcję gzopen(). Patrz również: gzopen(), gzgetc() i fgets().
string gzgets( int zp, int length )
gzgetss
Funkcja identyczna jak gzgets(), ale dodatkowo gzgetss() usiłuje usunąć znaczniki HTML i PHP z
odczytanego tekstu. Można użyć opcjonalnego trzeciego parametru w celu określenia znaczników, które mają
pozostać w tekście. Parametr $allowable_tags został dodany w PHP 3.0.13, PHP4B3. Patrz również: gzgets(),
gzopen() i strip_tags().
string gzgetss( int zp, int length [, string allowable_tags])
gzopen
Otwiera plik gzip (.gz) do odczytu lub zapisu. Parametr $mode jest taki jak w fopen() ("rb" lub "wb"), ale
może zawierać również poziom kompresji ("wb9") lub strategię: f dla filtrowania danych, na przykład "wb6f", h
dla kompresji tylko metodą Huffmana, np.: "wb1h". Więcej informacji na temat filtrowania znajduje się w opisie
deflateIni2 w pliku zlib.h. Można również wykorzystać gzopen() do odczytania danych, które nie są w formacie
gzip. W takim przypadku gzread() odczytuje plik bez jego dekompresji. Funkcja gzopen() zwraca wskaźnik do
otwartego pliku. Po tej operacji wszystkie dane odczytywane z tego pliku są dekompresowane, natomiast dane
zapisywane do pliku są kompresowane. Jeżeli otwarcie pliku nie uda się, funkcja zwraca False. Można użyć
opcjonalnego trzeciego argumentu i ustawić go na 1 w celu włączenia poszukiwania pliku do otwarcia na ścieżce
include_path.
int gzopen( string filename, string mode [, int use_include_path])
Przykład gzopen()
$fp = gzopen( "/tmp/file.gz", "r" );
Patrz również: gzclose().
gzpassthru
Odczytuje plik wskazywany przez wskaźnik do pliku gz, aż do znaku EOF, a jego (nieskompresowaną)
zawartość kieruje na wyjście. Jeżeli wystąpi błąd zwraca False. Wskaźnik pliku gz musi być prawidłowym
wskaźnikiem wskazującym na plik otwarty przez funkcję gzopen(). Po zakończeniu odczytu pliku jest on
zamykany.
int gzpassthru( int zp )
gzputs
Identyczna jak funkcja gzwrite().
int gzputs( int zp, string str [, int length])
gzread
Odczytuje maksymalnie $length bajtów z pliku gz wskazywanego przez $zp. Odczyt zostaje przerwany,
gdy zostanie odczytane $length znaków (nieskompresowanych), lub napotkany zostanie koniec pliku.
string gzread( int zp, int length )
Przykład: gzread()
// odzytanie zawartości pliku gz do ciągu
$filename = "/usr/local/somth.txt.gz";
$zd = gzopen( $filename, "r");
$contents = gzread( $dz, 10000 );
Patrz również: gzwrite(), gzopen(), gzgets(), gzgetss(), gzfile(), gzpassthru().
Dodatek A - Funkcje
232
gzrewind
Ustawia znacznik pozycji na początku pliku. Jeżeli wystąpi błąd, funkcja zwraca 0. Wskaźnik pliku gz
musi być prawidłowym wskaźnikiem wskazującym na plik otwarty przez funkcję gzopen(). Patrz również
gzseek(), gztell().
int gzrewind( int zp )
gzseek
Ustawia znacznik pozycji pliku wskazywanego przez $zp na pozycję określoną przez $offset. Jest to
odpowiednik wywołania (w C) gzseek( zp, offset, SEEK_SET). Jeżeli plik jest otwarty do odczytu, funkcja jest
wykonywana, ale może być to niezwykle powolne. Jeżeli plik jest otwarty do zapisu, obsługiwane jest jedynie
przesunięcie w przód; gzseek() kompresuje wtedy sekwencję zer aż do nowej pozycji. W przypadku powodzenia
operacji zwraca 0, w przeciwnym wypadku zwraca -1.
Uwaga
Przesunięcie poza znacznik EOF nie jest traktowane jako błąd.
Patrz również gztell() i gzrewind().
int gzseek( int zp, int offset )
gztell
Zwraca pozycje znacznika pozycji dla pliku wskazywanego przez $zp, to znaczy przesunięcie od początku
pliku. Jeżeli wystąpi błąd, funkcja zwraca False. Wskaźnik pliku gz musi być prawidłowym wskaźnikiem
wskazującym na plik otwarty przez funkcję gzopen(). Patrz również: gzopen(), gzseek() i gzrewind().
int gztell( int zp )
gzuncompress
Na podstawie danych $data, skompresowanych za pomocą funkcji gzcompress() zwraca oryginalne
nieskompresowane dane. W przypadku błędu zwraca False. Funkcja zakończy się niepowodzeniem, jeżeli
rozmiar rozkompresowanych danych przekracza 256 krotność wielkości danych wejściowych $data, lub jest
większy od opcjonalnego parametru $length. Patrz również gzcompress().
string gzuncompress( string data [, int length])
gzwrite
Zapisuje zawartość $string do pliku gz wskazywanego przez $zp. Jeżeli podano argument $length, zapis
jest przerywany po zapisaniu $length bajtów (nieskompresowanych), lub po osiągnięciu końca danych
wejściowych.
Uwaga
Jeżeli podany został argument $length, ignorowany jest parametr konfiguracji magic_quotes_runtime i z ciągu $string nie
będą usunięte ukośniki.
Patrz również: gzread(), gzopen() i gzputs().
header
Funkcja używana na początku pliku HTML do wysłania surowych nagłówków HTTP. Więcej informacji
na
temat
surowych
nagłówków
można
znaleźć
w
specyfikacji
protokołu
HTTP
1.1
(http://www.w3.org/Protocols/rfc2616/rfc2616).
Uwaga
233
PHP – Kompendium wiedzy
Należy pamiętać, że funkcja header() musi być wywołana przed wysłaniem danych HTML, niezależnie czy poprzez normalny kod
HTML czy poprzez PHP. Bardzo często spotykanym błędem jest umieszczanie wolnych linii przed wywołaniem funkcji header().
Istnieją dwa nagłówki specjalnego przeznaczenia. Pierwszy to nagłówek Location. Oprócz odesłania tego
nagłówka do przeglądarki zwraca on do Apache kod statusu REDIRECT. Dla programistów skryptów może nie być
to zbyt ważne, ale ważne jest dla programistów zainteresowanych działaniem serwera Apache.
int header( string string )
Przykład: header()
header("Location: http://www.php.net"); /* przekierowuje rzeglądarkę do witryny PHP */
exit;
/* należy się upewnić, że kod poniżej nie
zostanie wykonany. */
Drugim nagłówkiem specjalnego przeznaczenia jest nagłówek rozpoczynający się ciągiem HTTP/
(wielkość znaków bez znaczenia). Na przykład jeżeli skonfigurowana zostanie dyrektywa Apache ErrorDocument
404, tak aby wskazywała na skrypt PHP, dobrze jest się upewnić, że skrypt PHP generuje błąd 404. W tym celu
należy wysłać nastepujący nagłówek:
header("HTTP/1.0 404 Not Found");
Skrypty PHP często generują dynamiczny kod HTML, który nie powinien być buforowany w
przeglądarkach i serwerach proxy. Można zablokować wiele serwerów proxy za pomocą nagłówków:
header("Expires: Mon, 26 ul 1997 05:00:00 GMT");
header("LastModified: " .. gmdate("D, d M y H:i:s");
header("Cache-Control: no-cache, must-revalidate");
header("Pragme: no-cache");
//Data w przeszłości
// Czas GMT
// zawsze zmodyfikowane HTTP/1.1
// HTTP/1.0
Patrz również: headers_sent().
headers_sent
Zwraca True, jeżeli wysłane zostały nagłówki HTTP, w przeciwnym przypadku zwraca
również: header().
False.
Patrz
boolean headers_sent( void )
hebrev
Opcjonalny parametr $max_chas_per_line wskazuje na maksymalną ilość znaków w linii danych
wyjściowych. Funkcja próbuje uniknąć łamania wyrazów. Patrz również: hebrevc().
string hebrev(string hebrew_text [, int max_chars_per_line])
hebrevc
Funkcja podobna do hebrev() z tą różnicą, że konwertuje znaki nowej linii (\n) na <br>\n. Opcjonalny
parametr $max_chars_per_line wskazuje maksymalną ilość znaków w wyniku. Funkcja próbuje uniknąć łamania
wyrazów. Patrz również: hebrev().
string hebrevc( string hebrev_text [, int max_chars_per_line])
hexdec
Zwraca dziesiętny odpowiednik liczby szesnastkowej przekazanej w parametrze $hex_string. Funkcja
konwertuje ciąg szesnastkowy na liczbę dziesiętną. Największą liczbą, jaka może być skonwertowana
jest 7fffffff lub 2147483647 dziesiętnie. Patrz również: dechex().
hexdec()
int hexdec( string hex_string )
highlight_file
Wynikiem działania funkcji jest wersja pliku PHP, o nazwie $filename, z wyróżnioną składnią. Używane
kolory są zdefiniowane w wewnętrznym module wyróżniania składni.
void highlight_file( string filename )
Przykład: Tworzenie łączy do plików z wyróżnioną składnią
Aby utworzyć łącze umożliwiające wyróżnienie składni dowolnego pliku, skorzystamy z dyrektywy
Apache ForceType. Pozwala to na stworzenie eleganckiego adresu URL, natomiast użycie funkcji
Dodatek A - Funkcje
234
highlight_file()
pozwala na pokazanie ładnie wyglądającego kodu. W pliku httpd.conf należy dodać
następujące linie:
<Location /source>
ForceType application/x-httpd-php
</Location>
Następnie należy utworzyć plik o nazwie source i umieścić go w głównym katalogu serwera WWW:
<HTML>
<HEAD>
<TITLE>Wyświetlanie źródła</TITLE>
</HEAD>
<BODY COLOR BGCOLOR="white">
<?php
$script = getenv( "PATH_TRANSLATED");
if (!$script)
{
echo "<BR><B>BŁĄD: wymagana nazwa skryptu</B><BR>";
}
else
{
if ereg("(\.php|\.inc)$", $script))
{
echo "<H1>Źródło skryptu: $PATH_INFO</H1>\n<hr>\n";
highlight_file( $script );
}
else
echo "<H1>BŁĄD: Dopuszczalne sa jedynie rozszerzenia php i inc</H1>";
}
echo "Przetworzony: " . date( "Y/M/d H:i:s", time());
</BODY>
</HTML>
?>
Teraz można użyć adresów podobnych do przytoczonego poniżej, aby wyświetlić kolorową wersję skryptu
/sciezka/do/skryptu.php.
http://serwer.com/source/sciezka/do/skryptu.php
Patrz również: highlight_string() i show_source().
highlight_string
Wysyła na wyjście pokolorowaną wersję ciągu $str. Używane kolory są zdefiniowane w wewnętrznym
module PHP. Patrz również: highlight_file() i show_source().
void highlight_string( string str )
htmlentities
Funkcja jest identyczna z htmlspecialchars(), ale wszystkie znaki posiadające odpowiadające im symbole
HTML są zamieniane na te symbole. Tak jak w przypadku funkcji htmlspecialchars() można użyć opcjonalnego
argumentu wskazującego na sposób traktowania cudzysłowów i apostrofów. Wartość ENT_COMPAT (domyślna)
konwertuje jedynie cudzysłowy, pozostawiając bez zmian apostrofy. ENT_QUOTES powoduje konwersję zarówno
cudzysłowów jak i apostrofów. ENT_NOQUOTES powoduje, że zarówno cudzysłowy jak i apostrofy pozostają
niezmienione. W chwili obecnej używany jest zestaw znaków ISO-8859-1. Należy pamiętać, że argument
opcjonalny został dodany w PHP 3.0.17 i PHP 4.0.3. Patrz również: htmlspecialchars() i nl2br().
string htmlentities( string string [, int quote_style])
htmlspecialchars
Niektóre znaki mają specjalne znaczenie w HTML i powinny być reprezentowane przez symbole HTML.
Funkcja ta zwraca ciąg z zastosowanymi niektórymi z tych konwersji. Są to najczęściej używane konwersje przy
programowaniu dla WWW. Jeżeli wymagana jest kompletna konwersja, należy użyć funkcji htmlentities().
Funkcja ta jest użyteczna do usuwania znaczników HTML z tekstu wprowadzonego przez użytkownika, na
przykład w księdze gości lub na tablicy ogłoszeniowej. Argument opcjonalny, $quote_style wskazuje sposób
konwersji apostrofów i cudzysłowów. Domyślny tryb ENT_COMPAT jest dostępny dla zachowania zgodności z
poprzednimi wersjami i konwertuje jedynie cudzysłowy, pozostawiając bez zmian apostrofy. ENT_QUOTES
235
PHP – Kompendium wiedzy
powoduje konwersję zarówno cudzysłowów jak i apostrofów.
jak i apostrofy pozostają niezmienione.
ENT_NOQUOTES
powoduje, że zarówno cudzysłowy
string htmlspecialchars( string string [, int quote_style])
Wykonywane są następujące konwersje:
& jest zamieniane na &amp;
" jest zamieniany na &quot;, o ile nie jest ustawiona wartość ENT_NOQUOTES
' jest zmieniany na &#039; jeżeli jest ustawiona wartość ENT_QUOTES
< jest zmieniane na &lt;
> jest zmieniane na &gt;
•
•
•
•
•
Uwaga
Funkcja ta wykonuje jedynie przedstawione translacje. Aby przeprowadzić pełną translację należy użyć funkcji htmlentities().
Należy pamiętać, że argument opcjonalny został dodany w PHP 3.0.17 i PHP 4.0.3.
hw_Array2Objrec
Konwertuje $object_array na rekord obiektowy. Wielokrotne atrybuty na przykład Title w różnych
językach są obsługiwane prawidłowo. Patrz również: hw_objrec2array().
string hw_Array2Objrec( array object_array )
hw_Children
Zwraca tablicę identyfikatorów obiektów. Każdy identyfikator należy do elementu kolekcji o
identyfikatorze $objectID. Tablica zawiera wszystkie elementy potomne, zarówno dokumenty jak i kolekcje.
array hw_Children( int connection, int objectID )
hw_ChildrenObj
Zwraca tablicę rekordów obiektów. Każdy z obiektów należy do elementu potomnego o identyfikatorze
$objectID. Tablica zawiera wszystkie elementy potomne, zarówno dokumenty jak i kolekcje.
array hw_ChildrenObj( int connection, int objectID )
hw_Close
Zwraca False, jeżeli $connection nie jest prawidłowym indeksem połączenia, a w przeciwnym przypadku
True. Zamyka połączenie o podanym indeksie do serwera Hyperwave.
int hw_Close( int connection )
hw_Connect
Otwiera połączenie do serwera Hyperwave i zwraca indeks połączenia, jeżeli operacja się uda. Jeżeli nie,
False. Każdy z argumentów powinien być ciągiem poza numerem portu. Argumenty $username i
$password są opcjonalne i mogą być opuszczone. W takim przypadku nie będzie przeprowadzana identyfikacja
użytkownika. Jest to zbliżone do identyfikacji użytkownika anonimowego. Funkcja zwraca indeks połączenia,
który jest potrzebny w innych funkcjach Hyperwave. Można utrzymywać kilka połączeń do serwera, Należy
jedynie pamiętać, że przesyłane hasło nie jest zaszyfrowane. Patrz również: hw_pConnect().
zwraca
int hw_Connect( string host, int port, string username, string password )
hw_Cp
Kopiuje obiekt o identyfikatorze podanym w drugim parametrze do kolekcji o identyfikatorze
Zwracaną wartością jest ilość skopiowanych obiektów. Patrz również: hw_mv().
$destination_id.
int hw_Cp( int conection, array object_id_array, int destination_id
Dodatek A - Funkcje
236
hw_Deleteobject
Usuwa obiekt o identyfikatorze przekazanym w drugim argumencie funkcji. Usuwa wszystkie kopie
obiektu. Zwraca True, jeżeli nie wystąpiły żadne błędy, lub False gdy błędy wystąpiły. Patrz również hw_mv().
int hw_Deleteobject( int connection, int object_to_delete )
hw_DocByAnchor
Zwraca identyfikator obiektu, do którego należy $anchorID.
int hw_DocByAnchor( int connection, int anchorID )
hw_DocByAnchorObj
Zwraca rekord obiektu dokumentu, do którego należy $anchorID.
int hw_DocByAnchorObj( int connection, int anchorID )
hw_Document_Attributes
Zwraca rekord obiektu dokumentu. Dla zachowania zgodności z poprzednimi wersjami akceptowane jest
również hw_DocumentAttributes(). Jednak nie zaleca się stosowania tej nazwy. Patrz również:
hw_Document_BodyTag() i hw_Document_Size().
hw_Document_BodyTag
Zwraca znacznik BODY dokumentu. Jeżeli jest to dokument HTML, znacznik BODY powinien być
wydrukowany przez dokumentem. Patrz również: hw_Document_Attributes(), hw_Document_Size(). Dla
zapewnienia zgodności akceptowana jest również nazwa hw_DocumentBodyTag(). Nie zaleca się jej stosowania.
string hw_Document_BodyTag( int hw_document )
hw_Document_Content
Zwraca treść dokumentu. Jeżeli jest to dokument HTML, zawartością jest wszystko po znaczniku BODY.
ze znaczników BODY i HEAD są zapamiętywane w rekordzie obiektu. Parz również:
hw_Document_Attributes(), hw_Document_Size() i hw_DocumentSetContent().
Dane
string hw_Document_Content( int hw_document )
hw_Document_SetContent
Zapisuje lub zmienia zawartość dokumentu. Jeżeli dokument jest w formacie HTML, zawartość stanowi
wszystko po znaczniku BODY. Dane ze znaczników HEAD i BODY są przechowywane w rekordzie obiektu. Jeżeli
informacje te zostaną umieszczone w zawartości dokumentu, po wstawieniu dokumentu serwer Hyperwave
zmieni odpowiednio rekord obiektu; nie jest to najlepsze rozwiązanie. Jeżeli funkcja się nie powiedzie, dokument
będzie zawierał poprzednią zawartość. Patrz również: hw_Document_Attributes(), hw_Document_Size() i
hw_Document_Content().
string hw_DocumentSetContent( int hw_document, string content )
hw_Document_Size
Zwraca
wielkość
dokumentu
w
bajtach.
Patrz
również:
hw_Document_BodyTag()
i
W celu zachowania zgodności akceptowana jest również nazwa hw_DocumentSize, ale
jej stosowanie nie jest zalecane.
hw_Document_Attributes().
int hw_Document_Size( int hw_document )
237
PHP – Kompendium wiedzy
hw_EditText
Przesyła test dokumentu na serwer. Rekord obiektu dokumentu nie może być modyfikowany do czasu
zakończenia edycji. Funkcja ta działa jedynie dla dokumentów czysto tekstowych. Nie otwiera specjalnego
połączenia i przez to na czas przesyłania blokuje połączenie sterujące. Patrz również: hw_PipeDocument(),
hw_FreeDocument(), hw_Document_BodyTag(), hw_Document_Size(), hw_Output_Document() i hw_GetText().
int hw_EditText( int connection, int hw_document )
hw_Error
Zwraca kod ostatniego błędu. Jeżeli nie występowały żadne błędy, zwraca 0. Błąd odnosi się do ostatnio
wykonanej komendy.
int hw_Error( int connection )
hw_ErrorMsg
False.
Zwraca ciąg zawierający ostatni komunikat błędu lub ciąg No Error. Jeżeli funkcja się nie udała, zwraca
Komunikat błędu odnosi się do ostatnio wykonanej komendy.
string hw_ErrorMsg( int connection )
hw_Free_Document
Zwalnia pamięć zajmowaną przez dokument Hyperwave.
int hw_Free_Document( int hw_document )
hw_GetAnchors
Zwraca tablicę identyfikatorów obiektów z łączami dokumentów z identyfikatorem obiektu $objectID.
array hw_GetAnchors( int connection, int objectID )
hw_GetAnchorsObj
Zwraca tablicę rekordów obiektów z łączami dokumentów z identyfikatorem obiektu $objectID.
array hw_GetAnchorsObj( int connection, int objectID )
hw_GetAndLock
Zwraca rekord obiektu dla obiektu o identyfikatorze $objectID. Dodatkowo nakłada blokadę na obiekt,
dzięki czemu inni użytkownicy nie mają do niego dostępu do czasu zwolnienia blokady. Patrz również:
hw_Unlock() i hw_GetObject().
string hw_GetAndLock( int connection, int objectID )
hw_GetChildColl
Zwraca tablicę identyfikatorów obiektów. Każdy z identyfikatorów należy do kolekcji potomnej w
kolekcji o identyfikatorze $objectID. Funkcja nie zwraca dokumentów potomnych. Patrz również:
hw_GetChildren() i hw_GetChildDocColl().
array hw_GetChildColl( int connection, int objectID )
hw_GetChildCollObj
Zwraca tablicę rekordów obiektów. Każdy z rekordów obiektów należy do kolekcji potomnej w kolekcji o
identyfikatorze $objectID. Funkcja nie zwraca dokumentów potomnych. Patrz również: hw_ChildrenObj() i
hw_GetChildDocCollObj().
array hw_GetChildCollObj( int connection, int objectID )
Dodatek A - Funkcje
238
hw_GetChildDocColl
Zwraca tablicę identyfikatorów obiektów dokumentów potomnych w kolekcji. Patrz również:
hw_GetChildren() i hw_GetChildColl().
array hw_GetChldDocColl( int connection, int objectID )
hw_GetChildDocCollObj
Zwraca tablicę rekordów obiektów dla dokumentów potomnych w kolekcji. Patrz również:
i hw_GetChildCollObj().
hw_ChildrenObj()
array hw_GetChildDocCollObj( int connection, int objectID )
hw_GetObject
Jeżeli drugi parametr jest liczą całkowitą, zwraca rekord obiektu dla obiektu o identyfikatorze $objectID.
Jeżeli drugi parametr jest tablicą liczb całkowitych, funkcja zwróci tablicę rekordów obiektów. W tym przypadku
analizowany jest również trzeci parametr — ciąg zapytania.
array hw_GetObject( int connection, {int,array} objectID, string query )
Ciąg zapytania posiada następującą składnię:
<expr> ::= "(" <expr> ")" |
"!" <expr> | /* Negacja */
<expr> "||" <expr> | /* OR */
<expr> "&&" <expr> | /* AND */
<attribute> <operator> <value>
<attribute> ::= /* dowolna nazwa atrybutu (Tytuł, Autor, TypDokumentu ...) */
<operator> ::= "=" | /* równy */
"<" | /* mniejszy od (porównanie ciągów) */
">" | /* większy od (porównanie ciągów) */
"~" /* porównywanie wyrażeń regularnych */
Zapytanie pozwala na dalszy wybór odpowiednich obiektów z listy zwracanych obiektów. W
przeciwieństwie do pozostałych funkcji zapytań, to zapytanie może działać na atrybutach bez indeksów. Ilość
zwracanych rekordów obiektów zależy od zapytania i od tego, czy możliwy jest dostęp do dokumentu. Patrz
również: hw_GetAndLock() i hw_GetObjectByQuery().
hw_GetObjectByQuery
Przeszukuje wszystkie obiekty na serwerze i zwraca tablicę identyfikatorów obiektów. Maksymalna ilość
identyfikatorów jest ograniczona do $max_hits. Jeżeli $max_hits ma wartość -1, maksymalna ilość zwracanych
identyfikatorów nie jest ograniczona. Zapytanie działa jedynie na atrybutach posiadających indeksy. Patrz
również: hw_GetObjectByQueryObj().
array hw_GetObjectByQuery( int connection, string query, int max_hits )
hw_GetObjectByQueryColl
Przeszukuje obiekty w kolekcji o identyfikatorze $objectID i zwraca tablicę identyfikatorów obiektów.
Maksymalna ilość identyfikatorów jest ograniczona do $max_hits. Jeżeli $max_hits ma wartość -1, maksymalna
ilość zwracanych identyfikatorów nie jest ograniczona. Zapytanie działa jedynie na atrybutach posiadających
indeksy. Patrz również: hw_GetObjectByQueryCollObj().
array hw_GetObjectByQueryColl( int connection, int objectID,
string query, int max_hits )
hw_GetObjectByQueryCollObj
Przeszukuje obiekty w kolekcji o identyfikatorze $objectID i zwraca tablicę rekordów obiektów.
Maksymalna ilość obiektów jest ograniczona do $max_hits. Jeżeli $max_hits ma wartość -1, maksymalna ilość
zwracanych obiektów nie jest ograniczona. Zapytanie działa jedynie na atrybutach posiadających indeksy. Patrz
również: hw_GetObjectByQueryColl().
array hw_GetObjectByQueryCollObj( int connection, int objectID,
string query, int max_hits )
239
PHP – Kompendium wiedzy
hw_GetObjectByQueryObj
Przeszukuje wszystkie obiekty na serwerze i zwraca tablicę rekordów obiektów. Maksymalna ilość
identyfikatorów jest ograniczona do $max_hits. Jeżeli $max_hits ma wartość -1, maksymalna ilość zwracanych
identyfikatorów nie jest ograniczona. Zapytanie działa jedynie na atrybutach posiadających indeksy. Patrz
również: hw_GetObjectByQuery().
array hw_GetObjectByQueryObj( int connection, string query, int max_hits )
hw_GetParents
Zwraca indeksowaną tablicę identyfikatorów obiektów. Każdy identyfikator obiektu jest obiektem
podrzędnym do obiektu o identyfikatorze $objectID.
array hw_GetParents( int connection, int objectID )
hw_GetParentsObj
Zwraca indeksowaną tablicę rekordów obiektów oraz dodatkowo skorelowaną tablicę z danymi
statystycznymi o rekordach obiektów. Dodatkowa tablica jest umieszczona w ostatnim elemencie zwracanej
tablicy. Każdy z rekordów obiektów jest obiektem podrzędnym do obiektu o identyfikatorze $objectID.
array hw_GetParentsObj( int connection, int objectID )
hw_GetRemote
Zwraca zdalny dokument. Dokumenty zdalne w sensie Hyperwave są dokumentami pobieranymi z
zewnętrznych źródeł. Najczęściej dokumentami zdalnymi są strony WWW lub zapytania do baz danych. Aby był
możliwy dostęp do zewnętrznych źródeł dokumentów, Hyperwave wprowadza protokół Hyperwave Gateway
Interface (HGI), który jest podobny do CGI. W chwili obecnej poprzez HGI można uzyskać dostęp do serwerów
http, ftp i niektórych baz danych. Wywołanie hw_GetRemote() zwraca dokument pochodzący ze zdalnego źródła
danych. Jeżeli chcesz użyć tej funkcji, powinieneś dobrze znać HGI. Powinieneś również rozważyć użycie PHP
zamiast Hyperwave do komunikacji z zdalnym źródłem danych. Dodanie obsługi baz danych poprzez Hyperwave
będzie bardziej skomplikowane, niż wykonanie tego samego w PHP. Patrz również: hw_GetRemoteChildren().
int hw_GetRemote( int connection, int objectID )
hw_GetRemoteChilden
Zwraca obiekty pochodne do zdalnego dokumentu. Obiektami pochodnymi zdalnego dokumentu są
również zdalne dokumenty. Funkcja ta może być wykorzystana, jeżeli można ograniczyć zapytanie bazy danych.
Jest to opisane w podręczniku Hyperwave Programmer’s Guide. Jeżeli istnieje tylko jeden obiekt pochodny,
funkcja zwraca ten obiekt sformatowany przez HGI. Jeżeli istneije więcej niż jeden element pochodny, funkcja
zwraca tablice rekordów obiektów, z których każdy być może może być wartością wejściową w kolejnym
wywołaniu funkcji hw_GetRemoteChildren(). Obiekty te są obiektami wirtualnymi i nie istnieją w serwerze
Hyperwave, i dlatego nie posiadają własnych identyfikatorów. Jeżeli zamierzasz wykorzystać tą funkcję
powinieneś dobrze znać HGI. Powinieneś również rozważyć użycie PHP zamiast Hyperwave do komunikacji z
zdalnym źródłem danych. Dodanie obsługi baz danych poprzez Hyperwave będzie bardziej skomplikowane, niż
wykonanie tego samego w PHP. Patrz również: hw_GetRemote().
hw_GetSrcByDestObj
Zwraca rekordy obiektów wskazujących na obiekt o identyfikatorze
dokumentem lub zakotwiczeniem. Patrz również: hw_GetAnchors().
$objectID.
Obiekt ten może być
array hw_GetSrcByDestObj( int connection, int objectID )
Dodatek A - Funkcje
240
hw_GetText
Zwraca dokument z identyfikatorem $objectID. Jeżeli dokument posiada zakotwiczenia, które można do
niego wstawić, zostaną one wstawione. Opcjonalny parametr $rootID/$prefix może być ciągiem lub liczbą
całkowitą. Jeżeli jest to liczba, określa w jaki sposób wstawiane są do dokumentu łącza. Wartością domyślną jest
0 i powoduje to utworzenie łączy z nazwy i obiektu docelowego łącza. Jest to uzyteczne przy tworzeniu aplikacji
WWW. Jeżeli łącze wskazuje na nazwę internet_movie, łącze HTML będzie miało postać <A
HREF="/internet_movie">. Położenie źródła i celu łącza jest ignorowane. Będziesz musiał tak ustawić swój serwer
WWW, aby zamieniał takie łącza na, na przykład /my_script.php3/internet_movie. Skrypt my_script.php3 musi
sprawdzić zawartość $PATH_INFO i odczytać dokument. Wszystkie łącza powinny zaczynać się od
/my_script.php3/. Jeżeli nie chcesz tego robić, możesz ustawić odpowiednio parametr opcjonalny
$rootID/$prefix na dowolny prefiks. W tym przypadku musi być to ciąg.
int hw_GetText( int connection, int objectID [, mixed rootID/prefix])
Jeżeli $rootID/$prefix jest liczbą różną od 0, łącze jest tworzone z wszystkich nazw względem bieżącego
obiektu, zaczynając od $rootID/$prefix oddzielanych ukośnikami. Jeżeli na przykład poprzedni dokument
internet_movie jest umieszczony w a-b-c-internet_movie, gdzie znak - jest separatorem hierarchii w serwerze
Hyperwave, a dokument źródłowy znajduje się w a-b-d-source, wynikowe łącze HTML będzie miało postać <A
HREF="../c/internet_movie">. Jest to korzystne, jeżeli chcesz zapisać całą zawartość serwera na dysk i
odwzorować hierarchię dokumentów w systemie plików. Funkcja ta działa jedynie dla dokumentów tekstowych.
Nie otwiera ona specjalnego połączenia, więc blokuje na czas przesyłu połączenie sterujące.
Patrz również: hw_PipeDocument(), hw_FreeDocument(), hw_Document_BodyTag(), hw_Document_Size() i
hw_Open_Document().
hw_getusername
Zwraca nazwę użytkownika połączenia.
string hw_getusername( int connection )
hw_Identify
Autoryzuje użytkownika za pomocą ciągów $username i $password. Autoryzacja jest ważna jedynie w
bieżącej sesji. Funkcja nie jest potrzebna zbyt często. W większości przypadków łatwiejszą metodą autoryzacji
jest otwarcie połączenia. Patrz również: hw_Connect().
hw_InCollections
Sprawdza, czy zbiór obiektów (dokumentów lub kolekcji) przekazanych w $object_id_array jest częścią
kolekcji przekazanych w $collection_id_array. Jeżeli czwarty parametr, $return_collections jest równy 0,
podzbiór identyfikatorów będących częścią kolekcji (na przykład dokumenty lub kolekcje podrzędne do jednej,
lub więcej kolekcji) jest zwracany w postaci tablicy. Jednak gdy czwarty argument jest równy 1, zbiór kolekcji
posiadających co najmniej jeden obiekt w znalezionym podzbiorze obiektów podrzędnych jest zwracany w
postaci tablicy. Opcja ta pozwala na przykład, na wyróżnienie części hierarchii dokumentów, w której zawarte są
wyniki przekazanego zapytania.
array hw_InCollections( int connection, array object_id_array,
array collection_id_array, int return_collections)
hw_Info
Zwraca dane na temat bieżącego połączenia. Zwracany ciąg posiada następującą postać: <Serwer>,
<Host>, <Port>, <Użytkownik>, <Port na kliencie>, <Zamiana bajtów>.
string hw_Info( int connection )
241
PHP – Kompendium wiedzy
hw_InsColl
Wstawia nową kolekcję z atrybutami zawartymi w tablicy
$objectID.
$object_array,
do kolekcji o identyfikatorze
int hw_InsColl( int connection, int objectID, array object_array )
hw_InsDoc
Wstawia nowy dokument z atrybutami zawartymi w $object_record, do kolekcji o identyfikatorze
Funkcja wstawia rekord obiektu lub rekord obiektu oraz tekst przekazany w $text, o ile został podany.
Jeżeli chcesz wstawić dokument dowolnego typy, należy użyć funkcji hw_insertdocument(). Patrz również:
hw_InsertDocument() i hw_InsColl().
$parentID.
int hw_InsDoc( int connection, int parentID, string object_record, string 3text )
hw_InsertDocument
Przesyła dokument do kolekcji o identyfikatorze $parentID. Dokument musi być wcześniej utworzony za
pomocą funkcji hw_NewDocument(). Należy się upewnić, że rekord obiektu posiada co najmniej następujące
atrybuty: Type, DocumentType, Title i Name. Przydatne jest ustawienie atrybutu MimeType. Funkcja zwraca
identyfikator obiektu nowego dokumentu, lub False. Patrz również: hw_PipeDocument().
int hw_InsertDocument( int connection, int parent_id, int hw_document )
hw_InsertObject
Umieszcza obiekt na serwerze. Obiekt musi być prawidłowym obiektem Hyperwave. Więcej danych na
ten temat znajduje się w dokumentacji HG-CSP.
Uwaga
Jeżeli chcesz wstawić zakotwiczenie atrybut position musi być zawsze ustawiony na wartość początkową, końcową lub invisible.
Pozycje niewidoczne są wymagane, jeżeli opis ni ma odpowiedniego łącza do tekstu opisu.
Patrz również: hw_PipeDocument(), hw_InsertDocument(), hw_InsDoc() i hw_InsColl().
int hw_InsertObject( int connection, string object_rec, string parameter )
hw_mapid
Mapuje identyfikator globalnego obiektu na dowolnym serwerze Hyperwave, nawet jeżeli nie wykonano
podłączenia do niego za pomocą hw_connect(), do identyfikatora obiektu wirtualnego. Ten obiekt wirtualny może
być używany identycznie, jak każdy inny identyfikator obiektu, na przykład do pobrania rekordu obiektu za
pomocą hw_getobject(). Identyfikator serwera jest pierwszą częścią globalnego identyfikatora obiektu (GOid) i w
chwili obecnej jest to numer IP w postaci liczby.
Uwaga
Aby użyć tej funkcji należy ustawić znacznik F_DISTRIBUTED, co obecnie można wykonać jedynie w czasie kompilacji pliku
hg_comm.c. Nie jest to wykonywane domyślnie. Należy zapoznać się z komentarzami na początku pliku hg_comm.c.
int hw_mapid( int connection, int server_id, int object_id )
hw_Modifyobject
Polecenie to pozwala na usunięcie, dodanie lub zmianę poszczególnych atrybutów rekordu obiektu. Obiekt
jest określony za pomocą identyfikatora $object_to_change. Pierwsza tablica, $remove, jest listą atrybutów do
usunięcia. Druga tablica, $add, jest listą atrybutów które należy dodać do obiektu. W celu zmiany atrybutu, należy
usunąć stary atrybut i dodać nowy. Funkcja hw_Modifyobject() zawsze najpierw usuwa stare atrybuty a potem
dodaje nowe chyba, że wartości atrybutów do usunięcia nie są tablicą ciągów. Ostatni parametr wskazuje, czy
Dodatek A - Funkcje
242
operacja ma być wykonana w sposób rekurencyjny. Wartość 1 oznacza rekurencyjne wywołanie. Jeżeli nie jest
możliwa modyfikacja niektórych obiektów, zostaną pominięte bez żadnej informacji o tym fakcie. Funkcja
hw_error() może nie wskazać żadnego błędu, choć nie wszystkie obiekty będą zmienione.
int hw_Modifyobject( int connecion, int object_to_change, array remove,
array add, int mode )
Kluczami w obu tablicach są nazwy atrybutów. Wartością każdego z elementów tablicy może być tablica
ciągów, ciąg, bądź cokolwiek innego. Jeżeli będzie to tablica, wartość atrybutu jest tworzona z klucza, średnika i
wartości. Wstawienie pustego ciągu spowoduje całkowite usunięcie atrybutu. Jeżeli wartość nie jest ani ciągiem
ani tablicą, ale na przykład liczbą, nie będą podejmowane żadne operacje na atrybucie. Jest to niezbędne, jeżeli
chcesz dodać całkowicie nowy atrybut a nie wartość istniejącego atrybutu. Jeżeli tablica z elementami do
usunięcia będzie zawierała pusty ciąg dla atrybutu, usunięcie się nie uda. Ustawienie wartości tego atrybutu na, na
przykład 0, spowoduje, że nie będzie podjęta próba jego usunięcia, natomiast dodanie atrybutu powiedzie się.
Jeżeli chcesz zmienić atrybut Name z bieżącą wartością książki na artykuły, powinieneś utworzyć dwie tablice i
wywołać funkcję hw_modifyobject().
Przykład: zmiana atrybutu
// $connect jest istniejącym połączeniem do serwera Hyperwave
// $objid jest identyfikatorem obiektu do zmiany
$remarr = array("Name" => "książki");
$addarr = array("Name" => "artykuły");
$hw_modifyobject($connect, $objid, $remarr, $addarr);
Aby usunąć lub dodać parę nazwa–wartość, należy przekazać tablice zawierające dodawane i usuwane
atrybuty przekazując w trzecim parametrze pustą tablicę. Jeżeli atrybut jest pierwszym atrybutem o tej nazwie,
należy ustawić wartości w tablicy atrybutów do usunięcia na liczby całkowite.
Przykład: dodanie całkowicie nowego atrybutu
// $connect jest istniejącym połączeniem do serwera Hyperwave
// $objid jest identyfikatorem obiektu do zmiany
$remarr = array("Name" => 0);
$addarr = array("Name" => "artykuły");
$hw_modifyobject($connect, $objid, $remarr, $addarr);
Uwaga
Atrybuty w wielu językach, na przykład Title mogą być zmieniane na dwa sposoby. Pierwszym sposobem jest wpisywanie wartości
atrybutów w postaci język:tytuł, lub przekazywanie tablicy z elementami dla każdego języka zapisanymi w identyczny sposób jak
poprzednio. Poprzedni przykład może być zapisany w następujący sposób:
Przykład: zmiana atrybutu Title
$remarr = array("Title" => "en:Books");
$addarr = array("Title" => "en:Articles");
$hw_modifyobject($connect, $objid, $remarr, $addarr);
lub
Przykład: zmiana atrybutu Title
$remarr = array("Title" => array("en" => "Books"));
$addarr = array("Title" => array("en" => "Articles", "ge"=>"Artikel");
$hw_modifyobject($connect, $objid, $remarr, $addarr);
W przykładzie tym zostanie usunięty angielski tytuł Books i dodany tytuł angielski Articles i niemiecki
Artikel.
Przykład: usuwanie atrybutu
$remarr = array("Title" => "");
$addarr = array("Title" => "en:Articles");
$hw_modifyobject($connect, $objid, $remarr, $addarr);
Uwaga
Wykonanie poprzedniego przykładu spowoduje usunięcie wszystkich atrybutów o nazwie Title i dodanie nowego atrybutu Title. Jest to
wygodne, jeżeli chcesz usuwać atrybuty w sposób rekurencyjny. Jeżeli chcesz usunąć wszystkie atrybuty o zadanej nazwie, musisz
przekazać pusty ciąg jako wartość atrybutu. Jedynie atrybuty Title, Description i Keyword prawidłowo obsługują prefiksy języków.
Jeżeli atrybut nie posiada prefiksu języka, użyty zostanie prefiks xx. Atrybut Name ma specjalne znaczenie; w niektórych przypadkach
nie jest możliwe jego całkowite usunięcie. Otrzymasz wtedy komunikat błędu Change of base attribute (nie jest jasna przyczyna tego
błędu). Dlatego zawsze musisz dodawać nowy atrybut Name przed usunięciem starego.
Uwaga
Nie musisz otaczać wywołania tej funkcji wywołaniami hw_getandlock() i hw_unlock(). Funkcja hw_modifyobject() robi to
samodzielnie. Zwraca True w przypadku pomyślnego wykonania i False w przypadku błędu.
243
PHP – Kompendium wiedzy
hw_Mv
Przenosi obiekt o identyfikatorze podanym w drugim parametrze z kolekcji i identyfikatorze $source do
kolekcji o identyfikatorze $destination. Jeżeli identyfikator kolekcji docelowej wynosi 0, obiekt jest usuwany ze
źródłowej kolekcji. Jeżeli jest to ostatni egzemplarz obiektu, zostanie on usunięty. Jeżeli chcesz usunąć wszystkie
wystąpienia za pomocą jednego wywołania, należy użyć funkcji hw_deleteobject(). Zwracana wartość jest
ilością przeniesionych obiektów. Patrz również: hw_cp() i hw_deleteobject().
int hw_Mv( int connection, array object_id_array, int souce_id, int destination_id )
hw_New_Document
Zwraca nowy dokument Hyperwave. Zawartość dokumentu jest przekazana w parametrze $document_data,
natomiast rekord obiektu w $object_record. Wielkość danych musi być przekazana w parametrze
$document_size. Funkcja ta nie wstawia dokumentu do serwera Hyperwave. Patrz również: hw_FreeDocument(),
hw_Document_Size(), hw_Document_BodyTag(), hw_Output_Document() i hw_InsertDocument().
int hw_new_document (string object_record, string document_data, int document_size)
hw_Objrec2Array
Konwertuje $object_record na tablicę obiektów. Kluczami wynikowej tablicy są nazwy atrybutów.
Atrybuty wielowartościowe, takie jak Title, w różnych językach tworzą własne tablice. Kluczami w tych tablicach
części stojące z lewej strony dwukropka. Część ta musi mieć dwa znaki. Inne wartości wielowartościowe nie
posiadające prefiksów tworzą indeksowaną tablicę. Jeżeli nie podany został parametr opcjonalny, atrybuty Title,
Description i Keyword są traktowane jako atrybuty języka,, natomiast atrybuty Group, Parent i HtmlAttr są
traktowane jako wartości wielowartościowe bez prefiksu. Przekazując tablice zawierająca typy każdego z
argumentów można zmienić to zachowanie. Tablica jest tablicą asocjacyjną z nazwą atrybutu jako klucze i
wartościami będącymi jedną z wartości HW_ATTR_LANG lub HW_ATTR_NONE. Patrz również: hw_array2objrec().
array hw_objrec2array (string object_record [, array format])
hw_Output_Document
Drukuje dokument bez znacznika BODY. Dla zgodności z poprzednimi wersjami można użyć nazwy
ale jest to postać przestarzała.
hw_OutputDocument(),
int hw_output_document (int hw_document)
hw_pConnect
W przypadku powodzenia zwraca numer połączenia, lub False w przypadku, gdy połączenie nie może być
wykonane. Otwiera trwałe połączenie do serwera Hyperwave. Każdy z argumentów oprócz numeru portu,
powinien być ciągiem znaków. Argumenty $username i $password są opcjonalne. W takim przypadku nie jest
wykonywana autoryzacja na serwerze. Jest to zbliżone do korzystania z konta gościa. Funkcja zwraca numer
połączenia, który jest przekazywany do wszystkich funkcji Hyperwave. Można mieć kilka jednocześnie otwartych
trwałych połączeń. Patrz również: hw_Connect().
int hw_pconnect (string host, int port, string username, string password)
hw_PipeDocument
Zwraca dokument Hyperwave o identyfikatorze obiektu $objectID. Jeżeli dokument posiada możliwe do
wstawienia zakotwiczenia, zostaną one wstawione. Dokument zostanie przesłany poprzez połączenie specjalne,
które nie blokuje połączenia sterującego. Patrz również: hw_GetText(). Więcej informacji na temat wstawiania
łączy znajduje się w opisie funkcji hw_FreeDocument(), hw_Document_Size(), hw_Document_BodyTag() i
hw_Output_Document().
int hw_pipedocument (int connection, int objectID)
Dodatek A - Funkcje
244
hw_Root
Zwraca identyfikator obiektu kolekcji korzenia; w chwili obecnej posiada ona wartość 0. Kolekcja
potomna tej kolekcji jest główną kolekcją serwera.
int hw_root ()
hw_Unlock
Odblokowuje dokument, więc użytkownicy mają nów do niego dostęp. Patrz również: hw_GetAndLock().
int hw_unlock (int connection, int objectID)
hw_Who
Zwraca tablicę z użytkownikami obecnie zalogowanymi na serwerze Hyperwave. Każda pozycja jest
kolejna tablica, zawierającą atrybuty: identyfikator elementu, nazwa, system, pola onSinceDate, onSinceTime,
TotalTime, oraz self. Wartością self jest 1 jeżeli pozycja należy do użytkownika inicjującego żądanie.
int hw_who (int connection)
ibase_close
Zamyka połączenie z bazą danych InterBase identyfikowane przez identyfikator połączenia zwracany
przez funkcję ibase_connect(). Jeżeli identyfikator połączenia jest pominięty, funkcja działa na ostatnio
otwartym połączeniu. Domyślna transakcja w tym połączeniu jest zatwierdzana, natomiast pozostałe transakcje są
wycofywane.
int ibase_close ([int connection_id])
ibase_connect
Nawiązuje połączenie z serwerem InterBase. Argument $database musi być ścieżką do pliku bazy danych
na serwerze. Jeżeli serwer nie jest serwerem lokalnym, musi być poprzedzony albo ciągiem hostname: (TCP/IP),
//hostname (NetBEUI) lub hostname@ (IPX/SPX) w zależności od protokołu używanego w tym połączeniu.
Parametry $username i $password mogą być pobierane w dyrektywach konfiguracji ibase.default_user i
ibase.default_password. Parametr $charset jest domyślnym zestawem znaków dla bazy danych. Parametr
$buffers określa ilość buforów bazy danych zakładanych na serwerze. Jeżeli podane zostanie 0 lub parametr
zostanie opuszczony, serwer zakłada domyślną dla siebie ilość buforów. Parametr $dialect wybiera domyślny
dialekt SQL obowiązujący dla wszystkich wyrażeń wykonywanych poprzez bieżące połączenie. Wartością
domyślną jest najwyższy dialekt obsługiwany przez biblioteki klienta. Jeżeli ibase_connect() jest wywoływany
po raz drugi z tymi samymi parametrami, nie jest tworzone nowe połączenie. Zamiast tego zwracany jest
identyfikator istniejącego połączenia. Połączenie z serwerem jest zamykane natychmiast po zakończeniu
wykonywania skryptu, chyba, że wcześniej została wywołana funkcja ibase_close().
int ibase_connect(string database [, string username [, string password
[, string charset [, int buffers [, int dialect [, string role]]]]]])
Przykład: ibase_connect()
<?php
$dbh = ibase_connect ($host, $username, $password);
$stmt = 'SELECT * FROM tblname';
$sth = ibase_query ($dbh, $stmt);
while ($row = ibase_fetch_object ($sth))
{
print $row->email . "\n";
}
ibase_close ($dbh);
?>
Uwaga
Parametry $buffers i $dialect zostały dodane w PHP4-RC2. Działają one jedynie z serwerem InterBase 6 i nowszymi od niego.
Parametr $role działa jedynie z InterBase 5 i wyższymi.
Patrz również: ibase_pconnect().
245
PHP – Kompendium wiedzy
ibase_execute
Wykonuje zapytanie przygotowane za pomocą ibase_prepare(). W przypadku, gdy to samo zapytanie jest
powtarzane dla różnych parametrów, jest to o wiele bardziej efektywne niż wykorzystanie ibase_query().
int ibase_execute (int query [, int bind_args])
Przykład: ibase_execute()
<?php
$updates
1 =>
5 =>
7 =>
);
= array(
'Eric',
'Filip',
'Larry'
$query = ibase_prepare("UPDATE FOO SET BAR = ? WHERE BAZ = ?");
while (list($baz, $bar) = each($updates)) {
ibase_execute($query, $bar, $baz);
}
?>
ibase_fetch_object
Pobiera wiersz w postaci pseudoobiektu korzystając z
$result_id
zwróconego przez
ibase_query()
lub
ibase_execute().
object ibase_fetch_object (int result_id)
Przykład: ibase_fetch_object()
<php
$dbh = ibase_connect ($host, $username, $password);
$stmt = 'SELECT * FROM tblname';
$sth = ibase_query ($dbh, $stmt);
while ($row = ibase_fetch_object ($sth)) {
print $row->email . "\n";
}
ibase_close ($dbh);
?>
Patrz również: ibase_fetch_row().
ibase_fetch_row
Zwraca kolejny wiersz korzystając z identyfikatora wyniku zwracanego przez funkcję ibase_query().
array ibase_fetch_row (int result_identifier)
ibase_free_query
Zwalnia zapytanie przygotowane przez ibase_prepare().
int ibase_free_query (int query)
ibase_free_result
Zwalania wynik tworzony przez ibase_query().
int ibase_free_result (int result_identifier)
ibase_num_fields
Zwraca liczbę określającą ilość pól w wyniku zapytania. Patrz również ibase_field_info().
Uwaga
Funkcja ibase_num_fields() nie działa jeszcze w PHP 4.
Przykład: ibase_num_fields()
Dodatek A - Funkcje
246
<?php
$dbh = ibase_connect ($host, $username, $password);
$stmt = 'SELECT * FROM tblname';
$sth = ibase_query ($dbh, $stmt);
if (ibase_num_fields($sth) > 0) {
while ($row = ibase_fetch_object ($sth)) {
print $row->email . "\n";
}
} else {
die ("No Results were found for your query");
}
ibase_close ($dbh);
?>
ibase_pconnect
Działa bardzo podobnie do ibase_connect() z dwiema poważnymi różnicami. Po pierwsze, w czasie
dołączania do serwera funkcja próbuje odszukać istniejące (trwałe) połączenie otwarte z tym samym zestawem
argumentów. Jeżeli zostanie znalezione takie połączenie, jego identyfikator jest zwracany i nie jest tworzone
nowe połączenie. Po drugie, Połączenie do serwera InterBase nie jest zamykane po zakończeniu wykonywania
skryptu. Połączenie pozostaje otwarte do wykorzystania w przyszłości (ibase_close() nie zamyka połączeń
utworzonych przez ibase_pconnect()). Połączenie takie nazywane jest z tego powodu połączeniem trwałym. Opis
parametrów przekazywanych do funkcji jest zamieszczony przy opisie funkcji ibase_connect(); są one
identyczne.
int ibase_pconnect(string database [, string username [, string password
[, string charset [, int buffers [, int dialect [, string role]]]]]])
ibase_prepare
Przygotowuje zapytanie dodając obsługę parametrów dołączanych później za pomocą funkcji
ibase_execute().
int ibase_prepare ([int link_identifier, string query])
ibase_query
Wykonuje zapytanie na basie danych InterBase i zwraca identyfikator wyniku wykorzystywany w
funkcjach ibase_fetch_row(), ibase_fetch_object(), ibase_free_result() i ibase_free_query(). Mimo, że
funkcja ta obsługuje dołączanie zmiennych do parametrów, używanie tego udogodnienia w tej właśnie funkcji nie
ma wielkiego sensu. Przykład użycia funkcji jest umieszczony przy opisie funkcji ibase_prepare() i
ibase_execute().
int ibase_query ([int link_identifier, string query [, int bind_args]])
ibase_timefmt
Ustala format znacznika czasu, daty i czasu dla kolumn tych typów zwracanych zapytaniach.
Wewnętrznie kolumny są formatowane przez funkcję C strftime(), więc wszelkie szczegóły na temat ciągu
formatującego znajdują się w jej dokumentacji. Parametr $columntype jest jedną ze stałych IBASE_TIMESTAMP,
IBASE_DATE i IBASE_TIME. Jeżeli zostanie ion opuszczony, przyjmowana jest wartość IBASE_TIMESTAMP w celu
zapewnienia zgodności z poprzednimi wersjami.
int ibase_timefmt (string format [, int columntype])
Przykład: ibase_timefmt()
<?php
// kolumny InterBase 6 typu TIME będą zwracane w postaci
// '05 godzin 37 minut'.
ibase_timefmt("%H godzin %M minut", IBASE_TIME);
?>
Można również ustawić domyślny format za pomocą dyrektyw konfiguracji PHP ibase.timestampformat,
i ibase.timeformat. Parametr $columntype został dodany w PHP 4.0. Ma on znaczenie jedynie
w wersjach InterBase 6 i wyższych.
ibase.dateformat
247
PHP – Kompendium wiedzy
Uwaga
W PHP 4.0 wprowadzono zmianę, która powodowała niezgodność z poprzednimi wersjami, zmieniając nazwę dyrektywy konfiguracji
ibase.timeformat na ibase.timestampformat oraz dodane zostały dyrektywy ibase.dateformat i ibase.timeformat w
celu ulepszenia działania funkcji.
icap_close
Zamyka podany strumień icap.
int icap_close (int icap_stream [, int flags])
icap_delete_event
Usuwa zdarzenie z kalendarza o identyfikatorze podanym w $uid. Zwraca True.
string icap_delete_event (int sream_id, int uid)
icap_fetch_event
Pobiera zdarzenie określone przez $event_id ze strumienia kalendarza.
int icap_fetch_event (int stream_id, int event_id [, int options])
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Zwraca obiekt zdarzenia zawierający następujące atrybuty:
int id — Identyfikator zdarzenia.
int public — True jeżeli zdarzenie jest publiczne lub False, gdy jest prywatne.
string category — Ciąg zawierający kategorię zdarzenia.
string title — Ciąg zawierający tytuł zdarzenia.
string description — Ciąg z opisem zdarzenia .
int alarm — Ilość minut przed zdarzeniem gdy wysyłane jest powiadomienie lub alarm.
object start — Obiekt zawierający datę i czas.
object end — Obiekt zawierający datę i czas.
Wszystkie pozycje daty i czasu zawierają następujące atrybuty:
int year — rok
int month — miesiąc
int mday — dzień miesiąca
int hour — godzina
int min — minuty
int sec — sekundy
icap_list_alarms
Zwraca tablicę z identyfikatorami zdarzeń które wyślą alarm o podanej godzinie. Funkcja
wymaga podania daty i czasu oraz strumienia kalendarza. Zwracana jest tablica
identyfikatorów zdarzeń z aktywnym alarmem o podanej godzinie.
icap_list_alarms()
int icap_list_alarms (int stream_id, array date, array time)
•
•
•
•
•
•
Wszystkie pozycje z datą i czasem zawierają następujące atrybuty:
int year — rok
int month — miesiąc
int mday — dzień miesiąca
int hour — godzina
int min — minuty
int sec — sekundy
Dodatek A - Funkcje
248
icap_list_events
Zwraca tablicę identyfikatorów zdarzeń pomiędzy dwiema datami. Funkcja icap_list_events() pobiera
ze strumienia identyfikatory zdarzeń pomiędzy data początkową i końcową. Zwracana jest tablica identyfikatorów
zdarzeń pomiędzy podanymi datami.
array icap_list_events (int stream_id, int begin_date [, int end_date])
•
•
•
•
•
•
Wszystkie pozycje z datą i czasem zawierają następujące atrybuty:
int year — rok
int month — miesiąc
int mday — dzień miesiąca
int hour — godzina
int min — minuty
int sec — sekundy
icap_open
W przypadku powodzenia zwraca strumień ICAP, natomiast w przypadku wystąpienia błędu, False.
Funkcja icap_open() otwiera połączenie ICAP do podanego w $calendar magazynu. Jeżeli podany jest parametr
opcjonalny $options, jest on również przekazany do otwieranej skrzynki pocztowej.
stream icap_open (string calendar, string username, string password, string options)
icap_snooze
Włącza alarm dla zdarzenia kalendarza określonego przez $uid. Zwraca True.
string icap_snooze (int stream_id, int uid)
icap_store_event
Zapisuje zdarzenie w kalendarzu ICAP.
string icap_store_event (int stream_id, object event)
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Obiekt zdarzenia zawiera następujące atrybuty:
int id — Identyfikator zdarzenia.
int public — 1 jeżeli zdarzenie jest publiczne lub 0, gdy jest prywatne.
string category — Ciąg zawierający kategorię zdarzenia.
string title — Ciąg zawierający tytuł zdarzenia.
string description — Ciąg z opisem zdarzenia .
int alarm — Ilość minut przed zdarzeniem gdy wysyłane jest powiadomienie lub alarm.
object start — Obiekt zawierający datę i czas.
object end — Obiekt zawierający datę i czas.
Wszystkie pozycje daty i czasu zawierają następujące atrybuty:
int year — rok
int month — miesiąc
int mday — dzień miesiąca
int hour — godzina
int min — minuty
int sec — sekundy
Zwraca True w przypadku powodzenia operacji lub False w przypadku błędu.
ifxus_close_slob
Usuwa obiekt slob dla podanego w $bid identyfikatora obiektu slob. Zwraca
wystąpienia błędu, True w przypadku powodzenia operacji.
False
w przypadku
int ifxus_close_slob (int bid)
249
PHP – Kompendium wiedzy
ifxus_create_slob
Tworzy obiekt slob i otwiera go. Tryby: 1 = LO_RDONLY, 2 = LO_WRONLY, 4 = LO_APPEND, 8 = LO_RDWR, 16 =
LO_BUFFER, 32 = LO_NOBUFFER. Można również użyć stałych o nazwach IFX_LO_RDONLY, IFX_LO_WRONLY itd. Zwraca
False w przypadku wystąpienia błędu a w przypadku powodzenia, identyfikator obiektu slob.
ifxus_free_slob
Usuwa obiekt slob. Parametr $bid jest identyfikatorem obiektu slob. Zwraca
wystąpienia błędu i True w przeciwnym wypadku.
False
w przypadku
int ifxus_free_slob (int bid)
ifxus_open_slob
Otwiera obiekt slob. Parametr
powinien być identyfikatorem istniejącego obiektu. Tryby: 1 =
Zwraca False w
przypadku wystąpienia błędu a w przeciwnym wypadku identyfikator nowego obiektu slob.
$bid
LO_RDONLY, 2 = LO_WRONLY, 4 = LO_APPEND, 8 = LO_RDWR, 16 = LO_BUFFER, 32 = LO_NOBUFFER.
int ifxus_open_slob (long bid, int mode)
ifxus_read_slob
Czyta n bajtów z obiektu slob. Parametr $bid jest identyfikatorem istniejącego obiektu slob, natomiast
$nbytes jest ilością bajtów do przeczytania. Zwraca False w przypadku wystąpienia błędu a w przeciwnym
wypadku zwraca ciąg.
int ifxus_read_slob (long bid, long nbytes)
ifxus_seek_slob
Ustawia bieżący plik lub wyszukuje pozycję w otwartym obiekcie slob. Parametr $bid powinien być
identyfikatorem istniejącego obiektu slob. Tryby: 0 = LO_SEEK_SET, 1 = LO_SEEK_CUR, 2 = LO_SEEK_END natomiast
$offset jest przesunięciem w bajtach. Zwraca False w przypadku wystąpienia błędu a w przeciwnym wypadku
pozycję w pliku.
int ifxus_seek_slob (long bid, int mode, long offset)
ifxus_tell_slob
Zwraca bieżącą pozycję w pliku lub przesunięcie w otwartym obiekcie slob. Parametr $bid powinien być
identyfikatorem istniejącego obiektu slob. Zwraca False w przypadku wystąpienia błędu a w przeciwnym
wypadku pozycję w pliku.
int ifxus_tell_slob (long bid)
ifxus_write_slob
Zapisuje zawartość ciągu do obiektu slob. Parametr $bid musi być identyfikatorem obiektu slob, natomiast
zawiera dane do zapisania. Zwraca False w przypadku wystąpienia błędu, w przeciwnym przypadku
ilość zapisanych bajtów.
$content
int ifxus_write_slob (long bid, string content)
ifx_affected_rows
Parametr $result_id powinien być identyfikatorem wyniku zwracanym przez funkcję ifx_query() lub
Zwraca ilość wierszy zmienionych przez zapytanie związane z $result_id. W przypadku operacji
wstawienia, zamiany lub usunięcia, ilość ta jest prawdziwą liczbą operacji (sqlerrd[2]). W przypadku operacji
SELECT nie jest dokładną liczbą zwracanych wierszy, a jedynie oszacowaniem (sqlerrd[0]). Serwer bazy danych
może nigdy nie zwrócić ilości wierszy zwracanych przez operację SELECT w tej fazie operacji (zaraz po operacji
ifx_prepare().
Dodatek A - Funkcje
250
PREPARE,
po ustaleniu planu wykonania przez optymalizator), ponieważ nie rozpoczął on odczytywania
zwracanych wierszy. Jest to użyteczna funkcja do ograniczania zapytań do takich, które zwracają rozsądną ilość
wierszy po przygotowaniu zapytania przez ifx_prepare(). Patrz również: ifx_num_rows().
int ifx_affected_rows (int result_id)
Przykład: wykorzystanie funkcji serwera Informix ifx_affected_rows()
$rid = ifx_prepare ("select * from emp
where name like " . $name, $connid);
if (! $rid) {
... błąd ...
}
$rowcount = ifx_affected_rows ($rid);
if ($rowcount > 1000) {
printf ("Zapytanie zwraca zbyt dużo wierszy: (%d)\n<br>", $rowcount);
die ("Proszę ograniczyć zapytanie<br>\n");
}
ifx_blobinfile_mode
Ustawia domyślny tryb przechowywania obiektów blob w zapytaniach
przechowywanie blobów w pamięci, natomiast 1, przechowywanie ich w pliku.
SELECT.
Tryb
0
oznacza
void ifx_blobinfile_mode (int mode)
ifx_byteasvarchar
Ustawia domyślny tryb zapytaniach SELECT. Tryb
zwracanie pola varchar z danymi tekstowymi.
0
powoduje zwracanie identyfikatora blob, natomiast 1,
void ifx_byteasvarchar (int mode)
ifx_close
Zawsze zwraca True. Funkcja ifx_close() powoduje zamknięcie połączenia z bazą danych Informix,
skojarzoną z podanym identyfikatorem połączenia. Jeżeli nie został podany identyfikator połączenia, zamykane
jest ostatnio otwarte połączenie.
Uwaga
nie jest to operacja niezbędna, ponieważ nietrwałe połączenia są zamykane automatycznie po zakończeniu wykonywania skryptu.
Funkcja ifx_close() nie zamyka połączeń trwałych generowanych przez ifx_pconnect().
Patrz również: ifx_connect() i ifx_pconnect().
int ifx_close ([int link_identifier])
Przykład: Zamykanie połączenia z bazą danych Informix
$conn_id = ifx_connect ("mydb@ol_srv", "itsme", "mypassword");
... potrzebne zapytania ...
ifx_close($conn_id);
ifx_connect
Zwraca identyfikator połączenia lub false w przypadku wystąpienia błędu. Funkcja ifx_connect()
nawiązuje połączenie z serwerem Informix. Wszystkie argumenty są opcjonalne i w przypadku opuszczenia
któregoś z nich, z pliku konfiguracyjnego pobierane są wartości domyślne, ifx.default_host zawiera nazwę
serwera biblioteki Informixa korzystają ze zmiennej środowiskowej INFORMIXSERVER), ifx.default_user zawiera
nazwę użytkownika a ifx.default_password zawiera domyślne hasło (jeżeli nie jest zdefiniowana to bez hasła).
Jeżeli drugi raz wywołano funkcję ifx_connect() z tymi samymi argumentami, nie jest nawiązywane nowe
połączenie. Zamiast tego zwracany jest identyfikator istniejącego połączenia. Połączenie nie jest zamykane po
zakończeniu wykonywania skryptu lub po wywołaniu funkcji ifx_close(). Patrz również: ifx_pconnect() i
ifx_close().
int ifx_connect (string [database], string [userid], string [password])
Przykład: Podłączenie do bazy Informix
$conn_id = ifx_connect ("mydb@ol_srv", "itsme", "mypassword");
251
PHP – Kompendium wiedzy
ifx_copy_blob
Tworzy kopię podanego obiektu blob. Parametr $bid jest identyfikatorem obiektu blob. Zwraca
przypadku błędu, a w przeciwnym wypadku identyfikator nowego obiektu blob.
False
w
int ifx_copy_blob (int bid)
ifx_create_blob
Tworzy obiekt blob. Zwraca
obiektu blob.
False
w przypadku błędu, a w przeciwnym wypadku identyfikator nowego
int ifx_create_blob (int type, int mode, string param)
•
•
•
Parametr $type: 1 = TEXT, 0 = BYTE
Parametr $mode: 0 = obiekt blob jest przechowywany w pamięci, 1 = obiekt blob jest przechowywany w
pliku.
Parametr $param: Jeżeli tryb=0 jest to wskaźnik na zawartość, jeżeli tryb=1, wskaźnik na strumień pliku.
ifx_create_char
Tworzy obiekt znakowy. Parametr $param powinien zawierać zawartość obiektu.
int ifx_create_char (string param)
ifx_do
Zwraca True gdy operacja się powiodła i False w przypadku błędu. Wykonuje uprzednio przygotowane
zapytanie i otwiera dla niego kursor. W przypadku wystąpienia błędu nie zwalnia $result_id. Dla zapytań innych
od SELECT ustawia również właściwą liczbę zmienionych wierszy, którą można odczytać za pomocą
ifx_affected_rows(). Patrz również ifx_prepare().
int ifx_do (int result_id)
ifx_error
Kody błędów serwera Informix (SQLSTATE i SQLCODE) są formatowane następująco:
x [SQLSTATE = aa bbb SQLCODE=cccc]
Gdy x jest spacją, oznacza to brak błędu.
E — błąd
N — koniec danych
W — ostrzeżenie
? — niezdefiniowany
string ifx_error (void)
Jeżeli znak x jest czymkolwiek poza spacją, SQLSTATE i SQLCODE dokładniej opisują błąd. Opis
SQLSTATE i SQLCODE można znaleźć w podręczniku do serwera Informix. Zwraca jeden znak określający
wynik wyrażenia oraz zarówno wartość SQLSTATE jak i SQLCODE związane z ostatnio wykonywanym
wyrażeniem SQL. Format tego ciągu jest następujący: (znak) [SQLSTATE=(dwa znaki) (trzy znaki)
SQLCODE=(jeden znak)]. Pierwszym znakiem może być spacja (sukces), W (wyrażenie wygenerowało
ostrzeżenia), E (zdarzył się błąd w czasie wykonywania wyrażenia) lub N (wyrażenie nie zwróciło żadnych
danych). Patrz również: ifx_errormsg().
ifx_erormsg
Zwraca komunikat serwera Informix opisujący ostatni błąd w serwerze lub gdy podano wartość
opcjonalnego parametru $errorcode, komunikat związany z podanym numerem błędu. Patrz również:
idx_error().
string ifx_errormsg ([int errorcode])
Przykład: ifx_errormsg()
printf("%s\n<br>", ifx_errormsg(-201));
Dodatek A - Funkcje
252
ifx_fetch_row
Zwraca tablicę asocjacyjną zawierająca odczytany wiersz, lub False jeżeli nie ma następnego wiersza.
Kolumny blob są zwracane w postaci numerycznych identyfikatorów blob, które można użyć w funkcji
ifx_get_blob(), lub jeżeli zostały wywołane funkcje ifx_textasvarchar(1) lub ifx_byteasvarchar(1), pola blob
są zwracane w postaci ciągów znaków. W przypadku wystąpienia błędu zwraca False. Parametr $result_id musi
być prawidłowym identyfikatorem wyniku zwracanym przez ifx_query() lub ifx_prepare() (tylko dla zapytań
SELECT). Opcjonalny parametr $position wskazuje na rodzaj operacji na kursorze. Może być to NEXT, PREVIOUS,
CURRENT, FIRST, LAST lub liczba. Jeżeli podana zostanie liczba, odczytywany jest wiersz o podanym numerze. Jest
to parametr opcjonalny stosowany tylko dla kursorów typu SCROLL.
array ifx_fetch_row (int result_id [, mixed position])
Funkcja ifx_fetch_row() odczytuje jeden wiersz danych z wyniku związanego z podanym
identyfikatorem wyniku. Wiersz jest zwracany w postaci tablicy. Każda kolumna wyniku jest przechowywana w
osobnej komórce tablicy, której kluczem jest nazwa kolumny. Kolejne wywołania ifx_fetch_row() zwracają
kolejne wiersze wyniku lub False, gdy nie ma już kolejnych wierszy.
Przykład: Odczyt wierszy wyniku
$rid = ifx_prepare ("select * from emp where name like " . $name,
$connid, IFX_SCROLL);
if (! $rid) {
... error ...
}
$rowcount = ifx_affected_rows($rid);
if ($rowcount > 1000) {
printf ("Zapytanie zwraca zbyt dużo wierszy: (%d)\n<br>", $rowcount);
die ("Proszę ograniczyć zapytanie<br>\n");
}}
if (! ifx_do ($rid)) {
... error ...
}
$row = ifx_fetch_row ($rid, "NEXT");
while (is_array($row)) {
for(reset($row); $fieldname=key($row); next($row)) {
$fieldvalue = $row[$fieldname];
printf ("%s = %s,", $fieldname, $fieldvalue);
}
printf("\n<br>");
$row = ifx_fetch_row ($rid, "NEXT");
}
ifx_free_result ($rid);
ifx_fieldproperties
Zwraca tablicę asocjacyjną z nazwami pól jako kluczami i właściwościami pól SQL dla wyniku zapytania
określonego przez $result_id, jako danymi. W przypadku wystąpienia błędu zwraca False. Zwraca właściwości
SQL serwera Informix w postaci tablicy asocjacyjnej, dla każdego pola zwracanego przez zapytanie. Właściwości
te są zapisywane jako SQLTYPE:długość:dokładność:skala:ISNULLABLE, gdzie SQLTYPE jest typem Informixa,
np.: SQLVCHAR, natomiast ISNULLABLE może mieć wartość Y lub N.
array ifx_fieldproperties (int result_id)
Przykład: właściwości pól SQL serwera Informix
$properties = ifx_fieldproperties ($resultid);
if (! isset($properties)) {
... błąd ...
}
for ($i = 0; $i < count($properties); $i++) {
$fname = key ($properties);
printf ("%s:\t typ = %s\n", $fname, $properties[$fname]);
next ($properties);
}
ifx_fieldtypes
Dla wyniku zapytania o identyfikatorze $result_id zwraca tablicę asocjacyjną z nazwami pól jako
kluczami i typami pól SQL jako danymi. W przypadku wystąpienia błędu zwraca False.
array ifx_fieldtypes (int result_id)
Przykład: Nazwy i typy pól SQL
types = ifx_fieldtypes ($resultid);
253
PHP – Kompendium wiedzy
if (! isset ($types)) {
... błąd ...
}
for ($i = 0; $i < count($types); $i++) {
$fname = key($types);
printf("%s :\t typ = %s\n", $fname, $types[$fname]);
next($types);
}
ifx_free_blob
Usuwa obiekt blob o podanym identyfikatorze
przeciwnym wypadku True.
$bid.
W przypadku wystąpienia błędu zwraca
False,
w
int ifx_free_blob (int bid)
ifx_free_char
Usuwa obiekt znakowy o podanym identyfikatorze $bid. W przypadku wystąpienia błędu zwraca False, w
przeciwnym wypadku True.
int ifx_free_char (int bid)
ifx_free_result
Dla identyfikatora wyniku $result_id zwalnia zasoby przydzielone dla zapytania. W
przypadku wystąpienia błędu zwraca False.
int ifx_free_result (int bid)
ifx_getsqlca
Zwraca pseudo-wiersz (tablicę asocjacyjną) z wartościami sqlca.sqlerrd[0] ... sqlca.sqlerrd[5] po
skojarzeniu zapytania z $result_id. Parametr $result_id musi być prawidłowym identyfikatorem wyniku
zwracanym przez ifx_query() lub ifx_prepare().
array ifx_getsqlca (int result_id)
Dla zapytań INSERT, UPDATE i DELETE zwracane wartości są ustawiane przez serwer po wykonaniu
zapytania. Pozwala to odczytać ilość wierszy zmienionych przez zapytanie oraz numer kolejny wstawionego
wiersza. W przypadku wyrażeń SELECT, wartości te są ustawiane po wykonaniu operacji PREPARE. Pozwala to na
odczytanie przewidywanej ilości wierszy wyniku. Wykorzystanie tej funkcji pozwala na zmniejszenei narzutu
czasowego na wykonanie zapytania select dbinfo('sqlca.sqlerrdx') i odczytanie wartości zapisanych w
odpowiednim momencie przez sterownik bazy Informix.
Przykład: Odczytywanie wartości sqlca.sqlerrd[x]
/* zakładamy, że pierwsza kolumna 'sometable' jest numerem seryjnym rekordu */
$qid = ifx_query("insert into sometable
values (0, '2nd column', 'another column') ", $connid);
if (! $qid) {
... błąd ...
}
$sqlca = ifx_getsqlca ($qid);
$serial_value = $sqlca["sqlerrd1"];
echo "Numer seryjny wstawionego wiersza wynosi: " . $serial_value<br>\n";
ifx_get_blob
Zwraca zawartość obiektu blob o podanym identyfikatorze obiektu $bid.
int ifx_get_blob (int bid)
ifx_get_char
Zwraca zawartość obiektu znakowego o podanym identyfikatorze obiektu $bid.
int ifx_get_char (int bid)
Dodatek A - Funkcje
254
ifx_htmltbl_result
Zwraca ilość odczytanych wierszy, lub False w przypadku wystąpienia błędu. Formatuje wiersze wyniku
o identyfikatorze $result_id do postaci tabeli HTML. Drugim opcjonalnym parametrem funkcji jest ciąg
atrybutów znacznika <TABLE>.
int ifx_htmltbl_result (int result_id [, string html_table_options])
ifx_nullformat
Ustawia domyślną wartość wartości NULL po odczytaniu wiersza. Tryb 0 powoduje zwracanie "" a tryb 1
zwracanie "NULL".
void ifx_nullformat (int mode)
ifx_num_fields
Zwraca ilość kolumn zapytania o identyfikatorze $result_id lub False w przypadku wystąpienia błędu. Po
przygotowaniu lub wykonaniu zapytania wywołanie to pozwala na odczytanie ilości kolumn w zapytaniu.
int ifx_num_fields (int result_id)
ifx_num_rows
Zwraca ilość wierszy odczytanych do tej pory z wyniku zapytania $result_id, po wykonaniu ifx_query()
lub ifx_do().
int ifx_num_rows (int result_id)
ifx_pconnect
Zwraca dodatni identyfikator trwałego połączenia do serwera Informix lub False w przypadku wystąpienia
błędu. Funkcja ifx_pconnect() działa bardzo podobnie do ifx_connect() z dwoma wyjątkami. Funkcja działa
identycznie jak ifx_connect(), jeżeli PHP nie działa jako moduł Apache. Po pierwsze, w czasie połączenia
funkcja próbuje znaleźć łącze (trwałe) otwarte do tego samego serwera z identycznym użytkownikiem i hasłem.
Jeżeli zostanie znalezione takie połączenie, zamiast otwierania nowego połączenia, zwracany jest identyfikator
istniejącego połączenia. Po drugie, połączenie z serwerem SQL nie jest zamykane po zakończeniu wykonywania
skryptu. Zamiast tego łącze pozostanie otwarte do wykorzystania w przyszłości (ifx_close() nie zamyka łączy
zestawionych za pomocą ifx_pconnect()). Z tego powodu ten typ łącza nazywany jest trwałym. Patrz również:
ifx_connect().
int ifx_pconnect ([string database [, string userid [, string password]]])
ifx_query
Zwraca identyfikator wyniku lub w przypadku wystąpienia błędu wartość False. Identyfikator ten jest
używany przez inne funkcje do pobrania wyników działania zapytania. Ustawia jest wartość określająca ilość
wierszy zwracanych przez zapytanie, którą można odczytać przez wywołanie ifx_affected_rows(). Funkcja
ifx_query() wysyła zapytanie do bazy danych określanej przez podany identyfikator połączenia. Jeżeli nie
zostanie podany identyfikator połączenia, operacja jest wykonywana na ostatnio otwartym połączeniu. Jeżeli nie
istnieje otwarte połączenie, funkcja próbuje je ustanowić, identycznie jak funkcja ifx_connect() i następnie
wykorzystuje to połączenie. Wykonuje zapytanie $query na połączeniu $conn_id. W przypadku zapytań SELECT
deklarowany i otwierany jest kursor. Opcjonalny parametr $cursor_type pozwala na utworzenie kursora typu
SCROLL lub (oraz) HOLD. Jest to maska bitowa, która może przyjmować wartości IFX_SCROLL, IFX_HOLD lub
jednocześnie obie wartości. Zapytania inne niż SELECT wykonywane są w trybie natychmiastowym. IFX_SCROLL i
IFX_HOLD są stałymi symbolicznymi i nie należy ich zapisywać w apostrofach. Jeżeli nie podasz tego parametru,
otwierany jest zwykły kursor sekwencyjny. Dla dowolnego typu zapytania zapamiętywana jest ilość wierszy
będących wynikiem zapytania (rzeczywista lub szacowana), którą można odczytać za pomocą funkcji
ifx_affected_rows().
int ifx_query (string query [, int link_identifier [, int cursor_type,
255
PHP – Kompendium wiedzy
mixed [blobidarray]]])
Jeżeli w zapytaniu UPDATE występuje kolumna BLOB (BYTE lub TEXT), można dodać parametr $blobidarray,
zawierający odpowiednie identyfikatory blob, i powinieneś zamienić te kolumny znakiem ? w tekście zapytania.
Jeżeli zawartość kolumny TEXT (lub BYTE) pozwala na to, można wywołać funkcje ifx_textasvarchar(1) i
ifx_byteasvarchar(1). Pozwoli to na traktowanie kolumn TEXT (lub BYTE) w zapytaniach SELECT, tak, jakby była
to zwykła (choć długa) kolumna VARCHAR, i nie przejmować się identyfikatorami obiektów blob. Wywołując
ifx_textasvarchar(0) i ifx_byteasvarchar(0) (domyślna sytuacja) zapytania SELECT kolumny BLOB będą
zwracane jako identyfikatory obiektów blob (wartości numeryczne). Mając taki identyfikator można pobrać
zawartość kolumny BLOB za pomocą funkcji obsługujących bloby. Patrz również: ifx_connect().
Przykład: Wyświetlenie wszystkich wierszy tabeli orders jako tabeli html
ifx_textasvarchar(1);
// użycie "trybu tekstowego" do blobów
$res_id = ifx_query("select * from orders", $conn_id);
if (! $res_id) {
printf("Nie można wykonać zapytania : %s\n<br>%s<br>\n", ifx_error());
ifx_errormsg();
die;
}
ifx_htmltbl_result($res_id, "border=\"1\"");
ifx_free_result($res_id);
Przykład: Wstawienie kilku wierszy do tabeli catalog
// utworzenie identyfikatorów blobów dla kolunm byte i text
$textid = ifx_create_blob(0, 0, "Kolumna Text w pamięci!");
$byteid = ifx_create_blob(1, 0, "Kolumna Byte w pamięci");
// zapamiętanie identyfikatorów blob w tablicy blobid
$blobidarray[] = $textid;
$blobidarray[] = $byteid;
// wykonanie zapytania
$query = "insert into catalog (stock_num, manu_code, " .
"cat_descr,cat_picture) values(1,'HRO',?,?)";
$res_id = ifx_query($query, $conn_id, $blobidarray);
if (! $res_id) {
... błąd ...
}
// zwonienie identyfikatora wyniku
ifx_free_result($res_id);
ifx_textasvarchar
Ustawia domyślny tryb tekstowy dla zapytań SELECT. Tryb
natomiast tryb 1 powoduje zwracanie zawartości jako tekstu.
0
powoduje zwracanie identyfikatorów blob,
void ifx_textasvarchar (int mode)
ifx_update_blob
Uaktualnia zawartość obiektu blob dla podanego identyfikatora $bid. Parametr $content jest ciągiem
zawierającym nowe dane. Zwraca False w przypadku błędu a w przeciwnym przypadku True.
ifx_update_blob (int bid, string content)
ifx_update_char
Uaktualnia zawartość obiektu znakowego dla podanego identyfikatora $bid. Parametr $content jest
ciągiem zawierającym nowe dane. Zwraca False w przypadku błędu a w przeciwnym przypadku True.
ifx_update_char (int bid, string content)
ignore_user_abort
Funkcja ta ustawia znacznik, czy klient może spowodować przerwanie wykonywania skryptu. Zwraca
wcześniejsze ustawienie i może być wywołana bez argumentów w celu sprawdzenia bieżącego ustawienia, bez
jego zmiany.
int ignore_user_abort ([int setting])
Dodatek A - Funkcje
256
ImageArc
Rysuje fragment elipsy o środku o współrzędnych $cx, $cy (lewy górny róg to 0,0) na rysunku
reprezentowanym przez $im. Parametry $w i $h określają szerokość i wysokość elipsy, natomiast punkty
początkowe i końcowe są określane w stopniach podawanych w argumentach $s i $e.
int ImageArc (int im, int cx, int cy, int w, int h, int s, int e, int col)
ImageChar
Rysuje pierwszy znak w $c na rysunku określonym przez $id. Lewy górny róg litery znajduje się na
współrzędnych $x, $y (lewy górny róg to 0,0), kolor to $col. Jeżeli $font jest 1, 2, 3, 4 lub 5, używane są
wbudowane czcionki (największa liczba reprezentuje największą czcionkę). Patrz również imageloadfont().
int ImageChar (int im, int font, int x, int y, string c, int col)
ImageCharUp
Rysuje pionowo pierwszy znak w $c na rysunku określonym przez $id. Lewy górny róg litery znajduje się
na współrzędnych $x, $y (lewy górny róg to 0,0), kolor to $col. Jeżeli $font jest 1, 2, 3, 4 lub 5, używane są
wbudowane czcionki (największa liczba reprezentuje największą czcionkę). Patrz również imageloadfont().
int ImageCharUp (int im, int font, int x, int y, string c, int col)
ImageColorAllocate
Zwraca identyfikator koloru reprezentujący kolor stworzony z podanych składników RGB. Argument $im
jest wynikiem funkcji imagecreate(). Funkcja ImageColorAllocate() musi być wywołana do stworzenia każdego
koloru, który będzie używany na rysunku $im.
int imagecolorallocate (int im, int red, int green, int blue)
Przykład
$white = ImageColorAllocate ($im, 255, 255, 255);
$black = ImageColorAllocate ($im, 0, 0, 0);
ImageColorAt
Zwraca indeks koloru piksela o podanych współrzędnych. Patrz również:
ImageColorsForIndex().
ImageColorSet()
i
int imagecolorat (int im, int x, int y)
ImageColorClosest
Zwraca indeks koloru, w palecie kolorów rysunku, który jest najbliższy podanej wartości RGB. Odległość
od żądanego koloru i kolorów istniejących w palecie jest obliczana tak, jakby wartości RGB reprezentowały
punkty w przestrzeni trójwymiarowej. Patrz również: ImageColorExact().
int imagecolorclosest (int im, int red, int green, int blue)
ImageColorDeAllocate
Usuwa kolor poprzednio utworzony za pomocą funkcji ImageColorAllocate().
int imagecolordeallocate (int im, int index)
Przykład:
$white = ImageColorAllocate($im, 255, 255, 255);
ImageColorDeAllocate($im, $white);
ImageColorExact
Zwraca indeks podanego koloru w palecie kolorów rysunku. Jeżeli kolor nie występuje w palecie,
zwracana jest wartość -1. Patrz również: ImageColorClosest().
int imagecolorexact (int im, int red, int green, int blue)
257
PHP – Kompendium wiedzy
ImageColorResolve
Funkcja gwarantuje zwrócenie indeksu dla podanego koloru. Będzie to dokładnie identyczny kolor lub
najbliższy mu podobny. Patrz również: ImageColorClosest().
int imagecolorresolve (int im, int red, int green, int blue)
ImageColorSet
Ustawia indeks w palecie kolorów na podany kolor. Jest to przydatne do tworzenia efektów wypełniania
za pomocą palety, bez potrzeby wykonywania wypełniania. Patrz również: ImageColorAt().
bool imagecolorset (int im, int index, int red, int green, int blue)
ImageColorsForIndex
Zwraca tablicę asocjacyjną z kluczami red, green i blue, które zawierają odpowiednie wartości dla
podanego indeksu koloru. Patrz również: ImageColorAt() i ImageColorExact().
array imagecolorsforindex (int im, int index)
ImageColorsTransparent
Ustawia kolor przezroczysty w rysunku $im na $col. Parametr $im jest identyfikatorem zwracanym przez
natomiast $col jest identyfikatorem koloru zwracanym przez ImageColorAllocate(). Zwracany
jest identyfikator nowego (lub bieżącego, jeżeli nie podano nowego koloru) koloru przezroczystego.
ImageCreate(),
int imagecolortransparent (int im [, int col])
ImageCopy
Kopiuje fragment rysunku $src_im do $dst_im, rozpoczynając od współrzędnych $src_x, $src_y o
szerokości $src_w i wysokości $src_h. Zdefiniowany fragment jest kopiowany do docelowego rysunku na
współrzędne $dst_x i $dst_y.
int ImageCopy (resource dst_im, resource src_im, int dst_x, int dst_y,
int src_x, int src_y, int src_w, int src_h)
ImageCopyResized
Kopiuje prostokątny fragment rysunku do innego rysunku. Parametr $dst_im jest docelowym rysunkiem,
natomiast $src_im to identyfikator rysunku źródłowego. Jeżeli współrzędne źródła i celu oraz szerokość i
wysokość różnią się, stosowane jest odpowiednie przeskalowanie kopiowanego fragmentu. Współrzędne
wskazują na lewy górny róg. Funkcja może być używana do kopiowania obszarów tego samego rysunku (jeżeli
$dst_im jest taki sam jak $src_im), ale gdy obszary te nachodzą na siebie, wyniki są nieprzewidywalne.
int ImageCopyResized (resource dst_im, resource src_im, int dstX, int dstY,
int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
ImageCreate
Zwraca identyfikator rysunku wskazujący na pusty rysunek o rozmiarze $x_size na $y_size.
int imagecreate (int x_size, int y_size)
Przykład: Tworzenie nowego strumienia rysunku GD i tworzenie rysunku.
<?php
header ("Content-type: image/png");
$im = @ImageCreate (50, 100)
or die ("Nie można zainicjować nowego strumienia rysunku GD");
$background_color = ImageColorAllocate ($im, 255, 255, 255);
$text_color = ImageColorAllocate ($im, 233, 14, 91);
ImageString ($im, 1, 5, 5, "Prosty tekst przykładowy", $text_color);
ImagePng ($im);
?>
Dodatek A - Funkcje
258
ImageCreateFromGif
Zwraca identyfikator rysunku reprezentujący rysunek pobrany z pliku o podanej nazwie. Funkcja
ImageCreateFromGif() w przypadku wystąpienia błędu zwraca pusty ciąg. Wyświetla również komunikat błędu,
ale niestety jest on wyświetlany w przeglądarce jako nieprawidłowe łącze. Aby ułatwić uruchamianie można
zastosować poniższy przykład, który tworzy rysunek GIF z komunikatem błędu.
int ImageCreateFromGif (string filename)
Przykład: Obsługa błędu w czasie tworzenia rysunku (podziękowania dla [email protected])
function LoadGif ($imgname) {
$im = @ImageCreateFromGIF ($imgname); /* Próba otwarcia */
if (!$im) { /* Jeżeli się nie udało */
$im = ImageCreate (150, 30); /* Tworzenie pustego rysunku */
$bgc = ImageColorAllocate ($im, 255, 255, 255);
$tc = ImageColorAllocate ($im, 0, 0, 0);
ImageFilledRectangle ($im, 0, 0, 150, 30, $bgc);
/* Wyświetlenie komunikatu błędu */
ImageString($im, 1, 5, 5, "Błąd przy ładowaniu $imgname", $tc);
}
return $im;
}
Uwaga
Ponieważ obsługa GIF została usunięta z biblioteki GD od wersji 1.6 funkcja ta nie jest już dostępna.
ImageCreateFromJPEG
Zwraca identyfikator rysunku reprezentujący rysunek pobrany z pliku o podanej nazwie. Funkcja
w przypadku wystąpienia błędu zwraca pusty ciąg. Wyświetla również komunikat błędu,
ale niestety jest on wyświetlany w przeglądarce jako nieprawidłowe łącze. Aby ułatwić uruchamianie można
zastosować poniższy przykład, który tworzy rysunek JPEG z komunikatem błędu.
ImageCreateFromJPEG()
int ImageCreateFromJPEG (string filename)
Przykład: Obsługa błędu w czasie tworzenia rysunku (podziękowania dla [email protected])
function LoadJPEG ($imgname) {
$im = @ImageCreateFromJPEG ($imgname); /* Próba otwarcia */
if (!$im) { /* Jeżeli się nie udało */
$im = ImageCreate (150, 30); /* Tworzenie pustego rysunku */
$bgc = ImageColorAllocate ($im, 255, 255, 255);
$tc = ImageColorAllocate ($im, 0, 0, 0);
ImageFilledRectangle ($im, 0, 0, 150, 30, $bgc);
/* Wyświetlenie komunikatu błędu */
ImageString($im, 1, 5, 5, "Błąd przy ładowaniu $imgname", $tc);
}
return $im;
}
ImageCreateFromPNG
Zwraca identyfikator rysunku reprezentujący rysunek pobrany z pliku o podanej nazwie. Funkcja
w przypadku wystąpienia błędu zwraca pusty ciąg. Wyświetla również komunikat błędu,
ale niestety jest on wyświetlany w przeglądarce jako nieprawidłowe łącze. Aby ułatwić uruchamianie można
zastosować poniższy przykład, który tworzy rysunek PNG z komunikatem błędu.
Przykład: Obsługa błędu w czasie tworzenia rysunku (podziękowania dla [email protected])
ImageCreateFromPNG()
function LoadPNG ($imgname) {
$im = @ImageCreateFromPNG ($imgname); /* Próba otwarcia */
if (!$im) { /* Jeżeli się nie udało */
$im = ImageCreate (150, 30); /* Tworzenie pustego rysunku */
$bgc = ImageColorAllocate ($im, 255, 255, 255);
$tc = ImageColorAllocate ($im, 0, 0, 0);
ImageFilledRectangle ($im, 0, 0, 150, 30, $bgc);
/* Wyświetlenie komunikatu błędu */
ImageString($im, 1, 5, 5, "Błąd przy ładowaniu $imgname", $tc);
}
return $im;
}
259
PHP – Kompendium wiedzy
ImageDashedLine
Rysuje na rysunku $im linię przerywaną z
Patrz również: ImageLine().
$x1, $y1
do
$x2, $y2
(lewy górny róg to 0,0) o kolorze
$col.
int imagedashedline (int im, int x1, int y1, int x2, int y2, int col)
ImageDestroy
Zwalnia pamięć zajętą przez rysunek $im. Parametr $im jest identyfikatorem rysunku zwracanym przez
funkcję ImageCreate().
int imagedestroy (int im)
ImageFill
Wykonuje wypełnianie metodą zalewania (flood fill) rysunku
(lewy górny róg to 0,0) kolorem $col.
$im
rozpoczynając od współrzędnych $x,
$y
int imagefill (int im, int x, int y, int col)
ImageFilledPolygon
Tworzy wypełniony wielobok na rysunku $im. Parametr $points jest tablicą PHP zawierającą wierzchołki
wieloboku, to znaczy $points[0] = x0, $points[1] = y0, $points[2] = x1, $points[3] = y1 i tak dalej. Parametr
$num_points zawiera całkowitą ilość wierzchołków.
int imagefilledpolygon (int im, array points, int num_points, int col)
ImageFilledRectangle
Na rysunku $im tworzy wypełniony prostokąt o kolorze $col, rozpoczynając od górnego lewego rogu o
współrzędnych $x1, $y1, kończąc na prawym dolnym rogu o współrzędnych $x2, $y2. Lewy górny róg rysunku ma
współrzędne 0,0.
int imagefilledrectangle (int im, int x1, int y1, int x2, int y2, int col)
ImageFillToBorder
Wypełnia na rysunku obszar ograniczony kolorem zdefiniowanym w parametrze
rozpoczęcia wypełniania to $x, $y (lewy górny róg to 0,0), kolor wypełnienia to $col.
$border.
Punkt
int imagefilltoborder (int im, int x, int y, int border, int col)
ImageFontHeight
Zwraca wysokość znaku w pikselach dla określonej czcionki. Patrz również:
ImageFontWidth()
i
ImageFontHeiht()
i
ImageLoadFont().
int imagefontheight (int font)
ImageFontWidth
Zwraca szerokość znaku w pikselach dla określonej czcionki. Patrz również:
ImageLoadFont().
int ImageFontWidth (int font)
ImageGammaCorrect
Stosuje korekcję gamma na rysunku $im na podstawie wartości gamma wejściowej
wyjściowej $outputgamma.
$inputgamma
i
int imagegammacorrect (int im, float inputgamma, float outputgamma)
Dodatek A - Funkcje
260
ImageGIF
Tworzy plik GIF na podstawie rysunku $im. Parametr $im jest identyfikatorem zwracanym przez funkcję
ImageCreate(). Rysunek zostanie zapisany w formacie GIF87a chyba, że rysunek będzie zawierał kolor
przezroczysty stworzony za pomocą funkcji ImageColorTransparent(). W takim przypadku formatem pliku
będzie GIF89a. Nazwa pliku jest opcjonalna, jeżeli zostanie pominięta, utworzony zostanie bezpośredni surowy
strumień rysunku. Wysyłając za pomocą funkcji header() typ zawartości image/gif, można stworzyć skrypt PHP,
który bezpośrednio wysyła do przeglądarki rysunki GIF.
Uwaga
Ponieważ obsługa GIF została usunięta z biblioteki GD od wersji 1.6 funkcja ta nie jest już dostępna.
int imagegif (int im [, string filename])
ImageInterlace
Ustawia i kasuje bit przeplotu. Jeżeli $interlace jest równy 1, rysunek będzie z przeplotem. Jeżeli
jest 0, przeplot nie zostanie zastosowany. Funkcja zwraca bieżącą wartość bitu przeplotu dla rysunku.
$interlace
int imageinterlace (int im [, int interlace])
ImageJPEG
Tworzy plik JPEG na podstawie rysunku $im. Parametr $im jest identyfikatorem zwracanym przez funkcję
Nazwa pliku jest opcjonalna, jeżeli zostanie pominięta, utworzony zostanie bezpośredni surowy
strumień rysunku. Aby opuścić nazwę pliku i jednocześnie podać wartość parametru $quality należy użyć
pustego ciągu (""). Wysyłając za pomocą funkcji header() typ zawartości image/jpeg, można stworzyć skrypt
PHP, który bezpośrednio wysyła do przeglądarki rysunki JPEG.
ImageCreate().
Uwaga
Obsługa formatu JPEG jest dostępna jedynie, jeżeli biblioteka GD jest w wersji 1.8 lub nowszej.
int imagejpeg (int im [, string filename [, int quality]])
ImageLine
Na rysunku $im rysuje linię od $x1, $y1 do $x2, $y2 (lewy górny róg to 0,0) o kolorze $col. Patrz również:
ImageCreate() i ImageColorAllocate().
int imageline (int im, int x1, int y1, int x2, int y2, int col)
ImageLoadFont
Ładuje czcionkę bitmapową zdefiniowaną przez użytkownika i zwraca identyfikator czcionki (zawsze
większy od 5, więc nie koliduje z wbudowanymi czcionkami). Format pliku jest obecnie binarny, zależny od
architektury. Oznacza to, że należy generować pliki czcionek na komputerze z takim samym procesorem, co
komputer na którym jest uruchomione PHP. Format pliku jest następujący:
Pozycja
Typ
Opis
w bajtach
danych C
0 — 3
int
Ilość znaków w pliku czcionek
4 —7
int
Wartość pierwszego znaku czcionki (często 32 dla spacji)
8 — 11
int
Szerokość każdego znaku w pikselach
12 — 15
int
Wysokość każdego znaku w pikselach
16
—
char
Tablica danych znakowych, jeden bajt na piksel w każdym
xxx
znaku, razem (znaki*szerokość*wyskokość) bajtów
Patrz również: ImageFontWidth() i ImageFontHeight().
261
PHP – Kompendium wiedzy
int imageloadfont (string file)
ImagePNG
Otwiera strumień GD ($im) w formacie PNG i przesyła dane do standardowego wyjścia (zwykle jest to
przeglądarka), lub jeżeli podana jest nazwa pliku $filename, zapisuje rysunek do pliku.
int imagepng (int im [, string filename])
Przykład:
<?php
$im = ImageCreateFromPng("test.png");
ImagePng($im);
?>
ImagePolygon
Tworzy wielobok na rysunku $im. Parametr $points jest tablicą PHP zawierającą wierzchołki wieloboku
to znaczy $points[0] = x0, $points[1] = y0, $points[2] = x1, $points[3] = y1 i tak dalej. Parametr
$num_points zawiera całkowitą ilość wierzchołków. Patrz również: ImageCreate().
int imagepolygon (int im, array points, int num_points, int col)
ImagePSBBox
Parametr $size jest wyrażony w pikselach, $space pozwala zmienić domyślna wartość odstępu w
czcionkach. Wartość ta jest dodawana do standardowej wartości odstępu i może być ujemna. Parametr $tightness
pozwala kontrolować ilość światła pomiędzy literami. Wartość ta jest dodawana do normalnej szerokości znaku i
może również być ujemna. Parametr $angle jest wyrażony w stopniach. Parametry $space i $tightness są
podawane w jednostkach odstępu znaku, gdzie 1 jednostka odstępu jest 1/1000 pica do kwadratu. Parametry
$space, $tightness i $angle są opcjonalne. Ramka ograniczająca jest wyliczana z wykorzystaniem dostępnych
danych z metryki czcionki i niestety nieco różni się od wyników otrzymywanych przez rasteryzację tekstu. Jeżeli
kąt wynosi 0, należy się spodziewać, że tekst będzie potrzebował o 1 piksel więcej w każdym kierunku. Funkcja
zwraca tablicę zawierającą następujące elementy: 0 — lewa dolna współrzędna x, 1 — lewa dolna współrzędna y,
2 — prawa górna współrzędna x i 3 — prawa górna współrzędna y. Patrz również: ImagePSText().
array ImagePSBBox (string text, int font, int size [, int space [, int tightness
[, float angle]]])
ImagePSEncodeFont
Ładuje z pliku wektor kodowania znaków i zmienia na niego istniejący wektor kodowania czcionki.
Ponieważ w czcionkach PostScript wektor kodowania nie zawiera wielu znaków na pozycjach powyżej 127,
prawie na pewno musisz zmienić wektor kodowania w przypadku wykorzystywania języków innych niż
angielski. Dokładny format pliku jest opisany w dokumentacji T1lib. T1lib zawiera dwa gotowe do użycia pliki,
IsoLatin1.enc i IsoLatin2.enc. Jeżeli chcesz cały czas wykorzystywać tą funkcję, lepszym sposobem na
zdefiniowanie kodowania jest ustawienie w pliku konfiguracyjnym zmiennej ps.default_encoding na odpowiedni
plik kodowania. Wszystkie załadowane przez użytkownika czcionki będą miały odpowiednio zdefiniowane
kodowanie.
int imagepsencodefont (int font_index, string encodingfile)
ImagePsExtendfont
Powiększa lub zmniejsza czcionkę $font_index. Jeżeli wartość parametru $extend jest mniejsza od jeden,
funkcja zmniejsza czcionkę.
bool imagepsextendfont (int font_index, float extend)
ImagePSFreeFont
Patrz również: ImagePSLoadFont().
void imagepsfreefont (int fontindex)
Dodatek A - Funkcje
262
ImagePSLoadFont
Jeżeli wszystko odbędzie się bez błędów, funkcja zwraca prawidłowy indeks czcionki, który może być
użyty do innych celów. Jeżeli coś się nie powiedzie, funkcja zwraca False i drukuje komunikat opisujący błąd.
Patrz również: ImagePSFreeFont().
int ImagePSLoadFont (string filename)
ImagePsSlantFont
Pochyla czcionkę wskazywaną przez parametr $font_index o wartość przekazaną w parametrze $slant.
bool imagepsslantfont (int font_index, float slant)
ImagePSText
Parametr $size jest wyrażony w pikselach. Parametr $foreground jest kolorem jakim zostanie
namalowany tekst, natomiast $background to kolor na który tekst będzie się zmieniał przy zastosowaniu
wygładzania (antialiasing). Nie są rysowane żadne punkty w kolorze $background, więc tło nie będzie
zamalowane. Współrzędne przekazane w $x, $y definiują początek (punkt odniesienia) pierwszego znaku (mniej
więcej lewy dolny róg znaku). Funkcja różni się tym od ImageString(), gdzie $x, $y określają lewy górny róg
pierwszego znaku. Jeżeli potrzebujesz bliższych informacji na temat czcionek i systemu miar, znajdują się w
dokumentacji PostScript.
array imagepstext (int image, string text, int font, int size, int foreground,
int background, int x, int y [, int space [, int tightness
[, float angle [, int antialias_steps]]]])
Parametr $space pozwala na zmianę domyślnego odstępu w czcionce. Wartość ta jest dodawana do
normalnej wartości, więc może być ujemna. Parametr $tightness powala na kontrolowanie ilości światła
pomiędzy literami. Wartość ta jest dodawana do normalnej szerokości znaki i również może być ujemna. Wartość
$angle podawana jest w stopniach. Parametr $antialiasing_steps pozwala na określanie ilości kolorów użytych
do wygładzania tekstu. Dopuszczalnymi wartościami są 4 i 16. Wyższa wartość jest polecana dla tekstów o
rozmiarze mniejszych od 20, gdzie wygładzanie mocno wpływa na jakość tekstu. W przypadku większych
czcionek można użyć wartości 4, ponieważ potrzeba wtedy mniej obliczeń. Parametry $space i $tightness są
wyrażane w jednostkach odstępu znaku, gdzie 1 jednostka odstępu jest 1/1000 pica do kwadratu. Parametry
$space, $tightness, $angle i $antialias są opcjonalne. Funkcja zwraca tablicę zawierającą następujące elementy:
0 — lewa dolna współrzędna x, 1 — lewa dolna współrzędna y, 2 — prawa górna współrzędna x i 3 — prawa
górna współrzędna y. Patrz również: ImagePSBBox().
ImageRectangle
Na rysunku $im tworzy prostokąt w kolorze $col o współrzędnych lewego górnego rogu
prawego dolnego $x2, $y2. Lewy górny róg rysunku ma współrzędne 0,0.
$x1, $y1
i
int ImageRectangle (int im, int x1, int y1, int x2, int y2, int col)
ImageSetPixel
Rysuje na rysunku $im piksel w kolorze
również: ImageCreate() i ImageColorAllocate().
$col
na współrzędnych
$x, $y
(lewy górny róg to 0,0). Patrz
int ImageSetPixel (int im, int x, int y, int col)
ImageString
Na rysunku $im rysuje ciąg $s rozpoczynając od współrzędnych $x, $y (lewy górny róg to 0,0) w kolorze
$col. Jeżeli $font wynosi 1, 2, 3, 4 lub 5, używane są wbudowane czcionki. Patrz również: ImageLoadFont().
int ImageString (int im, int font, int x, int y, string s, int col)
263
PHP – Kompendium wiedzy
ImageStringUp
Na rysunku $im rysuje pionowo ciąg $s rozpoczynając od współrzędnych $x, $y (lewy górny róg to 0,0) w
kolorze $col. Jeżeli $font wynosi 1, 2, 3, 4 lub 5, używane są wbudowane czcionki. Patrz również:
ImageLoadFont().
int ImageStringUp (int im, int font, int x, int y, string s, int col)
ImageSX
Zwraca szerokość rysunku identyfikowanego przez $im. Patrz również: ImageCreate() i ImageSY().
int ImageSX (int im)
ImageSY
Zwraca wysokość rysunku identyfikowanego przez $im. Patrz również: ImageCreate() i ImageSX().
int ImageSY (int im)
ImageTTFBBox
Funkcja oblicza i zwraca ramkę otaczającą tekst TrueType (w pikselach). Parametr $text jest ciągiem do
zmierzenia. Parametr $size jest wielkością czcionki, $fontfile jest nazwą pliku z czcionką TrueType (może być
w postaci URL). $angle jest kątem pochylenia tekstu $text w stopniach. Funkcja ImageTTFBBox() zwraca tablicę
składająca się z ośmiu elementów reprezentujących cztery punkty tworzące ramkę otaczającą tekst: 0 —
współrzędna X lewego dolnego rogu, 1 — współrzędna Y lewego dolnego rogu, 2 — współrzędna X prawego
dolnego rogu, 3 — współrzędna Y prawego dolnego rogu, 4 — współrzędna X prawego górnego rogu, 5 —
współrzędna Y prawego górnego rogu, 6 — współrzędna X lewego górnego rogu, 7 — współrzędna Y lewego
górnego rogu. Punkty te są niezależne od pochylenia tekstu, więc „lewy górny” oznacza górny wierzchołek po
lewej stronie, patrząc na tekst poziomo. Funkcja wymaga bibliotek GD i FreeType. Patrz również:
ImageTTFText().
array imagettfbbox (int size, int angle, string fontfile, string text)
ImageTTFText
Na rysunku $im rysuje ciąg $text, rozpoczynając od współrzędnych $x, $y (lewy górny róg to 0,0), pod
kątem $angle w kolorze $col, za pomocą czcionki TrueType umieszczonej w pliku $fontfile. Współrzędne
podane w $x, $y określają punkt bazowy pierwszego znaku (mniej więcej lewy dolny róg znaku). Różni się to od
funkcji ImageString(), gdzie x, y określają prawy górny róg pierwszego znaku. Parametr $angle jest wyrażony w
stopniach, gdzie 0 stopni określa tekst czytany z lewej do prawej (kierunek na godzinę trzecią), natomiast wyższe
wartości reprezentują pochylenie w kierunku przeciwnym do ruchu wskazówek zegara. (wartość 90 powoduje
narysowanie tekstu od góry do dołu). Parametr $fontflile jest ścieżką do pliku TrueType z używaną czcionką.
Parametr $text jest ciągiem tekstowym, który może zawierać sekwencje znaków UTF-8 (w postaci :{) używane
do stosowania znaków o kodach powyżej 255. $col jest indeksem koloru. Użycie ujemnego indeksu koloru
powoduje wyłączenie wygładzania tekstu. Funkcja ImageTTFText() zwraca tablicę ośmioelementową
reprezentującą cztery punkty stanowiące ramkę ograniczającą tekst. Punkty te są umieszczone w tablicy w
kolejności lewy górny, prawy górny, prawy dolny i lewy dolny. Punkty te są niezależne od pochylenia tekstu,
więc „lewy górny” oznacza górny wierzchołek po lewej stronie, patrząc na tekst poziomo.
array imagettftext (int im, int size, int angle, int x, int y, int col,
string fontfile, string text)
Przykład: ImageTTFText
<?php
Header ("Content-type: image/gif");
$im = imagecreate (400, 30);
$black = ImageColorAllocate ($im, 0, 0, 0);
$white = ImageColorAllocate ($im, 255, 255, 255);
ImageTTFText ($im, 20, 0, 10, 20, $white, "/path/arial.ttf",
"Testowanie... Omega: &#937;");
ImageGif ($im);
ImageDestroy ($im);
Dodatek A - Funkcje
264
?>
Funkcja wymaga bibliotek GD i FreeType. Patrz również: ImageTTFBox().
ImageTypes
Funkcja zwraca maskę bitową związaną z formatami rysunków obsługiwanych przez bibliotekę GD
dołączoną do PHP. Zwracane są następujące bity: IMG_GIF | IMG_JPG | IMG_PNG | IMG_WBMP.
int imagetypes (void)
Przykład: ImageTypes
<?php
if (ImageTypes() & IMG_PNG) {
echo "Obsługa PNG jest aktywna";
}
?>
imap_8bit
Konwertuje ciąg 8-bitowy na ciąg quoted-printable (zgodnie z RFC2045, sekcja 6.7). Zwraca ciąg quotedprintable. Patrz również imap_qprint().
string imap_8bit (string string)
imap_alerts
Zwraca tablicę wszystkich komunikatów ostrzeżeń IMAP wygenerowanych od ostatniego wywołania
lub od początku strony. Gdy zostanie wywołana funkcja imap_alerts(), stos ostrzeżeń jest
czyszczony. Specyfikacja IMAP wymaga, aby komunikaty te były pokazywane użytkownikowi.
imap_alerts(),
array imap_alerts (void)
imap_append
Zwraca True w przypadku powodzenia i False w przypadku błędu. Funkcja dołącza ciąg komunikatu do
skrzynki pocztowej $mbox. Jeżeli podane zostały opcjonalne znaczniki $flags, funkcja dołącza również do
skrzynki te znaczniki. Działając na serwerze Cyrus IMAP, trzeba użyć terminatorów linii „\r\n” zamiast „\n”, lub
operacja się nie powiedzie.
int imap_append (int imap_stream, string mbox, string message [, string flags])
Przykład: imap_append()
$stream = imap_open("{your.imap.host}INBOX.Drafts","username", "password");
$check = imap_check($stream);
print "Ilość komunikatów przed dołączeniem: ". $check->Nmsgs."\n";
imap_append($stream,"{your.imap.host}INBOX.Drafts"
,"From: [email protected]\r\n"
."To: [email protected]\r\n"
."Subject: test\r\n"
."\r\n"
."przesyłka testowa, proszę zignorować\r\n"
);
$check = imap_check($stream);
print "Ilość komunikatów po dołączeniu : ". $check->Nmsgs."\n";
imap_close($stream);
imap_base64
Dekoduje tekst zakodowany metodą BASE-64 (patrz RFC2045, sekcja 6.8). Zdekodowany komunikat jest
zwracany w postaci ciągu. Patrz również: imap_binary().
string imap_base64 (string text)
265
PHP – Kompendium wiedzy
imap_binary
Konwertuje 8-bitowy ciąg na ciąg zakodowany metodą BASE-64 (zgodnie z RFC2045, sekcja 6.8).
Zwraca ciąg base64. Patrz również: imap_base64().
string imap_binary (string string)
imap_body
Zwraca treść przesyłki o numerze $msg_number z bieżącej skrzynki pocztowej. Opcjonalny parametr
jest maską bitową zawierającą jedną lub więcej wartości:
• FT_UID — Wartość $msgno jest idnetyfikatorem UID
• FT_PEEK — Nie ustawia znacznika \Seen, jeżeli jest już ustawiony
• FT_INTERNAL — Zwracany ciąg jest w formacie wewnętrznym
Funkcja imap_body() zwraca dosłowną kopię treści przesyłki. Aby odczytać jeden fragment
wieloczęściowej przesyłki kodowanej za pomocą MIME należy użyć funkcji imap_fetch_structure() do
zanalizowania struktury i imap_fetch_body() do skopiowania pojedynczego komponentu przesyłki.
$flags
string imap_body (int imap_stream, int msg_number [, int flags])
imap_check
Zwraca dane na temat bieżącej skrzynki pocztowej. W przypadku błędu zwraca False. Funkcja
imap_check() sprawdza status bieżącej skrzynki na serwerze i zwraca dane w postaci obiektu o następujących
właściwościach:
• Date — ostatnia zmiana zawartości skrzynki
• Driver — protokół używany do komunikacji ze skrzynką: POP3, IMAP, NNTP
• Mailbox — nazwa skrzynki pocztowej
• Nmsgs — ilość przesyłek w skrzynce
• Recent — ilość nowych przesyłek w skrzynce
object imap_check (int imap_stream)
imap_clearflag_full
Funkcja powoduje usunięcie określonego znacznika ze zbioru znaczników przesyłki w określonej
sekwencji. Znacznikami do usuwania są: \\Seen, \\Answered, \\Flagged, \\Deleted, \\Draft i \\Recent (według
RFC2060). Parametr $options jest maską bitową składającą się z następujących znaczników: ST_UID, sekwencja
argumentów zawierająca UID zamiast numerów sekwencji.
string imap_clearflag_full (int stream, string sequence, string flag, string options)
imap_close
Zamyka strumień imap. Posiada opcjonalny parametr $flag CL_EXPUNGE, który powoduje
wyczyszczenie skrzynki przed zamknięciem poprzez usunięcie przesyłek zaznaczonych jako usunięte.
int imap_close (int imap_stream [, int flags])
imap_createmailbox
Tworzy nową skrzynkę pocztową o nazwie $mbox. Nazwy zawierające znaki narodowe powinny być
zakodowane przy pomocy funkcji imap_utf7_encode(). Zwraca True w przypadku powodzenia lub False w
przypadku wystąpienia błędu. Patrz również: imap_renamemailbox(), imap_deletemailbox() i imap_open() gdzie
znajduje się opis formatów nazw $mbox.
int imap_createmailbox (int imap_stream, string mbox)
Przykład: imap_createmailbox()
$mbox = imap_open("{your.imap.host}","username","password",OP_HALFOPEN)
or die("nie można połączyć: ".imap_last_error());
$name1 = "phpnewbox";
Dodatek A - Funkcje
266
$name2 = imap_utf7_encode("phpnewböx");
$newname = $name1;
echo "Nową nazwą będzie '$name1'<br>\n";
# tworzymy nową skrzynkę o nazwie "phptestbox" w skrzynce poczty przychozącej
# sprawdzamy status po utworzeniu i na koniec usuwamy, przywracając skrzynkę
# do stanu początkowego
if(@imap_createmailbox($mbox,imap_utf7_encode("{your.imap.host}INBOX.$newname")))
{
$status = @imap_status($mbox,"{your.imap.host}INBOX.$newname",SA_ALL);
if($status) {
print("nowa skrzynka '$name1' ma następujący status:<br>\n");
print("Komunikatów:
". $status->messages
)."<br>\n";
print("Ostatnich:
". $status->recent
)."<br>\n";
print("Nieprzeczytanych:". $status->unseen
)."<br>\n";
print("Następny UID:
". $status->uidnext
)."<br>\n";
print("Poprawność UID: ". $status->uidvalidity)."<br>\n";
if(imap_renamemailbox($mbox,"{your.imap.host}INBOX.$newname",
"{your.imap.host}INBOX.$name2")) {
echo "zmieniono nazwę srzyni z '$name1' na '$name2'<br>\n";
$newname=$name2;
} else {
print "Nieudane wywołanie imap_renamemailbox na nowej skrzynce: "
.imap_last_error()."<br>\n";
}
} else {
print "Nieudane wywołanie imap_status na nowej skrzynce: "
.imap_last_error()."<br>\n";
}
if(@imap_deletemailbox($mbox,"{your.imap.host}INBOX.$newname")) {
print "nowa skrzynka usunięta, przywracając stan początkowy<br>\n";
} else {
print "Nieudane wywołanie imap_deletemailbox na nowej skrzynce: "
.implode("<br>\n",imap_errors())."<br>\n";
}
} else {
print "nie można utworzyć nowej skrzyki: ".implode("<br>\n",imap_errors())
."<br>\n";
}
imap_close($mbox);
imap_delete
Zwraca True. Funkcja imap_delete() oznacza do usunięcia przesyłkę wskazywaną przez $msg_number.
Opcjonalny parametr $flags posiada tylko jedną opcję, FT_UID, która wskazuje funkcji, że argumenty
$msg_number należy traktować jako identyfikatory UID. Przesyłki zaznaczone do usunięcia pozostają w skrzynce
do czasu wywołania funkcji imap_expunge() lub imap_close() z ustawionym parametrem opcjonalnym
CL_EXPUNGE.
int imap_delete (int imap_stream, int msg_number [, int flags])
Przykład: imap_delete()
$mbox = imap_open ("{your.imap.host}INBOX", "username", "password")
or die ("nie można połączyć: " . imap_last_error());
$check = imap_mailboxmsginfo ($mbox);
print "Przesyłki przed usunięciem: " . $check->Nmsgs . "<br>\n" ;
imap_delete ($mbox, 1);
$check = imap_mailboxmsginfo ($mbox);
print "Przesyłki po usunięciu: " . $check->Nmsgs . "<br>\n" ;
imap_expunge ($mbox);
$check = imap_mailboxmsginfo ($mbox);
print "Przesyłki po wyczyszczeni: " . $check->Nmsgs . "<br>\n" ;
imap_close ($mbox);
imap_deletemailbox
suwa podaną skrzynkę pocztową (format nazw $mbox można znaleźć przy opisie imap_open()). Zwraca
True w przypadku powodzenia i False w przypadku błędu. Patrz również: imap_createmailbox(),
imap_renamemailbox() i imap_open().
267
PHP – Kompendium wiedzy
int imap_deletemailbox (int imap_stream, string mbox)
imap_errors
Zwraca tablicę wszystkich komunikatów błędów IMAP wygenerowanych od ostatniego wywołania
lub od początku skryptu. Po wywołaniu imap_errors() stos błędów jest czyszczony.
imap_errors()
array imap_errors (void)
imap_expunge
Usuwa
przesyłki zaznaczone
Zwraca True.
jako
usunięte
przez
imap_delete(),
imap_mail_move()
lub
imap_setflag_full().
int imap_expunge (int imap_stream)
imap_fetchbody
Funkcja powoduje pobranie sekcji z treści podanego komunikatu w postaci tekstu i zwrócenie tego tekstu.
Specyfikacja sekcji jest ciągiem liczb rozdzielonych kropkami, które są indeksami w liście części, w sposób
określony przez specyfikację IMAP4. Części z treścią nie są dekodowane przez tą funkcję. Parametrem
imap_fetchbody() jest maska bitowa z jedną lub więcej stałych:
• FT_UID — Parametr $msg_number jest UID
• FT_PEEK — Nie ustawia znacznika \Seen, jeżeli nie był wcześniej ustawiony
• FT_INTERNAL — Zwracany ciąg jest w postaci wewnętrznej bez konwersji końców linii.
string imap_fetchbody (int imap_stream, int msg_number, string part_number
[, flags flags])
imap_fetchheader
Powoduje odczytanie całego, nieprzefiltrowanego RFC822 nagłówka formatu podanego komunikatu i
zwrócenie go ciągu znaków. Opcje są następujące:
• FT_UID — Parametr $msg_number jest UID
• FT_INTERNAL — Zwracany ciąg jest w postaci wewnętrznej bez konwersji końców linii.
• FT_PREFETCH — TEXT.RFC822 powinien być w tym samym czasie wstępnie pobrany. Pozwala to
uniknąć dodatkowego RTT na połączeniu IMAP, jeżeli wymagany jest pełny tekst przesyłki (na przykład,
operacja „zapis do pliku”)
string imap_fetchheader (int imap_stream, int msgno, int flags)
imap_fetchstructure
Funkcja pobiera wszystkie informacje o strukturze podanej przesyłki. Opcjonalny parametr $flags posiada
tylko jedną opcję, FT_UID, która wskazuje funkcji, że argumenty $msg_number należy traktować jako identyfikatory
UID. Zwracany obiekt zawiera kopertę, datę wewnętrzną, rozmiar, znaczniki i strukturę treści, oraz podobne
obiekty dla każdego załącznika MIME.
object imap_fetchstructure (int imap_stream, int msg_number [, int flags])
Tabela 1. Zwracany obiekt z imap_fetchstructure()
Typ
Typ treści
encoding
Kodowanie do przesłania treści
ifsubtype
TRUE jeżeli występuje ciąg podtypu
subtype
Podtyp MIME
ifdescription
TRUE jeżeli jest to ciąg opisu
description
Ciąg opisu treści
ifid
TRUE jeżeli jest to ciąg identyfikacyjny
id
Ciąg identyfikacyjny
lines
Ilość linii
Dodatek A - Funkcje
268
bytes
ifdisposition
disposition
ifdparameters
dparameters
ifparameters
parameters
parts
Ilość bajtów
TRUE jeżeli jest to ciąg rozmieszczenia
Ciąg rozmieszczenia
TRUE jeżeli istnieje tablica dparameters
Tablica parametrów rozmieszczenia
TRUE jeżeli istnieje tablica parametrów
Tablica parametrów MIME
Tablica obiektów opisujących każdą część przesyłki
Uwaga
Dparameters jest tablica obiektów posiadających atrybuty $attribute i $value. Parameters jest tablicą obiektów posiadających
atrybuty $attribute i $value. Parts jest tablicą obietów o identycznej strukturze jak nadrzędny obiekt, z ograniczeniem, że nie
mogą posiadać następnych obiektów parts.
Podstawowe typy treści
0:text, 1: multipart, 2:message, 3:application, 4:audio, 5:image, 6-video, 7-other
Rodzaje kodowania
0:7BIT, 1:8BIT, 2:BINARY, 3:BASE64, 4:QUOTED-PRINTABLE, 5:OTHER
imap_fetch_overview
Pobiera nagłówki dla podanej sekwencji $sequence i zwraca skrót ich zawartości. Parametr $sequence
może zawierać sekwencję indeksów wiadomości lub identyfikatorów UID, gdy parametr $flag zawiera FT_UID.
Funkcja zwraca tablicę obiektów opisujących następujące nagłówki kolejnych wiadomości:
• subject — temat wiadomości
• from — nadawca wiadomości
• date — data wysłania
• message_id — identyfikator wiadomości
• references — odwołania do tego identyfikatora wiadomości
• size — rozmiar w bajtach
• uid — identyfikator UID wiadomości w skrzynce
• msgno — numer kolejny komunikatu w skrzynce
• recent — wiadomość oznaczona jako niedawna
• flagged — wiadomość zaznaczona
• answered — wiadomość na którą została udzielona odpowiedź
• deleted — wiadomość zaznaczona do usunięcia
• seen — wiadomość przeczytana
• draft — wiadomość oznaczona jako szkic
array imap_fetch_overview (int imap_stream, string sequence [, int flags])
Przykład: imap_fetch_overview()
$mbox = imap_open("{your.imap.host:143}","username","password")
or die("błąd połaczenia: ".imap_last_error());
$overview = imap_fetch_overview($mbox,"2,4:6",0);
if(is_array($overview)) {
reset($overview);
while( list($key,$val) = each($overview)) {
print
$val->msgno
. " - " . $val->date
. " - " . $val->subject
. "\n";
}
}
imap_close($mbox);
269
PHP – Kompendium wiedzy
imap_getmailboxes
Zwraca tablicę obiektów zawierających dane na temat skrzynek pocztowych. Każdy obiekt posiada
następujące atrybuty: $name — zawiera pełną nazwę skrzynki, $delimiter — znak podziału w tej części
hierarchii, w której znajduje się skrzynka, $attributes — maska bitowa, która może być testowana za pomocą
następujących stałych:
• LATT_NOINFERIORS — skrzynka nie posiada „dzieci” (skrzynek w niej założonych)
• LATT_NOSELECT — jest to kontener a nie skrzynka i nie może być otwierany
• LATT_MARKED — skrzynka jest zaznaczona i używana jedynie przez UW-IMAPD
• LATT_UNMARKED — skrzynka nie jest zaznaczona i używana jedynie przez UW-IMAPD
array imap_getmailboxes (int imap_stream, string ref, string pattern)
Nazwy skrzynek zawierające znaki narodowe z poza drukowalnego zakresu kodów ASCII są zakodowane
i mogą być rozkodowane za pomocą funkcji imap_utf7_decode(). Normalnie $ref powinien być określany przez
specyfikację serwera, tak jak jest to opisane przy funkcji imap_open(), natomiast $pattern określa początek
przeszukiwania w hierarchii skrzynek pocztowych. Jeżeli chcesz uzyskać wszystkie skrzynki, należy przekazać
do parametru $pattern ciąg "*". Mogą być tu używane dwa znaki specjalne: * i %. Jeżeli użyjemy znaku * w
wyniku otrzymamy wszystkie skrzynki w hierarchii. Znak % powoduje otrzymanie jedynie skrzynek z bieżącego
poziomu hierarchii. Jeżeli podamy jedynie "%", otrzymamy skrzynki z głównego poziomu hierarchii, "~/mail/%"
na UW-IMAPD zwróci wszystkie skrzynki z katalogu ~/mail, ale bez podkatalogów.
Przykład: imap_getmailboxes()
$mbox = imap_open("{your.imap.host}","username","password",OP_HALFOPEN)
or die("błąd połączenia: ".imap_last_error());
$list = imap_getmailboxes($mbox,"{your.imap.host}","*");
if(is_array($list)) {
reset($list);
while (list($key, $val) = each($list))
{
print "($key) ";
print imap_utf7_decode($val->name).",";
print "'".$val->delimiter."',";
print $val->attributes."<br>\n";
}
} else
print "nieudane wywołanie funkcji imap_getmailboxes: ".imap_last_error()."\n";
imap_close($mbox);
imap_getsubscribed
Identyczna z
subskrypcję.
imap_getmailboxes(),
ale zwraca jedynie skrzynki, do których użytkownik posiada
array imap_getsubscribed (int imap_stream, string ref, string pattern)
imap_header
Alias funkcji imap_headerinfo(), działa dokładnie tak samo.
imap_header( void )
imap_headerinfo
Zwraca obiekt do różnych fragmentów nagłówka:
message_id, newsgroups, followup_to, references.
remail, date, Date, subject, Subject, in_reply_to,
imap_header( void )
Dostępne są następujące znaczniki wiadomości:
• Recent — 'R' jeżeli wiadomość jest przeczytana i niedawna, 'N' jeżeli jest niedawna i nieprzeczytana, ' '
jeżeli
nie
jest
niedawna
Unseen — 'U' jeżeli nie jest przeczytana i nie jest niedawna, ' ' jeżeli przeczytana lub niedawna
Answered —
'A' jeżeli
udzielono odpowiedzi, '
'
jeżeli nie udzielono odpowiedzi
Deleted — 'D' gdy
usunięta,
'
'
jeżeli
nie
usunięta
Dodatek A - Funkcje
270
— 'X' jeżeli
jest
szkicem,
'
'
Flagged — 'F' jeżeli jest zaznaczona, ' ' jeżeli jest oznaczona
Draft
gdy
nim
nie
jest
Uwaga
Działanie znaczników Recent i Unseen jest nieco dziwne. Jeżeli chcesz sprawdzić, czy wiadomość nie jest przeczytana, sprawdź
Unseen == 'U' || Recent == 'N'.
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
(kompletna linia to:, do 1024 znaków)
to[] (zwraca tablicę obiektów z linii to: zawierająca: personal, adl, mailbox, host)
fromaddress (kompletna linia from:, do 1024 znaków)
from[] (zwraca tablicę obiektów z linii from: zawierająca: personal, adl, mailbox, host)
ccaddress (kompletna linia cc:, do 1024 znaków)
cc[] (zwraca tablicę obiektów z linii cc: zawierająca: personal, adl, mailbox, host)
bccaddress (kompletna linia bcc:, do 1024 znaków)
bcc[] (zwraca tablicę obiektów z linii bcc: zawierająca: personal, adl, mailbox, host)
reply_toaddress (kompletna linia reply_to:, do 1024 znaków)
reply_to[] (zwraca tablicę obiektów z linii reply_to: zawierająca: personal, adl, mailbox, host)
senderaddress (kompletna linia sender:, do 1024 znaków)
sender[] (zwraca tablicę obiektów z linii sender: zawierająca: personal, adl, mailbox, host)
return_path (kompletna linia return_path:, do 1024 znaków)
return_path[] (zwraca tablicę obiektów z linii return_path: zawierająca: personal, adl, mailbox, host)
udate (mail, message, date, in, unix, time)
fetchfrom (linia from: sformatowana tak, aby zmieściła się w $fromlength znakach)
fetchsubject (linia subject: sformatowana tak, aby zmieściła się w $fromlength znakach)
toaddress
imap_headers
Zwraca tablicę ciągów sformatowanych z danymi nagłówków. Pozwala na jeden element na przesyłkę.
array imap_headers (int imap_stream)
imap_last_error
Zwraca pełny tekst ostatniego komunikatu błędu IMAP, który wystąpił na bieżącej stronie. Stos błędów
pozostaje niezmieniony. Kolejne wywołania imap_last_error() zwrócą ten sam błąd, jeżeli nie wystąpią w
międzyczasie inne błędy.
imap_listmailbox
Zwraca tablicę zawierającą nazwy skrzynek pocztowych. Opis parametrów
przy opisie imap_getmailboxes().
$ref
i
$pattern
znajduje się
array imap_listmailbox (int imap_stream, string ref, string pattern)
Przykład: imap_listmailbox()
$mbox = imap_open("{your.imap.host}","username","password",OP_HALFOPEN)
or die("błąd połaczenia: ".imap_last_error());
$list = imap_listmailbox($mbox,"{your.imap.host}","*");
if(is_array($list)) {
reset($list);
while (list($key, $val) = each($list))
print imap_utf7_decode($val)."<br>\n";
} else
print "Nieudane wywołanie funkcji imap_listmailbox: ".imap_last_error()."\n";
imap_close($mbox);
271
PHP – Kompendium wiedzy
imap_listsubscribed
Zwraca tablicę z wszystkimi skrzynkami pocztowymi, do których posiadasz subskrypcję. Jest ona niemal
identyczna jak imap_listmailbox(), ale zwraca jedynie te skrzynki, do których zalogowany użytkownik posiada
subskrypcję.
array imap_listsubscribed (int imap_stream, string ref, string pattern)
imap_mail
Funkcja ta jest obecnie dostępna tylko w PHP 3.
string imap_mail (string to, string subject, string message
[, string additional_headers [, string cc [, string bcc [, string rpath]]]])
imap_mailboxmsginfo
Zwraca informacje na temat bieżącej skrzynki pocztowej. Zwraca False w przypadku wystąpienia błędu.
Funkcja imap_mailboxmsginfo() sprawdza status skrzynki na serwerze. Jest podobna do imap_status(), ale
dodatkowo sumuje rozmiary wszystkich wiadomości w skrzynce, co jednak powoduje wydłużenie czasu
wykonywania funkcji. Zwraca dane w postaci obiektu z następującymi właściwościami.
object imap_mailboxmsginfo (int imap_stream)
•
•
•
•
•
•
•
•
Właściwości skrzynki pocztowej
Date — data ostatniej zmiany
Driver — sterownik
Mailbox — nazwa skrzynki
Nmsgs — ilość wiadomości
Recent — ilość ostatnich wiadomości
Unread — ilość wiadomości nie przeczytanych
Deleted — ilość usuniętych wiadomości
Size — rozmiar skrzynki
Przykład: imap_mailboxmsginfo()
<?php
$mbox = imap_open("{your.imap.host}INBOX","username", "password")
or die("błąd połączenia: ".imap_last_error());
$check = imap_mailboxmsginfo($mbox);
if($check) {
print "Date: "
.
print "Driver: " .
print "Mailbox: " .
print "Messages: ".
print "Recent: " .
print "Unread: " .
print "Deleted: " .
print "Size: "
.
} else {
print "imap_check()
}
$check->Date
$check->Driver
$check->Mailbox
$check->Nmsgs
$check->Recent
$check->Unread
$check->Deleted
$check->Size
."<br>\n"
."<br>\n"
."<br>\n"
."<br>\n"
."<br>\n"
."<br>\n"
."<br>\n"
."<br>\n"
;
;
;
;
;
;
;
;
failed: ".imap_last_error(). "<br>\n";
imap_close($mbox);
?>
imap_mail_compose
string imap_mail_compose (array envelope, array body)
Przykład: imap_mail_compose()
<?php
$envelope["from"]="[email protected]";
$envelope["to"]="musone@darkstar";
$envelope["cc"]="[email protected]";
$part1["type"]=TYPEMULTIPART;
Dodatek A - Funkcje
272
$part1["subtype"]="mixed";
$filename="/tmp/imap.c.gz";
$fp=fopen($filename,"r");
$contents=fread($fp,filesize($filename));
fclose($fp);
$part2["type"]=TYPEAPPLICATION;
$part2["encoding"]=ENCBINARY;
$part2["subtype"]="octet-stream";
$part2["description"]=basename($filename);
$part2["contents.data"]=$contents;
$part3["type"]=TYPETEXT;
$part3["subtype"]="plain";
$part3["description"]="description3";
$part3["contents.data"]="contents.data3\n\n\n\t";
$body[1]=$part1;
$body[2]=$part2;
$body[3]=$part3;
echo nl2br(imap_mail_compose($envelope,$body));
?>
imap_mail_copy
Zwraca True w przypadku sukcesu lub False w przypadku wystąpienia błędu. Kopiuje wiadomość
określoną przez $msglist do określonej skrzynki pocztowej. Parametr $msglist może zawierać zakres a nie tylko
numery komunikatów, jak to zostało opisane w RFC2060 (http://www.faqs.org/rfcs/rfc2060.html). Parametr
$flags jest maską bitową zawierającą CP_UID — sekwencja liczb zawiera UID i CP_MOVE — usuwa
komunikaty ze skrzynki po ich skopiowaniu.
int imap_mail_copy (int imap_stream, string msglist, string mbox [, int flags])
imap_mail_move
Przenosi przesyłkę pocztową określoną przez $msglist to podanej skrzynki pocztowej. Parametr $msglist
może zawierać zakres a nie tylko numery komunikatów, jak to zostało opisane w RFC2060
(http://www.faqs.org/rfcs/rfc2060.html). Parametr $flags jest maską bitową i może zawierać jedną wartość
CP_UID. Zwraca True w przypadku sukcesu lub False w przypadku wystąpienia błędu.
int imap_mail_move (int imap_stream, string msglist, string mbox [, int flags])
imap_mime_header_decode
Dekoduje rozszerzenia nagłówków komunikatów MIME, które zawierają tekst z poza ASCII (RFC2047
http://www.faqs.org/rfcs/rfc2047.html). Zdekodowane elementy są zwracane w postaci tablicy obiektów, z który
posiada dwie właściwości: charset i text. Jeżeli element nie może być zdekodowany a inne słowa są w USASCII, właściwość charset jest ustawiona na wartość domyślną.
array imap_mime_header_decode (string text)
Przykład: imap_mime_header_decode()
$text="=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <[email protected]>";
$elements=imap_mime_header_decode($text);
for($i=0;$i<count($elements);$i++) {
echo "Charset: {$elements[$i]->charset}\n";
echo "Text: {$elements[$i]->text}\n\n";
}
W przedstawionym przykładzie otrzymamy dwa elementy, gdzie pierwszy element jest zakodowany za
pomocą ISO-8859-1 a drugi będzie US-ASCII.
imap_msgno
Zwraca numer sekwencji wiadomości dla podanego UID. Jest to odwrotność imap_uid().
int imap_msgno (int imap_stream, int uid)
273
PHP – Kompendium wiedzy
imap_num_msg
Zwraca ilość przesyłek w bieżącej skrzynce pocztowej.
int imap_num_msg (int imap_stream)
imap_num_recent
Zwraca ilość ostatnich przesyłek w bieżącej skrzynki pocztowej.
int imap_num_recent (int imap_stream)
imap_open
W przypadku powodzenia zwraca strumień IMAP, a w przypadku błędu False. Funkcja może być
używana do otwarcia strumienia do serwerów POP3 i NNTP i nie wszystkie funkcje i własności są dostępne na
serwerach IMAP. Nazwa skrzynki składa się z dwóch części: nazwy serwera i ścieżki do skrzynki na tym
serwerze. Nazwa specjalna INBOX określa bieżącą skrzynkę pocztową użytkownika. Fragment nazwy
określający serwer jest otoczony nawiasami klamrowymi {} i zawiera nazwę serwera, lub jego numer IP,
określenie protokołu komunikacji (rozpoczynające się od /), oraz opcjonalnie numer portu rozpoczynający się od
znaku :. Podawanie nazwy serwera jest obowiązkowe we wszystkich parametrach skrzynki pocztowej. Nazwy
skrzynek zawierające znaki narodowe spoza drukowalnego podzbioru kodów ASCII są zakodowane za pomocą
funkcji imap_utf7_encode().
int imap_open (string mailbox, string username, string password [, int flags])
Opcje stanowią maskę bitową zawierającą jedną, lub więcej z poniższych wartości:
• OP_READONLY — otwiera skrzynkę tylko do odczytu,
• OP_ANONYMOUS — nie używa ani nie zmienia pliku .newsrc (tylko NNTP),
• OP_HALFOPEN — dla połączeń IMAP i NNTP, otwiera połączenie, ale nie otwiera skrzynki,
• CL_EXPUNGE — automatycznie czyści skrzynkę po jej zamknięciu.
Aby podłączyć się z serwerem IMAP działającym na porcie 143 na komputerze lokalnym, należy
wywołać funkcję w następujący sposób:
$mbox = imap_open ("{localhost:143}INBOX", "user_id", "password");
Aby podłączyć się z serwerem POP3 działającym na porcie 110 na komputerze lokalnym, należy wywołać
funkcję w następujący sposób:
$mbox = imap_open ("{localhost:110/pop3}INBOX", "user_id", "password");
Aby podłączyć się z serwerem NNTP działającym na porcie 119 na komputerze lokalnym, należy
wywołać funkcję w następujący sposób:
$mbox = imap_open ("{localhost:993/imap/ssl}INBOX", "user_id", "password");
Aby połączyć się ze zdalnym serwerem należy zastąpić localhost nazwą lub numerem IP serwera, z
którym ma być nawiązane połączenie.
Przykład: imap_open()
$mbox = imap_open ("{your.imap.host:143}", "username", "password");
echo "<p><h1>Skrzynki pocztowe</h1>\n";
$folders = imap_listmailbox ($mbox, "{your.imap.host:143}", "*");
if ($folders == false) {
echo "wywołanie nieudane<br>\n";
} else {
while (list ($key, $val) = each ($folders)) {
echo $val."<br>\n";
}
}
echo "<p><h1>nagłówki w INBOX</h1>\n";
$headers = imap_headers ($mbox);
if ($headers == false) {
echo "wywołanie nieudane<br>\n";
} else {
while (list ($key,$val) = each ($headers)) {
echo $val."<br>\n";
}
}
imap_close($mbox);
Dodatek A - Funkcje
274
imap_ping
Zwraca True, jeżeli strumień jest aktywny, False w przypadku nieaktywnego strumienia. Funkcja
imap_ping() sprawdza za pomocą operacji ping, czy strumień jest nadal aktywny. Może sprawdzać nową pocztę.
Jest to zalecana metoda okresowego sprawdzania nowej poczty oraz podtrzymywania połączenia do serwerów
rozłączających nieaktywne połączenia (ponieważ skrypty PHP nie działają zbyt długo, funkcja ta
prawdopodobnie nie będzie zbyt użyteczna).
int imap_ping (int imap_stream)
imap_qprint
Konwertuje ciąg zakodowany w postaci quoted-printable na ciąg 8-bitowy zgodnie z RFC2045
(http://www/faqs.org/rfcs/rfc2045.html, sekcja 6.7). Zwraca ciąg 8-bitowy (binarny). Patrz również: imap_8bit().
string imap_qprint (string string)
imap_renamemailbox
Zmienia nazwę skrzynki pocztowej na nową (format nazw skrzynek opisany jest przy funkcji
imap_open()). Zwraca True gdy operacja się powiodła i False w przypadku błędu. Patrz również:
imap_createmailbox(), imap_deletemailbox() i imap_open().
int imap_renamemailbox (int imap_stream, string old_mbox, string new_mbox)
imap_reopen
Ponownie otwiera strumień do nowej skrzynki na serwerze IMAP lub NNTP. Opcje są maską bitową
zawierającą jedną lub więcej następujących wartości:
• OP_READONLY — otwiera skrzynkę tylko do odczytu,
• OP_ANONYMOUS — nie używa ani nie zmienia pliku .newsrc (tylko NNTP),
• OP_HALFOPEN — dla połączeń IMAP i NNTP, otwiera połączenie, ale nie otwiera skrzynki,
• CL_EXPUNGE — automatycznie czyści skrzynkę po jej zamknięciu.
Zwraca True w przypadku powodzenia i False w przypadku błędu.
int imap_reopen (int imap_stream, string mailbox [, string flags])
imap_rfc822_parse_adrlist
Analizuje adresy w sposób zdefiniowany w RFC822 (http://www/faqs.org/rfcs/rfc2045.html). Dla każdego
adresu zwraca tablicę obiektów. Właściwościami obiektów są:
• mailbox — nazwa skrzynki (nazwa użytkownika),
• host — nazwa hosta,
• personal — nazwa opisowa użytkownika,
• adl — ścieżka do domeny źródłowej.
array imap_rfc822_parse_adrlist (string address, string default_host)
Przykład: imap_rfc822_parse_adrlist()
$address_string =
"Hartmut Holzgraefe <[email protected]>, [email protected], root";
$address_array = imap_rfc822_parse_adrlist($address_string,"somedomain.net");
if(! is_array($address_array)) die("coś poszło źle\n");
reset($address_array);
while(list($key,$val)=each($address_array)){
print "mailbox : ".$val->mailbox."<br>\n";
print "host
: ".$val->host."<br>\n";
print "personal: ".$val->personal."<br>\n";
print "adl
: ".$val->adl."<p>\n";
}
275
PHP – Kompendium wiedzy
imap_rfc822_parse_headers
Zwraca obiekt z różnymi elementami nagłówka, podobnie do imap_header(), ale bez znaczników i innych
elementów pochodzących z serwera IMAP.
object imap_rfc822_parse_headers (string headers [, string defaulthost])
imap_rfc822_write_address
Zwraca
prawidłowo
sformatowany
adres
e-mail
według
definicji
w
(http://www/faqs.org/rfcs/rfc2045.html), na podstawie skrzynki pocztowej, hosta i danych osobistych.
RFC822
string imap_rfc822_write_address (string mailbox, string host, string personal)
Przykład: imap_rfc822_write_address()
print imap_rfc822_write_address("hartmut","cvs.php.net","Hartmut Holzgraefe")."\n";
imap_scanmailbox
Zwraca tablicę zawierającą nazwy skrzynek, które zawierają tekst przekazany w $string. Funkcja ta jest
podobna do imap_listmailbox(), ale dodatkowo sprawdza czy w danych skrzynki zawarty tekst $content. Opis
parametrów $ref i $pattern można znaleźć przy funkcji imap_getmailboxes().
array imap_scanmailbox (int imap_stream, string ref, string pattern, string content)
imap_search
Przeszukuje skrzynkę pocztową otwartą za pocą podanego strumienia IMAP. Parametr $criteria zawiera
ciąg, w którym dozwolone są zamieszczone poniżej słowa kluczowe rozdzielone spacjami. Wszystkie elementy
wielowyrazowe muszą być otoczone apostrofami, na przykład FROM "jan kowalski".
array imap_search (int imap_stream, string criteria, int flags)
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
— zwraca wszystkie wiadomości spełniające pozostałe warunki
— szuka wiadomości z ustawionym znacznikiem \\ANSWERED
BCC "string" — szuka wiadomości z ciągiem "string" w polu Bcc:
BEFORE "date" — szuka wiadomości sprzed podanej daty
BODY "string" — szuka wiadomości z ciągiem "string" w temacie wiadomości
CC "string" — szuka wiadomości z ciągiem "string" w polu Cc:
DELETED — szuka usuniętych wiadomości
FLAGGED — szuka wiadomości z ustawionym znacznikiem \\FLAGGED (czasami nazywanymi
wiadomościami ważnymi)
FROM "string" — szuka wiadomości z ciągiem "string" w polu From:
KEYWORD "string" — szuka wiadomości ze słowem kluczowym "string"
NEW — szuka nowych wiadomości
OLD — szuka starych wiadomości
ON "date" — szuka wiadomości z polem Date: ustawionym na "date"
RECENT — szuka wiadomości z ustawionym znacznikiem \\RECENT
SEEN — szuka przeczytanych wiadomości (z ustawionym znacznikiem \\SEEN)
SINCE "date" — szuka wiadomości z polem Date: ustawionym na datę wcześniejszą od "date"
SUBJECT "string" — szuka wiadomości z ciągiem "string" w polu Subject:
TEXT "string" — szuka wiadomości z ciągiem "string" w tekście
TO "string" — szuka wiadomości z ciągiem "string" w polu To:
UNANSWERED — szuka wiadomości, a które nie była udzielona odpowiedź
UNDELETED — szuka wiadomości, które nie są usunięte
UNFLAGGED — szuka wiadomości, które nie są oznaczone
UNKEYWORD "string" — szuka wiadomości nie posiadających słowa kluczowego "string"
UNSEEN — szuka wiadomości nie przeczytanych
ALL
ANSWERED
Dodatek A - Funkcje
276
Na przykład, aby odnaleźć wszystkie wiadomości wysłanych przez Mama, na które nie była udzielona
odpowiedź, należy użyć ciągu "UNANSWERED FROM Mama". Przy przeszukiwaniu duże i małe litery nie są
rozróżniane. Podana lista warunków jest odczytana ze źródeł UW c-client i może być niekompletna lub
nieprecyzyjna (patrz RFC2060 sekcja 6.4.4). Prawidłową wartością parametru $flags jest SE_UID, który powoduje
zwracanie tablicy zawierającej identyfikatory UID zamiast numerów kolejnych wiadomości.
imap_setflag_full
Powoduje dodanie określonych znaczników do wiadomości z podanej sekwencji. Znaczniki jakie można
ustawić to: \\Seen, \\Answered, \\Flagged, \\Deleted, \\Draft i \\Recent (według RFC2060). Prawidłową wartością
parametru $flags jest ST_UID, który powoduje zwracanie tablicy zawierającej identyfikatory UID zamiast
numerów kolejnych wiadomości.
string imap_setflag_full (int stream, string sequence, string flag, string options)
Przykład: imap_setflag_full()
$mbox = imap_open("{your.imap.host:143}","username","password")
or die("błąd połączenia: ".imap_last_error());
$status = imap_setflag_full($mbox,"2,5","\\Seen \\Flagged");
print gettype($status)."\n";
print $status."\n";
imap_close($mbox);
imap_sort
Zwraca tablicę numerów wiadomości posortowaną według podanego parametru. Jeżeli
sortowanie jest odwrotne.
$reverse
jest 1,
array imap_sort (int stream, int criteria, int reverse, int options)
•
•
•
•
•
•
•
•
•
Sortowanie może się odbywać według jednego (tylko jednego) z poniższych warunków:
SORTDATE — data wiadomości
SORTARRIVAL — data otrzymania wiadomości
SORTFROM — adresu nadawcy (From:)
SORTSUBJECT — tematu wiadomości
SORTTO — adresu z pola To:
SORTCC — adresu z pola Cc:
SORTSIZE — wielkości przesyłki liczonej w oktetach
Opcje są maską bitową z następującymi wartościami:
SE_UID — Funkcja zwraca identyfikatory UID zamiast numerów kolejnych
SE_NOPREFETCH — nie odczytuje wstępnie szukanych wiadomości
imap_status
Zwraca obiekt zawierający dane statusu.
object imap_status (int imap_stream, string mailbox, int options)
Dozwolonymi znacznikami są:
SA_MESSAGES — ustawia status->messages na ilość wiadomości w skrzynce
SA_RECENT — ustawia status->recent na ilość niedawnych wiadomości w skrzynce
SA_UNSEEN — ustawia status->unseen na ilość nierzeczytanych (nowych) wiadomości w skrzynce
SA_UIDNEXT — ustawia status->uidnext na następny UID jaki zostanie użyty w skrzynce
SA_UIDVALIDITY — ustawia status->uidvalidity na stałą, która zmienia się, gdy UID skrzynki przestaje
być prawidłowy
• SA_ALL — ustawia wszystkie powyższe właściwości
Dodatkowo ustawiany jest status->flags zawierający maskę bitową, która może być porównywana z
przedstawionymi powyżej stałymi.
Przykład: imap_status()
•
•
•
•
•
$mbox = imap_open("{your.imap.host}","username","password",OP_HALFOPEN)
or die("błąd połaczenia: ".imap_last_error());
277
PHP – Kompendium wiedzy
$status = imap_status($mbox,"{your.imap.host}INBOX",SA_ALL);
if($status) {
print("Wiadomości:
". $status->messages
)."<br>\n";
print("Niedawnych:
". $status->recent
)."<br>\n";
print("Nieprzeczytanych:". $status->unseen
)."<br>\n";
print("Następny UID:
". $status->uidnext
)."<br>\n";
print("Poprawność UID: ". $status->uidvalidity)."<br>\n";
} else
print "nieudane wywołanie imap_status: ".imap_last_error()."\n";
imap_close($mbox);
imap_subscribe
Subskrybuje nową skrzynkę. Zwraca
True
po poprawnym wykonaniu operacji lub
False
w przypadku
błędu.
int imap_subscribe (int imap_stream, string mbox)
imap_uid
Zwraca identyfikator UID wiadomości na podstawie jej numeru kolejnego. UID to jednoznaczny
identyfikator nie zmieniający się w czasie w przeciwieństwie do numerów kolejnych, które mogą się zmienić po
zmianie zawartości skrzynki. Funkcja jest odwrotna do imap_msgno().
int imap_uid (int imap_stream, int msgno)
imap_undelete
Usuwa znacznik usunięcia dla podanej wiadomości ustawiony przez funkcję
Zwraca True w przypadku powodzenia i False w przypadku błędu.
imap_delete()
lub
imap_move().
int imap_undelete (int imap_stream, int msg_number)
imap_unsubscribe
Usuwa subskrypcję do podanej skrzynki. Zwraca
True
w przypadku powodzenia i
False
w przypadku
błędu.
int imap_unsubscribe (int imap_stream, string mbox)
imap_utf7_decode
Dekoduje $text w postaci UTF-7 do danych 8-bitowych. Zwraca zdekodowane dane 8-bitowe, lub False,
gdy ciąg wejściowy nie jest prawidłowym ciągiem UTF-7. Funkcja ta jest niezbędna do dekodowania nazw
skrzynek zwierających znaki narodowe spoza drukowalnego zakresu kodów ASCII. Zmodyfikowane kodowanie
UTF-7 jest zdefiniowane w RFC2060 (http://www/faqs.org/rfcs/rfc2060.html sekcja 5.1.3), natomiast oryginalne
kodowanie UTF-7 jest zdefiniowane w RFC1642 (http://www/faqs.org/rfcs/rfc1642.html).
string imap_utf7_decode (string text)
imap_utf7_encode
Konwertuje 8-bitowe dane do tekstu UTF-7. Jest to niezbędne do zakodowania nazw skrzynek
zawierających znaki narodowe spoza drukowalnego zakresu kodów ASCII. Zmodyfikowane kodowanie UTF-7
jest zdefiniowane w RFC2060 (http://www/faqs.org/rfcs/rfc2060.html sekcja 5.1.3), natomiast oryginalne
kodowanie UTF-7 jest zdefiniowane w RFC1642 (http://www/faqs.org/rfcs/rfc1642.html). Zwraca ciąg
zakodowany zmodyfikowaną metodą UTF-7.
string imap_utf7_encode (string data)
imap_utf8
Konwertuje podany ciąg na postać UTF8 w sposób zdefiniowany w RFC2044.
string imap_utf8 (string text)
Dodatek A - Funkcje
278
implode
Zwraca ciąg zawierający wszystkie elementy tablicy w tej samej kolejności z ciągiem sklejającym
pomiędzy elementami.
Uwaga
Funkcja implode() może, z powodów historycznych, pobierać swoje argumenty w dowolnym porządku. Jednak z powodu spójności
z explode() powinno się korzystać z kolejności przedstawionej w dokumentacji.
Patrz również: explode(), join() i split().
string implode (string glue, array pieces)
Przykład: implode()
$colon_separated = implode(":", $array);
ini_alter
Zmienia wartość podanej opcji konfiguracji. Zwraca
przypadku sukcesu, poprzednią wartość opcji.
False
w przypadku niepowodzenia, natomiast w
Uwaga
Jest to alias do ini_set().
Patrz również: ini_get(), ini_restore() i ini_set().
string ini_alter (string varname, string newvalue)
ini_get
Zwraca wartość opcji konfiguracji lub False w przypadku wystąpienia błędu. Patrz również: ini_alter(),
i ini_set().
ini_restore()
string ini_get (string varname)
ini_restore
Przywraca oryginalną wartość podanej opcji konfiguracji. Patrz również
ini_alter(), ini_get()
i
ini_set().
string ini_restore (string varname)
ini_set
Ustawia wartość podanej opcji konfiguracji. Zwraca False w przypadku niepowodzenia, natomiast w
przypadku sukcesu, poprzednią wartość opcji. Patrz również: ini_alter(), ini_get() i ini_restore().
string ini_set (string varname, string newvalue)
intval
Zwraca wartość całkowitą zmiennej $var przy użyciu konwersji o podanej podstawie (wartością domyślną
jest 10). Parametr $var może być dowolnym typem skalarnym. Nie można używać funkcji intval() na tablicach i
obiektach. Patrz również doubleval(), strval() i settype().
int intval (mixed var [, int base])
in_array
Szuka $needle w
zostanie znaleziony.
$haystack.
Zwraca
True,
jeżeli ciąg zostanie znaleziony w tablicy i
False,
jeżeli nie
bool in_array (mixed needle, array haystack)
279
PHP – Kompendium wiedzy
Przykład: in_array()
$os = array ("Mac", "NT", "Irix", "Linux");
if (in_array ("Irix", $os)) {
print "Znaleziono Irix";
}
ip2long
Generuje adres IPv4 na podstawie standardowego formatu (ciąg z kropkami).
int ip2long (string ip_address)
Przykład: ip2long()
<?php
$ip = gethostbyname("www.php.net");
$out = "Następujące adresy są swoimi odpowiednikami:<br>\n";
$out .= "http://www.php.net/, http://".$ip."/ i http://".ip2long($ip)."/<br>\n";
echo $out;
?>
Patrz również: long2ip().
iptcparse
Dzieli pojedynczy blok IPTC na pojedyncze znaczniki. Zwraca tablicę używając jako indeksów oznaczeń
znaczników a jako wartości, wartości znaczników. W przypadku błędu lub braku danych IPTC zwraca False.
Patrz również: GetImageSize().
array iptcparse (string iptcblock)
isset
Jeżeli istnieje $var zwraca True, a
unset(), funkcja isset() zwraca False.
False
gdy nie istnieje. Jeżeli zmienna została usunięta za pomocą
boolean isset (mixed var)
Przykład: isset()
$a = "test";
echo isset ($a); // TRUE
unset ($a);
echo isset ($a); // FALSE
$foo = NULL;
print isset ($foo); // FALSE
Patrz również: empty() i unset().
is_array
Zwraca True, jeżeli $var jest tablicą i
i is_object().
False,
gdy nią nie jest. Patrz również:
is_float(), is_int(),
is_integer(), is_string()
bool is_array (mixed var)
is_bool
Zwraca True, jeżeli parametr $var jest wartością boolean. Parz również: is_array(), is_float(), is_int(),
is_integer(), is_string() i is_object().
bool is_bool (mixed var)
is_dir
Zwraca True, jeżeli istnieje katalog o podanej nazwie. Wynik funkcji jest przechowywany w pamięci
podręcznej. Więcej szczegółów na ten temat znajduje się w opisie funkcji clearstatchache(). Patrz również:
is_file() i is_link().
bool is_dir (string filename)
Dodatek A - Funkcje
280
is_double
Zwraca True, jeżeli parametr $var jest liczbą double, w przeciwnym wypadku zwraca
również: is_bool(), is_int(), is_integer(), is_string(), is_array() i is_object().
False.
Patrz
int is_double( mixed var)
is_executable
Zwraca True, jeżeli istnieje plik o podanej nazwie pliku i jest on plikiem wykonywalnym. Wyniki
działania funkcji są przechowywane w pamięci podręcznej. Więcej szczegółów na ten temat znajduje się w opisie
funkcji clearstatchache(). Patrz również: is_file() i is_link().
bool is_executable (string filename)
is_file
Zwraca True, jeżeli istnieje plik o podanej nazwie pliku i jest on zwykłym plikiem. Wyniki działania
funkcji są przechowywane w pamięci podręcznej. Więcej szczegółów na ten temat znajduje się w opisie funkcji
clearstatchache(). Patrz również: is_dir() i is_link().
bool is_file (string filename)
is_float
Alias do funkcji is_double(). Patrz również: is_bool(), is_int(), is_integer(), is_string(), is_array()
i is_object().
bool is_float (mixed var)
is_int
Alias do
is_object().
is_long().
Patrz również:
is_bool(), is_float(), is_integer(), is_string(), is_array()
i
Patrz również:
is_bool(), is_float(), is_integer(), is_string(), is_array()
i
bool is_int (mixed var)
is_integer
Alias do
is_object().
is_long().
bool is_integer (mixed var)
is_link
Zwraca True, jeżeli istnieje plik o podanej nazwie pliku i jest on łączem symbolicznym. Wyniki działania
funkcji są przechowywane w pamięci podręcznej. Więcej szczegółów na ten temat znajduje się w opisie funkcji
clearstatchache(). Patrz również: is_dir() i is_file(). Funkcja ta nie działa w systemie Windows.
bool is_link (string filename)
is_long
Zwraca True, jeżeli $var jest liczbą całkowitą (long), w przeciwnym wypadku zwraca
również: is_bool(), is_float(), is_integer(), is_string(), is_array() i is_object().
False.
Patrz
is_long( mixed var)
is_numeric
Zwraca True, jeżeli $var jest liczbą lub ciągiem zawierającym liczbę, w przeciwnym wypadku zwraca
False. Patrz również: is_bool(), is_float(), is_int(), is_string(), is_object(), is_array() i is_integer().
bool is_numeric (mixed var)
281
PHP – Kompendium wiedzy
is_object
Zwraca True, jeżeli $var jest obiektem, w przeciwnym wypadku zwraca
is_int(), is_integer(), is_float(), is_string() i is_array().
False.
Patrz również:
is_bool(),
bool is_object (mixed var)
is_readable
Zwraca True, jeżeli plik o podanej nazwie istnieje i można go odczytać. Należy pamiętać, że PHP może
czytać ten plik jako użytkownik na rzecz którego jest uruchomiony serwer WWW (często jest to nobody). Nie są
brane pod uwagę ograniczenia trybu bezpiecznego. Więcej szczegółów na ten temat znajduje się w opisie funkcji
clearstatchache(). Patrz również: is_writable().
bool is_readable (string filename)
is_real
Alias do funkcji is_double(). Patrz również: is_bool(), is_int(), is_integer(), is_string(), is_array()
i is_object().
int is_real( mixed var )
is_resource
Zwraca True, jeżeli zmienna przekazana przez parametr $var jest zasobem, w przeciwnym przypadku
zwraca False. Zasobami są identyfikatory plików lub wyników zapytań do bazy danych, które są tworzone i
usuwane poprzez wewnętrzne funkcje PHP. Jeżeli nie są one używane można zastosować ich porządkowanie, ale
nie powinny być one zwalniane przez kod użytkownika.
bool is_resource (mixed var)
is_string
Zwraca True, jeżeli $var jest ciągiem, w przeciwnym wypadku zwraca
is_bool(), is_int(), is_integer(), is_float(), is_real(), is_object() i is_array().
False.
Patrz
również:
bool is_string (mixed var)
is_subclass_of
Zwraca True, jeżeli $obj jest obiektem klasy, która jest klasą pochodną po
wypadku zwraca False. Patrz również: get_class(), get_parent_class().
$superclass,
w przeciwnym
bool is_subclass_of (object obj, string superclass)
is_uploaded_file
Funkcja ta jest dostępna w PHP3 począwszy od wersji PHP 3.0.16 i w PHP od wersji 4.0.2. Zwraca True,
jeżeli plik o podanej nazwie został przesłany poprzez HTTP POST. Jest ona użyteczna do sprawdzenia, czy
złośliwy użytkownik nie próbuje oszukać skryptu tak, aby pracował on na pliku, na którym nie powinien, na
przykład /etc/passwd. Jest to użyteczne, gdy istnieje jakakolwiek szansa, że zawartość przesyłanego pliku może
być pokazana użytkownikowi, lub innym użytkownikom na tym samym systemie. Patrz również:
move_uploaded_file().
bool is_uploaded_file (string filename)
is_writeable
Zwraca True, jeżeli plik o podanej nazwie istnieje i można do niego pisać. Parametr może być również
nazwą katalogu, co pozwala sprawdzić, czy można zapisywać do tego katalogu. Należy pamiętać, że PHP może
czytać ten plik jako użytkownik na rzecz którego jest uruchomiony serwer WWW (często jest to nobody). Nie są
Dodatek A - Funkcje
282
brane pod uwagę ograniczenia trybu bezpiecznego. Więcej szczegółów na ten temat znajduje się w opisie funkcji
clearstatchache(). Patrz również: is_readable().
bool is_writeable (string filename)
JDDayOfWeek
Zwraca dzień tygodnia. W zależności od trybu może zwracać ciąg lub liczbę.
mixed jddayofweek (int julianday, int mode)
Tabela 2. Tryby tygodni w kalendarzu
Tryb
Znaczenie
0
Zwraca numer dnia jako liczbę (0=niedziela,
1=poniedziałek, itd.)
1
Zwraca ciąg zawierający dzień tygodnia (angielskigregoriański)
2
Zwraca ciąg zawierający skrót dnia tygodnia
(angielski-gregoriański)
JDMonthName
Zwraca ciąg zawierający nazwę miesiące. Parametr $mode wskazuje funkcji do którego kalendarza
skonwertować liczbę dni juliańskich i jaki typ nazwy miesiąca należy zwrócić.
string jdmonthname (int julianday, int mode)
Tabela 3. Tryby kalendarza
Tryb
Znaczenie
0
Gregoriański — skrócony
1
Gregoriański
2
Juliański — skrócony
3
Juliański
4
Żydowski
5
Republiki francuskiej
JDToFrench
Konwertuje liczbę dni juliańskich do kalendarza Rewolucji Francuskiej.
string jdtofrench (int juliandaycount)
JDToGregorian
Konwertuje liczbę dni juliańskich na ciąg zawierający datę gregoriańską w formacie miesiąc/dzień/rok.
string jdtogregorian (int julianday)
JDToJewish
Konwertuje liczbę dni juliańskich na kalendarz żydowski.
string jdtojewish (int julianday)
JDToJulian
Konwertuje liczbę dni juliańskich na ciąg zawierający datę w kalendarzu juliańskim w formacie
miesiąc/dzień/rok.
string jdtojulian (int julian3day)
283
PHP – Kompendium wiedzy
jdtounix
Zwraca znacznik czasu Uniksa odpowiadający dacie juliańskiej przekazanej w $jday, lub False jeżeli
$jday wykracza poza erę Uniksa (lata gregoriańskie pomiędzy 1970 i 2037 lub 2440588 <= $jday <= 2465342).
Patrz również: jdtounix().
Uwaga
Funkcja ta jest dostępna od wersji PHP4RC1.
int jdtounix (int jday)
JewishToJD
Mimo, że oprogramowanie może obsługiwać daty aż do roku 1 (3761 p.n.e.), jednak może być to mylące.
Kalendarz żydowski jest w użyciu od kilku tysięcy lat, ale w początkowym okresie nie było wzoru na wyliczenie
początku miesiąca. Miesiąc był rozpoczynany po zaobserwowaniu nowiu księżyca.
int jewishtojd (int month, int day, int year)
join
Jest to alias do funkcji implode() i działa identycznie. Patrz również: explode(), implode() i split().
string join (string glue, array pieces)
JulianToJD
Zakres dat kalendarza juliańskiego to 4713 p.n.e. do 9999 n.e. Mimo, że oprogramowanie może
obsługiwać daty od 413 p.n.e., jednak może być to mylące. Kalendarz został utworzony w roku 46 p.n.e., ale jego
szczegóły nie ustabilizowały się do roku 8 n.e. a nawet prawdopodobnie do 4 wieku. Również początek roku
różnił się w różnych kulturach — nie wszyscy zaakceptowali styczeń jako pierwszy miesiąc.
int juliantojd (int month, int day, int year)
key
Zwraca klucz bieżącej pozycji tablicy. Patrz również: current() i next().
mixed key (array array)
krsort
Sortuje tablicę w odwrotnej kolejności utrzymując korelację między kluczami i danymi. Jest to przydatne
w przypadku tablic asocjacyjnych.
int krsort (array array [, int sort_flags])
Przykład: krsort()
<?
$fruits = array ("d"=>"cytryna", "a"=>"pomarańcza", "b"=>"banan", "c"=>"jabłko");
krsort ($fruits);
reset ($fruits);
while (list ($key, $val) = each ($fruits)) {
echo "$key = $val\n";
}
?>
Wykonanie przykładu spowoduje wyświetlenie:
d
c
b
a
=
=
=
=
cytryna
jabłko
banan
pomarańcza
Można zmienić działanie funkcji używając opcjonalnego parametru $sort_flags. Szczegółowy opis
znajduje się przy funkcji sort(). Patrz również: asort(), arsort(), ksort(), sort(), natsort() i rsort().
Dodatek A - Funkcje
284
ksort
Sortuje tablicę utrzymując korelację między kluczami i danymi. Jest to przydatne w przypadku tablic
asocjacyjnych.
int ksort (array array [, int sort_flags])
Przykład: ksort()
<?
$fruits = array ("d"=>"cytryna", "a"=>"pomarańcza", "b"=>"banan", "c"=>"jabłko");
ksort ($fruits);
reset ($fruits);
while (list ($key, $val) = each ($fruits)) {
echo "$key = $val\n";
}
?>
Wykonanie przykładu spowoduje wyświetlenie:
a
b
c
d
=
=
=
=
pomarańcza
banan
jabłko
cytryna
Można zmienić działanie funkcji używając opcjonalnego parametru $sort_flags. Szczegółowy opis
znajduje się przy funkcji sort(). Patrz również: asort(), arsort(), krsort(), sort(), natsort() i rsort().
lcg_value
Zwraca liczbę pseudolosową z zakresu (0, 1). Funkcja łączy dwie wartości CG z okresem 2^31 - 85 i 2^31
- 249. Okres tej funkcji jest równy iloczynowi obu liczb pierwszych.
double lcg_value( void )
ldap_add
Zwraca True w przypadku powodzenia operacji i False w przypadku błędu. Funkcja ldap_add() jest
używana do dodawania wpisów do katalogu LDAP. DN dodawanego wpisu jest określane w parametrze $dn.
Tablica $entry zawiera informacje na temat wpisów. Wartości wpisów są indeksowane kolejnymi atrybutami. W
przypadku wielu wartości atrybutu są one indeksowane liczbami rozpoczynając od 0:
entry["atrybut1"] = wartość
entry["atrybut2"][0] = wartość1
entry["atrybut2"][1] = wartość 2
int ldap_add (int link_identifier, string dn, array entry)
Przykład: Kompletny przykład autoryzowanego wiązania
<?php
$ds=ldap_connect("localhost"); // zakładając,że serwer LDAP
// działa na tym komputerze
if ($ds) {
// wiązanie z odpowiednim dn, aby uzyskać możliwość wprowadzania zmian
$r=ldap_bind($ds,"cn=root, o=My Company, c=US", "secret");
// przygotowanie danych
$info["cn"]="John Jones";
$info["sn"]="Jones";
$info["mail"]="[email protected]";
$info["objectclass"]="person";
// dodanie danych do katalogu
$r=ldap_add($ds, "cn=John Jones, o=My Company, c=US", $info);
ldap_close($ds);
} else {
echo "Błąd wiązania z serwerem LDAP";
}
?>
285
PHP – Kompendium wiedzy
ldap_bind
Wiąże z katalogiem LDAP z odpowiednim RDN i hasłem. Zwraca True w przypadku powodzenia i False
w przypadku błędu. Funkcja ldap_bind() wykonuje operację wiązania. Parametry $bind_rdn i $bind_password są
opcjonalne. Jeżeli nie zostaną podane, wykonane zostanie wiązanie anonimowe.
int ldap_bind (int link_identifier [, string bind_rdn [, string bind_password]])
ldap_close
Zwraca True w przypadku powodzenia i False w przypadku błędu. Funkcja ldap_close() zamyka
połączenie z serwerem LDAP, skojarzone z podanym identyfikatorem $link_identifier. Wywołanie to jest
wewnętrznie identyczne z ldap_unbind(). API LDAP korzysta z funkcji ldap_unbind(), więc prawdopodobnie
należy używać tej funkcji zamiast ldap_close().
int ldap_close (int link_identifier)
ldap_compare
Zwraca True, jeżeli zostanie dopasowana wartość $value, w przeciwnym przypadku zwraca False. Zwraca
-1 w przypadku błędu. Funkcja ldap_compare() jest używana do porównywania wartości $value atrybutu
$attribute z wartością tego samego atrybutu w pozycji katalogu LDAP określonej przez $dn. Zamieszczony
przykład pokazuje, w jaki sposób można sprawdzić czy podane hasło odpowiada zdefiniowanemu w pozycji DN.
int ldap_compare (int link_identifier, string dn, string attribute, string value)
Przykład: Przykład kontroli hasła
<?php
$ds=ldap_connect("localhost"); // zakładając,że serwer LDAP
// działa na tym komputerze
if ($ds) {
// wiązanie
if(ldap_bind($ds)) {
// przygotowanie danych
$dn = "cn=Matti Meikku, ou=My Unit, o=My Company, c=FI";
$value = "secretpassword";
$attr = "password";
// porównanie wartości
$r=ldap_compare($ds, $dn, $attr, $value);
if ($r === -1) {
echo "Błąd: ".ldap_error($ds);
} elseif ($r === TRUE) {
echo "Hasło prawdłowe.";
} elseif ($r === FALSE) {
echo "Hasło nieprawidłowe!";
}
} else {
echo "Błąd przy łączeniu z serwerem LDAP.";
}
ldap_close($ds);
} else {
echo "Nie można przyłączyć do serwera LDAP.";
}
?>
Uwaga
Funkcja ldap_compare() nie może porównywać wartości binarnych! Funkcja została dodana w PHP 4.0.2.
ldap_connect
W przypadku powodzenia operacji zwraca dodatni identyfikator łącza LDAP, w przypadku błędu zwraca
Funkcja ldap_connect() zestawia połączenie z serwerem LDAP na komputerze $hostname i porcie $port.
Oba argumenty są opcjonalne. Jeżeli nie podane zostaną argumenty, zwracany jest identyfikator istniejącego
połączenia. Jeżeli zostanie podana jedynie nazwa komputera, domyślnym portem jest 389.
False.
int ldap_connect ([string hostname [, int port]])
Dodatek A - Funkcje
286
ldap_count_entries
Zwraca ilość pozycji w wyniku lub False w przypadku wystąpienia błędu. Funkcja ldap_count_entries()
zwraca ilość pozycji zapamiętanych w wyniku ostatniej operacji szukania. Parametr $result_identifier określa
wewnętrzny wynik LDAP.
int ldap_count_entries (int link_identifier, int result_identifier)
ldap_delete
Zwraca True w przypadku powodzenia operacji lub
usuwa pozycję z katalogu LDAP określoną przez $dn.
False
w przypadku błędu. Funkcja
ldap_delete()
int ldap_delete (int link_identifier, string dn)
ldap_dn2ufn
Używana do przekształcania DN na postać bardziej czytelna dla człowieka poprzez usunięcie nazw typów.
string ldap_dn2ufn (string dn)
ldap_err2str
Zwraca ciąg z komunikatem błędu. Funkcja ta zwraca komunikat błędu opisujący błąd numer $errno.
Choć numery błędów LDAP są zestandaryzowane, różne biblioteki zwracają różne, nawet przetłumaczone,
tekstowe opisy błędów. Nigdy nie należy porównywać tekstu komunikatów błędów, zamiast tego zawsze należy
używać do porównania numerów błędów. Patrz również: ldap_errno() i ldap_error().
string ldap_err2str (int errno)
Przykład: Wyliczanie wszystkich komunikatów błędów LDAP
<?php
for($i=0; $i<100; $i++) {
printf("Błąd $i: %s<br>\n", ldap_err2str($i));
}
?>
ldap_errno
Zwraca numer błędu LDAP dla ostatniego polecenia LDAP na podanym połączeniu. Funkcja ta zwraca
standardowy numer błędu zwracany przez ostatnie polecenie LDAP. Numer ten może zostać zamieniony na
komunikat tekstowy za pomocą funkcji ldap_err2str(). Jeżeli nie zmniejszysz wystarczająco poziomu ostrzeżeń
w pliku php.ini lub nie będziesz poprzedzał funkcji LDAP znakiem @, generowane błędy będą pokazywały się
również w wynikowym HTML.
int ldap_errno (int link_id)
Przykład: Generowanie i przechwytywanie błędów
<?php
// przykład ten zawiera błąd, który zostanie przechwycony
$ld = ldap_connect("localhost");
$bind = ldap_bind($ld);
// błąd składni w wyrażeniu filtrującym (nr: 87),
// aby działało musi być "objectclass=*"
$res = @ldap_search($ld, "o=Myorg, c=DE", "objectclass");
if (!$res) {
printf("LDAP-Errno: %s<br>\n", ldap_errno($ld));
printf("LDAP-Error: %s<br>\n", ldap_error($ld));
die("Aaaaaa!<br>\n");
}
$info = ldap_get_entries($ld, $res);
printf("%d pasujących wpisów.<br>\n", $info["count"]);
?>
Patrz również: ldap_err2str() i ldap_error().
ldap_error
Zwraca ciąg z komunikatem błędu. Funkcja zwraca komunikat błędu objaśniający błąd wygenerowany
przez ostatnie polecenie LDAP wykonane na podanym połączeniu. Choć numery błędów LDAP są
PHP – Kompendium wiedzy
287
zestandaryzowane, różne biblioteki zwracają różne, nawet przetłumaczone, tekstowe opisy błędów. Nigdy nie
należy porównywać tekstu komunikatów błędów, zamiast tego zawsze należy używać do porównania numerów
błędów. Jeżeli nie zmniejszysz wystarczająco poziomu ostrzeżeń w pliku php.ini lub nie będziesz poprzedzał
funkcji LDAP znakiem @, generowane błędy będą pokazywały się również w wynikowym HTML. Patrz również:
ldap_err2str() i ldap_errno().
string ldap_error (int link_id)
ldap_explode_dn
Funkcja używana do podziału ciągu DN zwracanego przez funkcję ldap_get_dn(), na pojedyncze
komponenty. Każda z części nazywana jest Relative Distinguished Name (RDN). Funkcja ldap_explode_dn()
zwraca tablicę zawierającą wszystkie te części. Za pomocą parametru $with_attrib można zdecydować, czy
RDN są zwracane ze swoimi wartościami, czy bez. Aby otrzymać RDN z wartością (to znaczy w postaci
atrybut=wartość) należy ustawić $with_attrib na 0. Aby otrzymać tylko wartości, należy ustawić go na 1.
array ldap_explode_dn (string dn, int with_attrib)
ldap_first_attribute
Zwraca pierwszy atrybut pozycji lub False w przypadku błędu. Podobnie do odnośnych pozycji, atrybuty
również mogą być czytane po kolei z określonej pozycji. Funkcja ldap_first_attribute() zwraca pierwszy
atrybut pozycji wskazywanej przez identyfikator pozycji. Pozostałe atrybuty mogą być odczytane za pomocą
kolejnych wywołań ldap_next_attribute(). Parametr $ber_identifier jest identyfikatorem wewnętrznego
wskaźnika pamięci. Jest on przekazywany przez referencję. Ten sam $ber_identifier jest przekazywany do
ldap_next_attribute(), która modyfikuje wskaźnik. Patrz również: ldap_get_attributes().
string ldap_first_attribute (int link_identifier, int result_entry_identifier,
int ber_identifier)
ldap_first_entry
Zwraca identyfikator pierwszej pozycji wyniku lub False w przypadku błędu. Pozycje w wyniku LDAP
mogą być czytane sekwencyjnie przy użyciu funkcji ldap_first_entry() i ldap_next_entry(). Funkcja
ldap_first_entry() zwraca identyfikator pierwszej pozycji wyniku. Identyfikator ten przekazywany jest do
funkcji ldap_next_entry() w celu odczytania kolejnych pozycji wyniku. Patrz również: ldap_get_entries().
int ldap_first_entry (int link_identifier, int result_identifier)
ldap_free_result
Zwraca
w przypadku powodzenia operacji lub False w przypadku błędu. Funkcja
ldap_free_result() zwalnia pamięć zajmowaną przez wynik, na który wskazuje $result_identifier. Cała
pamięć zajmowana przez wynik jest automatycznie zwalniana po zakończeniu skryptu. W przypadku, gdy skrypt
wykonuje kolejne wyszukiwania, które powodują powstanie dużych wyników można wywołać funkcję
ldap_free_result(), aby zmniejszyć ilość pamięci zużywaną przez skrypt.
True
int ldap_free_result (int result_identifier)
ldap_get_attributes
Zwraca wszystkie dane pozycji w postaci wielowymiarowej tablicy lub w przypadku wystąpienia błędu,
False. Funkcja ldap_get_attribues() używana jest w celu uproszczenia odczytywania atrybutów i wartości z
pozycji znajdującej się w wyniku. Zwracaną wartością jest wielowymiarowa tablica atrybutów i wartości. Po
odszukaniu odpowiedniej pozycji w katalogu możesz za pomocą takiego wywołania odczytać wszystkie
informacje przechowywane w tej pozycji. Można wykorzystać tą funkcje do napisania aplikacji za pomocą której
można przeglądać pozycje katalogu nawet, gdy nie znamy struktury określonych atrybutów. We wielu aplikacjach
szuka się określonego atrybutu, na przykład adresu e-mail lub nazwiska i nie ma potrzeby przejmować się
zawartością innych pozycji. Struktura tabeli jest następująca:
Dodatek A - Funkcje
288
return_value["count"] = ilość atrybutów w pozycji
return_value[0] = pierwszy atrybut
return_value[n] = n-ty atrybut
return_value["atrybut"]["count"] = ilość wartości atrybutu
return_value["atrybut"][0] = pierwsza wartość atrybutu
return_value["atrybut"][i] = i-ta wartość atrybutu
array ldap_get_attributes (int link_identifier, int result_entry_identifier)
Przykład: Wyświetlenie listy atrybutów przechowywanych w pozycji katalogu
// $ds jest identyfikatorem połączenia z katalogiem
// $sr jest prawidłowym wynikiem pochodzącym z
// wywołania jednej z funkcji przeszukujących
$entry = ldap_first_entry($ds, $sr);
$attrs = ldap_get_attributes($ds, $entry);
echo $attrs["count"]." atrybutów w tej pozycji:<p>";
for ($i=0; $i<$attrs["count"]; $i++)
echo $attrs[$i]."<br>";
Patrz również: ldap_first_attribute() i ldap_next_attribute().
ldap_get_dn
Zwraca DN pozycji wyniku lub
sprawdzenia DN pozycji wyniku.
False
w przypadku błędu. Funkcja
ldap_get_dn()
jest używana do
string ldap_get_dn (int link_identifier, int result_entry_identifier)
ldap_get_entries
Zwraca wszystkie dane pozycji w postaci wielowymiarowej tablicy lub w przypadku wystąpienia błędu,
Funkcja ldap_get_entries() używana jest w celu uproszczenia odczytywania wielu pozycji z wyniku i
następnie odczytywanie atrybutów i wielokrotnych wartości. Wszystkie dane są zwracane za pomocą jednego
wywołania funkcji we wielowymiarowej tablicy.
Struktura tablicy jest następująca. Indeksy atrybutów są konwertowane do małych liter (wielkość liter w
atrybutach ma znaczenie dla serwerów katalogów, ale nie gdy są używane jako indeksy tablicy).
False.
return_value["count"] = ilość pozycji w wyniku
return_value[0] : szczegóły pierwszej pozycji
return_value[i]["dn"] = DN i-tej pozycji w wyniku
return_value[i]["count"] = ilość atrybutów w i-tej pozycji
return_value[i][j] = j-ty atrybut i-tej pozycji w wyniku
return_value[i]["atrybut"]["count"] = ilość wartości dla atrybutów i-tej pozycji
return_value[i]["atrybut"][j] = j-ta wartość atrybutu na i-tej pozycji
array ldap_get_entries (int link_identifier, int result_identifier)
ldap_get_values
Zwraca tablicę wartości atrybutu lub False w przypadku wystąpienia błędu. Funkcja ldap_get_values()
jest używana do odczytania wszystkich wartości atrybutów z pozycji wyniku. Pozycja jest określona przez
$result_entry_identifier. Ilość wartości można odczytać z wynikowej tablicy, spod indeksu count.
Poszczególne wartości mogą być odczytane poprzez numeryczne indeksy tablicy. Pierwszy indeks ma wartość 0.
Funkcja wymaga identyfikatora pozycji wyniku, więc musi być poprzedzona przez jedną z funkcji wyszukujących
i jedno z wywołań pobierających poszczególne pozycje. W aplikacji można na stałe zapisać nazwy interesujących
nas atrybutów (na przykład surname lub mail), można również użyć funkcji ldap_get_attributes() do
sprawdzenia jakie atrybuty istnieją dla danej pozycji. LDAP pozwala na przechowywanie więcej niż jednej
pozycji dla atrybuty, więc można na przykład zapamiętywać kilka adresów e-mail w pozycji katalogu
zawierającej określoną osobę.
return_value["count"] = ilość wartości atrybutu
return_value[0] = pierwsza wartość atrybutu
return_value[i] = i-ta wartość atrybutu
array ldap_get_values (int link_identifier, int result_entry_identifier,
string attribute)
Przykład: Lista wszystkich wartości atrybutu ‘mail’ dla pozycji katalogu
// $ds jest identyfikatorem połączenia z katalogiem
// $sr jest prawidłowym wynikiem pochodzącym z
289
PHP – Kompendium wiedzy
// wywołania jednej z funkcji przeszukujących
// $entry jest idnetyfikatorem pozycji pochodzącym z
//
jednego z wywołań zwracających pozycje katalogu
$values = ldap_get_values($ds, $entry,"mail");
echo $values["count"]." adresów email dla tej pozycji.<p>";
for ($i=0; $i < $values["count"]; $i++)
echo $values[$i]."<br>";
ldap_get_values_len
Zwraca
tablicę
wartości atrybutu lub False w przypadku wystąpienia błędu. Funkcja
używana jest do odczytania wszystkich wartości atrybutu dla pozycji wyniku. Pozycja
jest określona przez $result_entry_identifier. Ilość wartości można odczytać z indeksu count wynikowej
tablicy. Poszczególne wartości są dostępne w tablicy pod indeksami całkowitymi. Indeksy zaczynają się od 0.
Funkcji tej używa się identycznie jak ldap_get_values(), ale obsługuje dane binarne a nie ciągi.
ldap_get_values_len()
Uwaga
Funkcja została dodana w PHP 4.0.
array ldap_get_values_len (int link_identifier, int result_entry_identifier,
string attribute)
ldap_list
Zwraca identyfikator wyniku poszukiwania, lub False w przypadku wystąpienia błędu. Funkcja
ldap_list() przeszukuje katalog w poszukiwaniu wartości pasujących do podanego filtra z zastosowaniem
zasięgu LDAP_SCOPE_ONELEVEL. Zasięg LDAP_SCOPE_ONELEVEL oznacza, że przeszukiwany zostanie tylko poziom
bezpośrednio po podanym bazowym DN podanym w wywołaniu funkcji (ekwiwalent wpisania ls i pobrania naw
plików i folderów w bieżącym katalogu). Funkcja posiada 5 parametrów opcjonalnych. Opis znajduje się przy
omawianiu funkcji ldap_search().
Uwaga
Parametry opcjonalne $attrsonly, $sizelimit, $timelimit i $deref zostały dodane w PHP 4.0.2.
int ldap_list (int link_identifier, string base_dn, string filter [, array attributes
[, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
Przykład: Utworzenie listy wszystkich jednostek organizacyjnych w organizacji
// $ds jest identyfikatorem połączenia do serwera katalogu
$basedn = "o=My Company, c=US";
$justthese = array("ou");
$sr=ldap_list($ds, $basedn, "ou=*", $justthese);
$info = ldap_get_entries($ds, $sr);
for ($i=0; $i<$info["count"]; $i++)
echo $info[$i]["ou"][0] ;
ldap_modify
Zwraca True w przypadku powodzenia operacji lub False w przypadku błędu. Funkcja ldap_modify()
używana jest do zmiany istniejących pozycji w katalogu LDAP. Struktura pozycji jest identyczna jak ldap_add().
int ldap_modify (int link_identifier, string dn, array entry)
ldap_mod_add
Zwraca True w przypadku powodzenia operacji lub False w przypadku błędu. Funkcja dodaje atrybut do
podanego $dn. Wykonuje zmianę na poziomie atrybutu a nie na poziomie obiektu. Dodawanie na poziomie
obiektu wykonywane jest za pomocą funkcji ldap_add().
int ldap_mod_add (int link_identifier, string dn, array entry)
Dodatek A - Funkcje
290
ldap_mod_del
Zwraca True w przypadku powodzenia operacji lub False w przypadku błędu. Funkcja usuwa atrybut do
podanego $dn. Wykonuje zmianę na poziomie atrybutu a nie na poziomie obiektu. Usuwanie na poziomie obiektu
wykonywane jest za pomocą funkcji ldap_del().
int ldap_mod_del (int link_identifier, string dn, array entry)
ldap_mod_replace
Zwraca True w przypadku powodzenia operacji lub False w przypadku błędu. Funkcja zamienia atrybut(y)
z podanego $dn. Wykonuje zmianę na poziomie atrybutu a nie na poziomie obiektu. Modyfikacje na poziomie
obiektu wykonywane jest za pomocą funkcji ldap_modify().
int ldap_mod_replace (int link_identifier, string dn, array entry)
ldap_next_attribute
Zwraca
kolejny atrybut w pozycji lub False w przypadku wystąpienia błędu. Funkcja
jest wywoływana w celu odczytania atrybutów pozycji. Stan wewnętrznego wskaźnika
jest utrzymywany przez $ber_identifier. Jest on przekazywany do funkcji przez referencję. Pierwsze wywołanie
ldap_next_identifier()
jest
wykonywane
z
$result_entry_identifier
zwracanym
przez
ldap_first_identifier(). Patrz również: ldap_get_atributes().
ldap_next_attribute()
string ldap_next_attribute (int link_identifier, int result_entry_identifier,
int ber_identifier)
ldap_next_entry
Zwraca identyfikator pozycji dla następnej pozycji w wyniku, którego pierwsza pozycja została odczytana
za pomocą ldap_first_entry(). Jeżeli nie ma już kolejnych pozycji w wyniku, funkcja zwraca False. Funkcja
ldap_next_entry() używana jest do odczytania pozycji znajdujących się w wyniku. Kolejne wywołania
ldap_next_entry() powoduje zwracanie kolejnych pozycji aż do ich wyczerpania. Pierwsze wywołanie
ldap_next_entry() jest wykonywane z identyfikatorem wyniku zwróconym przez ldap_first_entry(). Patrz
również: ldap_get_entries().
int ldap_next_entry (int link_identifier, int result_entry_identifier)
ldap_read
Zwraca identyfikator wyniku przeszukiwania lub False w przypadku wystąpienia błędu. Funkcja
szuka filtra w katalogu z zakresie LDAP_SCOPE_BASE, więc jest odpowiednikiem odczytania pozycji z
katalogu. Nie jest dozwolone używanie pustego filtra. Jeżeli chcesz odczytać wszystkie dane z tej pozycji należy
użyć filtra objectClass=*. Jeżeli wiesz, jaki typ pozycji jest użyty w serwerze katalogu, można wykorzystać
odpowiedni filtr, na przykład objectClass=inetOrgPerson. Funkcja posiada pięć parametrów opcjonalnych. Opis
znajduje się przy omawianiu funkcji ldap_search().
ldap_read()
Uwaga
Parametry opcjonalne $attrsonly, $sizelimit, $timelimit i $deref zostały dodane w PHP 4.0.2.
int ldap_read (int link_identifier, string base_dn, string filter [, array attributes
[, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
ldap_search
Zwraca identyfikator wyniku przeszukiwania lub False w przypadku błędu. Funkcja ldap_search() szuka
podanego filtra w katalogu, z zastosowaniem zasięgu LDAP_SCOPE_SUBTREE. Jest to ekwiwalent przeszukania
zawartości katalogu. Parametr $base_dn określa bazowy DN w katalogu. Dostępny jest czwarty parametr
opcjonalny, który pozwala ograniczyć ilość zwracanych atrybutów i wartości. Użycie tego parametru powinno
291
PHP – Kompendium wiedzy
być traktowane jako dobrą praktykę programistyczną. Czwarty parametr jest zwykłą tablicą ciągów zawierających
wymagane atrybuty, na przykład: array( "mail", "cn").
Uwaga
DN jest zawsze zwracany niezależnie od typów żądanych typów atrybutów. Należy pamiętać, że niektóre serwery katalogów są tak
skonfigurowane, aby zwracać nie więcej, niż skonfigurowaną ilość pozycji. Jeżeli wystąpi taka sytuacja, serwer wskazuje, że zwraca
jedynie częściowy wynik. Występuje to również, gdy ustawiony zostanie szósty parametr $sizelimit ograniczający ilość
pobieranych pozycji.
int ldap_search (int link_identifier, string base_dn, string filter
[, array attributes [, int attrsonly [, int sizelimit
[, int timelimit [, int deref]]]]])
Piąty parametr $attrsonly powinien być ustawiony na 1, jeżeli potrzebujemy jedynie atrybutu. Jeżeli
ustawiony jest na 0, pobierane są zarówno atrybuty jak i ich wartości. Jest to ustawienie domyślne. Za pomocą
szóstego parametru, $sizelimit, można ograniczyć ilość pobieranych pozycji.
Uwaga
Parametr ten nie może zwiększyć limitu ustawionego na serwerze, ale może go zmniejszyć.
Siódmy parametr, $timelimit, ogranicza czas przeszukiwania katalogu do podanej liczby sekund.
Ustawienie tego parametru na 0 powoduje zniesienie limitu.
Uwaga
Parametr ten nie może zwiększyć limitu ustawionego na serwerze, ale może go zmniejszyć.
Ósmy parametr, $deref, wskazuje na sposób obsługi aliasów w czasie szukania. Może przyjmować
następujące wartości:
• LDAP_DEREF_NEVER — (domyślny) aliasy nie są rozwijane
• LDAP_DEREF_SEARCHING — aliasy są rozwijane w czasie szukania, ale nie w czasie określania
podstawowych obiektów przeszukiwania
• LDAP_DEREF_FINDING — aliasy są rozwijane w czasie określania podstawowych obiektów przeszukiwania,
ale nie w czasie szukania
• LDAP_DEREF_ALWAYS — aliasy są zawsze rozwijane
Parametry opcjonalne $atrsonly, $sizelimit, $timelimit i $deref zostały dodane w PHP 4.0.2. Filtry
przeszukiwania mogą być proste lub zaawansowane z wykorzystaniem operatorów logicznych w formacie
opisanym
w
dokumentacji
LDAP
(np.:
Netscape
Directory
SDK
pod
adresem
http://developer.netscape.com/docs/manuals/directory/41/ag/find.htm). Poniższy przykład odczytuje jednostkę
organizacyjną, nazwisko, imię i e-mail wszystkich osób w firmie „Firma”, których nazwiska zawierają ciąg
określony przez zmienną $person. Przykład ten wykorzystuje filtry logiczne nakazujące serwerowi poszukiwanie
danych we większej ilości atrybutów.
Przykład: Przeszukiwanie LDAP
// $ds jest identyfikatorem połączenia z katalogiem
// $person jest kompletną nazwą lub jej częścią np: "Jo"
$dn = "o=Firma, c=US";
$filter="(|(sn=$person*)(givenname=$person*))";
$justthese = array( "ou", "sn", "givenname", "mail");
$sr=ldap_search($ds, $dn, $filter, $justthese);
$info = ldap_get_entries($ds, $sr);
print $info["count"]." pozycji w wyniku<p>";
ldap_unbind
Zwraca True w przypadku powodzenia operacji lub
odłącza od katalogu LDAP.
False
w przypadku błędu. Funkcja
ldap_unbind()
int ldap_unbind (int link_identifier)
Dodatek A - Funkcje
292
leak
Powoduje „wyciek” określonej ilości pamięci. Jest to przydatne przy testowaniu zarządcy pamięci, który
automatycznie odzyskuje pamięć utraconą po „wycieku”, po zakończeniu każdego żądania.
void leak (int bytes)
levenshtein
Zwraca odległość Levenshtein pomiędzy dwoma ciągami przekazanymi jako argumenty lub -1 gdy jeden z
ciągów jest dłuższy niż 255 znaków (255 powinno wystarczyć do porównywania nazwisk lub katalogów a nikt
rozsądny nie będzie wykonywał analizy genetycznej za pomocą PHP). Odległość Levenshtein jest definiowana
jako minimalna ilość znaków jakie trzeba zamienić, wstawić lub usunąć, aby zamienić $str1 na $str2. Algorytm
ten ma złożoność O(m*n), gdzie m i n są długością ciągów $str1 i $str2 (całkiem nieźle w porównaniu do
similar_text(), która ma złożoność O(max(n,m)**3), ale i tak jest to kosztowny algorytm)
int levenshtein (string str1, string str2)
int levenshtein (string str1, string str2, int cost_ins, int cost_rep, int cost_del)
int levenshtein (string str1, string str2, function cost)
W swojej najprostszej postaci funkcja wymaga jedynie dwóch ciągów jako parametry i oblicza ilość
operacji wstawienia, zamiany lub usunięcia potrzebnych do zamiany $str1 na $str2. Drugi wariant potrzebuje
trzech dodatkowych paramterów definiujących koszt operacji wstawienia, zamiany i usunięcia. Jest to bardziej
ogólny i adaptowalny wariant funkcji, ale nie jest on tak wydajny. Trzeci wariant, który jeszcze nie został
zaimplementowany, będzie najbardziej ogólny, ale również najwolniejszy. Będzie wywoływał funkcję napisaną
przez użtkownika, która będzie zwracała koszt każdej operacji. Funkcja użytkownika posiadać musi następujące
parametry:
• operacja do wykonania: I, R lub D
• bieżący znak w ciągu 1
• bieżący znak w ciągu 2
• pozycja w ciągu 1
• pozycja w ciągu 2
• pozostałe znaki w ciągu 1
• pozostałe znaki w ciągu 2
Funkcja napisana przez użytkownika musi zwracać liczbę dodatnią oznaczającą koszt bieżącej operacji,
ale do tego celu może używać tylko niektórych z przekazanych argumentów. Użycie funkcji użytkownika
pozwala na możliwość wzięcia pod uwagę różnicy pomiędzy znakami lub nawet kontekstu, w jakim występują w
ciągu. Jednak wywoływanie tej funkcji do obliczenia kosztu każdej operacji, powoduje utratę wszystkich
optymalizacji użycia rejestrów procesora i pamięci podręcznej, które są zastosowane w poprzednich dwóch
wariantach. Patrz również: soundex(), similar_text() i metaphone().
link
Tworzy trwałe łącze. Patrz również:
linkinfo().
symlink()
do tworzenia łącz symbolicznych oraz
readlink()
i
Uwaga
Funkcja ta nie działa w systemie Windows
int link (string target, string link)
linkinfo
Zwraca pole st_dev ze struktury stat zwracanej przez funkcję systemową lstat w systemie UNIX.
Funkcja ta używana jest do sprawdzania, czy łącze (wskazywane przez $path) istnieje (wykorzystując metodę
293
PHP – Kompendium wiedzy
zdefiniowaną w makro S_ISLNK z pliku stat.h). Zwraca 0 lub False w przypadku błędu. Patrz również: symlink(),
link() i readlink().
Uwaga
Funkcja ta nie działa w systemie Windows
int linkinfo (string path)
list
Podobnie jak array() nie jest prawdziwą funkcją, ale konstrukcją języka.
przypisywania wartości do listy zmiennych przy pomocy jednej operacji.
list()
jest używane do
void list (...)
Przykład: list()
<table>
<tr>
<th>Nazwisko pracownika</th>
<th>Pensja</th>
</tr>
<?php
$result = mysql_query ($conn, "SELECT id, name, salary FROM employees");
while (list ($id, $name, $salary) = mysql_fetch_row ($result)) {
print (" <tr>\n".
" <td><a href=\"info.php3?id=$id\">$name</a></td>\n".
" <td>$salary</td>\n".
" </tr>\n");
}
?>
</table>
Patrz również: each() i array().
listen
Po utworzeniu gniazda $socket za pomocą funkcji socket() i przyłączeniu go za pomocą bind(), można
za pomocą funkcji listen() nakazać nasłuchiwanie przychodzących połączeń. Kolejkowane i przetwarzane
będzie $backlog połączeń. Funkcja listen() działa jedynie na gniazdach o typie SOCK_STREAM lub SOCK_SEQPACKET.
Zwraca 0 w przypadku powodzenia lub ujemny kod błędu w przypadku niepowodzenia. Kod ten może być
przekazany do strerror() w celu otrzymania tekstu opisującego błąd. Patrz również: socket_connect(), bind(),
connect(), socket(), socket_get_status() i strerror().
int listen (resource socket, int backlog)
localtime
Zwraca tablicę identyczną ze strukturą zwracaną przez tą samą funkcję w C. Pierwszym argumentem
localtime() jest znacznik czasu. Jeżeli nie zostanie podany, użyty zostanie bieżący czas. Drugi argument to
$is_associative. Jeżeli jest ustawiony na 0 lub nie zostanie podany, zwracana tablica jest zwykłą tablicą z
indeksami numerycznymi. Jeżeli argument ten zostanie ustawiony na 1, localtime() zwróci tablicę asocjacyjną
zawierającą wszystkie elementy struktury zwracanej przez wywołanie funkcji localtime() w C.
array localtime ([int timestamp [, bool is_associative]])
Nazwy kluczy w tablicy asocjacyjnej są:
• tm_sec — sekundy
• tm_min — minuty
• tm_hour — godziny
• tm_mday — dzień miesiąca
• tm_mon — miesiąc w roku
• tm_year — rok, nie jest zgodny z rokiem 2000
• tm_wday — dzień tygodnia
• tm_yday — dzień kolejny w roku
• tm_isdst — czy zastosowano czas zimowy
Dodatek A - Funkcje
294
log
Zwraca logarytm naturalny z $arg.
float log (float arg)
log10
Zwraca logarytm o podstawie 10 z $arg.
float log10 (float arg)
long2ip
Generuje adres internetowy w postaci z kropkami (aaa.bbb.ccc.ddd) na podstawie właściwej reprezentacji
adresu.
string long2ip (int proper_address)
lstat
Zbiera statystyki pliku lub łącza symbolicznego o podanej nazwie. Funkcja jest podobna do stat() poza
tym, że gdy parametr $filename jest łączem symbolicznym, zwracany jest stan łącza a nie status pliku, na który
wskazuje łącze.
array lstat (string filename)
Zwraca tablicę ze statystykami następujących parametrów pliku:
urządzenie
i-node
tryb zabezpieczenia inode
liczba dowiązań
identyfikator
właściciela
typ urządzenia, jeżeli
rozmiar w bajtach
jest to urządzenie z i-node *
czas
ostatniej
czas ostatniej zmiany
modyfikacji
identyfikator grupy
czas
ostatniego
dostępu
rozmiar bloku dla
operacji
wejścia-wyjścia
systemu plików *
ilość przydzielonych
bloków
* dostępne tylko na systemach obsługujących typ st_blksize — inne systemy (na przykład Windows)
zwracają -1. Wyniki tej funkcji są przechowywane w buforze. Szczegóły zostały opisane przy funkcji
clearstatcache().
ltrim
Usuwa znaki odstępu z początku ciągu i zwraca obcięty ciąg. Obsługiwanymi znakami odstępu są: \n, \r,
\t, \v, \0 oraz spacja. Patrz również: chop() i trim().
string ltrim (string str [, string charlist])
mail
Wysyła wiadomość pocztową o treści przekazanej w $message do odbiorcy w
odbiorców umieszczając średnik pomiędzy adresami przekazanymi w parametrze $to.
$to.
Można podać wielu
bool mail (string to, string subject, string message [, string additional_headers
[, string additional_parameters]])
Przykład: wysyłanie poczty
mail("[email protected]", "Temat", "Linia 1\nLinia 2\nLinia 3");
Jeżeli zostanie przekazany czwarty argument ciąg ten jest wstawiany na końcu nagłówka. Jest on zwykle
używany do wstawiania do wiadomości dodatkowych nagłówków. Kolejne wiersze nagłówka muszą być
rozdzielone znakiem nowego wiersza.
PHP – Kompendium wiedzy
295
Przykład: Wysyłanie wiadomości z dodatkowymi nagłówkami
mail("[email protected]", "Temat", $message,
"From: webmaster@$SERVER_NAME\nReply-To: webmaster@$SERVER_NAME\nX-Mailer: PHP/"
. phpversion());
Można również stosować proste techniki budowania ciągów do tworzenia całkiem skomplikowanych
wiadomości e-mail.
Przykład: Wysyłanie skomplikowanych przesyłek e-mail
/* odbiorcy */
$recipient .= "Mary <[email protected]>" . ", " ; //zwróć uwagę na przecinek
$recipient .= "Kelly <[email protected]>" . ", ";
$recipient .= "[email protected]";
/* temat */
$subject = "Przypomnienie o urodzinach w sierpniu";
/* wiadomość */
$message .= "Wiadomość zawiera tabelę sformatowaną za pomocą znaków ASCII\n";
$message .= "Dzień \t\tMiesiąc \t\tRok\n";
$message .= "3 \t\tSierpień \t\t1970\n";
$message .= "17\t\tSierpień \t\t1973\n";
/* można dodać sygnaturkę */
$message .= "--\r\n"; //Separator sygnaturki
$message .= "Przypominacz urodzin oddany do publicznego używania";
/* dodatkowe fragmenty nagłówka, From cc, bcc, itp. */
$headers .= "From: Pzrypominacz urodzin <[email protected]>\n";
$headers .= "X-Sender: <[email protected]>\n";
$headers .= "X-Mailer: PHP\n"; // klient poczty
$headers .= "X-Priority: 1\n"; // wiadomość ważna!
$headers .= "Return-Path: <[email protected]>\n"; // ścieżka zwrotna dla błedów
/* jeżeli chcez wysłać pocztę HTML, usuń komentarz z poniższej linii */
// $headers .= "Content-Type: text/html; charset=iso-8859-1\n"; // Typ mime
$headers .= "cc: [email protected]\n"; // CC
$headers .= "bcc: [email protected], [email protected]"; // BCC
/* wyślij wiadomość */
mail($recipient, $subject, $message, $headers);
max
Zwraca parametr o największej wartości numerycznej. Jeżeli pierwszy parametr jest tablicą, max() zwraca
największą wartość w tablicy. Jeżeli pierwszy parametr jest liczbą całkowitą, ciągiem lub liczbą double, funkcja
wymaga co najmniej dwóch parametrów i zwraca największy z nich. Można porównywać nieograniczoną ilość
wartości. Jeżeli jedna lub więcej wartości jest liczbą double, wszystkie wartości są traktowane jako double i
zwracana jest liczba typu double. Jeżeli żadna z wartości nie jest liczbą double, wszystkie są traktowane jako
liczby całkowite i również zwracana jest liczba całkowita.
mixed max (mixed arg1, mixed arg2, mixed argn)
mcal_append_event
Zapamiętuje globalne zdarzenie w kalendarzu MCAL, dla podanego strumienia. Zwraca identyfikator
wstawionego zdarzenia.
int mcal_append_event (int mcal_stream)
mcal_close
Zamyka podany strumień MCAL.
int mcal_close (int mcal_stream, int flags)
mcal_create_calendar
Tworzy nowy kalendarz o nazwie $calendar.
string mcal_create_calendar (int stream, string calendar)
mcal_date_compare
Porównuje dwie podane daty. Zwraca <0, 0, >0 gdy a<b, a==b, a>b.
int mcal_date_compare (int a_year, int a_month, int a_day,
int b_year, int b_month, int b_day)
Dodatek A - Funkcje
296
mcal_date_valid
Zwraca
prawidłowa.
True,
jeżeli podany rok, miesiąc i dzień jest prawidłową datą lub
False,
gdy nie jest to data
int mcal_date_valid (int year, int month, int day)
mcal_days_in_month
Zwraca ilość dni w podanym miesiącu biorąc pod uwagę, czy rok jest przestępny czy nie.
int mcal_days_in_month (int month, int leap year)
mcal_day_of_week
Zwraca dzień tygodnia dla podanej daty.
int mcal_day_of_week (int year, int month, int day)
mcal_day_of_year
Zwraca dzień w roku dla podanej daty.
int mcal_ (int year, int month, int day)
mcal_delete_calendar
Usuwa kalendarz o nazwie $calendar.
string mcal_delete_calendar (int stream, string calendar)
mcal_delete_event
Usuwa zdarzenie kalendarza wskazywane przez $event_id. Zwraca True.
int mcal_delete_event (int mcal_stream [, int event_id])
mcal_event_add_attribute
Dodaje do globalnej struktury zdarzeń strumienia atrybut o wartości przekazanej w parametrze $value.
void mcal_event_add_attribute (int stream, string attribute, string value)
mcal_event_init
Inicjuje globalną strukturę strumienia. Powoduje to ustawienie wszystkich elementów struktury na 0 lub
na wartość domyślną. Zwraca True.
int mcal_event_init (int stream)
mcal_event_set_alarm
Ustawia alarm w globalnej strukturze strumienia na podaną liczbę minut przed zdarzeniem. Zwraca True.
int mcal_event_set_alarm (int stream, int alarm)
mcal_event_set_category
Ustawia kategorię globalnej struktury zdarzenia na podany ciąg. Zwraca True.
int mcal_event_set_category (int stream, string category)
mcal_event_set_class
Ustawia klasę globalnej struktury zdarzenia na podaną wartość. Klasa może mieć wartość
lub 0 — prywatna. Zwraca True.
297
1
— publiczna
PHP – Kompendium wiedzy
int mcal_event_set_class (int stream, int class)
mcal_event_set_description
Ustawia opis globalnej struktury zdarzenia na podaną wartość. Zwraca True.
int mcal_event_set_description (int stream, string description)
mcal_event_set_end
Ustawia datę i czas zakończenia w globalnej strukturze zdarzenia na podaną wartość. Zwraca True.
int mcal_event_set_end (int stream, int year, int month [, int day
[, int hour [, int min [, int sec]]]])
mcal_event_set_recur_daily
Ustawia wartość powtarzania w globalnej strukturze zdarzenia na podaną codzienne powtarzanie kończące
się na podanej dacie.
int mcal_event_set_recur_daily (int stream, int year, int month, int day,
int interval)
mcal_event_set_recur_monthly_mday
Ustawia wartość powtarzania w globalnej strukturze zdarzenia na podaną comiesięczne powtarzanie
opierając się na dniu miesiąca, kończące się na podanej dacie.
int mcal_event_set_recur_monthly_mday (int stream, int year, int month, int day,
int interval)
mcal_event_set_recur_monthly_wday
Ustawia wartość powtarzania w globalnej strukturze zdarzenia na podaną comiesięczne powtarzanie
opierając się na tygodniu, kończące się na podanej dacie.
int mcal_event_set_recur_monthly_wday (int stream, int year, int month, int day,
int interval)
mcal_event_set_recur_none
Wyłącza powtarzanie w globalnej strukturze zdarzenia (event->recur_type jest ustawiane na
MCAL_RECUR_NONE).
int mcal_event_set_recur_none (int stream)
mcal_event_set_recur_weekly
Ustawia wartość powtarzania w globalnej strukturze zdarzenia na podaną cotygodniowe powtarzanie,
kończące się na podanej dacie.
int mcal_event_set_recur_weekly (int stream, int year, int month, int day,
int interval, int weekdays)
mcal_event_set_recur_yearly
Ustawia wartość powtarzania w globalnej strukturze zdarzenia na podaną coroczne powtarzanie, kończące
się na podanej dacie.
int mcal_event_set_recur_yearly (int stream, int year, int month, int day,
int interval)
mcal_event_set_start
Ustawia datę i czas rozpoczęcia w globalnej strukturze zdarzenia na podaną wartość. Zwraca True.
int mcal_event_set_start (int stream, int year, int month [, int day [, int hour
Dodatek A - Funkcje
298
[, int min [, int sec]]]])
mcal_event_set_title
Ustawia tytuł w globalnej strukturze zdarzenia na podany ciąg. Zwraca True.
int mcal_event_set_title (int stream, string title)
mcal_expunge
Usuwa wszystkie zdarzenia oznaczone jako usunięte.
int mcal_expunge (int stream)
mcal_fetch_current_stream_event
object mcal_fetch_current_stream_event (int stream)
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Zwraca bieżącą strukturę zdarzenia ze strumienia w postaci obiektu zawierający następujące atrybuty:
int id — Identyfikator zdarzenia.
int public — TRUE jeżeli zdarzenie jest publiczne, FALSE jeżeli jest prywatne.
string category — Ciąg z kategorią zdarzenia.
string title — Ciąg z tytułem zdarzenia.
string description — Ciąg z opisem zdarzenia.
int alarm — Ilość minut przed zdarzeniem do wysłania alarmu lub przypomnienia.
object start — Obiekt zawierający początkową datę i czas.
object end — Obiekt zawierający końcową datę i czas.
int recur_type — Typ powtarzania.
int recur_interval — Okres powtarzania.
datetime recur_enddate — Data zakończenia powtarzania.
int recur_data — Dane powtarzania.
Wszystkie pozycje zawierające datę i czas są obiektem zawierającym:
int year — rok
int month — miesiąc
int mday — dzień miesiąca
int hour — godzina
int min — minuty
int sec — sekundy
int alarm — ilość minut przed zdarzeniem kiedy należy wysłać przypomnienie
mcal_fetch_event
Pobiera zdarzenie ze strumienia kalendarza określonego przez $id.
object mcal_fetch_event (int mcal_stream, int event_id [, int options])
•
•
•
•
•
•
•
•
•
•
299
Zwraca obiekt zdarzenia zawierający następujące atrybuty:
int id — Identyfikator zdarzenia.
int public — TRUE jeżeli zdarzenie jest publiczne, FALSE jeżeli jest prywatne.
string category — Ciąg z kategorią zdarzenia.
string title — Ciąg z tytułem zdarzenia.
string description — Ciąg z opisem zdarzenia.
int alarm — Ilość minut przed zdarzeniem do wysłania alarmu lub przypomnienia.
object start — Obiekt zawierający początkową datę i czas.
object end — Obiekt zawierający końcową datę i czas.
int recur_type — Typ powtarzania.
int recur_interval — Okres powtarzania.
PHP – Kompendium wiedzy
•
•
•
•
•
•
•
•
•
— Data zakończenia powtarzania.
int recur_data — Dane powtarzania.
Wszystkie pozycje zawierające datę i czas są obiektem zawierającym:
int year — rok
int month — miesiąc
int mday — dzień miesiąca
int hour — godzina
int min — minuty
int sec — sekundy
int alarm — ilość minut przed zdarzeniem kiedy należy wysłać przypomnienie
datetime recur_enddate
mcal_is_leap_year
Zwraca 1 gdy podany rok jest przestępny, 0 gdy nie jest.
int mcal_is_leap_year (int year)
mcal_list_alarms
Zwraca tablicę identyfikatorów zdarzeń, które posiadają ustawiony alarm pomiędzy datą początkową i
końcową, lub jeżeli podano tylko strumień, używane są daty z globalnej struktury zdarzeń. Funkcja
mcal_list_alarms() posiada opcjonalne parametry: datę początkowa końcową dla strumienia kalendarza.
Zwracana jest tablica identyfikatorów zdarzeń, które mają alarm pomiędzy podanymi datami lub datami z
wewnętrznej struktury zdarzeń.
array mcal_list_alarms (int mcal_stream [, int begin_year [, int begin_month
[, int begin_day [, int end_year [, int end_month [, int end_day]]]]]])
mcal_list_events
Zwraca tablicę identyfikatorów zdarzeń występujących pomiędzy datą początkową i końcową, lub jeżeli
podano tylko strumień, używane są daty z globalnej struktury zdarzeń. Funkcja mcal_list_events() posiada
opcjonalne parametry: datę początkowa końcową dla strumienia kalendarza. Zwracana jest tablica
identyfikatorów zdarzeń, które są pomiędzy podanymi datami lub datami z wewnętrznej struktury zdarzeń.
array mcal_list_events (int mcal_stream, objectbegin_date [, object end_date])
mcal_next_recurrence
Zwraca obiekt z kolejną datą wystąpienia zdarzenia po podanej dacie. Zwraca puste pole daty, jeżeli
zdarzenie nie wystąpi lub wystąpił błąd. Używa parametru $weekstart do określenia dnia rozpoczynającego
tydzień.
int mcal_next_recurrence (int stream, int weekstart, array next)
mcal_open
Zwraca strumień MCAL lub False w przypadku błędu. Funkcja mcal_open() otwiera połączenie MCAL
do określonego kalendarza. Jeżeli podany zostanie opcjonalny parametr $options, funkcja przekazuje również ten
parametr do skrzynki. Po zestawieniu połączenia inicjowana jest również wewnętrzna struktura strumienia.
int mcal_open (string calendar, string username, string password [, int options])
mcal_popen
Zwraca strumień MCAL lub False w przypadku błędu. Funkcja mcal_open() otwiera połączenie MCAL
do określonego kalendarza. Jeżeli podany zostanie opcjonalny parametr $options, funkcja przekazuje również ten
parametr do skrzynki. Po zestawieniu połączenia inicjowana jest również wewnętrzna struktura strumienia.
int mcal_popen (string calendar, string username, string password [, int options])
Dodatek A - Funkcje
300
mcal_rename_calendar
Zmienia nazwę kalendarza z $old_name na $new_name.
string mcal_rename_calendar (int stream, string old_name, string new_name)
mcal_reopen
Funkcja mcal_reopen() ponownie otwiera połączenie MCAL do określonego kalendarza. Jeżeli podany
zostanie opcjonalny parametr $options, funkcja przekazuje również ten parametr do skrzynki.
int mcal_reopen (string calendar [, int options])
mcal_snooze
Wyłącza alarm dla kalendarza o podanym identyfikatorze. Zwraca True.
int mcal_snooze (int id)
mcal_store_event
Zapamiętuje zmiany w bieżącym globalnym zdarzeniu dla podanego strumienia. Zwraca
przypadku powodzenia a False w przypadku błędu.
True
w
int mcal_store_event (int mcal_stream)
mcal_time_valid
Zwraca True, jeżeli podana godzina, minuta i sekunda tworzą prawidłowy czas,
nieprawidłowy.
False
gdy jest to czas
int mcal_time_valid (int hour, int minutes, int seconds)
mcrypt_cbc
Pierwszy prototyp jest dla przypadku, gdy dołączona jest biblioteka libmcrypt 2.2.x, drugi gdy libmcrypt
2.4.x. Funkcja mcrypt_cbc() szyfruje i deszyfruje (w zależności od trybu) dane $data za pomocą $cipher i $key w
trybie szyfrowania CBC i zwraca wynikowy ciąg. Patrz również: mcrypt_cfb(), mcrypt_ecb() i mcrypt_ofb().
string mcrypt_cbc (int cipher, string key, string data, int mode [, string iv])
string mcrypt_cbc (string cipher, string key, string data, int mode [, string iv])
•
•
•
•
•
jest jedną ze stałych MCRYPT_ciphername.
$Key jest kluczem przekazywanym do algorytmu. Musi być tajny.
$Data to dane do zaszyfrowania lub odszyfrowania.
$Mode to MCRYPT_ENCRYPT lub MCRYPT_DECRYPT.
$IV jest opcjonalnym wektorem inicjalizacji.
$Cipher
mcrypt_cfb
Pierwszy prototyp jest dla przypadku, gdy dołączona jest biblioteka libmcrypt 2.2.x, drugi gdy libmcrypt
2.4.x. Funkcja mcrypt_cfb() szyfruje i deszyfruje (w zależności od trybu) dane $data za pomocą $cipher i $key w
trybie szyfrowania CFB i zwraca wynikowy ciąg. Patrz również: mcrypt_cbc(), mcrypt_ecb() i mcrypt_ofb().
string mcrypt_cfb (int cipher, string key, string data, int mode, string iv)
string mcrypt_cfb (string cipher, string key, string data, int mode [, string iv])
•
•
•
•
•
301
jest jedną ze stałych MCRYPT_ciphername.
$Key jest kluczem przekazywanym do algorytmu. Musi być tajny.
$Data to dane do zaszyfrowania lub odszyfrowania.
$Mode to MCRYPT_ENCRYPT lub MCRYPT_DECRYPT.
$IV jest opcjonalnym wektorem inicjalizacji.
$Cipher
PHP – Kompendium wiedzy
mcrypt_create_iv
Funkcja używana do tworzenia wektora IV. Posiada dwa argumenty, $size określa rozmiar IV, natomiast
$source określa źródło IV. Źródłem może być MCRYPT_RAND (systemowy generator liczb losowych),
MCRYPT_DEV_RANDOM (odczytanie danych z /dev/random) lub MCRYPT_DEV_URANDOM (odczytanie danych z
/dev/urandom). Jeżeli używasz MCRYPT_RAND, upewnij się, że wywołałeś srand() przed inicjalizacją generatora
liczb losowych.
string mcrypt_create_iv (int size, int source)
Przykład: mcrypt_create_iv()
<?php
$cipher = MCRYPT_TripleDES;
$block_size = mcrypt_get_block_size ($cipher);
$iv = mcrypt_create_iv ($block_size, MCRYPT_DEV_RANDOM);
?>
mcrypt_decrypt
Pobiera dane zaszyfrowane i zwraca je w postaci odszyfrowanej.
string mcrypt_decrypt (string cipher, string key, string data, string mode
[, string iv])
•
•
•
•
•
jest jedną ze stałych MCRYPT_ciphername.
$Key jest kluczem przekazywanym do algorytmu. Jeżeli jest mniejszy od wymaganej wielkości klucza, jest
dopełniany znakami \0.
$Data to dane do odszyfrowania za pomocą podanego szyfru i trybu.
$Mode to jedna ze stałych MCRYPT_MODE_modename która może być: ecb, cbc, cfb, ofb, nofb lub stream.
$IV jest parametrem używanym do inicjalizacji dla trybów: CBC, CFB, OFB oraz w niektórych algorytmach
dla trybu STREAM. Jeżeli nie podasz IV, gdy jest on wymagany przez algorytm, funkcja wypisze ostrzeżenie
i użyje IV z wszystkimi bajtami ustawionymi na \0.
$Cipher
mcrypt_ecb
Pierwszy prototyp jest dla przypadku, gdy dołączona jest biblioteka libmcrypt 2.2.x, drugi gdy libmcrypt
2.4.x. Funkcja mcrypt_ecb() szyfruje i deszyfruje (w zależności od trybu) dane $data za pomocą $cipher i $key w
trybie szyfrowania CFB i zwraca wynikowy ciąg. Patrz również: mcrypt_cbc(), mcrypt_ecb() i mcrypt_ofb().
string mcrypt_ecb (int cipher, string key, string data, int mode)
string mcrypt_ecb (string cipher, string key, string data, int mode [, string iv])
•
•
•
•
•
jest jedną ze stałych MCRYPT_ciphername.
jest kluczem przekazywanym do algorytmu. Musi być tajny.
$Data to dane do zaszyfrowania lub odszyfrowania.
$Mode to MCRYPT_ENCRYPT lub MCRYPT_DECRYPT.
$IV jest opcjonalnym wektorem inicjalizacji.
Patrz również mcrypt_cbc(), mcrypt_cfb() i mcrypt_ofb().
$Cipher
$Key
mcrypt_encrypt
Szyfruje dane i zwraca ich zaszyfrowaną postać.
string mcrypt_encrypt (string cipher, string key, string data, string mode
[, string iv])
•
•
•
•
jest jedną ze stałych MCRYPT_ciphername.
$Key jest kluczem przekazywanym do algorytmu. Jeżeli jest mniejszy od wymaganej wielkości klucza, jest
dopełniany znakami \0.
$Data to dane do zaszyfrowania za pomocą podanego szyfru i trybu. Jeżeli rozmiar danych nie jest n *
blocksize, dane będą dopełnione znakami \0. Zwracany zaszyfrowany ciąg może być dłuższy od danych
przekazanych w parametrze $data.
$Mode to jedna ze stałych MCRYPT_MODE_modename która może być: ecb, cbc, cfb, ofb, nofb lub stream.
$Cipher
Dodatek A - Funkcje
302
•
jest parametrem używanym do inicjalizacji dla trybów: CBC, CFB, OFB oraz w niektórych algorytmach
dla trybu STREAM. Jeżeli nie podasz IV, gdy jest on wymagany przez algorytm, funkcja wypisze ostrzeżenie
i użyje IV z wszystkimi bajtami ustawionymi na \0.
Przykład: mcrypt_encrypt()
$IV
<?php
$iv = mcrypt_create_iv (
mcrypt_get_iv_size (MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
$key = "To jest sekretny klucz";
$text = "Spotkajmy się o 11:00 za pomnikiem.";
echo strlen ($text)."\n";
$crypttext = mcrypt_encrypt (MCRYPT_RIJNDAEL_256, $key, $text,
MCRYPT_MODE_ECB, $iv);
echo strlen ($crypttext)."\n";
?>
Przykład ten powinien wypisać:
35
64
mcrypt_enc_get_algorithms_name
Zwraca nazwę algorytmu.
string mcrypt_enc_get_algorithms_name (resource td)
mcrypt_enc_get_block_size
Zwraca wielkość bloku dla algorytmu określonego przez deskryptor $td w bajtach.
int mcrypt_enc_get_block_size (resource td)
mcrypt_enc_get_iv_size
Zwraca wielkość iv dla algorytmu określonego przez deskryptor szyfrowania w bajtach. Jeżeli zwraca 0,
IV jest ignorowany przez algorytm. Parametru IV używają tryby cbc, cfb o ofb, oraz niektóre algorytmy w trybie
stream.
int mcrypt_enc_get_iv_size (resource td)
mcrypt_enc_get_key_size
Zwraca maksymalną wielkość klucza obsługiwaną przez algorytm określony przez deskryptor
bajtach.
$td,
w
int mcrypt_enc_get_key_size (resource td)
mcrypt_enc_get_modes_name
Zwraca nazwę trybu.
string mcrypt_enc_get_modes_name (resource td)
mcrypt_enc_get_supported_key_sizes
Zwraca tablicę z wielkościami kluczy obsługiwanymi przez algorytm określony przez deskryptor
szyfrowania. Jeżeli zwróci pustą tablicę to oznacza, że wszystkie wielkości kluczy pomiędzy 1 i
mcrypt_enc_get_key_size() są obsługiwane przez algorytm.
array mcrypt_enc_get_supported_key_sizes (resource td)
mcrypt_enc_is_block_algorithm
Zwraca 1, jeżeli algorytm jest blokowy, 0 jeżeli jest to algorytm strumieniowy.
int mcrypt_enc_is_block_algorithm (resource td)
303
PHP – Kompendium wiedzy
mcrypt_enc_is_block_algorithm_mode
Zwraca 1, gdy tryb jest używany przez algorytm blokowy, w przeciwnym przypadku zwraca
przykład, 0 dla stream a 1 dla cbc, cfb, ofb).
0
(na
int mcrypt_enc_is_block_algorithm_mode (resource td)
mcrypt_enc_is_block_mode
Zwraca 1, gdy tryb zwraca bloki bajtów lub 0, gdy zwraca bajty (na przykład
1
dla
cbc
i
ecb
a
0
dla
cfb
i
stream).
int mcrypt_enc_is_block_mode (resource td)
mcrypt_enc_self_test
Uruchamia samotestowanie algorytmu określonego przez deskryptor
przypadku błędu zwraca 1.
$td.
Jeżeli test się uda, zwraca 0. W
int mcrypt_enc_self_test (resource td)
mcrypt_generic
Szyfruje dane. Dane są dopełniane znakami \0 do wielkości n
* blocksize.
Funkcja zwraca zaszyfrowane
dane.
Uwaga
Wielkość zwracanego ciągu może być większa od danych wejściowych z powodu dopełniania danych.
string mcrypt_generic (resource td, string data)
mcrypt_generic_end
Kończy szyfrowanie określone przez deskryptor szyfrowania ($td). Czyści wszystkie bufory i zamyka
użyte moduły. Zwraca False w przypadku wystąpienia błędu a True w przypadku powodzenia operacji.
bool mcrypt_generic_end (resource td)
mcrypt_generic_init
Maksymalna długość klucza powinna być pobrana poprzez wywołane funkcji mcrypt_enc_get_key_size()
i wszystkie wartości mniejsze od uzyskanej są dopuszczalne. Parametr $iv powinien mieć normalnie wielkość
bloku używanego przez algorytm, ale należy odczytać tą wielkość przy pomocy funkcji
mcrypt_enc_get_iv_size(). W trybie ECB IV jest ignorowany. IV jest wymagany w trybach CFB, CBC,
STREAM, nOFB i OFB. Musi być on losowy i niepowtarzalny, ale nie musi być tajny. Ten sam wektor IV musi
być użyty do kodowania i rozkodowywania. Jeżeli nie chcesz go używać, można zainicjować go zerami, ale nie
jest to zalecane. W przypadku wystąpienia błędu funkcja zwraca -1. Funkcja ta musi zostać wywołana przed
każdym wywołaniem mcrypt_generic() lub mdecrypt_generic().
int mcrypt_generic_init (resource td, string key, string iv)
mcrypt_get_block_size
Pierwszy prototyp jest dla przypadku, gdy dołączona jest biblioteka libmcrypt 2.2.x, drugi gdy libmcrypt
2.4.x. Funkcja mcrypt_get_block_size() jest używana do pobierania wielkości bloku dla podanego szyfrowania,
$cipher. Funkcja wymaga dwóch argumentów, $cipher oraz $module i zwraca wielkość w bajtach. Patrz również:
mcrypt_get_key_size().
int mcrypt_get_block_size (int cipher)
int mcrypt_get_block_size (string cipher, string module)
Dodatek A - Funkcje
304
mcrypt_get_cipher_name
Funkcja używana do pobierania nazwy podanego szyfrowania. Wymaga podania szyfrowania w postaci
liczby (libmcrypt 2.2.x) lub pobiera nazwę szyfrowania jako argument i zwraca nazwę szyfrowania lub False,
jeżeli nie istnieje ten sposób szyfrowania.
string mcrypt_get_cipher_name (int cipher)
string mcrypt_get_cipher_name (string cipher)
Przykład: mcrypt_get_cipher_name()
<?php
$cipher = MCRYPT_TripleDES;
print mcrypt_get_cipher_name ($cipher);
?>
Przykład ten zwróci następujący napis:
TripleDES
mcrypt_get_iv_size
Pierwszy prototyp jest dla przypadku, gdy dołączona jest biblioteka libmcrypt 2.2.x, drugi gdy libmcrypt
2.4.x. Funkcja mcrypt_get_iv_size() zwraca wielkość wektora inicjalizacji (IV) w bajtach. W przypadku błędu
zwraca FALSE. Jeżeli w podanym trybie IV jest ignorowany, funkcja zwraca 0.
int mcrypt_get_iv_size (string cipher, string mode)
int mcrypt_get_iv_size (resource td)
•
•
•
jest jedną ze stałych MCRYPT_ciphername.
$Mode to jedna ze stałych MCRYPT_MODE_modename która może być: ecb, cbc, cfb, ofb, nofb lub stream.
$Cipher
$Td jest podanym algorytmem.
mcrypt_get_key_size
Pierwszy prototyp jest dla przypadku, gdy dołączona jest biblioteka libmcrypt 2.2.x, drugi gdy libmcrypt
2.4.x. Funkcja używana do pobierania wielkości klucza dla podanego szyfrowania, $cipher. Funkcja
mcrypt_get_key_size() wymaga podania jednego lub dwóch parametrów, $cipher oraz $module i zwraca wielkość
w bajtach. Patrz również: mcrypt_get_block_size().
int mcrypt_get_key_size (int cipher)
int mcrypt_get_key_size (string cipher, string module)
mcrypt_list_algorithms
Funkcja używana do pobrania tablicy wszystkich obsługiwanych algorytmów w $lib_dir. Posiada
parametr opcjonalny, określający katalog w którym znajdują się wszystkie algorytmy. Jeżeli nie zostanie on
podany, użyta zostanie wartość mcrypt.algorithms_dir z pliku php.ini.
array mcrypt_list_algorithms ([string lib_dir])
Przykład: mcrypt_algorithms()
<?php
$algorithms = mcrypt_list_algorithms ("/usr/local/lib/libmcrypt");
foreach ($algorithms as $cipher) {
echo $cipher."/n";
}
?>
Przykład ten utworzy listę wszystkich obsługiwanych algorytmów z katalogu /usr/local/lib/mcrypt.
mcrypt_list_modes
Funkcja używana do pobrania tablicy z wszystkimi obsługiwanymi trybami w $lib_dir. Posiada parametr
opcjonalny, określający katalog w którym znajdują się wszystkie tryby. Jeżeli nie zostanie on podany, użyta
zostanie wartość mcrypt.modes_dir z pliku php.ini.
array mcrypt_list_modes ([string lib_dir])
Przykład: mcrypt_list_modes()
<?php
$modes = mcrypt_list_modes ();
foreach ($modes as $mode) {
echo "$mode </br>";
305
PHP – Kompendium wiedzy
}
?>
Przykład ten tworzy listę wszystkich obsługiwanych algorytmów w domyślnym katalogu trybów. Jeżeli
nie jest ustawiony w pliku php.ini jako dyrektywa mcrypt.modes_dir, użyty zostanie domyślny katalog dla
biblioteki mcrypt (/usr/local/lib/libmcrypt)
mcrypt_module_get_algo_block_size
Zwraca wielkość bloku w bajtach dla podanego algorytmu. W opcjonalnym parametrze
podać miejsce, gdzie są zapisane moduły trybów.
$lib_dir
można
$lib_dir
można
int mcrypt_module_get_algo_block_size (string algorithm [, string lib_dir])
mcrypt_module_get_algo_key_size
Zwraca największą obsługiwaną wielkość klucza w bajtach. W opcjonalnym parametrze
podać miejsce, gdzie są zapisane moduły trybów.
int mcrypt_module_get_algo_key_size (string algorithm [, string lib_dir])
mcrypt_module_get_algo_supported_key_sizes
Zwraca tablicę z wielkościami kluczy obsługiwanych przez podany algorytm. Jeżeli funkcja zwróci pustą
tablicę, dopuszczalne są wszystkie rozmiary klucza pomiędzy 1 i mcrypt_get_algo_key_size().W opcjonalnym
parametrze $lib_dir można podać miejsce, gdzie są zapisane moduły trybów.
array mcrypt_module_get_algo_supported_key_sizes (string algorithm [, string lib_dir])
mcrypt_module_is_block_algorithm
Zwraca True, jeżeli podany algorytm jest algorytmem blokowym i False, jeżeli jest algorytmem
strumieniowym. W opcjonalnym parametrze $lib_dir można podać miejsce, gdzie są zapisane moduły trybów.
bool mcrypt_module_is_block_algorithm (string mode [, string lib_dir])
mcrypt_module_is_block_algorithm_mode
Zwraca True, jeżeli tryb używany jest z algorytmem blokowym, w przeciwnym wypadku zwraca 0 (na
przykład 0 dla stream i 1 dla cbc, cfb, cfb). W opcjonalnym parametrze $lib_dir można podać miejsce, gdzie są
zapisane moduły trybów.
bool mcrypt_module_is_block_algorithm_mode (string mode [, string lib_dir])
mcrypt_module_is_block_mode
Zwraca True, jeżeli tryb powoduje wysyłanie bloków bajtów lub False, gdy pojedynczych bajtów (na
przykład: 1 dla cbc i ecb a 0 dla cfb i stream). W opcjonalnym parametrze $lib_dir można podać miejsce, gdzie
są zapisane moduły trybów.
bool mcrypt_module_is_block_mode (string mode [, string lib_dir])
mcrypt_module_open
Otwiera moduł używanego algorytmu i trybu. Nazwa algorytmu jest podana w parametrze $algorithm, na
przykład: twofish jest jedną ze stałych MCRYPT_ciphername. Biblioteka jest zamykana przez
mcrypt_module_close() ale wywołanie tej funkcji jest niepotrzebne, jeżeli została wywołana funkcja
mcrypt_generic_end(). Normalnie zwraca deskryptor szyfrowania lub False w przypadku wystąpienia błędu.
Parametry $algorithm_directory i $mode_directory używane są do odnalezienia modułów szyfrowania.
Jeżeli jeden z tych parametrów zostanie ustawiony na "", użyte zostaną wartości znajdujące się w dyrektywach
mcrypt.algorithms_dir lub mcrypt.modes_dir. Jeżeli parametry nie zostaną ustawione, użyte zostaną wartości
wkompilowane w bibliotekę libmcrypt (zwykle /usr/local/lib/libmcrypt).
resource mcrypt_module_open (string algorithm, string algorithm_directory,
Dodatek A - Funkcje
306
string mode, string mode_directory)
Przykład: mcrypt_module_open()
<?php
$td = mcrypt_module_open (MCRYPT_DES, "", MCRYPT_MODE_ECB, "/usr/lib/mcrypt-modes");
?>
Przykład ten będzie próbował otworzyć szyfrowanie DES z bieżącego katalogu i tryb ECB z katalogu
/usr/lib/mcrypt-modes.
mcrypt_module_self_test
Uruchamia samotestowanie szyfrowania podanego szyfrowania. W opcjonalnym parametrze $lib_dir
można podać miejsce, gdzie są zapisane moduły trybów. Funkcja zwraca True, jeżeli test się powiedzie i False,
jeżeli się nie uda.
bool mcrypt_module_self_test (string algorithm [, string lib_dir])
mcrypt_ofb
Pierwszy prototyp jest dla przypadku, gdy dołączona jest biblioteka libmcrypt 2.2.x, drugi gdy libmcrypt
2.4.x. Funkcja mcrypt_ofb() szyfruje i deszyfruje (w zależności od trybu) dane $data za pomocą $cipher i $key w
trybie szyfrowania OFB i zwraca wynikowy ciąg.
string mcrypt_ofb (int cipher, string key, string data, int mode, string iv)
string mcrypt_ofb (string cipher, string key, string data, int mode [, string iv])
•
•
•
•
•
jest jedną ze stałych MCRYPT_ciphername.
$Key jest kluczem przekazywanym do algorytmu. Musi być tajny.
$Data to dane do zaszyfrowania lub odszyfrownania.
$Mode to jedna ze stałych MCRYPT_ENCRYPT lub MCRYPT_DECRYPT.
$IV jest wektorem inicjalizacji.
Patrz również: mcrypt_cbc(), mcrypt_cfb() i mcrypt_ecb().
$Cipher
md5
Wykonuje mieszanie ciągu
$str
metodą MD5 używaną przez RSA Data Cecurity Inc. Patrz również:
crc32().
string md5 (string str)
mdecrypt_generic
Odszyfrowuje dane.
Uwaga
Długość zwracanego ciągu może być większa niż ciąg niezaszyfrowany z powodu wyrównywania danych.
string mdecrypt_generic (resource td, string data)
Przykład: mdecrypt_generic()
<?php
$iv_size = mcrypt_enc_get_iv_size ($td));
$iv = @mcrypt_create_iv ($iv_size, MCRYPT_RAND);
if (@mcrypt_generic_init ($td, $key, $iv) != -1)
{
$c_t = mcrypt_generic ($td, $plain_text);
@mcrypt_generic_init ($td, $key, $iv);
$p_t = mdecrypt_generic ($td, $c_t);
}
if (strncmp ($p_t, $plain_text, strlen($plain_text)) == 0)
echo "ok";
else
echo "błąd";
?>
Przykład pokazuje w jaki sposób sprawdzić, czy dane przed szyfrowaniem są takie same jak po
odszyfrowaniu.
307
PHP – Kompendium wiedzy
metaphone
Oblicza klucz metaphone dla $str. Podobnie jak soundex(), funkcja ta zwraca ten sam klucz dla podobnie
brzmiących słów. Jest ona dokładniejsza od soundex(), ponieważ stosuje podstawowe zasady wymowy
angielskiej. Klucze wygenerowane przez funkcję są zmiennej długości. Autorem algorytmu jest Lawrence Philips
<[email protected]>. Został on opisany w książce „Practical Algorithms for Programmers”, Binstock & Rex,
Addison Wesley, 1995.
string metaphone (string str)
method_exists
Funkcja zwraca True jeżeli dla obiektu
przypadku zwraca False.
$object
zdefiniowana jest metoda
$method_name.
W przeciwnym
bool method_exists (object object, string method_name)
mhash
Uruchamia funkcję mieszającą określoną w $hash na danych $data i zwraca wynik mieszania.
string mhash (int hash, string data, string [ key ])
mhash_count
Zwraca największy dostępny identyfikator funkcji mieszającej. Są one numerowane od 0.
int mhash_count (void)
Przykład: Przeglądanie funkcji mieszających
<?php
$nr = mhash_count();
for ($i = 0; $i <= $nr; $i++) {
echo sprintf ("Wielkość bloku dla %s wynosi %d\n",
mhash_get_hash_name ($i),
mhash_get_block_size ($i));
}
?>
mhash_get_block_size
Funkcja używana do pobrania wielkości bloku dla podanej funkcji mieszającej. Wymaga podania jednego
parametru, identyfikatora funkcji mieszającej i zwraca wielkość bloku w bajtach lub False jeżeli nie istnieje
podana funkcja.
int mhash_get_block_size (int hash)
mhash_get_hash_name
Funkcja używana do pobrania nazwy podanej funkcji mieszającej. Wymaga podania jednego parametru,
identyfikatora funkcji mieszającej i zwraca jej nazwę lub False jeżeli podana funkcja nie istnieje.
string mhash_get_hash_name (int hash)
Przykład: mhash_get_hash_name()
<?php
$hash = MHASH_MD5;
print mhash_get_hash_name ($hash);
?>
Uruchomienie przykładu spowoduje wypisanie następującego wyniku:
MD5
microtime
Zwraca ciąg „mikrosekundy sekundy” gdzie sekundy są bieżącym czasem wyrażonym w sekundach od
początku epoki Uniksa (1 stycznia 1970, 0:00:00). Funkcja jest dostępna w systemach obsługujących funkcję
systemową gettimeofday(). Parz również: time().
string microtime (void)
Dodatek A - Funkcje
308
min
Zwraca wartość najmniejszego numerycznie parametru. Jeżeli pierwszy parametr jest tablicą, min()
zwraca najmniejszą wartość w tablicy. Jeżeli pierwszy parametr jest liczbą całkowitą, ciągiem lub liczbą double,
funkcja wymaga co najmniej dwóch parametrów i zwraca najmniejszy z nich. Można porównywać
nieograniczoną ilość wartości. Jeżeli jedna lub więcej wartości jest liczbą double, wszystkie wartości są
traktowane jako double i zwracana jest liczba typu double. Jeżeli żadna z wartości nie jest liczbą double,
wszystkie są traktowane jako liczby całkowite i również zwracana jest liczba całkowita.
number min (number arg1, number arg2 [, ...])
mkdir
Tworzy katalog określony o podanej nazwie.
Uwaga
Prawdopodobnie będziesz chciał podać typ jako liczbę ósemkową, musisz więc dodać na jej początku zero.
int mkdir (string pathname, int mode)
Zwraca True w przypadku powodzenia operacji lub False w przypadku wystąpienia błędu. Patrz również:
rmdir().
mkdir ("/sciezka/do/nowego/katalogu", 0700);
mktime
Ostrzeżenie
Zwróć uwagę na dziwną kolejność argumentów, która różni się od kolejności stosowanej w wywołaniu funkcji Uniksa mktime() która
nie pomaga w opuszczaniu parametrów od prawej do lewej strony. Częstym błędem jest pomieszanie tych parametrów w skrypcie.
Zwraca znacznik czasu Uniksa odpowiadający podanym argumentom. Znacznik ten to liczba całkowita
zawierająca ilość sekund od początku ery Uniksa (1 stycznia 1970) do podanego czasu. Argumenty mogą być
opuszczane od prawej do lewej strony a opuszczone wartości będą zastępowane bieżącym czasem lokalnym.
int mktime (int hour, int minute, int second, int month, int day, int year
[, int is_dst])
Parametr $is_dst może być ustawiony na 1 w przypadku, gdy obowiązuje czas zimowy, na
obowiązuje czas letni lub na -1 (domyślnie) gdy nie wiadomo jaki czas obowiązuje.
0
gdy
Uwaga
Parametr $is_dst został dodany w PHP 3.0.10.
Funkcja mktime() jest pożyteczna do obliczeń na datach oraz kontroli ich poprawności, ponieważ
automatycznie oblicza właściwe wartości dla parametrów spoza zakresu. Na przykład: każdy z poniższych
wierszy powoduje wypisanie ciągu Jan-01-1998.
Przykład: mktime()
echo
echo
echo
echo
date
date
date
date
("M-d-Y",
("M-d-Y",
("M-d-Y",
("M-d-Y",
mktime
mktime
mktime
mktime
(0,0,0,12,32,1997));
(0,0,0,13,1,1997));
(0,0,0,1,1,1998));
(0,0,0,1,1,98));
Parametr $year może być liczbą dwu bądź czterocyfrową o wartościach 0–69 odpowiadających 2000–
2069 oraz 70–99 odpowiadających 1970–1999 (w systemach w których time_t jest 32-bitową liczą ze znakiem,
czyli większości współczesnych, prawidłowym zakresem dla $year jest 1902–2037). Ostatni dzień dowolnego
miesiąca może być podany jako dzień 0 miesiąca następnego. Poniższy przykład wypisze dwukrotnie Ostatnim
dniem lutego 2000 jest: 29.
Przykład: Ostatni dzień miesiąca:
$lastday = mktime (0,0,0,3,0,2000);
echo strftime ("Ostatnim dniam lutego 2000 jest: %d", $lastday);
$lastday = mktime (0,0,0,4,-31,2000);
309
PHP – Kompendium wiedzy
echo strftime ("Ostatnim dniam lutego 2000 jest: %d", $lastday);
Jeżeli jako rok, miesiąc i dzień podane zostaną wartości 0, data taka uznana zostanie za błędną. Jeżeli by
tak nie było, odpowiadało by to dacie 30.11.1999, co wydawać by się mogło dziwnym działaniem. Patrz również:
date() i time().
move_uploaded_file
Funkcja dostępna w PHP 3 powyżej wersji 3.0.16 i w PHP 4 powyżej 4.0.2. Funkcja sprawdza, czy plik
określony przez $filename jest plikiem przesłanym na serwer (za pomocą mechanizmu przesyłania HTTP POST).
Jeżeli plik jest prawidłowy zostaje on przeniesiony na ścieżkę określoną przez $destination. Jeżeli $filename nie
jest prawidłowym plikiem załadowanym na serwer, nie jest wykonywana żadna operacja i funkcja
move_upload_file() zwraca False. Jeżeli $filename jest prawidłowym plikiem załadowanym na serwer, ale z
jakichkolwiek przyczyn nie może być on przeniesiony, nie jest wykonywana żadna operacja a funkcja
move_upload_file() zwraca False. Dodatkowo wyświetlane jest ostrzeżenie. Sprawdzenie to jest szczególnie
istotne w przypadkach, gdy istnieje jakakolwiek szansa, że zawartość przesyłanego pliku może być pokazana
użytkownikowi, lub innym użytkownikom na tym samym systemie. Patrz również: is_uploaded_file() oraz
część podręcznika sieciowego zatytułowaną: Handling file uploads.
bool move_uploaded_file (string filename, string destination)
msql
Zwraca dodatni identyfikator wyniku zapytania mSQL, lub False w przypadku wystąpienia błędu. Funkcja
mSQL wybiera bazę danych i wykonuje na niej zapytanie. Jeżeli nie zostanie podany opcjonalny identyfikator
połączenia, funkcja próbuje znaleźć otwarte połączenie do serwera mSQL. Jeżeli nie zostanie znalezione takie
połączenie, funkcja spróbuje nawiązać je wywołując funkcję msql_connect() bez parametrów. Patrz również:
msql_connect().
int msql (string database, string query, int link_identifier)
msql_affected_rows
Zwraca ilość wierszy biorących udział w zapytaniu (to znaczy ilość wierszy zwróconych przez SELECT,
ilość wierszy zmienionych przez UPDATE lub ilość wierszy usuniętych przez DELETE). Patrz również: msql_query().
int msql_affected_rows (int query_identifier)
msql_close
Zwraca True w przypadku powodzenia operacji a False w przypadku błędu. Funkcja zamyka połączenie z
bazą mSQL skojarzoną z podanym identyfikatorem połączenia. Jeżeli nie zostanie podany identyfikator
połączenia, zostanie użyty ostatnio otwarte połączenie.
Uwaga
Zwykle nie jest konieczne używanie tej funkcji, ponieważ połączenia nie otwarte jako trwałe są zamykane automatycznie po
zakończeniu skryptu.
Funkja msql_close() nie zamyka połączeń trwałych wygenerowanych przez
również: msql_connect() i msql_pconnect().
msql_pconnect().
Patrz
int msql_close (int link_identifier)
msql_connect
Zwraca dodatni identyfikator połączenia do mSQL, lub False w przypadku błędu. Funkcja msql_connect()
nawiązuje połączenie z serwerem mSQL. Nawa komputera jest opcjonalna i jeżeli jest opuszczona, przyjmowana
jest nazwa localhost. Drugie wywołanie msql_connect() z takimi samymi argumentami nie spowoduje
zestawienia następnego połączenia. Zamiast tego zwrócony zostanie identyfikator istniejącego już połączenia.
Dodatek A - Funkcje
310
Połączenie z serwerem zostanie zamknięte po zakończeniu wykonywania skryptu chyba, że wcześniej zostanie
zamknięte za pomocą msql_close(). Patrz również: msql_pconnect() i msql_close().
int msql_connect ([string hostname [, string hostname[:port] [, string username
[, string password]]]])
msql_createdb
Taka sama jak msql_create_db().
int msql_createdb (string database name [, int link_identifier])
msql_create_db
Tworzy bazę danych na serwerze skojarzonym z podanym identyfikatorem połączenia. Patrz również:
msql_drop_db().
int msql_create_db (string database name [, int link_identifier])
msql_data_seek
Zwraca True w przypadku powodzenia operacji a False w przypadku błędu. Przesuwa wewnętrzny
znacznik wiersza w wyniku mSQL skojarzonym z podanym identyfikatorem wyniku zapytania do wiersza o
podanym numerze. Kolejne wywołanie funkcji msql_fetch_row() zwróci ten wiersz. Patrz również:
msql_fetch_row().
int msql_data_seek (int query_identifier, int row_number)
msql_dbname
Zwraca nazwę bazy danych zapisaną na pozycji $i wskaźnika zwracanego przez funkcję msql_listdbs().
Funkcja może być wykorzystana do sprawdzenia ilości dostępnych baz danych.
string msql_dbname (int query_identifier, int i)
msql_dropdb
Patrz msql_drop_db().
int msql_dropdb (void)
msql_drop_db
Zwraca True w przypadku powodzenia operacji a False w przypadku błędu. Funkcja msql_drop_db()
próbuje usunąć z serwera całą bazę danych skojarzoną z podanym identyfikatorem połączenia. Patrz również:
msql_create_db().
int msql_drop_db (string database_name, int link_identifier)
msql_error
Błędy przychodzące z serwera mSQL nie są traktowane jako ostrzeżenia PHP. Zamiast tego należy
używać tej funkcji do pobierania ciągu z opisem błędu.
string msql_error ()
msql_fetch_array
Zwraca tablicę odpowiadająca pobranemu wierszowi, lub False jeżeli nie ma już wierszy do pobrania.
Funkcja msql_fetch_array() jest rozszerzeniem funkcji msql_fetch_row(). Oprócz zapamiętywania danych pod
indeksami numerycznymi, dodatkowo dane są zapisywane pod indeksami asocjacyjnymi, używając nazw pól jako
kluczy. Drugi argument, $result_type w funkcji msql_fetch_array() jest jedną z następujących stałych:
MSQL_ASSOC, MSQL_NUM i MSQL_BOTH. Należy być uważym przy odczytywaniu wyników zapytania, które może
zwrócić tylko jedno pole, które ma wartość 0 (pusty ciąg albo NULL).
PHP – Kompendium wiedzy
311
Uwaga
Funkcja msql_fetch_array() NIE jest wyraźnie wolniejsza od funkcji msql_fetch_row(), jedynie dostarcza więcej wyników.
Bardziej szczegółowo jest to opisane przy funkcji msql_fetch_row().
int msql_fetch_array (int query_identifier [, int result_type])
msql_fetch_field
Zwraca obiekt zawierający informacje o polu. Funkcja msql_fetch_field() może być użyta do pobrania
danych na temat pól w wyniku. Jeżeli nie zostanie podane przesunięcie, odczytywane jest następne pole, które nie
było jeszcze odczytane.
object msql_fetch_field (int query_identifier, int field_offset)
•
•
•
•
•
•
Właściwości zwracanego obiektu są następujące:
name — nazwa kolumny
table — nazwa tabeli do której należy kolumna
not_null — 1 jeżeli kolumna nie może być pusta
primary_key — 1 jeżeli kolumna jest kluczem głównym
unique — 1 jeżeli kolumna jest kluczem unikalnym
type — typ kolumny
msql_fetch_object
Zwraca obiekt z właściwościami odpowiadającymi polom pobieranego wiersza lub False, jeżeli nie ma
więcej wierszy do pobrania. Funkcja msql_fetch_object() jest podobna do msql_fetch_array() z jedną różnicą
— zwracany jest obiekt a nie tablica. Oznacza to, że możesz odwoływać się do pól poprzez nazwy a nie poprzez
indeks( liczby nie są prawidłowymi nazwami właściwości). Drugi argument, $result_type w funkcji
msql_fetch_array() jest jedną z następujących stałych: MSQL_ASSOC, MSQL_NUM i MSQL_BOTH. Funkcja jest identyczna
wydajnościowo z msql_fetch_array() i prawie tak samo szybka jak msql_fetch_row() — różnica jest nieznaczna.
Patrz również: msql_fetch_array() i msql_fetch_row().
int msql_fetch_object (int query_identifier [, int result_type])
msql_fetch_row
Zwraca tablicę odpowiadająca pobranemu wierszowi, lub False jeżeli nie ma już wierszy do pobrania.
Funkcja msql_fetch_row() pobiera jeden wiersz z wyniku określonego przez identyfikator zapytania. Wiersz jest
zwracany w postaci tablicy. Każda kolumna jest zapisywana w osobnym indeksie tablicy, rozpoczynając od 0.
Kolejne wywołanie msql_fetch_row() powoduje zwracanie kolejnych wierszy z wyniku lub False jeżeli nie ma
już więcej wierszy. Patrz również: msql_fetch_array(), msql_fetch_object(), msql_data_seek() i msql_result().
array msql_fetch_row (int query_identifier)
msql_fieldflags
Zwraca atrybuty podanego pola. Atrybutami są not null, primary key, kombinacja obu oraz pusty ciąg.
string msql_fieldflags (int query_identifier, int i)
msql_fieldlen
Zwraca długość podanego pola.
int msql_fieldlen (int query_identifier, int i)
Dodatek A - Funkcje
312
msql_fieldname
Zwraca nazwę podanego pola. Parametr $query_identifier jest identyfikatorem zapytania, a $field jest
numerem kolejnym pola. Funkcja msql_fieldname($result, 2) zwróci nazwę drugiego pola z wyniku
związanego z podanym identyfikatorem wyniku.
string msql_fieldname (int query_identifier, int field)
msql_fieldtable
Zwraca nazwę tabel do której należy pole $field.
int msql_fieldtable (int query_identifier, int field)
msql_fieldtype
Podobna do funkcji msql_fieldname(). Argumenty są takie same, ale zwracany jest typ pola. Może być to
int, char lub real.
string msql_fieldtype (int query_identifier, int i)
msql_field_seek
Przesuwa wskaźnik do podanego numeru pola. Jeżeli następne wywołanie msql_fetch_field() nie będzie
zawierało numeru pola, zostanie zwrócone to właśnie pole. Patrz również: msql_fetch_field().
int msql_field_seek (int query_identifier, int field_offset)
msql_freeresult
Patrz msql_free_result().
msql_freeresult( void )
msql_free_result
Zwalnia pamięć przydzieloną dla $query_identifier. Po zakończeniu wykonywania żądania pamięć jest
zwalniana automatycznie. Funkcja ta jest potrzebna tylko wtedy, gdy nie chcemy zużywać zbyt wiele pamięci w
czasie działania skryptu.
int msql_free_result (int query_identifier)
msql_listdbs
Patrz msql_list_dbs().
msql_listdbs( void )
msql_listfields
Patrz msql_list_fields().
msql_listfields( void )
msql_listtables
Patrz msql_list_tables().
msql_listtables( void )
msql_list_dbs
Zwraca znacznik wyniku zawierającego bazy danych dostępne dla demona msql. Należy użyć funkcji
do odczytania tego znacznika wyniku.
msql_dbname()
int msql_list_dbs (void)
313
PHP – Kompendium wiedzy
msql_list_fields
Pobiera dane na temat podanej tabeli. Parametrami są nazwa bazy danych i nazwa tabeli. Zwracany jest
znacznik wyniku, który może być użyty w funkcjach msql_fieldflags(), msql_fieldlen(), msql_fieldname() i
msql_fieldtype(). Identyfikator zapytania jest dodatnią liczbą całkowitą. W przypadku błędu funkcja zwraca -1.
Ciąg opisujący błąd umieszczany jest w $phperrmsg i jeżeli funkcja nie została wywołana jako
@msql_list_fields(), ciąg ten jest wypisywany na wyjście. Patrz również: msql_error().
int msql_list_fields (string database, string tablename)
msql_list_tables
Pobiera jako argument nazwę bazy danych i zwraca znacznik wyniku podobnie do funkcji
pobrania wyniku na podstawie znacznika powinna zostać użyta funkcja msql_table_name().
msql().
Do
int msql_list_tables (string database)
msql_numfields
Identyczna z msql_num_fields().
int msql_numfields (int query_identifier)
msql_numrows
Identyczna z msql_num_rows().
int msql_numrows (void)
msql_num_fields
Zwraca ilość pól w wyniku. Patrz również: msql(), msql_query(), msql_fetch_field() i msql_num_rows().
int msql_num_fields (int query_identifier)
msql_num_rows
Zwraca ilość wierszy w wyniku. Patrz również: msql(), msql_query() i
msql_fetch_row().
int msql_num_rows (int query_identifier)
msql_pconnect
Zwraca dodatni identyfikator łącza trwałego lub False w przypadku wystąpienia błędu. Funkcja
msql_pconnect() działa bardzo podobnie do msql_connect() z dwiema różnicami. Po pierwsze, w czasie
połączenia zamiast otwierać nowe połączenie funkcja próbuje znaleźć istniejące łącze (trwałe). Jeżeli zostanie ono
znalezione, zostaje zwrócone zamiast nowego połączenia. Po drugie, połączenie do serwera mSQL nie jest
zamykane po zakończeniu pracy skryptu. Łącze takie pozostaje otwarte do wykorzystania w przyszłości
(msql_close() nie zamyka połączeń utworzonych przez msql_pconnect()).
int msql_pconnect ([string hostname [, string hostname[:port] [, string username
[, string password]]]])
msql_query
Wysyła zapytanie do aktywnej bazy danych skojarzonej z podanym identyfikatorem łącza. Jeżeli
identyfikator ten nie zostanie podany, użyte zostanie ostatnio otwarte łącze. Jeżeli nie ma otwartego łącza, funkcja
próbuje utworzyć połączenie identycznie jak robi to funkcja msql_connect() a następnie używa łącza do
wykonania zapytania. Zwraca dodatni identyfikator zapytania mSQL lub False w przypadku wystąpienia błędu.
Patrz również: msql(), msql_select_db() i msql_connect().
int msql_query (string query, int link_identifier)
Dodatek A - Funkcje
314
msql_regcase
Patrz sql_regcase().
msql_regcase( void )
msql_result
Zwraca zawartość komórki w podanym wierszu, numerze i wyniku mSQL. Funkcja msql_result() zwraca
zawartość jednej komórki z wyniku mSQL. Argument $field może być numerem pola, nazwą pola lub nazwą w
postaci tabela kropka pole (pole.tabela). Jeżeli kolumna otrzymała w zapytaniu alias (select foo as bar from
...), należy użyć aliasu a nie oryginalnej nazwy kolumny. Pracując na dużych wynikach należy rozważyć użycie
jednej funkcji do wczytania całego wiersza. Ponieważ funkcje te zwracają zawartość wielu pól za pomocą
jednego wywołania, są one dużo szybsze od msql_result(). Podawanie numerów pól zamiast ich nazw powoduje
szybsze działanie funkcji. Zalecanymi szybszymi funkcjami są: msql_fetch_row(), msql_fetch_array() i
msql_fetch_object().
int msql_result (int query_identifier, int i, mixed field)
msql_selectdb
Patrz msql_select_db().
msql_selectdb( void )
msql_select_db
Zwraca True w przypadku powodzenia a False w przypadku błędu. Funkcja msql_select_db() ustawia na
serwerze bieżącą aktywną bazę danych o podanym identyfikatorze łącza. Jeżeli identyfikator ten nie zostanie
podany, użyte zostanie ostatnio otwarte łącze. Jeżeli nie ma otwartego łącza, funkcja próbuje utworzyć połączenie
identycznie jak robi to funkcja msql_connect() a następnie używa łącza do wybrania bazy danych. Kolejne
wywołania msql_query() wykonywane są na aktywnej bazie danych. Patrz również: msql_connect(),
msql_pconnect() i msql_query().
int msql_select_db (string database_name, int link_identifier)
msql_tablename
Na podstawie identyfikatora wyniku zwracanego przez msql_list_tables() oraz numeru kolejnego
pobiera i zwraca nazwę tabeli. Funkcja msql_numrows() może być użyta do określenia ilości tabel w wyniku.
string msql_tablename (int query_identifier, int field)
Przykład: msql_tablename()
<?php
msql_connect ("localhost");
$result = msql_list_tables ("wisconsin");
$i = 0;
while ($i < msql_numrows ($result)) {
$tb_names[$i] = msql_tablename ($result, $i);
echo $tb_names[$i] . "<BR>";
$i++;
}
?>
mssql_close
Zwraca True w przypadku powodzenia a False w przypadku błędu. Zamyka połączenie z bazą danych MS
SQL Server, która jest skojarzona z podanym identyfikatorem połączenia. Jeżeli identyfikator połączenia nie
zostanie podany, używane jest ostatnio otwarte połączenie.
Uwaga
Nie jest to zwykle konieczne, ponieważ połączenia nietrwałe są automatycznie zamykane po zakończeniu wykonywania skryptu.
Funkcja mssql_close() nie zamyka połączeń trwałych otwartych za pomocą mssql_pconnect().
315
PHP – Kompendium wiedzy
Patrz również: mssql_connect() i mssql_pconnect().
int mssql_close ([int link_identifier])
mssql_connect
Zwraca dodatni identyfikator połączenia do MS SQL, lub False w przypadku błędu. Funkcja
mssql_connect() nawiązuje połączenie z serwerem MS SQL. Argument $servername musi być prawidłową
nazwą serwera zdefiniowaną w pliku interfejsów. Drugie wywołanie mssql_connect() z takimi samymi
argumentami nie spowoduje zestawienia następnego połączenia. Zamiast tego zwrócony zostanie identyfikator
istniejącego już połączenia. Połączenie z serwerem zostanie zamknięte po zakończeniu wykonywania skryptu
chyba, że wcześniej zostanie zamknięte za pomocą mssql_close(). Patrz również: mssql_pconnect() i
mssql_close().
int mssql_connect ([string servername [, string username [, string password]]])
mssql_data_seek
Zwraca True w przypadku powodzenia a False w przypadku błędu. Funkcja mssql_data_seek() przesuwa
wewnętrzny wskaźnik wiersza w wyniku MS SQL, skojarzonym z podanym identyfikatorem wyniku, do wiersza
o podanym numerze. Następne wywołanie funkcji mssql_fetch_row() zwróci ten wiersz. Patrz również:
mssql_data_seek().
int mssql_data_seek (int result_identifier, int row_number)
mssql_fetch_array
Zwraca tablicę odpowiadająca pobranemu wierszowi, lub False jeżeli nie ma już wierszy do pobrania.
Funkcja mssql_fetch_array() jest rozszerzeniem funkcji mssql_fetch_row(). Oprócz zapamiętywania danych pod
indeksami numerycznymi, dodatkowo dane są zapisywane pod indeksami asocjacyjnymi, używając nazw pól jako
kluczy.
Uwaga
Funkcja mssql_fetch_array() NIE jest wyraźnie wolniejsza od funkcji mssql_fetch_row(), jedynie dostarcza więcej wyników.
Bardziej szczegółowo jest to opisane przy funkcji mssql_fetch_row().
int mssql_fetch_array (int result)
mssql_fetch_field
Zwraca obiekt zawierający informacje o polu. Funkcja mssql_fetch_field() może być użyta do pobrania
danych na temat pól w wyniku. Jeżeli nie zostanie podane przesunięcie, odczytywane jest następne pole, które nie
było jeszcze odczytane.
object mssql_fetch_field (int result [, int field_offset])
•
•
•
•
— Nazwa kolumny. Jeżeli kolumna jest wynikiem działania funkcji, właściwość ta ma wartość
computed#N, gdzie #N jest numerem seryjnym.
column_source — Tabela z której pochodzi kolumna.
max_length — Maksymalna długość kolumny.
numeric — 1 gdy kolumna jest numeryczna.
name
mssql_fetch_object
Zwraca obiekt z właściwościami odpowiadającymi polom pobieranego wiersza lub False, jeżeli nie ma
więcej wierszy do pobrania. Funkcja mssql_fetch_object() jest podobna do mssql_fetch_array() z jedną różnicą
— zwracany jest obiekt a nie tablica. Oznacza to, że możesz odwoływać się do pól poprzez nazwy a nie poprzez
indeks( liczby nie są prawidłowymi nazwami właściwości). Funkcja jest identyczna wydajnościowo z
Dodatek A - Funkcje
316
i prawie tak samo szybka jak mssql_fetch_row() — różnica jest nieznaczna. Patrz również:
mssql_fetch_array() i mssql_fetch_row().
mssql_fetch_array()
int mssql_fetch_object (int result)
mssql_fetch_row
Zwraca tablicę odpowiadająca pobranemu wierszowi, lub False jeżeli nie ma już wierszy do pobrania.
Funkcja mssql_fetch_row() pobiera jeden wiersz z wyniku określonego przez identyfikator zapytania. Wiersz jest
zwracany w postaci tablicy. Każda kolumna jest zapisywana w osobnym indeksie tablicy, rozpoczynając od 0.
Kolejne wywołanie mssql_fetch_row() powoduje zwracanie kolejnych wierszy z wyniku lub False jeżeli nie ma
już więcej wierszy. Patrz również: mssql_fetch_array(), mssql_fetch_object(), mssql_data_seek(),
mssql_fetch_lengths() i mssql_result().
array mssql_fetch_row (int result)
mssql_field_length
int mssql_field_length (int result [, int offset])
mssql_field_name
int mssql_field_name (int result [, int offset])
mssql_field_seek
Przesuwa wskaźnik do określonego numeru pola. Jeżeli następne wywołanie mssql_fetch_field() nie
będzie zawierało numeru pola, zostanie zwrócone to właśnie pole. Patrz również: mssql_fetch_field().
int mssql_field_seek (int result, int field_offset)
mssql_field_type
string mssql_field_type (int result [, int offset])
mssql_free_result
Zwalnia pamięć przydzieloną dla $result. Po zakończeniu wykonywania żądania pamięć jest zwalniana
automatycznie. Funkcja ta jest potrzebna tylko wtedy, gdy nie chcemy zużywać zbyt wiele pamięci w czasie
działania skryptu.
int mssql_free_result (int result)
mssql_get_last_message
string mssql_get_last_message (void)
mssql_min_error_severity
void mssql_min_error_severity (int severity)
mssql_min_message_severity
void mssql_min_message_severity (int severity)
mssql_num_fields
Zwraca ilość pól w wyniku. Patrz również:
mssql_db_query(), mssql_query(), mssql_fetch_field()
i
mssql_num_rows().
int mssql_num_fields (int result)
317
PHP – Kompendium wiedzy
mssql_num_rows
Zwraca ilość wierszy w wyniku. Patrz również: mssql_db_query(), mssql_query() i
mssql_fetch_row().
int mssql_num_rows (string result)
mssql_pconnect
Zwraca dodatni identyfikator łącza trwałego lub False w przypadku wystąpienia błędu. Funkcja
działa bardzo podobnie do mssql_connect() z dwiema różnicami. Po pierwsze, w czasie
połączenia zamiast otwierać nowe połączenie funkcja próbuje znaleźć istniejące łącze (trwałe). Jeżeli zostanie ono
znalezione, zostaje zwrócone zamiast nowego połączenia. Po drugie, połączenie do serwera MS SQL nie jest
zamykane po zakończeniu pracy skryptu. Łącze takie pozostaje otwarte do wykorzystania w przyszłości
(mssql_close() nie zamyka połączeń utworzonych przez mssql_pconnect()).
mssql_pconnect()
int mssql_pconnect ([string servername [, string username [, string password]]])
mssql_query
Zwraca dodatni identyfikator zapytania MS SQL lub False w przypadku wystąpienia błędu. Wysyła do
aktywnej bazy danych zapytanie skojarzone z podanym identyfikatorem łącza. Jeżeli identyfikator ten nie
zostanie podany, użyte zostanie ostatnio otwarte łącze. Jeżeli nie ma otwartego łącza, funkcja próbuje utworzyć
połączenie identycznie jak robi to funkcja mssql_connect() a następnie używa łącza do wykonania zapytania.
Patrz również: mssql_db_query(), mssql_select_db() i mssql_connect().
int mssql_query (string query [, int link_identifier])
mssql_result
Funkcja mssql_result() zwraca zawartość jednej komórki z wyniku MS SQL. Argument $field może być
numerem pola, nazwą pola lub nazwą w postaci tabela kropka pole (pole.tabela). Jeżeli kolumna otrzymała w
zapytaniu alias (select foo as bar from ...), należy użyć aliasu a nie oryginalnej nazwy kolumny. Pracując na
dużych wynikach należy rozważyć użycie jednej funkcji do wczytania całego wiersza. Ponieważ funkcje te
zwracają zawartość wielu pól za pomocą jednego wywołania, są one dużo szybsze od mssql_result(). Podawanie
numerów pól zamiast ich nazw powoduje szybsze działanie funkcji. Zalecanymi szybszymi funkcjami są:
mssql_fetch_row(), mssql_fetch_array() i mssql_fetch_object().
int mssql_result (int result, int i, mixed field)
mssql_select_db
Zwraca True w przypadku powodzenia a False w przypadku błędu. Funkcja mssql_select_db() ustawia na
serwerze bieżącą aktywną bazę danych o podanym identyfikatorze łącza. Jeżeli identyfikator ten nie zostanie
podany, użyte zostanie ostatnio otwarte łącze. Jeżeli nie ma otwartego łącza, funkcja próbuje utworzyć połączenie
identycznie jak robi to funkcja mssql_connect() a następnie używa łącza do wybrania bazy danych. Kolejne
wywołania mssql_query() wykonywane są na aktywnej bazie danych. Patrz również: mssql_connect(),
mssql_pconnect() i mssql_query().
int mssql_select_db (string database_name [, int link_identifier])
mt_getrandmax
Zwraca maksymalną wartość, jaka może być zwrócona przez funkcję
mt_rand(), mt_srand(), rand(), srand() i getrandmax().
mt_rand().
Patrz również:
int mt_getrandmax (void)
mt_rand
Wiele generatorów liczb losowych ze starszych bibliotek libc miało problematyczną lub nieznaną
charakterystykę i były powolne. Domyślnie PHP korzysta z generatora liczb losowych z libc dostępnego za
Dodatek A - Funkcje
318
pomocą funkcji rand(). Funkcja mt_rand() jest jej zamiennikiem. Korzysta ona z generatora liczb losowych
Mersenne Twister o znanej charakterystyce, który generuje liczby losowe wystarczające do inicjowania
niektórych rodzajów funkcji kryptograficznych (więcej informacji na stronie domowej) i jest średnio cztery razy
szybszy od generatora dostarczanego w libc. Strona domowa generatora Mersenne Twister znajduje się pod
adresem http://www.math.keio.ac.jp/~matumoto/emt.html, a zoptymalizowane źródła MT znajdują się pod
adresem http://www.scp.syr.edu/~marc/hawk/twister.html.
int mt_rand (void)
int mt_rand (int min, int max)
Jeżeli funkcja zostanie wywołana bez opcjonalnych parametrów $min i $max, mt_rand() zwraca liczbę
pseudolosową z przedziału 0 do RAND_MAX. Jeżeli chcesz otrzymać liczby pomiędzy, na przykład, 5 a 15 (włącznie)
użyj mt_rand(5, 15). Należy pamiętać, że trzeba zainicjować generator liczb losowych przed użyciem funkcji
mt_srand().
Uwaga
W wersjach wcześniejszych od 3.0.7, drugi parametr oznaczał wielkość przedziału. Aby otrzymać te same wyniki, co w naszym
krótkim przykładzie trzeba było wywołać funkcję mt_rand(5, 11).
Patrz również: mt_srand(), mt_getrandmax(), srand(), rand() i getrandmax().
mt_srand
Inicjuje generator liczb losowych wartością $seed.
void mt_srand (int seed)
Przykład:
//inicjowanie mikrosekundami od ostatniej pełnej sekundy
mt_srand((double) microtime() * 1000000);
$randval = mt_rand();
Patrz również: mt_rand(), mt_getrandmax(), srand(), rand() i getrandmax().
mysql_affected_rows
Zwraca ilość wierszy zmienionych przez ostatnie wyrażenie INSERT, UPDATE lub DELETE na serwerze
skojarzonym z podanym identyfikatorem łącza. Jeżeli nie zostanie podany identyfikator łącza, używany jest
ostatnio otwarte połączenie. Jeżeli ostatnim zapytaniem było zapytanie DELETE bez klauzuli WHERE, usunięte
zostaną wszystkie wiersze z tabeli, ale funkcja zwróci zero. Funkcja nie działa dla wyrażeń typu SELECT, jedynie
dla wyrażeń zmieniających rekordy. Aby pobrać ilość wierszy zwracanych przez zapytanie SELECT, należy użyć
mysql_num_rows().
int mysql_affected_rows ([resource link_identifier])
mysql_change_user
Zmienia użytkownika na bieżącym połączeniu lub połączeniu podanym przez identyfikator połączenia
$link_identifier. Jeżeli zostanie podana baza danych, będzie ona ustawiona jako bieżąca baza danych. Jeżeli nie
uda się autoryzacja nowego użytkownika, aktywne pozostanie połączenie wcześniej podłączonego użytkownika.
Uwaga
Funkcja została wprowadzona w PHP 3.0.13 i wymaga MySQL w wersji co najmniej 3.23.3.
int mysql_change_user (string user, string password [, string database
[, resource link_identifier]])
mysql_close
Zwraca True w przypadku powodzenia a False w przypadku błędu. Funkcja mysql_close() zamyka
połączenie do bazy danych MySQL, która jest skojarzona z podanym identyfikatorem połączenia. Jeżeli
319
PHP – Kompendium wiedzy
identyfikator połączenia nie zostanie podany, używane jest ostatnio otwarte połączenie. Użycie tej funkcji nie jest
zwykle konieczne, ponieważ połączenia nietrwałe są automatycznie zamykane po zakończeniu wykonywania
skryptu.
Uwaga
Funkcja mysql_close() nie zamyka połączeń trwałych otwartych za pomocą mysql_pconnect().
bool mysql_close ([resource link_identifier])
Przykład: MySQL_close()
<?php
$link = mysql_connect ("kraemer", "marliesle", "secret")
or die ("Nie można podłączyć");
print ("Podłączenie udane");
mysql_close ($link);
?>
Patrz również: mysql_connect() i mysql_pconnect().
mysql_connect
Zwraca dodatni identyfikator połączenia do MySQL, lub False w przypadku błędu. Funkcja
mysql_connect() nawiązuje połączenie z serwerem MySQL. Jeżeli nie zostaną podane parametry domyślne,
przyjmowane są następujące wartości domyślne: $host:port = 'localhost:3306', $username — nazwa
użytkownika, który jest właścicielem procesu i $password — pusty ciąg. Ciąg z nazwą komputera może zawierać
numer portu lub ścieżkę do gniazda, np.: ":/sciezka/do/gniazda" dla komputera lokalnego.
Uwaga
Obsługa ":port" została dodana w PHP 3.0B4. Obsługa ":/sciezka/do/gniazda" została dodana w PHP 3.0.10. Można
zapobiec generowaniu komunikatów błędu umieszczając znak @ przed nazwą funkcji.
Drugie wywołanie mysql_connect() z takimi samymi argumentami nie spowoduje zestawienia następnego
połączenia. Zamiast tego zwrócony zostanie identyfikator istniejącego już połączenia. Połączenie z serwerem
zostanie zamknięte po zakończeniu wykonywania skryptu chyba, że wcześniej zostanie zamknięte za pomocą
mysql_close().
resource mysql_connect ([string hostname [:port] [:/path/to/socket]
[, string username [, string password]]])
Przykład: MySQL_connect()
<?php
$link = mysql_connect ("kraemer", "marliesle", "secret")
or die ("Nie można podłączyć");
print ("Podłączenie udane");
mysql_close ($link);
?>
Patrz również: mysql_pconnect() i mysql_close().
mysql_create_db
Tworzy nową bazę danych na serwerze wskazywanym przez podany identyfikator łącza.
int mysql_create_db (string database name [, resource link_identifier])
Przykład: Tworzenie bazy danych MySQL
<?php
$link = mysql_pconnect ("kron", "jutta", "geheim")
or die ("Nie można podłączyć");
if (mysql_create_db ("my_db")) {
print ("Udane utworzenie bazy danych\n");
} else {
printf ("Błąd tworzenia bazy danych: %s\n", mysql_error ());
}
?>
Aby zachować zgodność z poprzednimi wersjami można również używać funkcji mysql_createdb(). Patrz
również: mysql_drop_db().
Dodatek A - Funkcje
320
mysql_data_seek
Zwraca True w przypadku powodzenia a False w przypadku błędu. Przesuwa wewnętrzny znacznik
wiersza w wyniku MySQL skojarzonym z podanym identyfikatorem wyniku zapytania do wiersza o podanym
numerze. Kolejne wywołanie funkcji mysql_fetch_row() zwróci ten wiersz. Parametr $row_number przyjmuje
wartości rozpoczynające się od 0.
bool mysql_data_seek (resource result_identifier, int row_number)
Przykład: Przesuwanie wskaźnika w wyniku
<?php
$link = mysql_pconnect ("kron", "jutta", "geheim")
or die ("Nie można podłączyć");
mysql_select_db ("samp_db")
or die ("Nie można wybrać bazy danych");
$query = "SELECT last_name, first_name FROM friends";
$result = mysql_query ($query)
or die ("Zapytanie nieudane");
# Pobieranie wierszy w odwrotnej kolejności
for ($i = mysql_num_rows ($result) - 1; $i >=0; $i--) {
if (!mysql_data_seek ($result, $i)) {
echo "Nie mogę przejść do wersza $i\n";
continue;
}
if(!($row = mysql_fetch_object ($result)))
continue;
echo ("$row->last_name $row->first_name<BR>\n";
}
mysql_free_result ($result);
?>
mysql_db_name
Jako pierwszego parametru wymaga wskaźnika wyniku zwracanego przez funkcję mysql_list_dbs().
Parametr $row jest indeksem w wyniku. Jeżeli wystąpi błąd, zwracana jest wartość False. Aby określić rodzaj
błędu należy użyć funkcji mysql_errno() i mysql_error().
string mysql_db_name (resource result, int row [, mixed field])
Przykład: mysql_db_name()
<?php
error_reporting(E_ALL);
mysql_connect('dbhost', 'username', 'password');
$db_list = mysql_list_dbs();
$i = 0;
$cnt = mysql_num_rows($db_list);
while ($i < $cnt) {
echo mysql_db_name($db_list, $i) . "\n";
$i++;
}
?>
Dla zachowania zgodności z poprzednimi wersjami można również używać nazwy
jest to jednak zalecane.
mysql_dbname().
Nie
mysql_db_query
Zwraca dodatni identyfikator zapytania MySQL lub False w przypadku wystąpienia błędu. Wybiera bazę
danych i wykonuje na niej zapytanie. Jeżeli opcjonalny identyfikator łącza nie zostanie podany, użyte zostanie
ostatnio otwarte łącze. Jeżeli nie ma otwartego łącza, funkcja próbuje utworzyć połączenie identycznie jak robi to
funkcja mysql_connect() wywołana bez argumentów. Patrz również: mysql_connect(). Dla zachowania zgodności
można również używać nazwy mysql().
resource mysql_db_query (string database, string query [, resource link_identifier])
mysql_drop_db
Zwraca True w przypadku powodzenia operacji a False w przypadku błędu. Funkcja mysql_drop_db()
próbuje usunąć z serwera całą bazę danych skojarzoną z podanym identyfikatorem połączenia. Patrz również:
mysql_create_db(). Dla zachowania zgodności można równie używać funkcji mysql_dropdb().
bool mysql_drop_db (string database_name [, resource link_identifier])
321
PHP – Kompendium wiedzy
mysql_errno
Zwraca numer błędu dla ostatnio wykonanej funkcji MySQL lub 0, jeżeli nie wystąpił żaden błąd. Błędy
wysyłane przez serwer MySQL nie mogą być traktowane jako ostrzeżenia, zamiast tego należy pobierać numery
błędów za pomocą funkcji mysql_errno().
Uwaga
Funkcja zwraca kod błędu dla ostatnio wykonanej funkcji MySQL (opócz mysql_error() i mysql_errno()). Jeżeli chcesz jej użyć,
należy sprawdzać kod błędu przed wywołaniem kolejnej funkcji MySQL.
int mysql_errno ([resource link_identifier])
Przykład: mysql_errno()
<?php
mysql_connect("marliesle");
echo mysql_errno().": ".mysql_error()."<BR>";
mysql_select_db("nonexistentdb");
echo mysql_errno().": ".mysql_error()."<BR>";
$conn = mysql_query("SELECT * FROM nonexistenttable");
echo mysql_errno().": ".mysql_error()."<BR>";
?>
Patrz również: mysql_error().
mysql_error
Zwraca komunikat błędu dla ostatnio wykonanej funkcji MySQL lub 0, jeżeli nie wystąpił żaden błąd.
Błędy wysyłane przez serwer MySQL nie mogą być traktowane jako ostrzeżenia, zamiast tego należy pobierać
komunikaty błędów za pomocą funkcji mysql_error().
Uwaga
Funkcja zwraca kod błędu dla ostatnio wykonanej funkcji MySQL (opócz mysql_error() i
mysql_errno()). Jeżeli chcesz jej użyć, należy sprawdzać kod błędu przed wywołaniem kolejnej funkcji MySQL.
string mysql_error ([resource link_identifier])
Przykład: mysql_errno()
<?php
mysql_connect("marliesle");
echo mysql_errno().": ".mysql_error()."<BR>";
mysql_select_db("nonexistentdb");
echo mysql_errno().": ".mysql_error()."<BR>";
$conn = mysql_query("SELECT * FROM nonexistenttable");
echo mysql_errno().": ".mysql_error()."<BR>";
?>
Patrz również: mysql_errno().
mysql_fetch_array
Zwraca tablicę odpowiadająca pobranemu wierszowi, lub False jeżeli nie ma już wierszy do pobrania.
Funkcja mysql_fetch_array() jest rozszerzeniem funkcji mysql_fetch_row(). Oprócz zapamiętywania danych pod
indeksami numerycznymi, dodatkowo dane są zapisywane pod indeksami asocjacyjnymi, używając nazw pól jako
kluczy. Jeżeli dwie lub więcej pól w wyniku ma takie same nazwy, zwrócona zostanie wartość ostatniego z nich.
Aby odczytać wartości kolumn o tych samych nazwach należy korzystać z indeksów numerycznych lub stworzyć
aliasy dla kolumn.
array mysql_fetch_array (resource result [, int result_type])
Należy przypomnieć, że funkcja mysql_fetch_array() NIE jest wyraźnie wolniejsza od funkcji
mysql_fetch_row(), jedynie dostarcza więcej wyników. Opcjonalny drugi argument, $result_type może być
jedną ze stałych: MYSQL_ASSOC, MYSQL_NUM i MYSQL_BOTH (parametr ostał dodany w PHP 3.0.7). Patrz również:
mysql_fetch_row() i mysql_fetch_assoc().
Przykład: mysql_fetch_array()
<?php
mysql_connect ($host, $user, $password);
$result = mysql_db_query ("database","select user_id, fullname from table");
while ($row = mysql_fetch_array ($result)) {
Dodatek A - Funkcje
322
echo
echo
echo
echo
"ID użytkownika:
"ID użytkownika:
"Pełna nazwa
:
"Pełna nazwa
:
".$row["user_id"]."<br>\n";
".$row[0]."<br>\n";
".$row["fullname"]."<br>\n";
".$row[1]."<br>\n";
}
mysql_free_result ($result);
?>
mysql_fetch_assoc
Zwraca tablicę asocjacyjną odpowiadającą bieżącemu wierszowi lub False, jeżeli nie ma już więcej
wierszy w wyniku. Funkcja mysql_fetch_assoc() jest odpowiednikiem wywołania funkcji mysql_fetch_array() z
parametrem MYSQL_ASSOC. Powoduje to zwrócenie tylko tablicy asocjacyjnej. Jest to sposób w jaki wcześniej
działała funkcja mysql_fetch_array(). Jeżeli dwie lub więcej pól w wyniku ma takie same nazwy, zwrócona
zostanie wartość ostatniego z nich. Aby odczytać wartości kolumn o tych samych nazwach należy użyć funkcji
mysql_fetch_array()
i skorzystać z indeksów numerycznych. Należy przypomnieć, że funkcja
mysql_fetch_assoc() NIE jest wyraźnie wolniejsza od funkcji mysql_fetch_row(), jedynie dostarcza więcej
wyników. Patrz również: mysql_fetch_row() i mysql_fetch_array().
array mysql_fetch_assoc (resource result)
Przykład: mysql_fetch_assoc()
<?php
mysql_connect ($host, $user, $password);
$result = mysql_db_query ("database","select * from table");
while ($row = mysql_fetch_assoc ($result)) {
echo $row["user_id"];
echo $row["fullname"];
}
mysql_free_result ($result);
?>
mysql_fetch_field
Zwraca obiekt zawierający informacje o polu. Funkcja mysql_fetch_field() może być użyta do pobrania
danych na temat pól w wyniku. Jeżeli nie zostanie podane przesunięcie, odczytywane jest następne pole, które nie
było jeszcze odczytane.
object mysql_fetch_field (resource result [, int field_offset])
•
•
•
•
•
•
•
•
•
•
•
•
Właściwości zwracanego obiektu są następujące:
name — nazwa kolumny
table — nazwa tabeli do której należy kolumna
max_length — maksymalna długość pola
not_null — 1 jeżeli kolumna nie może być pusta
primary_key — 1 jeżeli kolumna jest kluczem głównym
unique_key — 1 jeżeli kolumna jest kluczem unikalnym
multiple_key — 1 jeżeli kolumna nie jest kluczem unikalnym
numeric — 1 jeżeli kolumna jest numeryczna
blob — 1 jeżeli kolumna jest typu BLOB
type — typ kolumny
unsigned — 1 jeżeli kolumna jest bez znaku
zerofill — 1 jeżeli kolumna jest wypełniana zerami
Przykład: mysql_fetch_field()
<?php
mysql_connect ($host, $user, $password)
or die ("Nie można podłączyć");
$result = mysql_db_query ("database", "select * from table")
or die ("Zapytanie nieudane");
# pobranie metadanych kolumny
$i = 0;
while ($i < mysql_num_fields ($result)) {
echo "Informacje na temat kolumny: $i:<BR>\n";
$meta = mysql_fetch_field ($result);
if (!$meta) {
echo "Brak dostępnych danych<BR>\n";
}
323
PHP – Kompendium wiedzy
echo "<PRE>
blob:
$meta->blob
max_length:
$meta->max_length
multiple_key: $meta->multiple_key
name:
$meta->name
not_null:
$meta->not_null
numeric:
$meta->numeric
primary_key: $meta->primary_key
table:
$meta->table
type:
$meta->type
unique_key:
$meta->unique_key
unsigned:
$meta->unsigned
zerofill:
$meta->zerofill
</PRE>";
$i++;
}
mysql_free_result ($result);
?>
mysql_fetch_lengths
Zwraca
tablicę zawierającą długości pól z ostatniego wiersza odczytanego przez funkcję
mysql_fetch_row() lub False w przypadku błędu. Funkcja mysql_fetch_lengths() przechowuje długości każdej
kolumny wyniku w ostatnim wierszu zwracanym przez mysql_fetch_row(), mysql_fetch_array() i
mysql_fetch_object() w tablicy rozpoczynającej się od indeksu 0. Patrz również: mysql_fetch_row().
array mysql_fetch_lengths (resource result)
mysql_fetch_object
Zwraca obiekt z właściwościami odpowiadającymi polom pobieranego wiersza lub False, jeżeli nie ma
więcej wierszy do pobrania. Funkcja mysql_fetch_object() jest podobna do mysql_fetch_array() z jedną różnicą
— zwracany jest obiekt a nie tablica. Oznacza to, że możesz odwoływać się do pól poprzez nazwy a nie poprzez
indeks( liczby nie są prawidłowymi nazwami właściwości). Drugi argument, $result_type w funkcji
mysql_fetch_array() jest jedną z następujących stałych: MYSQL_ASSOC, MYSQL_NUM i MYSQL_BOTH. Funkcja jest
identyczna wydajnościowo z mysql_fetch_array() i prawie tak samo szybka jak mysql_fetch_row() — różnica
jest nieznaczna.
object mysql_fetch_object (resource result [, int result_type])
Przykład: mysql_fetch_object()
<?php
mysql_connect ($host, $user, $password);
$result = mysql_db_query ("database", "select * from table");
while ($row = mysql_fetch_object ($result)) {
echo $row->user_id;
echo $row->fullname;
}
mysql_free_result ($result);
?>
Patrz również: mysql_fetch_array() i mysql_fetch_row().
mysql_fetch_row
Zwraca tablicę odpowiadająca pobranemu wierszowi, lub False jeżeli nie ma już wierszy do pobrania.
Funkcja mysql_fetch_row() pobiera jeden wiersz z wyniku określonego przez identyfikator zapytania. Wiersz jest
zwracany w postaci tablicy. Każda kolumna jest zapisywana w osobnym indeksie tablicy, rozpoczynając od 0.
Kolejne wywołanie mysql_fetch_row() powoduje zwracanie kolejnych wierszy z wyniku lub False jeżeli nie ma
już więcej wierszy. Patrz również: mysql_fetch_array(), mysql_fetch_object(), mysql_data_seek() i
mysql_result().
array mysql_fetch_row (resource result)
mysql_field_flags
Zwraca atrybuty podanego pola. Atrybuty są zwracane w jednym ciągu rozdzielone spacjami, więc można
je łatwo rozdzielić za pomocą funkcji explode(). Zwracane są następujące atrybuty o ile twoja wersja MySQL je
Dodatek A - Funkcje
324
wszystkie obsługuje: not_null, primary_key, unique_key, multiple_key, blob, unsigned, zerofill, binary, enum,
auto_increment i timestamp. Dla zachowania zgodności wstecz można używać również nazwy
mysql_fieldflags().
string mysql_field_flags (resource result, int field_offset)
mysql_field_len
Zwraca długość podanego pola. Dla zachowania zgodności wstecz można używać również nazwy
mysql_fieldlen().
int mysql_field_len (resource result, int field_offset)
mysql_field_name
Zwraca nazwę podanego pola. Parametr
numerem kolejnym pola.
$result
jest identyfikatorem zapytania, a
$field_index
jest
Uwaga
Wartości $field_index rozpoczynają się od 0. Na przykład, indeks trzeciego pola będzie 2, czwartego — 3 itd.
string mysql_field_name (resource result, int field_index)
Przykład: mysql_field_name()
// Tabela users składa się z trzech pól:
//
user_id
//
username
//
password.
$res = mysql_db_query("users", "select * from users", $link);
echo mysql_field_name($res, 0) . "\n";
echo mysql_field_name($res, 2);
Wykonanie tego przykładu spowoduje wypisanie następującego wyniku:
user_id
password
Dla zachowania zgodności wstecz można używać również nazwy mysql_fieldname().
mysql_field_seek
Przesuwa wskaźnik do podanego numeru pola. Jeżeli następne wywołanie mysql_fetch_field() nie będzie
zawierało numeru pola, zostanie zwrócone to właśnie pole. Patrz również: mysql_fetch_field(). Patrz również:
mysql_fetch_field().
int mysql_field_seek (resource result, int field_offset)
mysql_field_table
Zwraca nazwę tabeli, z której pochodzi podane pole. Dla zachowania zgodności wstecz można używać
również nazwy mysql_fieldtable().
string mysql_field_table (resource result, int field_offset)
mysql_field_type
Funkcja podobna do mysql_field_name(). Argumenty są identyczne, ale zwracane są typy pól. Typami
tymi mogą być int, real, string, blob i inne opisane w dokumentacji MySQL.
string mysql_field_type (iresource result, int field_offset)
Przykład: Typy pól MySQL
<?php
mysql_connect ("localhost:3306");
mysql_select_db ("wisconsin");
$result = mysql_query ("SELECT * FROM onek");
$fields = mysql_num_fields ($result);
$rows
= mysql_num_rows ($result);
$i = 0;
325
PHP – Kompendium wiedzy
$table = mysql_field_table ($result, $i);
echo "Tabela '".$table."' ma ".$fields." pól i ".$rows." rekordów <BR>";
echo "Tabela składa się z następujących pól: <BR>";
while ($i < $fields) {
$type = mysql_field_type ($result, $i);
$name = mysql_field_name ($result, $i);
$len
= mysql_field_len
($result, $i);
$flags = mysql_field_flags ($result, $i);
echo $type." ".$name." ".$len." ".$flags."<BR>";
$i++;
}
mysql_close();
?>
Dla zachowania zgodności wstecz można używać również nazwy mysql_fieldtype().
mysql_free_result
Zwalnia pamięć przydzieloną dla $result. Po zakończeniu wykonywania żądania pamięć jest zwalniana
automatycznie. Funkcja ta jest potrzebna tylko wtedy, gdy nie chcemy zużywać zbyt wiele pamięci w czasie
działania skryptu. Dla zachowania zgodności wstecz można używać również nazwy mysql_freeresult().
int mysql_free_result (resource result)
mysql_insert_id
Zwraca identyfikator generowany dla kolumn AUTO_INCREMENT przez ostatnie wyrażenie INSERT wykonane
na podanym identyfikatorze łącza. Jeżeli nie zostanie podany identyfikator łącza, przyjmowane jest ostatnio
otwarte łącze. Funkcja mysql_insert_id() zwraca 0 jeżeli poprzednie zapytanie nie generowało wartości
AUTO_INCREMENT. Jeżeli chcesz zachować tą wartość do późniejszego użycia trzeba pamiętać, aby wywołać funkcję
natychmiast po zapytaniu generującym wartość.
Uwaga
Wartość funkcji MySQL LAST_INSERT_ID() zawsze zawiera ostatnio wygenerowaną wartość AUTO_INCREMENT i nie jest ona
kasowana pomiędzy zapytaniami.
Funkcja mysql_insert_id() konwertuje typ wartości zwracanej przez funkcję MySQL API na typ long.
Jeżeli kolumna AUTO_INCREMENT będzie miała typ BIGINT, wartości zwracane przez mysql_insert_id() będą
nieprawidłowe. Zamiast tego można używać wewnętrznej funkcji MySQL — LAST_INSERT_ID().
int mysql_insert_id ([resource link_identifier])
mysql_list_dbs
Zwraca znacznik wyniku zawierającego bazy danych dostępne dla demona mysql. Należy użyć funkcji
mysql_tablename() do odczytania tego znacznika wyniku.
Uwaga
Funkcja działa również z funkcjami mysql_fetch_row() lub podobnymi.
Dla zachowania zgodności wstecz można używać również nazwy mysql_listdbs().
resource mysql_list_dbs ([resource link_identifier])
Przykład: mysql_list_dbs()
$link = mysql_connect('localhost', 'myname', 'secret');
$db_list = mysql_list_dbs($link);
while ($row = mysql_fetch_object($db_list)) {
echo $row->Database . "\n";
}
Przykład ten może dać następujące wyniki:
database1
database2
database3
...
Dodatek A - Funkcje
326
mysql_list_fields
Pobiera dane na temat podanej tabeli. Parametrami są nazwa bazy danych i nazwa tabeli. Zwracany jest
znacznik wyniku, który może być użyty w funkcjach mysql_fieldflags(), mysql_fieldlen(), mysql_fieldname()
i mysql_fieldtype(). Identyfikator wyniku jest dodatnią liczbą całkowitą. W przypadku błędu funkcja zwraca -1.
Ciąg opisujący błąd umieszczany jest w $phperrmsg i jeżeli funkcja nie została wywołana jako
@mysql_list_fields(), ciąg ten jest wypisywany na wyjście. Dla zachowania zgodności wstecz można używać
również nazwy mysql_listfields().
resource mysql_list_fields (string database_name, string table_name
[, resource link_identifier])
Przykład: mysql_list_fields()
$link = mysql_connect('localhost', 'myname', 'secret');
$fields = mysql_list_fields("database1", "table1", $link);
$columns = mysql_num_fields($fields);
for ($i = 0; $i < $columns; $i++) {
echo mysql_field_name($fields, $i) . "\n";;
}
Przykład ten może dać następujące wyniki:
field1
fiels2
field3
...
mysql_list_tables
Pobiera jako argument nazwę bazy danych i zwraca znacznik wyniku podobnie do funkcji
Do pobrania wyniku na podstawie znacznika powinna zostać użyta funkcja
mysql_tablename(). Dla zachowania zgodności wstecz można używać również nazwy mysql_listtables().
mysql_db_query().
resource mysql_list_tables (string database [, resource link_identifier])
mysql_num_fields
Zwraca ilość pól w wyniku. Patrz również: mysql_db_query(), mysql_query(), mysql_fetch_field() i
mysql_num_rows(). Dla zachowania zgodności wstecz można używać również nazwy mysql_numfields().
int mysql_num_fields (resource result)
mysql_num_rows
Zwraca ilość wierszy w wyniku. Funkcja działa jedynie dla wyrażeń SELECT. Aby odczytać ilość wierszy
zwracanych z wyrażeń INSERT, UPDATE lub DELETE należy używać funkcji mysql_affected_rows(). Patrz również:
mysql_db_query(), mysql_query() i mysql_fetch_row().Dla zachowania zgodności wstecz można używać
również nazwy mysql_numrows().
int mysql_num_rows (resource result)
mysql_pconnect
Zwraca dodatni identyfikator trwałego połączenia do MySQL, lub False w przypadku błędu. Funkcja
nawiązuje połączenie z serwerem MySQL. Jeżeli nie zostaną podane parametry domyślne,
przyjmowane są następujące wartości domyślne: $host:port = 'localhost:3306', $username — nazwa
użytkownika, który jest właścicielem procesu i $password — pusty ciąg. Ciąg z nazwą komputera może zawierać
numer portu lub ścieżkę do gniazda, np.: ":/sciezka/do/gniazda" dla komputera lokalnego.
mysql_pconnect()
Uwaga
Obsługa ":port" została dodana w PHP 3.0B4. Obsługa ":/sciezka/do/gniazda" została dodana w PHP 3.0.10. Można
zapobiec generowaniu komunikatów błędu umieszczając znak @ przed nazwą funkcji.
resource mysql_pconnect ([string hostname [:port] [:/path/to/socket]
[, string username [, string password]]])
327
PHP – Kompendium wiedzy
Funkcja mysql_pconnect() działa bardzo podobnie do mysql_connect() z dwiema różnicami. Po pierwsze,
w czasie połączenia zamiast otwierać nowe połączenie funkcja próbuje znaleźć istniejące łącze (trwałe). Jeżeli
zostanie ono znalezione, zostaje zwrócone zamiast nowego połączenia. Po drugie, połączenie do serwera MySQL
nie jest zamykane po zakończeniu pracy skryptu. Łącze takie pozostaje otwarte do wykorzystania w przyszłości
(mysql_close() nie zamyka połączeń utworzonych przez mysql_pconnect()). Dlatego ten typ połączenia
nazywany jest „trwałym”.
mysql_query
Wysyła zapytanie do aktywnej bazy danych skojarzonej z podanym identyfikatorem łącza. Jeżeli
identyfikator ten nie zostanie podany, użyte zostanie ostatnio otwarte łącze. Jeżeli nie ma otwartego łącza, funkcja
próbuje utworzyć połączenie identycznie jak robi to funkcja mysql_connect() wywołana bez parametrów a
następnie używa łącza do wykonania zapytania.
Uwaga
Ciąg z zapytaniem nie może kończyć się średnikiem.
Funkcja mysql_query() zwraca True (wartość różną od zera) jeżeli zapytanie udało się lub False gdy nie
udało się. Zwrócenie wartości True wskazuje tylko, że zapytanie może być wykonane przez serwer. Nie mówi to
nic na temat ilości zmienionych lub zwróconych wierszy. Jest możliwe wykonanie poprawnego zapytania, które
nie zwróci żadnych wierszy.
resource mysql_query (string query [, resource link_identifier])
Poniższe zapytanie jest niepoprawne składniowo, więc funkcja mysql_query() zwróci False.
Przykład: mysql_query()
<?php
$result = mysql_query ("SELECT * WHERE 1=1")
or die ("Nieprawidłowe zapytanie");
?>
Kolejne zapytanie może być niepoprawne, jeżeli kolumna my_col nie będzie istniała w tabeli my_tbl i w
takim przypadku mysql_query() zwróci False.
Przykład: mysql_query()
<?php
$result = mysql_query ("SELECT my_col FROM my_tbl")
or die ("Nieprawidłowe zapytanie");
?>
Funkcja mysql_query() może się również nie udać i zwrócić False, jeżeli nie masz wystarczających
uprawnień do tabel na których operuje zapytanie. Zakładając, że zapytanie się uda, można wywołać funkcję
mysql_num_rows() aby sprawdzić ile wierszy zwróciło zapytanie SELECT lub mysql_affected_rows() aby sprawdzić
ile wierszy zostało zmienionych przez wyrażenie DELETE, INSERT, REPLACE lub UPDATE. Dla wyrażeń SELECT funkcja
mysql_query() zwraca nowy identyfikator wyniku, który może być przekazany do funkcji mysql_result(). Po
zakończeniu pracy na wyniku można zwolnić zasoby z nim związane wywołując mysql_free_result().
Przydzielona pamięć jest jednak automatycznie zwalniana po zakończeniu skryptu. Patrz również:
mysql_affected_rows(), mysql_db_query(),
mysql_free_result(), mysql_result(), mysql_select_db() i
mysql_connect().
mysql_result
Zwraca zawartość komórki w podanym wierszu, numerze i wyniku MySQL. Argument $field może być
numerem pola, nazwą pola lub nazwą w postaci tabela kropka pole (pole.tabela). Jeżeli kolumna otrzymała w
zapytaniu alias (select foo as bar from ...), należy użyć aliasu a nie oryginalnej nazwy kolumny. Pracując na
dużych wynikach należy rozważyć użycie jednej funkcji do wczytania całego wiersza. Ponieważ funkcje te
zwracają zawartość wielu pól za pomocą jednego wywołania, są one dużo szybsze od mysql_result(). Podawanie
numerów pól zamiast ich nazw powoduje szybsze działanie funkcji. Wywołania funkcji mysql_result() nie
powinny być mieszane z wywołaniami innych funkcji operujących na wyniku. Zalecanymi szybszymi funkcjami
są: mysql_fetch_row(), mysql_fetch_array() i mysql_fetch_object().
mixed mysql_result (resource result, int row [, mixed field])
Dodatek A - Funkcje
328
mysql_select_db
Zwraca True w przypadku powodzenia a False w przypadku błędu. Funkcja mysql_select_db() ustawia na
serwerze bieżącą aktywną bazę danych o podanym identyfikatorze łącza. Jeżeli identyfikator ten nie zostanie
podany, użyte zostanie ostatnio otwarte łącze. Jeżeli nie ma otwartego łącza, funkcja próbuje utworzyć połączenie
identycznie jak robi to funkcja mysql_connect() a następnie używa łącza do wybrania bazy danych. Kolejne
wywołania mysql_query() wykonywane są na aktywnej bazie danych. Patrz również: mysql_connect(),
mysql_pconnect() i mysql_query(). Dla zgodności z poprzednimi wersjami można korzystać z nazwy
mysql_selectdb().
bool mysql_select_db (string database_name [, resource link_identifier])
mysql_tablename
Na podstawie identyfikatora wyniku zwracanego przez mysql_list_tables() oraz numeru kolejnego
pobiera i zwraca nazwę tabeli. Funkcja mysql_numrows() może być użyta do określenia ilości tabel w wyniku.
string mysql_tablename (resource result, int i)
Przykład: mysql_tablename()
<?php
mysql_connect ("localhost:3306");
$result = mysql_list_tables ("wisconsin");
$i = 0;
while ($i < mysql_num_rows ($result)) {
$tb_names[$i] = mysql_tablename ($result, $i);
echo $tb_names[$i] . "<BR>";
$i++;
}
?>
natcasesort
Stosuje algorytm sortowania ciągów w sposób w jaki robią to ludzie. Jest on nazwany „porządkowaniem
naturalnym”. Funkcja natcasesort() jest wersją funkcji natsort(), która nie rozróżnia wielkości liter. Różnica
pomiędzy sortowaniem naturalnym a zwykłym algorytmem sortowania pokazana jest w przykładzie zastosowania
funkcji natsort(). Więcej informacji na temat tego algorytmu można znaleźć na stronie
http://www.linuxcare.com.au/projects/natsort/. Patrz również: sort(), natsort(), strnatcmp() i strnatcasecmp().
void natcasesort (array array)
natsort
Stosuje algorytm sortowania ciągów w sposób w jaki robią to ludzie. Jest on nazwany „porządkowaniem
naturalnym”. Różnica pomiędzy sortowaniem naturalnym a zwykłym algorytmem sortowania pokazana jest na
poniższym przykładzie.
void natsort (array array)
Przykład: natsort()
$array1 = $array2 = array ("img12.png", "img10.png", "img2.png", "img1.png");
sort($array1);
echo "Zwykłe sortowanie\n";
print_r($array1);
natsort($array2);
echo "\nSortowanie w porządku naturalnym\n";
print_r($array2);
Wykonanie tego kodu da następujący wynik:
Zwykłe sortowanie
Array
(
[0] => img1.png
[1] => img10.png
[2] => img12.png
[3] => img2.png
)
Sortowanie w porządku naturalnym
Array
(
[3] => img1.png
[2] => img2.png
329
PHP – Kompendium wiedzy
[1] => img10.png
[0] => img12.png
)
Więcej
informacji
można
znaleźć
na
stronie
poświęconej
temu
algorytmowi,
http://www.linuxcare.com.au/projects/natsort/. Patrz również: natcasesort(), strnatcmp() i strnatcasecmp().
next
Zwraca element tablicy znajdujący się na następnym miejscu wskazywanym przez wewnętrzny wskaźnik
tablicy lub False, jeżeli nie ma już więcej elementów. Funkcja next() zachowuje się podobnie do current(), z
jedną różnicą. Next() przesuwa wewnętrzny wskaźnik tablicy o jeden element dalej. Jeżeli przesunięcie
wskaźnika spowoduje wyjście wskaźnika poza tablicę, next() zwraca False. Jeżeli tablica zawiera pusty element
lub element o wartości klucza 0, funkcja wróci False po napotkaniu takiego elementu. Aby prawidłowo
przeglądać tablice, które mogą zawierać puste elementy lub klucze o wartości 0, należy użyć funkcji each(). Patrz
również: curent(), end(), prev() i reset().
mixed next (array array)
nl2br
Zwraca ciąg ze znacznikami
htmlspecialchars(), htmlentities()
<BR> wstawionymi przed wszystkimi znakami nowej linii. Patrz również:
i word_wrap().
string nl2br (string string)
number_format
Zwraca liczbę $number w sformatowanej postaci. Funkcja może być wywołana z jednym, dwoma lub
czterema parametrami (nie z trzema). Jeżeli podany został jeden parametr, liczba $number jest formatowana bez
części ułamkowej, ale z przecinkami pomiędzy kolejnymi grupami tysięcy. Jeżeli podane są dwa parametry,
liczba jest formatowana z $decimals cyfr po przecinku, z kropką dziesiętną i przecinkami pomiędzy grupami
tysięcy. Jeżeli są podane wszystkie cztery parametry, liczba jest z $decimals cyfr po przecinku, ze znakiem
$dec_point zamiast kropki dziesiętnej i znakiem $thousand_sep zamiast przecinka pomiędzy grupami tysięcy.
string number_format (float number [, int decimals [, string dec_point
[, string thousands_sep]]])
ob_end_clean
Usuwa zawartość bufora wyjściowego i wyłącza buforowanie wyjścia. Patrz również:
ob_end_flush().
ob_start()
i
void ob_end_clean (void)
ob_end_flush
Wysyła zawartość bufora wyjściowego (o ile istnieje) na wyjście i wyłącza buforowanie wyjścia. Jeżeli
chcesz przetworzyć zawartość bufora musisz użyć funkcji ob_get_contents() przed ob_end_flush(), ponieważ
zawartość bufora jest usuwana po wywołaniu ob_get_contents(). Patrz również: ob_start(), ob_get_contents() i
ob_end_clean().
void ob_end_flush (void)
ob_get_contents
Zwraca zawartość bufora wyjściowego lub
również: ob_start() i ob_get_length().
False,
jeżeli buforowanie wyjścia nie jest aktywne. Patrz
string ob_get_contents (void)
Dodatek A - Funkcje
330
ob_get_length
Zwraca ilość danych w buforze wyjściowym lub False, jeżeli buforowanie wyjścia nie jest aktywne. Patrz
również: ob_start() i ob_get_contents().
string ob_get_length (void)
ob_implicit_flush
Włącza lub wyłącza ukryte opróżnianie bufora wyjściowego (jeżeli nie podany został znacznik $flag,
domyślnie włącza opcję). Ukryte opróżnianie bufora powoduje opróżnianie bufora po każdej operacji wyjścia,
więc nie są potrzebne jawne wywołania funkcji flush(). Włączenie ukrytego opróżniania powoduje wyłączenie
buforowania wyjścia i zawartość bufora wyjściowego jest wysyłana tak samo, jak po wywołaniu funkcji
ob_end_flush(). Patrz również: flush(), ob_start() i ob_end_flush().
void ob_implicit_flush ([int flag])
ob_start
Włącza buforowanie wyjścia. Gdy aktywne jest buforowanie wyjścia, ze skryptu nie są przesyłane żadne
dane wyjściowe. Zamiast tego są one zbierane w wewnętrznym buforze. Zawartość tego bufora może być
skopiowana do zmiennej za pomocą ob_get_contents(). Aby wysłać na wyjście dane zebrane w buforze, należy
wywołać funkcję ob_end_flush(). Można również usunąć całą zawartość bufora za pomocą funkcji
ob_end_clean(). Patrz również: ob_get_contents(), ob_end_flush(), ob_end_clean() i ob_implict_flush().
void ob_start ([string output_callback])
OCIBindByName
Łączy zmienną PHP $variable z obszarem zablokowanym $ph_name. To, czy zostanie on użyty jako
wejście czy jako wyjście jest określane w czasie pracy i wtedy przydzielana jest niezbędna pamięć. Parametr
$length określa maksymalną długość dla połączenia. Jeżeli ustawisz $length na -1, OCIBindByName() do
ustawienia długości użyje bieżącego rozmiaru $variable. Jeżeli musisz dołączyć abstrakcyjny typ danych (LOB,
ROWID, BFILE), musisz je najpierw zarezerwować za pomocą funkcji OCINewDescriptor(). Parametr $length nie
jest używany dla abstrakcyjnych typów danych i powinien być ustawiony na -1. Parametr $type określa typ
używanego deskryptora. Możliwymi wartościami są: OCI_B_FILE (plik binarny), OCI_B_CFILE (plik znakowy),
OCI_B_CLOB (znakowy LOB), OCI_B_BLOB (binarny LOB) i OCI_B_ROWID (ROWID).
int OCIBindByName (int stmt, string ph_name, mixed &variable, int length [, int type])
Przykład: OCIDefineByName
<?php
/* przykład uzycia OCIBindByPos, [email protected] (980221)
wstawia trzy rekordy do emp, i używa ROWID do zmiany rekordów
zaraz p ich wstawieniu
*/
$conn = OCILogon("scott","tiger");
$stmt = OCIParse($conn,"insert into emp (empno, ename) ".
"values (:empno,:ename) ".
"returning ROWID into :rid");
$data = array(1111 => "Larry", 2222 => "Bill", 3333 => "Jim");
$rowid = OCINewDescriptor($conn,OCI_D_ROWID);
OCIBindByName($stmt,":empno",&$empno,32);
OCIBindByName($stmt,":ename",&$ename,32);
OCIBindByName($stmt,":rid",&$rowid,-1,OCI_B_ROWID);
$update = OCIParse($conn,"update emp set sal = :sal where ROWID = :rid");
OCIBindByName($update,":rid",&$rowid,-1,OCI_B_ROWID);
OCIBindByName($update,":sal",&$sal,32);
$sal = 10000;
while (list($empno,$ename) = each($data)) {
OCIExecute($stmt);
OCIExecute($update);
}
$rowid->free();
OCIFreeStatement($update);
OCIFreeStatement($stmt);
$stmt = OCIParse($conn,"select * from emp where empno in (1111,2222,3333)");
OCIExecute($stmt);
while (OCIFetchInto($stmt,&$arr,OCI_ASSOC)) {
331
PHP – Kompendium wiedzy
var_dump($arr);
}
OCIFreeStatement($stmt);
/* usunięcie naszych "śmieci" t tabeli emp.... */
$stmt = OCIParse($conn,"delete from emp where empno in (1111,2222,3333)");
OCIExecute($stmt);
OCIFreeStatement($stmt);
OCILogoff($conn);
?>
Jednoczesne użycie magic-quotes i OciBindByName() jest bardzo niedobrym pomysłem, ponieważ nie jest
potrzebne dodawanie apostrofów na zmiennych. Wszystkie apostrofu i cudzysłowy dodane w sposób
automatyczny zostaną zapisane w bazie, ponieważ funkcja OciBindByName() nie potrafi odróżnić apostrofów
dodanych automatycznie od tych dodanych z rozmysłem.
OCIColumnIsNULL
Zwraca True, jeżeli kolumna $column znajdująca się w wyniku z wyrażenia $stmt ma wartość NULL. Można
użyć numerów kolumn (numerowane od 1) lub nazw. Patrz również: OCINumCols(), OCIColumnType() i
OCIColumnSize().
int OCIColumnIsNULL (int stmt, mixed column)
OCIColumnName
Zwraca nazwę kolumny odpowiadającą przekazanemu numerowi kolumny (numerowane od 1).
string OCIColumnName (int stmt, int col)
Przykład: OCIColumnName()
<?php
print "<HTML><PRE>\n";
$conn = OCILogon("scott", "tiger");
$stmt = OCIParse($conn,"select * from emp");
OCIExecute($stmt);
print "<TABLE BORDER=\"1\">";
print "<TR>";
print "<TH>Nazwa</TH>";
print "<TH>Typ</TH>";
print "<TH>Długość</TH>";
print "</TR>";
$ncols = OCINumCols($stmt);
for ( $i = 1; $i <= $ncols; $i++ ) {
$column_name = OCIColumnName($stmt,$i);
$column_type = OCIColumnType($stmt,$i);
$column_size = OCIColumnSize($stmt,$i);
print "<TR>";
print "<TD>$column_name</TD>";
print "<TD>$column_type</TD>";
print "<TD>$column_size</TD>";
print "</TR>";
}
OCIFreeStatement($stmt);
OCILogoff($conn);
print "</PRE>";
print "</HTML>\n";
?>
OCIColumnSize
Zwraca rozmiar kolumny Oracle. Do parametru $col można użyć numeru kolumny (numerowane od 1)
lub nazwy kolumny. Patrz również: OCINumCols(), OCIColumnName() i OCIColumnSize().
int OCIColumnSize (int stmt, mixed column)
Przykład OCIColumnSize()
<?php
print "<HTML><PRE>\n";
$conn = OCILogon("scott", "tiger");
$stmt = OCIParse($conn,"select * from emp");
OCIExecute($stmt);
print "<TABLE BORDER=\"1\">";
print "<TR>";
print "<TH>Nazwa</TH>";
print "<TH>Typ</TH>";
print "<TH>Długość</TH>";
Dodatek A - Funkcje
332
print "</TR>";
$ncols = OCINumCols($stmt);
for ( $i = 1; $i <= $ncols; $i++ ) {
$column_name = OCIColumnName($stmt,$i);
$column_type = OCIColumnType($stmt,$i);
$column_size = OCIColumnSize($stmt,$i);
print "<TR>";
print "<TD>$column_name</TD>";
print "<TD>$column_type</TD>";
print "<TD>$column_size</TD>";
print "</TR>";
}
print "</TABLE>";
OCIFreeStatement($stmt);
OCILogoff($conn);
print "</PRE>";
print "</HTML>\n";
?>
OCIColumnType
Zwraca typ danych kolumny o podanym numerze Patrz również:
OCIColumnSize().
OCINumCols(), OCIColumnName()
i
mixed OCIColumnType (int stmt, int col)
Przykład: OCIColumnType()
<?php
print "<HTML><PRE>\n";
$conn = OCILogon("scott", "tiger");
$stmt = OCIParse($conn,"select * from emp");
OCIExecute($stmt);
print "<TABLE BORDER=\"1\">";
print "<TR>";
print "<TH>Nazwa</TH>";
print "<TH>Typ</TH>";
print "<TH>Długość</TH>";
print "</TR>";
$ncols = OCINumCols($stmt);
for ( $i = 1; $i <= $ncols; $i++ ) {
$column_name = OCIColumnName($stmt,$i);
$column_type = OCIColumnType($stmt,$i);
$column_size = OCIColumnSize($stmt,$i);
print "<TR>";
print "<TD>$column_name</TD>";
print "<TD>$column_type</TD>";
print "<TD>$column_size</TD>";
print "</TR>";
}
OCIFreeStatement($stmt);
OCILogoff($conn);
print "</PRE>";
print "</HTML>\n";
?>
OCICommit
Zatwierdza wszystkie zaległe zapytania dla połączenia do Oracle $connection.
int OCICommit( int connection )
OCIDefineByName
Powoduje przesłanie zawartości kolumn SQL do zmiennych PHP. Należy pamiętać, że Oracle zapisuje
nazwy kolumn zawsze wielkimi literami a wyrażenia SELECT najczęściej piszemy małymi literami. Funkcja
OCIDefineByName() oczekuje, że $column-name będzie zapisana wielkimi literami. Jeżeli zdefiniujesz zmienna nie
istniejącą w wyrażeniu SELECT, nie zostanie wygenerowany żaden błęd. Jeżeli musisz zdefiniować abstrakcyjny
typ danych (LOB, ROWID, BFILE) musisz najpierw użyć funkcji OCINewDescriptor(). Patrz również:
OCIBindByName().
int OCIDefineByName (int stmt, string Column-Name, mixed variable [, int type])
Przykład: OCIDefineByName()
<?php
/* przykład użycia OCIDefineByPos, [email protected] (980219) */
333
PHP – Kompendium wiedzy
$conn = OCILogon("scott","tiger");
$stmt = OCIParse($conn,"select empno, ename from emp");
/* ta definicja MUSI znajdować się przed ociexecute! */
OCIDefineByName($stmt,"EMPNO",$empno);
OCIDefineByName($stmt,"ENAME",$ename);
OCIExecute($stmt);
while (OCIFetch($stmt)) {
echo "empno:".$empno."\n";
echo "ename:".$ename."\n";
}
OCIFreeStatement($stmt);
OCILogoff($conn);
?>
OCIError
Zwraca ostatni napotkany błąd. Jeżeli nie podany zostanie parametr opcjonalny $stmt|conn|global,
zwracany jest ostatni błąd, Jeżeli nie napotkano błędu, OCIEror() zwraca False. Funkcja zwraca błąd w tablicy
asocjacyjnej. W tablicy $code zawiera numer błędu Oracle, natomiast $message, komunikat błędu.
array OCIError ([int stmt|conn|global])
OCIExecute
Wykonuje zanalizowane wyrażenie (OCIParse()). Opcjonalny parametr $mode pozwala określić tryb
wykonania (domyślnie jest to OCI_COMMIT_ON_SUCCESS). Jeżeli nie chcesz aby wyrażenia były automatycznie
zatwierdzane, należy zastosować tryb OCI_DEFAULT.
int OCIExecute (int statement [, int mode])
OCIFetch
Pobiera kolejny wiersz (dla wyrażeń SELECT) do wewnętrznego bufora wyniku.
int OCIFetch (int statement)
OCIFetchInto
Pobiera kolejny wiersz (dla wyrażeń SELECT) do tabeli $result. Funkcja OCIFetchInto() nadpisuje
poprzednią zawartość tablicy $result. Domyślnie $result zawiera tablicę (numerowaną od 1) wszystkich kolumn
mających wartości inne niż NULL. Parametr $mode pozwala zmienić domyślny tryb pracy. Można podać więcej niż
jeden znacznik dodając wartości, na przykład: OCI_ASSOC+OCIRETURN_NULLS.
int OCIFetchInto (int stmt, array &result [, int mode])
•
•
•
•
Możliwymi wartościami znacznika są:
OCI_ASSOC — zwraca tablic asocjacyjną
OCI_NUM — zwraca tablicę o indeksach numerycznych rozpoczynających się od 1 (domyślnie)
OCI_RETURN_NULLS — zwraca puste kolumny
OCI_RETURN_LOBS — zwraca wartości LOB zamiast deskryptorów
OCIFetchStatement
Pobiera
wszystkie wiersze wyniku do tablicy
zwraca ilość pobranych wierszy.
zdefiniowanej
przez
użytkownika.
Funkcja
OCIFetchStatement()
int OCIFetchStatement (int stmt, array &variable)
Przykład: OCIFetchStatement()
<?php
/* przykład OCIFetchStatement, [email protected] (990624) */
$conn = OCILogon("scott","tiger");
$stmt = OCIParse($conn,"select * from emp");
OCIExecute($stmt);
$nrows = OCIFetchStatement($stmt,$results);
if ( $nrows > 0 ) {
print "<TABLE BORDER=\"1\">\n";
print "<TR>\n";
while ( list( $key, $val ) = each( $results ) ) {
Dodatek A - Funkcje
334
print "<TH>$key</TH>\n";
}
print "</TR>\n";
for ( $i = 0; $i < $nrows; $i++ ) {
reset($results);
print "<TR>\n";
while ( $column = each($results) ) {
$data = $column['value'];
print "<TD>$data[$i]</TD>\n";
}
print "</TR>\n";
}
print "</TABLE>\n";
} else {
echo "Brak danych<BR>\n";
}
print "Wybano $nrows rekordów<BR>\n";
OCIFreeStatement($stmt);
OCILogoff($conn);
?>
OCIFreeCursor
Zwraca True, jeżeli funkcja się udała lub False, jeżeli się nie udała.
int OCIFreeCursor (int stmt)
OCIFreeDesc
Zwraca True, jeżeli funkcja się udała lub False, jeżeli się nie udała.
int OCIFreeDesc (object lob)
OCIFreeStatement
Zwraca True, jeżeli funkcja się udała lub False, jeżeli się nie udała.
int OCIFreeStatement (int stmt)
OCIInternalDebug
Włącza wyjście wewnętrznego debugera. Należy ustawić parametr
debugera, 1 aby je włączyć.
$onoff
na 0 aby wyłączyć wyjście
void OCIInternalDebug (int onoff)
OCILogOff
Zamyka połączenie do Oracle.
int OCILogOff (int connection)
OCILogon
Zwraca identyfikator połączenia niezbędny we większości funkcji OCI. Opcjonalny trzeci parametr może
zawierać nazwę lokalnej instancji Oracle, do której funkcja ma się przyłączyć lub nazwę wpisu w pliku
tnsnames.ora. Jeżeli nie zostanie podany trzeci parametr, PHP używa zmiennej środowiskowej ORACLE_SID
(instancja Oracle) lub TWO_TASK (tnsnames.ora) do określenia bazy danych do której ma się przyłączyć. Używając
funkcji OCILogon() połączenia są współdzielone na poziomie strony. Oznacza to, że operacje CONNECT i ROLLBACK
działają dla wszystkich otwartych transakcji nawet, jeżeli skrypt tworzy wiele połączeń. Poniższy przykład
pokazuje sposób współdzielenia połączeń.
int OCILogon (string username, string password [, string db])
Przykład: OCILogon()
<?php
print
$db =
$c1 =
$c2 =
335
"<HTML><PRE>";
"";
ocilogon("scott","tiger",$db);
ocilogon("scott","tiger",$db);
PHP – Kompendium wiedzy
function create_table($conn)
{ $stmt = ociparse($conn,"create table scott.hallo (test varchar2(64))");
ociexecute($stmt);
echo $conn." tabela utworzona\n\n";
}
function drop_table($conn)
{ $stmt = ociparse($conn,"drop table scott.hallo");
ociexecute($stmt);
echo $conn." tabela usunięta\n\n";
}
function insert_data($conn)
{ $stmt = ociparse($conn,"insert into scott.hallo
values('$conn' || ' ' || to_char(sysdate,'DD-MON-YY HH24:MI:SS'))");
ociexecute($stmt,OCI_DEFAULT);
echo $conn." wstawione dane przykładowe\n\n";
}
function delete_data($conn)
{ $stmt = ociparse($conn,"delete from scott.hallo");
ociexecute($stmt,OCI_DEFAULT);
echo $conn." usunięte dane przykładowe\n\n";
}
function commit($conn)
{ ocicommit($conn);
echo $conn." zatwierdzone\n\n";
}
function rollback($conn)
{ ocirollback($conn);
echo $conn." wycofane\n\n";
}
function select_data($conn)
{ $stmt = ociparse($conn,"select * from scott.hallo");
ociexecute($stmt,OCI_DEFAULT);
echo $conn."----wybieranie\n\n";
while (ocifetch($stmt))
echo $conn." <".ociresult($stmt,"TEST").">\n\n";
echo $conn."----gotowe\n\n";
}
create_table($c1);
insert_data($c1);
// Wstawienie wiersza za pomocą c1
insert_data($c2);
// Wstawienie wiersza za pomocą c2
select_data($c1);
// Zwracamy wynik obu wyrażeń INSERT
select_data($c2);
rollback($c1);
// wycofanie przy uzyciu c1
select_data($c1);
// Oba inserty ostały wycofane
select_data($c2);
insert_data($c2);
// Wstawienie wiersza za pomocą c2
commit($c2);
// zatwierdzanie za pmocą c2
select_data($c1);
// zwrócony jest wynik inserta na c2
delete_data($c1);
// usunięcie wszystkich wierszy w tabeli za pomocą c1
select_data($c1);
// brak wierszy
select_data($c2);
// brak wierszy
commit($c1);
// zatwierdzenie na c1
select_data($c1);
// brak wierszy
select_data($c2);
// brak wierszy
drop_table($c1);
print "</PRE></HTML>";
?>
Patrz również: OCIPLogon() i OCINLogon().
OCINewCursor
Przydziela nowy uchwyt wyrażenia do podanego połączenia.
int OCINewCursor (int conn)
Przykład: Użycie kursora REF z procedury przechowywanej
<?php
// zakładamy, że procedura przechowywana info.output zwraca kursor ref w :data
$conn = OCILogon("scott","tiger");
$curs = OCINewCursor($conn);
$stmt = OCIParse($conn,"begin info.output(:data); end;");
ocibindbyname($stmt,"data",&$curs,-1,OCI_B_CURSOR);
ociexecute($stmt);
ociexecute($curs);
while (OCIFetchInto($curs,&$data)) {
var_dump($data);
}
OCIFreeStatement($stmt);
OCIFreeCursor($curs);
OCILogoff($conn);
Dodatek A - Funkcje
336
?>
Przykład: Użycie kursora REF z wyrażenia SELECT
<?php
print "<HTML><BODY>";
$conn = OCILogon("scott","tiger");
$count_cursor = "CURSOR(select count(empno) num_emps from emp " .
"where emp.deptno = dept.deptno) as EMPCNT from dept";
$stmt = OCIParse($conn,"select deptno,dname,$count_cursor");
ociexecute($stmt);
print "<TABLE BORDER=\"1\">";
print "<TR>";
print "<TH>NAZWA WYDZIAŁU</TH>";
print "<TH>NR #</TH>";
print "<TH># PRACOWNIKÓW</TH>";
print "</TR>";
while (OCIFetchInto($stmt,&$data,OCI_ASSOC)) {
print "<TR>";
$dname = $data["DNAME"];
$deptno = $data["DEPTNO"];
print "<TD>$dname</TD>";
print "<TD>$deptno</TD>";
ociexecute($data[ "EMPCNT" ]);
while (OCIFetchInto($data[ "EMPCNT" ],&$subdata,OCI_ASSOC)) {
$num_emps = $subdata["NUM_EMPS"];
print "<TD>$num_emps</TD>";
}
print "</TR>";
}
print "</TABLE>";
print "</BODY></HTML>";
OCIFreeStatement($stmt);
OCILogoff($conn);
?>
OCINewDescriptor
Przydziela pamięć do przechowywania deskryptorów lub lokalizatorów LOB. Prawidłowymi wartościami
są: OCI_D_FILE, OCI_D_LOB i OCI_D_ROWID. Dla deskryptorów LOB z deskryptorami związane są metody
load, save i savefile. Dla BFILE istnieje tylko metoda load. Przyjrzyj się uwagom z komentarzy w drugim
przykładzie.
$type
string OCINewDescriptor (int connection [, int type])
Przykład: OCINewDescriptor()
<?php
/* Skrypt ten jest zaprojektowany do wywoływania z formularza HTML.
* Wymaga przekazania zmiennych$user, $password, $table, $where i
* $commitsize z formularza. Skrypt usuwa wybrae wiersze
* korzystając z ROWID i zatwierdza operacje po
* $commitsize wierszy. (używać rozważnie, brak możliwości wycofania)
*/
$conn = OCILogon($user, $password);
$stmt = OCIParse($conn,"select rowid from $table $where");
$rowid = OCINewDescriptor($conn,OCI_D_ROWID);
OCIDefineByName($stmt,"ROWID",&$rowid);
OCIExecute($stmt);
while ( OCIFetch($stmt) ) {
$nrows = OCIRowCount($stmt);
$delete = OCIParse($conn,"delete from $table where ROWID = :rid");
OCIBindByName($delete,":rid",&$rowid,-1,OCI_B_ROWID);
OCIExecute($delete);
print "$nrows\n";
if ( ($nrows % $commitsize) == 0 ) {
OCICommit($conn);
}
}
$nrows = OCIRowCount($stmt);
print "usunięto $nrows .\n";
OCIFreeStatement($stmt);
OCILogoff($conn);
?>
<?php
/*
*
*
*
337
Skrypt pokazuje sposób ładowania plików do kolumn LOB
Formularz używany w tym przykładzie jes następujący
<form action="upload.php3" method="post" enctype="multipart/form-data">
<input type="file" name="lob_upload">
PHP – Kompendium wiedzy
* ...
*/
if(!isset($lob_upload) || $lob_upload == 'none'){
?>
<form action="upload.php3" method="post" enctype="multipart/form-data">
Prześlij plik: <input type="file" name="lob_upload"><br>
<input type="submit" value="Wyśłij"> - <input type="reset">
</form>
<?php
} else {
// $lob_upload zawieera nazwę pliku tymczasowego przesłanego pliku
$conn = OCILogon($user, $password);
$lob = OCINewDescriptor($conn, OCI_D_LOB);
$stmt = OCIParse($conn,"insert into $table (id, the_blob)
values(my_seq.NEXTVAL, EMPTY_BLOB()) returning the_blob into :the_blob");
OCIBindByName($stmt, ':the_blob', &$lob, -1, OCI_B_BLOB);
OCIExecute($stmt, OCI_DEFAULT);
if($lob->savefile($lob_upload)){
OCICommit($conn);
echo "Udane przesłanie BLOB-a \n";
}else{
echo "Nieudane przesłanie BLOB-a \n";
}
OCIFreeDesc($lob);
OCIFreeStatement($stmt);
OCILogoff($conn);
}
?>
OCINLogon
Zwraca identyfikator nowego połączenia do bazy Oracle 8 i loguje się do bazy. Opcjonalny trzeci parametr
może zawierać nazwę lokalnej instancji Oracle, do której funkcja ma się przyłączyć lub nazwę wpisu w pliku
tnsnames.ora. Jeżeli nie zostanie podany trzeci parametr, PHP używa zmiennej środowiskowej ORACLE_SID
(instancja Oracle) lub TWO_TASK (tnsnames.ora) do określenia bazy danych do której ma się przyłączyć. Funkcja
OCINLogon() wymusza powstanie nowego połączenia. Powinno być to używane jedynie wtedy, gdy musisz
odizolować transakcje. Domyślnie połączenia są współdzielone na poziomie strony, jeżeli używa się funkcji
OCILogon() lub na poziomie serwera WWW, jeżeli używa się funkcji OCIPLogon(). Jeżeli posiadasz kilka połączeń
otwartych za pomocą OCINLogon() wszystkie operacje CONNECT i ROLLBACK działają tylko dla podanego połączenia.
Poniższy przykład pokazuje sposób separowania połączeń. Patrz również: OCILogon() i OCIPLogon().
int OCINLogon (string username, string password [, string db])
Przykład: OCINLogon()
<?php
print "<HTML><PRE>";
$db = "";
$c1 = ocilogon("scott","tiger",$db);
$c2 = ocinlogon("scott","tiger",$db);
function create_table($conn)
{ $stmt = ociparse($conn,"create table scott.hallo (test varchar2(64))");
ociexecute($stmt);
echo $conn." tabela utworzona\n\n";
}
function drop_table($conn)
{ $stmt = ociparse($conn,"drop table scott.hallo");
ociexecute($stmt);
echo $conn." tabela usunięta\n\n";
}
function insert_data($conn)
{ $stmt = ociparse($conn,"insert into scott.hallo
values('$conn' || ' ' || to_char(sysdate,'DD-MON-YY HH24:MI:SS'))");
ociexecute($stmt,OCI_DEFAULT);
echo $conn." wstawione dane przykładowe\n\n";
}
function delete_data($conn)
{ $stmt = ociparse($conn,"delete from scott.hallo");
ociexecute($stmt,OCI_DEFAULT);
echo $conn." usunięte dane przykładowe\n\n";
}
function commit($conn)
{ ocicommit($conn);
echo $conn." zatwierdzone\n\n";
}
Dodatek A - Funkcje
338
function rollback($conn)
{ ocirollback($conn);
echo $conn." wycofane\n\n";
}
function select_data($conn)
{ $stmt = ociparse($conn,"select * from scott.hallo");
ociexecute($stmt,OCI_DEFAULT);
echo $conn."----wybieranie\n\n";
while (ocifetch($stmt))
echo $conn." <".ociresult($stmt,"TEST").">\n\n";
echo $conn."----gotowe\n\n";
}
create_table($c1);
insert_data($c1);
select_data($c1);
select_data($c2);
rollback($c1);
select_data($c1);
select_data($c2);
insert_data($c2);
commit($c2);
select_data($c1);
delete_data($c1);
select_data($c1);
select_data($c2);
commit($c1);
select_data($c1);
select_data($c2);
drop_table($c1);
print "</PRE></HTML>";
?>
OCINumCols
Zwraca ilość kolumn w wyrażeniu.
int OCINumCols (int stmt)
Przykład: OCINumCols()
<?php
print "<HTML><PRE>\n";
$conn = OCILogon("scott", "tiger");
$stmt = OCIParse($conn,"select * from emp");
OCIExecute($stmt);
while ( OCIFetch($stmt) ) {
print "\n";
$ncols = OCINumCols($stmt);
for ( $i = 1; $i <= $ncols; $i++ ) {
$column_name = OCIColumnName($stmt,$i);
$column_value = OCIResult($stmt,$i);
print $column_name . ': ' . $column_value . "\n";
}
print "\n";
}
OCIFreeStatement($stmt);
OCILogoff($conn);
print "</PRE>";
print "</HTML>\n";
?>
OCIParse
Analizuje zapytanie $query korzystając z połączenia $conn. Zwraca identyfikator wyrażenia, jeżeli
zapytanie jest prawidłowe lub False, jeżeli nie jest. Parametr $query może zawierać dowolne prawidłowe
zapytanie SQL.
int OCIParse (int conn, string query)
OCIPLogon
Zwraca identyfikator trwałego połączenia do serwera Oracle 8 i loguje się do bazy. Opcjonalny trzeci
parametr może zawierać nazwę lokalnej instancji Oracle, do której funkcja ma się przyłączyć lub nazwę wpisu w
pliku tnsnames.ora. Jeżeli nie zostanie podany trzeci parametr, PHP używa zmiennej środowiskowej ORACLE_SID
339
PHP – Kompendium wiedzy
(instancja Oracle) lub TWO_TASK (tnsnames.ora) do określenia bazy danych do której ma się przyłączyć. Patrz
również: OCILogon() i OCINLogon().
int OCIPLogon (string username, string password [, string db])
OCIResult
Zwraca dane z kolumny $column w bieżącym wierszu (patrz OCIFetch()). Funkcja
wszystko poza typami abstrakcyjnymi (ROWID, LOB, FILE) w postaci ciągów.
OCIesult()
zwraca
mixed OCIResult (int statement, mixed column)
OCIRollback
Wycofuje zmiany wykonane poprzez połączenie $connection.
int OCIRollback (int connection)
OCIRowCount
Zwraca ilość wierszy zmienionych przez wyrażenie SQL. Funkcja nie zwraca ilości wierszy zwracanych
przez wyrażenie SELECT.
int OCIRowCount (int statement)
Przykład: OCIRowCount()
<?php
print "<HTML><PRE>";
$conn = OCILogon("scott","tiger");
$stmt = OCIParse($conn,"create table emp2 as select * from emp");
OCIExecute($stmt);
print " wstawiono ".OCIRowCount($stmt) . " wierszy.<BR>";
OCIFreeStatement($stmt);
$stmt = OCIParse($conn,"delete from emp2");
OCIExecute($stmt);
print"usunięto ". OCIRowCount($stmt) . " wierszy.<BR>";
OCICommit($conn);
OCIFreeStatement($stmt);
$stmt = OCIParse($conn,"drop table emp2");
OCIExecute($stmt);
OCIFreeStatement($stmt);
OCILogOff($conn);
print "</PRE></HTML>";
?>
OCIServerVersion
string OCIServerVersion (int conn)
Przykład: OCIServerVersion()
<?php
$conn = OCILogon("scott","tiger");
print "Wersja serwera: " . OCIServerVersion($conn);
OCILogOff($conn);
?>
OCIStatementType
string OCIStatementType (int stmt)
Funkcja OCIStatementType() zwraca jedną z następujących wartości:
SELECT
INSERT
ALTER
UNKNOWN
UPDATE
CREATE
BEGIN
DELETE
DROP
DECLARE
Przykład:
<?php
print "<HTML><PRE>";
$conn = OCILogon("scott","tiger");
$sql = "delete from emp where deptno = 10";
$stmt = OCIParse($conn,$sql);
if ( OCIStatementType($stmt) == "DELETE" ) {
die "Nie możesz usuwać z tej tabeli<BR>";
Dodatek A - Funkcje
340
}
OCILogoff($conn);
print "</PRE></HTML>";
?>
octdec
Zwraca dziesiętny odpowiednik liczby ósemkowej reprezentowanej przez argument $octal_string.
Funkcja octdec() konwertuje ciąg ósemkowy na liczbę dziesiętna. Największą liczbą możliwą do
skonwertowania jest 17777777777 lub dziesiętnie 2147483647. Patrz również: decoct().
int octdec( string octal_string )
odbc_autocommit
Funkcja wywołana bez parametru $onoff zwraca stan mechanizmu automatycznego zatwierdzania dla
połączenia $connection_id. Jeżeli automatyczne zatwierdzanie jest włączone, zwraca True natomiast False, jeżeli
jest wyłączone lub wystąpił błąd. Jeżeli parametr $onoff ma wartość True, automatyczne zatwierdzanie jest
włączane, jeżeli ma wartość False — wyłączane. Zwraca True w przypadku sukcesu i False w przypadku błędu.
Domyślnie automatyczne zatwierdzanie jest włączone dla połączenia. Wyłączenie automatycznego zatwierdzania
jest ekwiwalentem rozpoczęcia transakcji. Patrz również: odbc_commit() i odbc_rollback().
int odbc_autocommit (int connection_id [, int OnOff])
odbc_binmode
int odbc_binmode (int result_id, int mode)
(Funkcja ma wpływ na typy SQL ODBC: BINARY, VARBINARY i LONGVARBINARY)
• ODBC_BINMODE_PASSTHRU — Dane BINARY są przekazywane dalej.
• ODBC_BINMODE_RETURN — Zwraca w takiej postaci jak otrzymał
• ODBC_BINMODE_CONVERT — Konwertuje znaki i końce linii.
Gdy dane binarne SQL są konwertowane do danych znakowych C, każdy bajt (8 bitów) źródła jest
reprezentowany jako dwa znaki ASCII. Znaki te są znakami ASCII reprezentującymi liczbę w postaci
szesnastkowej. Na przykład, liczba binarna 00000001 jest konwertowana na "01" natomiast 11111111 na "FF".
Obsługa typu LONGVARBINARY
longreadlen
Wynik
Tryb binarny
ODBC_BINMODE_PASSTHRU
0
przelotka
ODBC_BINMODE_RETURN
0
przelotka
ODBC_BINMODE_CONVERT
0
przelotka
ODBC_BINMODE_PASSTHRU
0
przelotka
ODBC_BINMODE_PASSTHRU
>0
przelotka
ODBC_BINMODE_RETURN
>0
zwraca w niezmienionej
postaci
ODBC_BINMODE_CONVERT
>0
zwraca jako ciąg znaków
Jeżeli zostanie użyta funkcja odbc_fetch_into(), „przelotka” oznacza, że dla tych kolumn zwracany jest
pusty ciąg. Jeżeli $result_id jest równy 0, ustawienia te są wartościami domyślnymi dla nowych wyników.
Uwaga
Wartością domyślną dla longreadlen jest 4096 a tryb binarny ODBC_BINMODE_RETURN. Obsługa kolumn binarnych jest również
realizowana przez odbc_longreadlen().
odbc_close
Zamyka połączenie do serwera bazy danych skojarzonego z podanym identyfikatorem łącza.
Uwaga
341
PHP – Kompendium wiedzy
Funkcja ta się nie uda, jeżeli na tym połączeniu są otwarte transakcje. W takim przypadku połączenie pozostanie otwarte.
void odbc_close (int connection_id)
odbc_close_all
Zamyka wszystkie połączenia do serwera bazy danych.
Uwaga
Funkcja ta się nie uda, jeżeli na tym połączeniu są otwarte transakcje. W takim przypadku połączenie pozostanie otwarte.
void odbc_close_all (void)
odbc_columnprivileges
False
Zwraca listę kolumn i uprawnień do nich dla podanej tablicy. Zwraca identyfikator wyniku ODBC lub
w przypadku wystąpienia błędu.
int odbc_columnprivileges (int connection_id [, string qualifier [, string owner
[, string table_name [, string column_name]]]])
Wynik zawiera następujące kolumny:
•
•
•
•
•
•
•
TABLE_QUALIFIER
TABLE_OWNER
TABLE_NAME
GRANTOR
GRANTEE
PRIVILEGE
IS_GRANTABLE
Wynik jest uporządkowany według TABLE_QUALIFIER, TABLE_OWNER i TABLE_NAME. Argument $column_name
pozwala na stosowanie wzorców przeszukiwania (% zastępuje zero lub więcej znaków i _ zastępuje jeden znak).
odbc_columns
Tworzy listę kolumn w określonym zakresie. Zwraca identyfikator wyniku ODBC lub False w przypadku
wystąpienia błędu.
int odbc_columns (int connection_id [, string qualifier [, string owner
[, string table_name [, string column_name]]]])
Wynik składa się z następujących kolumn:
TABLE_QUALIFIER
COLUMN_NAME
PRECISION
RADIX
TABLE_OWNER
DATA_TYPE
LENGTH
NULLABLE
TABLE_NAME
TYPE_NAME
SCALE
REMARKS
Wynik jest uporządkowany według TABLE_QUALIFIER, TABLE_OWNER i TABLE_NAME. Argument $column_name,
$table_name i $column_name pozwalają na stosowanie wzorców przeszukiwania (% zastępuje zero lub więcej
znaków i _ zastępuje jeden znak). Patrz również: odbc_columnprivileges().
odbc_commit
Zwraca True w przypadku sukcesu lub False w przypadku błędu. Wszystkie transakcje rozpoczęte poprzez
$connection_id są zatwierdzane.
int odbc_commit (int connection_id)
odbc_connect
Zwraca identyfikator połączenia ODBC lub 0 (False) w przypadku błędu. Identyfikator połączenia
zwracany przez tą funkcję jest wymagany przez inne funkcje ODBC. Możesz mieć jednocześnie wiele połączeń.
Opcjonalny czwarty parametr określa typ kursora, jaki jest używany na tym połączeniu. Parametr ten nie jest
Dodatek A - Funkcje
342
zwykle wymagany, ale może być użyteczny przy obchodzeniu problemów ze sterownikami ODBC. W przypadku
niektórych sterowników ODBC, wykonywanie skomplikowanych procedur przechowywanych mogą powodować
błąd Cannot open a cursor on a stored procedure that anything other than a single select statement in it. Użycie
SQL_CUR_USE_ODBC może pomóc uniknąć błędu. Niektóre sterowniki nie obsługują opcjonalnego parametru
$row_number w odbc_fetch_row(). Parametr SQL_CUR_USE_ODBC może również pomóc w tym przypadku.
int odbc_connect (string dsn, string user, string password [, int cursor_type])
Dla parametru $cursor_type zdefiniowane są następujące stałe:
•
•
•
•
SQL_CUR_USE_IF_NEEDED
SQL_CUR_USE_ODBC
SQL_CUR_USE_DRIVER
SQL_CUR_DEFAULT
Dla połączyć trwałych patrz odbc_pconnect().
odbc_cursor
Zwraca nazwę kursora dla podanego $result_id.
string odbc_cursor (int result_id)
odbc_do
Uruchamia zapytanie na podanym połączeniu.
int odbc_do (int conn_id, string query)
odbc_exec
Zwraca False w przypadku wystąpienia błędu. Zwraca identyfikator wyniku ODBC, jeżeli udało się
poprawnie wykonać wyrażenie SQL. Funkcja odbc_exec() wysyła wyrażenie SQL do serwera bazy danych
wskazywanego przez $connection_id. Parametr ten musi być prawidłowym identyfikatorem zwracanym przez
odbc_connect() lub odbc_pconnect(). Patrz również: odbc_prepare() i odbc_execute() dla wielokrotnego
wykonania wyrażenia SQL.
int odbc_exec (int connection_id, string query_string)
odbc_execute
Wykonuje zapytanie przygotowanie za pomocą odbc_prepare(). Zwraca True w przypadku udanego
wykonania, False w przeciwnym przypadku. Tablica $parameters_array jest potrzebna, jeżeli w wyrażeniu SQL
występują parametry.
int odbc_execute (int result_id [, array parameters_array])
odbc_fetch_into
Zwraca ilość kolumn w wyniku lub False w przypadku wystąpienia błędu. Tablica $result_array musi
być przekazana przez referencję, ale może być to dowolny typ, ponieważ zostanie skonwertowany na typ
tablicowy. Tablica zawiera wartości kolumn pod indeksami rozpoczynającymi się od 0.
int odbc_fetch_into (int result_id [, int rownumber, array result_array])
odbc_fetch_row
Jeżeli funkcja się powiedzie (był wiersz wyniku) zwracana jest wartość True. Jeżeli nie ma już wierszy,
zwracana jest wartość False. Funkcja pobiera wiersz danych zwróconych przez funkcję odbc_do() lub
odbc_exec(). Po wywołaniu odbc_fetch_row() pola z wyniku są dostępne dla funkcji odbc_result(). Jeżeli nie
zostanie podany parametr $row_number, funkcja próbuje pobrać kolejny wiersz wyniku. Wywołania funkcji
odbc_fetch_row() z parametrem $row_number i bez niego mogą być mieszane. Aby więcej niż raz odczytać wyniki
zapytania, należy wywołać odbc_fetch_row() z $row_number równym 1 i kontynuować pobieranie danych za
343
PHP – Kompendium wiedzy
pomocą odbc_fetch_row() bez parametru $row_number. Jeżeli sterownik nie obsługuje odczytywania wiersza o
podanym numerze, parametr ten jest ignorowany.
int odbc_fetch_row (int result_id [, int row_number])
odbc_field_len
Zwraca długość pola wskazywanego przy pomocy numeru w wyniku ODBC o podanym identyfikatorze.
Numerowanie pól rozpoczyna się od 1. Patrz również: odbc_field_scale().
int odbc_field_len (int result_id, int field_number)
odbc_field_name
Zwraca nazwę pola wskazywanego przy pomocy numeru w wyniku ODBC o podanym identyfikatorze.
Numerowanie pól rozpoczyna się od 1. W przypadku wystąpienia błędu zwraca False.
string odbc_field_name (int result_id, int field_number)
odbc_field_num
Zwraca numer kolumny o podanej nazwie w wyniku ODBC o podanym identyfikatorze. Numerowanie pól
rozpoczyna się od 1. W przypadku wystąpienia błędu zwraca False.
int odbc_field_num (int result_id, string field_name)
odbc_field_precision
Zwraca dokładność kolumny o podanym numerze w wyniku ODBC o podanym identyfikatorze. Patrz
również: odbc_field_scale().
string odbc_field_precision (int result_id, int field_number)
odbc_field_scale
Zwraca skalę kolumny o podanym numerze w wyniku ODBC o podanym identyfikatorze.
string odbc_field_scale (int result_id, int field_number)
odbc_field_type
Zwraca typ SQL pola wskazywanego przy pomocy numeru w wyniku ODBC o podanym identyfikatorze.
Numerowanie pól rozpoczyna się od 1.
string odbc_field_type (int result_id, int field_number)
odbc_foreignkeys
Odczytuje dane na temat kluczy obcych. Zwraca identyfikator wyniku ODBC lub
False
w przypadku
błędu.
int odbc_foreignkeys (int connection_id, string pk_qualifier, string pk_owner,
string pk_table, string fk_qualifier, string fk_owner, string fk_table)
Wynik składa się z następujących kolumn:
PKTABLE_QUALIFIER
PKCOLUMN_NAME
FKTABLE_NAME
UPDATE_RULE
PK_NAME
PKTABLE_OWNER
FKTABLE_QUALIFIER
FKCOLUMN_NAME
DELETE_RULE
PKTABLE_NAME
FKTABLE_OWNER
KEY_SEQ
FK_NAME
Jeżeli parametr $pk_table zawiera nazwę tabeli, odbc_foreignkeys() zwraca w wynik zawierający klucz
główny i wszystkie klucze obce odwołujące się do tej tabeli. Jeżeli $fk_table zawiera nazwę tabeli,
odbc_foreignkeys() zwraca wynik zawierający wszystkie klucze obce w podanej tabeli oraz klucze główne, do
których się odwołują. Jeżeli zarówno $pk_table jak i $fk_table zawierają nazwy tabel, odbc_foreignkeys()
zwraca klucze obce z tabeli określonej przez $fk_table odwołujące się do klucza głównego z tabeli $pk_table. W
większości przypadków będzie to tylko jeden klucz.
Dodatek A - Funkcje
344
odbc_free_result
Zawsze zwraca True. Wywołanie tej funkcji jest wymagane jedynie wtedy, gdy skrypt zużywa zbyt dużo
pamięci podczas pracy. Cała pamięć przydzielona do wyniku jest automatycznie zwalniana po zakończeniu
działania skryptu. Jeżeli jesteś pewien, że nie będziesz już używał danych z wyniku, możesz wywołać funkcję
odbc_free_result(), aby zwolnić pamięć przydzieloną do $result_id.
Uwaga
Jeżeli automatyczne zatwierdzanie jest zablokowane, (patrz odbc_autocommit()) i wywołasz odbc_free_result() przed
zatwierdzeniem, wszystkie otwarte transakcje zostaną wycofane.
int odbc_free_result (int result_id)
odbc_gettypeinfo
Pobiera dane na temat typów danych obsługiwanych przez źródło danych. Zwraca identyfikator wyniku
ODBC lub False w przypadku wystąpienia błędu. Można użyć opcjonalnego parametru $data_type do
ograniczenia danych do jednego typu.
int odbc_gettypeinfo (int connection_id [, int data_type])
Wynik składa się z następujących kolumn:
TYPE_NAME
LITERAL_PREFIX
NULLABLE
UNSIGNED_ATTRIBUTE
LOCAL_TYPE_NAME
DATA_TYPE
LITERAL_SUFFIX
CASE_SENSITIVE
MONEY
MINIMUM_SCALE
PRECISION
CREATE_PARAMS
SEARCHABLE
AUTO_INCREMENT
MAXIMUM_SCALE
Wynik jest uporządkowany według DATA_TYPE i TYPE_NAME.
odbc_longreadlen
(Funkcja ma wpływ na typ SQL ODBC LONG i LONGVARBINARY) Ilość bajtów zwracanych do PHP jest
określana przez wartość parametru. Jeżeli ma wartość 0, dane z kolumn long są przepuszczane do klienta.
Uwaga
Obsługa kolumn LONGVARBINARY jest również realizowana przez odbc_binmode().
int odbc_longreadlen (int result_id, int length)
odbc_num_fields
Zwraca ilość pól (kolumn) w wyniku ODBC. Funkcja zwraca -1 w przypadku wystąpienia błędu.
Argumentem jest prawidłowy identyfikator wyniku zwracany przez odbc_exec().
int odbc_num_fields (int result_id)
odbc_num_rows
Zwraca ilość wierszy w wyniku ODBC. W przypadku wystąpienia błędu funkcja zwraca -1. Dla wyrażeń
i DELETE funkcja zwraca ilość zmienionych wierszy. Dla wyrażeń SELECT zwraca ilość zwracanych
wierszy.
INSERT, UPDATE
Uwaga
Użycie funkcji odbc_num_rows() do sprawdzenia ilości wierszy dostępnych po wykonaniu wyrażenia SELECT zwróci dla wielu
sterowników -1.
int odbc_num_rows (int result_id)
345
PHP – Kompendium wiedzy
odbc_pconnect
Zwraca identyfikator połączenia ODBC lub 0 (False) w przypadku wystąpienia błędu. Funkcja jest
podobna do odbc_connect(), poza tym, że połączenie nie jest zamykane po zakończeniu skryptu. Kolejne żądania
połączenia z tą samą kombinacją $dsn, $user i $password (poprzez odbc_connect() i odbc_pconnect()) powodują
ponowne wykorzystanie połączenia trwałego.
Uwaga
Połączenia trwałe nie działają, jeżeli PHP jest użyty jako program CGI. Opis opcjonalnego parametru $cursor_type znajduje się
przy opisie funkcji odbc_connect(). Więcej informacji na temat połączeń trwałych znajduje się w PHP FAQ.
int odbc_pconnect (string dsn, string user, string password [, int cursor_type])
odbc_prepare
Zwraca False w przypadku błędu. Zwraca identyfikator wyniku ODBC dla poprawnie przygotowanego
wyrażenia SQL. Wynikowy identyfikator może być użyty do uruchomienia wyrażenia za pomocą
odbc_execute().
int odbc_prepare (int connection_id, string query_string)
odbc_primarykeys
Zwraca nazwy kolumn składających się na klucz główny tabeli. Zwraca identyfikator wyniku ODBC lub
False w przypadku błędu.
int odbc_primarykeys (int connection_id, string qualifier, string owner, string table)
Wynik posiada następujące kolumny:
TABLE_QUALIFIER
COLUMN_NAME
TABLE_OWNER
KEY_SEQ
TABLE_NAME
PK_NAME
odbc_procedurecolumns
Zwraca listę parametrów wejściowych i wyjściowych oraz kolumn będących wynikiem działania
procedury. zwraca identyfikator wyniku ODBC lub False w przypadku błędu.
int odbc_procedurecolumns (int connection_id [, string qualifier [, string owner
[, string proc [, string column]]]])
Wynik posiada następujące kolumny:
PROCEDURE_QUALIFIER
COLUMN_NAME
TYPE_NAME
SCALE
REMARKS
PROCEDURE_OWNER
COLUMN_TYPE
PRECISION
RADIX
Wynik jest posortowany według kolumn
PROCEDURE_NAME
DATA_TYPE
LENGTH
NULLABLE
PROCEDURE_QUALIFIER,
PROCEDURE_NAME
i
COLUMN_TYPE.
Argumenty $owner, $proc i $column mogą zawierać wzorzec przeszukiwania (% zastępuje zero lub więcej
znaków i _ zastępuje jeden znak).
odbc_procedures
Tworzy listę procedur w określonym zakresie. Zwraca identyfikator wyniku ODBC lub
przypadku błędu.
False
w
int odbc_procedures (int connection_id [, string qualifier [, string owner [, string name]]])
Wynik zawiera następujące kolumny:
PROCEDURE_QUALIFIER
NUM_INPUT_PARAMS
REMARKS
PROCEDURE_OWNER
NUM_OUTPUT_PARAMS
PROCEDURE_TYPE
PROCEDURE_NAME
NUM_RESULT_SETS
Argumenty $owner, $proc i $column mogą zawierać wzorzec przeszukiwania (% zastępuje zero lub
więcej znaków i _ zastępuje jeden znak).
Dodatek A - Funkcje
346
odbc_result
Zwraca zawartość pola. Parametr
zawierającym nazwę pola.
$field
może być liczbą określającą numer pola lub ciągiem
string odbc_result (int result_id, mixed field)
Przykład:
$item_3 = odbc_result ($Query_ID, 3);
$item_val = odbc_result ($Query_ID, "val");
Pierwsze wywołanie odbc_result() zwraca wartość trzeciego pola w bieżącym rekordzie Drugie
wywołanie funkcji odbc_result() zwraca wartość pola o nazwie val w bieżącym rekordzie w wyniku. Błąd
wystąpi, jeżeli numer kolumny dla jest mniejsza od jeden lub przekracza ilość kolumn w bieżącym rekordzie.
Podobnie błąd wystąpi, jeżeli podana nazwa nie jest nazwą pola znajdującego się w wyniku. Numery pól
rozpoczynają się od 1. W zależności od trybu obsługi kolumn long, zwracane są dane binarne lub long. Patrz
również: odbc_binmode() i odbc_longreadlen().
odbc_result_all
Zwraca ilość wierszy w wyniku lub False w przypadku błędu. Funkcja odbc_result_all() powoduje
wydruk wszystkich wierszy z wyniku tworzonego za pomocą odbc_exec(). Wynikiem funkcji jest tabela HTML.
Dodatkowe formatowanie tabeli może być realizowane za pomocą opcjonalnego ciągu $format.
int odbc_result_all (int result_id [, string format])
odbc_rollback
Wycofuje transakcje otwarte poprzez połączenie
wykonania operacji lub False w przypadku błędu.
$connection_id.
Zwraca
True
w przypadku pomyślnego
int odbc_rollback (int connection_id)
odbc_setoption
Funkcja pozwala operować opcjami ODBC dla połączenia lub wyniku zapytania. Funkcja została napisana
w celu umożliwienia znalezienia obejścia problemów ze sterownikami ODBC zawierającymi błędy. Powinieneś
używać tej funkcji jedynie wtedy, gdy jesteś programistą ODBC i znasz konsekwencje ustawiania różnych opcji.
Powinieneś również posiadać dobry podręcznik ODBC zawierający objaśnienie wszystkich opcji i ich wartości.
Różne wersje sterowników obsługują różne opcje.
int odbc_setoption (int id, int function, int option, int param)
Ponieważ efekty mogą bardzo zależeć od sterownika ODBC, używanie tej funkcji w skryptach
udostępnianych publicznie nie jest zalecane. Niektóre opcje ODBC nie są dostępne dla tej funkcji, ponieważ
muszą być ustawiane przed nawiązaniem połączenia lub przygotowania zapytania. Jednak może ona pomóc w
konkretnym przypadku. Parametr $id jest identyfikatorem połączenia lub identyfikatorem wyniku, na którym
chcesz zmienić opcje. Dla SQLSetConnectOption() jest to identyfikator połączenia. Dla SQLSetStmtOption() jest to
identyfikator wyniku. Parametr $function jest używaną funkcją ODBC. Wartością może być: 1 dla
SQLSetConnectOption() i 2 dla SQLSetStmtOption(). Parametr $option jest wartością ustawianej opcji. Parametr
$param jest wartością dla podanej opcji.
Przykład: ODBC SetOption
// 1. Opcje 102 dla SQLSetConnectOption() wynosi SQL_AUTOCOMMIT.
//
Wartość 1 dla SQL_AUTOCOMMIT to SQL_AUTOCOMMIT_ON.
//
Przykład ten jest analogiczny do wywołania
//
odbc_autocommit($conn, true);
odbc_setoption ($conn, 1, 102, 1);
// 2. Opcja 0 dla SQLSetStmtOption() wynosi SQL_QUERY_TIMEOUT.
//
Przykład ustawia czas wygaśnięcia zapytania na 30 sekund.
$result = odbc_prepare ($conn, $sql);
odbc_setoption ($result, 2, 0, 30);
odbc_execute ($result);
347
PHP – Kompendium wiedzy
odbc_specialcolumns
Gdy wartością parametru $type wynosi SQL_BEST_ROWID, funkcja odbc_specialcolumns() zwraca kolumnę
lub kolumny, które jednoznacznie identyfikują każdy wiersz tabeli. Jeżeli $typ wynosi SQL_ROWVER, funkcja
odbc_specialcolumns() zwraca optymalną kolumnę lub zestaw kolumn, która po odczytaniu wartości kolumny
lub kolumn pozwala na jednoznaczną identyfikację wierszy z tablicy. Funkcja zwraca identyfikator wyniku
ODBC lub False w przypadku błędu.
int odbc_specialcolumns (int connection_id, int type, string qualifier,
string owner, string table, int scope, int nullable)
Wynik zawiera następujące kolumny:
SCOPE
TYPE_NAME
SCALE
COLUMN_NAME
PRECISION
PSEUDO_COLUMN
DATA_TYPE
LENGTH
Wynik jest uporządkowany według kolumny SCOPE.
odbc_statistics
Odczytuje statystyki na temat tablicy i indeksów. Zwraca identyfikator wyniku ODBC lub
przypadku błędu.
False
w
INDEX_NAME
i
int odbc_statistics (int connection_id, string qualifier, string owner,
string table_name, int unique, int accuracy)
Wynik zawiera następujące kolumny:
TABLE_QUALIFIER
NON_UNIQUE
TYPE
COLLATION
FILTER_CONDITION
TABLE_OWNER
INDEX_QUALIFIER
SEQ_IN_INDEX
CARDINALITY
Wynik jest uporządkowany według kolumn:
TABLE_NAME
INDEX_NAME
COLUMN_NAME
PAGES
NON_UNIQUE,
TYPE,
INDEX_QUALIFIER,
SEQ_IN_INDEX.
odbc_tableprivileges
Tworzy listę tabel w żądanym zakresie oraz uprawnień związanych z każdą tabelą. Zwraca identyfikator
wyniku ODBC lub False w przypadku błędu.
int odbc_tableprivileges (int connection_id [, string qualifier [, string owner
[, string name]]])
Wynik zawiera następujące kolumny:
TABLE_QUALIFIER
GRANTOR
IS_GRANTABLE
TABLE_OWNER
GRANTEE
TABLE_NAME
PRIVILEGE
Wynik jest uporządkowany według kolumn: TABLE_QUALIFIER, TABLE_OWNER i TABLE_NAME. Argumenty
$owner, $proc i $column mogą zawierać wzorzec przeszukiwania (% zastępuje zero lub więcej znaków i _
zastępuje jeden znak).
odbc_tables
Tworzy listę tabel w żądanym zakresie. Zwraca identyfikator wyniku ODBC lub
False
w przypadku
błędu.
int odbc_tables (int connection_id [, string qualifier [, string owner
[, string name [, string types]]]])
Wynik zawiera następujące kolumny:
TABLE_QUALIFIER
TABLE_TYPE
TABLE_OWNER
REMARKS
Wynik jest uporządkowany według:
TABLE_NAME
i TABLE_NAME. Argumenty
$owner, $proc i $column mogą zawierać wzorzec przeszukiwania (% zastępuje zero lub więcej znaków i _
zastępuje jeden znak). Aby obsłużyć wyliczanie kwalifikatorów, właścicieli i typów tabel dostępna jest specjalna
składnia parametrów $qualifier, $owner, $name i $table_type.
Jeżeli $qualifier zawiera jeden znak procentu (%) natomiast $owner i $name są pustymi ciągami, wynik
zawiera listę kwalifikatorów dla źródła danych (wszystkie kolumny poza TABLE_QUALIFIER zawierają wartości
Dodatek A - Funkcje
TABLE_TYPE, TABLE_QUALIFIER, TABLE_OWNER
348
NULL).
Jeżeli $owner zawiera znak procentu (%) a $qualifier i $name są pustymi ciągami, wynik jest listą
właścicieli dla podanego źródła danych (wszystkie kolumny poza TABLE_OWNER zawierają wartości NULL). Jeżeli
$table_type zawiera znak procentu (%) a $qualifier, $owner i $name są pustymi ciągami, wynik jest listą typów
tabel dla podanego źródła danych (wszystkie kolumny poza TABLE_TYPE zawierają wartości NULL). Jeżeli
$table_type nie jest pustym ciągiem, musi zawierać listę wartości rozdzielonych przecinkami interesujących
typów tabel Każda wartość może być otoczona apostrofami (') lub bez apostrofów, na przykład: 'TABLE','VIEW'
lub TABLE,VIEW. Jeżeli źródło danych nie obsługuje jakiegoś typu tabel, odbc_tables() nie zwraca wyników dla
tego typu. Sposób odczytywania uprawnień opisany jest przy funkcji odbc_tableprivileges().
opendir
Zwraca uchwyt katalogu, który jest później używany w funkcjach closedir(), readdir() i rewinddir().
resource opendir (string path)
openlog
Otwiera dla programu połączenie do dziennika systemowego. Ciąg $ident jest dodawany do każdego
komunikatu. Wartości $option i $facility są wymienione w tabeli poniżej. Argument $option używany jest do
wskazania, opcji używanych przy generowaniu komunikatów. Pozwala to podać (w konfiguracji dziennika
systemowego) w jaki sposób są obsługiwane komunikaty przychodzące z różnych urządzeń. Użycie funkcji
openlog() jest opcjonalne. Jest ona wywoływana w razie potrzeby przez funkcję syslog() i w takim przypadku
$ident ma wartość False.
int openlog (string ident, int option, int facility)
Opcje openlog()
Stała
Opis
Jeżeli wystąpił błąd przy wysyłaniu danych do dziennika
systemowego dane są wypisywane na konsolę systemową.
LOG_NDELAY
Natychmiast otwiera połączenie z dziennikiem systemowym.
LOG_ODELAY
(domyślny) Opóźnia otwarcie połączenia do zapisu pierwszego
komunikatu.
LOG_PERROR
Wysyła komunikaty dziennika również na standardowe wyjście
błędów.
LOG_PID
Dodaje PID do każdego komunikatu.
Można korzystać z więcej niż jednej z tych opcji. Używając kilku opcji do ich łączenia należy użyć
operatora OR. Na przykład, aby uzyskać natychmiastowe otwarcie połączenia, pisanie na konsolę i dodanie PID do
każdego komunikatu należy użyć LOG_CONS | LOG_NDELAY | LOG_PID.
Urządzenia dla openlog()
Stała
Opis
LOG_AUTH
Komunikaty systemu bezpieczeństwa (należy użyć
LOG_AUTHPRIV w systemach gdzie jest zdefiniowana ta stała).
LOG_AUTHPRIV
Komunikaty systemu bezpieczeństwa (prywatne).
LOG_CRON
Demony zegara (cron i at).
LOG_DAEMON
Inne demony systemowe.
LOG_KERN
Komunikaty jądra.
LOG_LOCAL0
...
Zarezerwowane.
LOG_CONS
LOG_LOCAL7
LOG_LPR
LOG_MAIL
LOG_NEWS
LOG_SYSLOG
LOG_USER
LOG_UUCP
349
Podsystem drukarki.
Podsystem poczty.
Podsystem USENET.
Komunikaty generowane przez syslogd.
Komunikaty generowane przez programy użytkownika.
Podsystem UUCP.
PHP – Kompendium wiedzy
Patrz również: define_syslog_variables(), syslog() i closelog().
Ora_Bind
Zwraca True jeżeli wiązanie udało się lub False w przeciwnym przypadku. Szczegóły na temat błędu
mogą być pobrane za pomocą funkcji ora_error() i ora_errorcode(). Funkcja ta wiąże nazwę zmiennej PHP z
parametrem SQL. Parametr SQL musi mieć postać :nazwa. Za pomocą opcjonalnego parametru $type można
zdefiniować, czy parametr ma być wyjściowy i wejściowy (0 — domyślnie), wejściowy (10) lub wyjściowy (2).
Od wersji PHP 3.0.1 można korzystać ze stałych ORA_BIND_INOUT, ORA_BIND_IN i ORA_BIND_OUT zamiast liczb.
Funkcja ora_bind() musi być wywołana po ora_parse() i przed ora_exec(). Wartości wejściowe mogą być
przekazywane poprzez przypisanie do związanych zmiennych PHP. Po wywołaniu ora_exec(), wartości
wyjściowe, jeżeli są dostępne, są dostępne w odpowiednich związanych zmiennych.
int ora_bind (int cursor, string PHP variable name, string SQL parameter name,
int length [, int type])
Przykład: ora_bind()
<?php
ora_parse($curs, "declare tmp INTEGER; begin tmp := :in; :out := tmp; :x := 7.77; end;");
ora_bind($curs, "result", ":x", $len, 2);
ora_bind($curs, "input", ":in", 5, 1);
ora_bind($curs, "output", ":out", 5, 2);
$input = 765;
ora_exec($curs);
echo "Wynik: $result<BR>Wyjście: $output<BR>Wejście: $input";
?>
Ora_Close
Zwraca True jeżeli udało się zamknięcie, False w przeciwnym wypadku. Szczegóły na temat błędu mogą
być pobrane za pomocą funkcji ora_error() i ora_errorcode(). Funkcja zamyka kursor otwarty za pomocą
ora_open().
int ora_close (int cursor)
Ora_ColumnName
Zwraca nazwę kolumny (pola) numer
literami.
$column
z kursora
$cursor.
Zwracana nazwa zapisana jest wielkimi
string Ora_ColumnName (int cursor, int column)
Ora_ColumnSize
Zwraca rozmiar kolumny (pola) numer $column z kursora $cursor.
int Ora_ColumnSize (int cursor, int column)
Ora_ColumnType
Zwraca typ Oracle kolumny (pola) numer $column z kursora $cursor.
string Ora_ColumnType (int cursor, int column)
Zwracany typ może być jedną z poniższych wartości:
•
•
•
•
•
•
•
•
•
VARCHAR2
VARCHAR
CHAR
NUMBER
LONG
LONG RAW
ROWID
DATE
CURSOR
Dodatek A - Funkcje
350
Ora_Commit
Zwraca True w przypadku powodzenia operacji lub False w przypadku wystąpienia błędu. Szczegóły na
temat błędu mogą być pobrane za pomocą funkcji ora_error() i ora_errorcode(). Funkcja zatwierdza transakcję
Oracle. Transakcja jest definiowana jako wszystkie zmiany wykonane poprzez połączenie od czasu ostatniej
operacji COMMIT lub ROLLBACK, wyłączenia automatycznego zatwierdzania lub nawiązania połączenia.
int ora_commit (int conn)
Ora_CommitOff
Zwraca True w przypadku powodzenia operacji lub False w przypadku wystąpienia błędu. Szczegóły na
temat błędu mogą być pobrane za pomocą funkcji ora_error() i ora_errorcode(). Funkcja wyłącza automatyczne
zatwierdzanie operacji po każdej funkcji ora_exec().
int ora_commitoff (int conn)
Ora_CommitOn
Funkcja włącza automatyczne zatwierdzanie operacji po każdej funkcji ora_exec() na podanym
połączeniu. Zwraca True w przypadku powodzenia operacji lub False w przypadku wystąpienia błędu. Szczegóły
na temat błędu mogą być pobrane za pomocą funkcji ora_error() i ora_errorcode().
int ora_commiton (int conn)
Ora_Do
Funkcja ta jest kombinacją funkcji ora_parse(), ora_exec() i ora_fetch(). Analizuje, wykonuje
wyrażenie oraz pobiera pierwszy wiersz. Zwraca True w przypadku powodzenia operacji lub False w przypadku
wystąpienia błędu. Szczegóły na temat błędu mogą być pobrane za pomocą funkcji ora_error() i
ora_errorcode(). Patrz również: ora_parse(), ora_exec() i ora_fetch().
int ora_do (int conn, string query)
Ora_Error
Zwraca komunikat błędu w postaci XXX-NNNNN, gdzie XXX jest źródłem błędu a NNNNN określa
komunikat błędu.
Uwaga
Obsługę identyfikatorów połączenia została dodana w PHP 3.0.4.
string Ora_Error (int cursor_or_connection)
Na Oracle dla systemów Unix można znaleźć komunikaty błędów podobne do następujących:
$ oerr ora 00001 00001, 00000, "unique constraint (%s.%s) violated" // *Cause: An update or insert statement
attempted to insert a duplicate key // For Trusted ORACLE configured in DBMS MAC mode, you may see // this
message if a duplicate entry exists at a different level. // *Action: Either remove the unique restriction
or do not insert the key
Ora_ErrorCode
Zwraca numeryczny kod błędu ostatniej wykonywanego wyrażenia na określonym kursorze lub
połączeniu.
Uwaga
Obsługę identyfikatorów połączenia została dodana w PHP 3.0.4.
int Ora_ErrorCode (int cursor_or_connection)
351
PHP – Kompendium wiedzy
Ora_Exec
Zwraca True w przypadku powodzenia operacji lub False w przypadku wystąpienia błędu. Szczegóły na
temat błędu mogą być pobrane za pomocą funkcji ora_error() i ora_errorcode(). Patrz również: ora_parse(),
ora_fetch() i ora_do().
int ora_exec (int cursor)
Ora_Fetch
Zwraca True (został odczytany wiersz) lub False (brak wierszy lub wystąpił błąd). Szczegóły na temat
błędu mogą być pobrane za pomocą funkcji ora_error() i ora_errorcode(). Jeżeli nie wystąpił błąd,
ora_errorcode() zwraca 0. Pobiera wiersz danych z podanego kursora. Patrz również: ora_parse(), ora_exec() i
ora_do().
int ora_fetch (int cursor)
Ora_Fetch_Into
Pobiera wiersz do tablicy.
Uwaga
Musisz przekazywać tablicę przez referencję.
Patrz również: ora_parse(), ora_exec(), ora_fetch() i ora_do().
int ora_fetch_into (int cursor, array result [, int flags])
Przykład: Pobranie wiersza wyniku Oracle do tablicy
<?php
array($results);
ora_fetch_into($cursor, &$results);
echo $results[0];
echo $results[1];
?>
Ora_GetColumn
Zwraca dane kolumny. Jeżeli wystąpi błąd zwracana jest wartość False, a ora_errorcode() zwraca
niezerową wartość. Należy pamiętać, że sprawdzanie czy funkcja zwróciła wartość False powoduje, że będą
wykrywane również sytuacje gdy błąd nie wystąpił (wartość NULL, pusty ciąg, liczba 0, ciąg "0"). Pobiera dane z
kolumny lub wynik funkcji.
mixed ora_getcolumn (int cursor, mixed column)
Ora_Logoff
Zwraca True w przypadku powodzenia operacji lub False w przypadku wystąpienia błędu. Szczegóły na
temat błędu mogą być pobrane za pomocą funkcji ora_error() i ora_errorcode(). Wylogowuje użytkownika i
odłącza od serwera. Patrz również: ora_logon().
int ora_logoff (int connection)
Ora_Logon
Zestawia połączenie pomiędzy PHP a bazą danych Oracle, korzystając z podanej nazwy użytkownika i
hasła.
int ora_logon (string user, string password)
Podając nazwę TNS i użytkownika połączenie może być zestawione za pomocą SQL*Net:
$conn = Ora_Logon("user@TNSNAME", "pass");
Jeżeli dane znakowe zawierają znaki spoza zakresu ASCII, powinieneś ustawić w systemie zmienną
środowiska NLS_LANG. W przypadku korzystania z modułu serwera, zmienna ta powinna być ustawiona w
środowisku serwera przed uruchomieniem serwera. W przypadku powodzenia operacji zwraca identyfikator
Dodatek A - Funkcje
352
połączenia lub False w przypadku wystąpienia błędu. Szczegóły na temat błędu mogą być pobrane za pomocą
funkcji ora_error() i ora_errorcode().
Ora_Numcols
Zwraca liczbę kolumn w wyniku. Zwraca prawidłowe wartości jedyni po wykonaniu sekwencji parse –
exec – fetch. Patrz również: ora_parse(), ora_exec(), ora_fetch() i ora_do().
int ora_numcols (int cursor_ind)
Ora_Numrows
Zwraca ilość wierszy w wyniku.
int ora_numrows (int cursor_ind)
Ora_Open
Otwiera kursor Oracle skojarzony z połączeniem. Zwraca identyfikator kursora lub False w przypadku
błędu. Szczegóły na temat błędu mogą być pobrane za pomocą funkcji ora_error() i ora_errorcode().
int ora_open (int connection)
Ora_Parse
Analizuje wyrażenie SQL lub blok PL/SQL i łączy je z podanym kursorem. Zwraca 0 w przypadku
powodzenia operacji lub -1 w przypadku błędu. Patrz również: ora_exec(), ora_fetch() i ora_do().
int ora_parse (int cursor_ind, string sql_statement, int defer)
Ora_pLogon
Zestawia trwałe połączenie pomiędzy PHP a bazą danych Oracle, korzystając z podanej nazwy
użytkownika i hasła. Patrz również: ora_logon().
int ora_plogon (string user, string password)
Ora_Rollback
Wycofuje transakcję Oracle (definicja transakcji znajduje się przy funkcji ora_commit()).Zwraca
identyfikator kursora lub False w przypadku błędu. Szczegóły na temat błędu mogą być pobrane za pomocą
funkcji ora_error() i ora_errorcode().
int ora_rollback (int connection)
OrbitEnum
Klasa ta reprezentuje wyliczenie identyfikowane przez parametr $id. Parametr ten może być nazwą
wyliczenia (na przykład: MyEnum) lub pełnym identyfikatorem repozytorium (na przykład: IDL:MyEnum:1:0)
new OrbitEnum (string id)
Przykład: przykładowy plik IDL
enum MyEnum {
a,b,c,d,e
};
Przykład: kod PHP korzystający z MyEnum
<?php
$enum = new OrbitEnum ("MyEnum");
echo $enum->a;
/* wypisuje 0 */
echo $enum->c;
/* wypisuje 2 */
echo $enum->e;
/* wypisuje 4 */
?>
353
PHP – Kompendium wiedzy
OrbitObject
Klasa pozwalająca na dostęp do obiektu CORBA. Parametr
Interoperable Object Reference (IOR) identyfikujący zdalny obiekt.
$id
powinien być ciągiem zawierającym
new OrbitObject (string ior)
Przykład: Przykładowy plik IDL
interface MyInterface {
void SetInfo (string info);
string GetInfo();
attribute int value;
}
Przykład: kod PHP korzystający z MyInterface
<?php
$obj = new OrbitObject ($ior);
$obj->SetInfo ("Obiekt");
echo $obj->GetInfo();
$obj->value = 42;
echo $obj->value;
?>
OrbitStruct
Klasa reprezentująca strukturę o identyfikatorze $id. Parametr $id może być nazwą struktury (na przykład
MyStruct) lub pełnym identyfikatorem repozytorium (na przykład: IDL:MyStruct:1:0)
new OrbitStruct (string id)
Przykład: przykładowy plik IDL
struct MyStruct {
short shortvalue;
string stringvalue;
};
interface SomeInterface {
void SetValues (MyStruct values);
MyStruct GetValues();
}
Przykład: kod PHP korzystający z MyStruct
<?php
$obj = new OrbitObject ($ior);
$initial_values = new OrbitStruct ("IDL:MyStruct:1.0");
$initial_values->shortvalue = 42;
$initial_values->stringvalue = "HGTTG";
$obj->SetValues ($initial_values);
$values = $obj->GetValues();
echo $values->shortvalue;
echo $values->stringvalue;
?>
ord
Zwraca wartość ASCII dla pierwszego znaku ciągu
również: chr().
$string.
Funkcja jest odwrotnością
chr().
Patrz
int ord (string string)
Przykład: ord()
if (ord($str) == 10) {
echo "Pierwszym znakiem \$str jest znak nowego wiersza.\n";
}
pack
Pakuje podane argumenty do postaci ciągu binarnego zgodnie z formatem $format. Zwraca ciąg binarny
zawierający dane. Idea tej funkcji jest zapożyczona z języka Perl i wszystkie kody formatujące działają
identycznie. Jednak brakuje kilku kodów, na przykład kod Perla u. Ciąg formatu składa się z kodów
formatowania po których następują opcjonalne argumenty powtarzania. Argument ten może być liczbą całkowita
lub * dla powtarzania do końca danych wejściowych. Dla kodów a, A, h i H ilość powtórzeń określa ilość
pobieranych znaków jednego argumentu danych. Dla @, jest to bezwzględna pozycja na której należy umieścić
Dodatek A - Funkcje
354
kolejne dane. Dla pozostałych kodów ilość powtórzeń określa ile argumentów jest pobieranych i pakowanych do
wynikowego ciągu binarnego.
string pack (string format [, mixed args ...])
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Zaimplementowane są następujące kody:
a — ciąg dopełniany zerami
A — ciąg dopełniany spacjami
h — ciąg szesnastkowy, pierwszy jest mniej znaczący półbajt
H — ciąg szesnastkowy, pierwszy jest bardziej znaczący półbajt
c — litera ze znakiem
C — litera bez znaku
s — krótka liczba ze znakiem (zawsze 16 bitów, kolejność bajtów zależna od komputera)
S — krótka liczba bez znaku (zawsze 16 bitów, kolejność bajtów zależna od komputera)
n — krótka liczba bez znaku (zawsze 16 bitów, z malejącym porządkiem bitów)
v — krótka liczba bez znaku (zawsze 16 bitów, z rosnącym porządkiem bitów)
i — liczba całkowita ze znakiem (rozmiar i porządek bitów zależny od komputera)
I — liczba całkowita bez znaku (rozmiar i porządek bitów zależny od komputera)
l — liczba długa ze znakiem (zawsze 32 bity, kolejność bajtów zależna od komputera)
L — liczba długa bez znaku (zawsze 32 bity, kolejność bajtów zależna od komputera)
N — liczba długa bez znaku (zawsze 32 bity, z malejącym porządkiem bitów)
V — liczba długa bez znaku (zawsze 32 bity, z rosnącym porządkiem bitów)
f — liczba zmiennoprzecinkowa (rozmiar i reprezentacja zależna od komputera)
d — liczba double (rozmiar i reprezentacja zależna od komputera)
x — bajt NUL
X — cofnięcie o jeden bajt
@ — wypełnienie znakami NUL do określonej pozycji
Przykład: ciąg formatu dla pack()
$binarydata = pack ("nvc*", 0x1234, 0x5678, 65, 66);
Wynikowy ciąg będzie miał 6 bajtów i zawierał sekwencję bajtów: 0x12, 0x34, 0x78, 0x56, 0x41 i 0x42.
Uwaga
Rozróżnienie pomiędzy wartościami ze znakiem lub bez znaku jest ważne jedynie dla funkcji unpack(), a funkcja pack() daje
identyczne wartości dla kodów formatowania ze znakiem jak i bez.
Należy zauważyć, że PHP wewnętrznie przechowuje wartości całkowite jako wartości ze znakiem o
wielkości zależnej od komputera. Jeżeli zostanie przekazana zbyt duża wartość, zostanie ona skonwertowana do
double, co może prowadzić do niespodziewanych wyników.
parse_str
Analizuje ciąg $str tak, jakby był przekazany poprzez adres URL i ustawia zmienne w bieżącym zakresie
widoczności. Jeżeli podany jest drugi parametr $arr zmienne są umieszczane w przekazanej tablicy.
void parse_str (string str [, array arr])
Przykład: użycie parse_str()
<?php
$str = "first=value&second[]=this+works&second[]=another";
parse_str($str);
echo $first;
/* wypisuje "value" */
echo $second[0]; /* wypisuje "this works" */
echo $second[1]; /* wypisuje "another" */
?>
parse_url
Zwraca tablicę asocjacyjną zawierającą różne składniki podanego adresu URL. Są dostępne: scheme, host,
i fragment.
port, user, pass, path, query
array parse_url (string url)
355
PHP – Kompendium wiedzy
passthru
Podobna do funkcji exec(), uruchamia polecenie podane w $command. Jeżeli podany jest parametr
$return_var, umieszczana jest w nim wartość kodu powrotu wykonywanego polecenia. Funkcja ta powinna być
używana zamiast exec() lub system() dla przypadków, gdy wynikiem działania polecenia są dane binarne, które
muszą być wysłane do przeglądarki. Częstym zastosowaniem jest uruchomienie programu podobnego do pbmplus,
który potrafi bezpośrednio pisać do strumienia wyjściowego. Ustawiając content-type na image/gif i wywołując
pbmplus z opcją tworzenia pliku gif, można stworzyć skrypt PHP bezpośrednio wyświetlający rysunki.
Uwaga
Jeżeli uruchamiasz program przy pomocy tej funkcji i chcesz pozostawić go aby działał w tle, musisz przekierować jego wyjście do
pliku lub innego strumienia wyjściowego, ponieważ inaczej PHP zatrzyma się czekając na zakończenie tego programu.
Patrz również: exec(), popen(), EscapeShellCmd() oraz operator `.
void passthru (string command [, int return_var])
pdf_add_outline
Dodaje zakładkę z tekstem $text wskazującą na bieżącą stronę. Zakładka jest wstawiana w postaci
obiektu potomnego do $parent i jest domyślnie otwierana chyba, że parametr $open jest różny od 0. Wynikiem
jest identyfikator zakładki i może być on użyty jako obiekt nadrzędny dla innych zakładek. Dzięki temu można
tworzyć hierarchię zakładek. Niestety pdflib nie tworzy kopii ciągu, co powoduje wymuszenie przydzielania
pamięci przez PHP. Ten fragment pamięci nie jest zwalniany przez żadną z funkcji PDF i jest to w gestii zarządcy
pamięci PHP.
int pdf_add_outline( int pdf_document, string text [, int parent] [, int open])
pdf_arc
Rysuje łuk o środku w punkcie ($x-coor, $y-coor) i promieniu $radius rozpoczynając pod kątem $start a
kończąc na $end. Patrz również: pdf_circle() i pdf_stroke().
void pdf_arc (resource pdf_object, float x, float y, float r, float alpha, float beta)
pdf_begin_page
Rozpoczyna nową stronę o wysokości $height i szerokości $width. Aby stworzyć prawidłowy dokument
musisz co najmniej raz wywołać funkcję pdf_end_page(). Patrz również: pdf_end_page().
void pdf_begin_page (int pdf_object, float width, float height)
pdf_circle
Rysuje okrąg o środku w punkcie ($x-coor,
pdf_stroke().
$y-coor)
i promieniu
$radius.
Patrz również:
pdf_arc()
i
void pdf_circle (int pdf_object, float x, float y, float r)
pdf_clip
Przycina rysunek do bieżącej ścieżki.
void pdf_clip (int pdf_object)
pdf_close
Zamyka dokument pdf. Patrz również: pdf_open() i fclose().
void pdf_close (int pdf_object)
Dodatek A - Funkcje
356
pdf_closepath
Zamyka bieżącą ścieżkę. Oznacza to, że rysuje linię od bieżącego punktu do punktu, w którym zostało
rozpoczęte rysowanie ścieżki. Wiele funkcji, np. pdf_moveto(), pdf_circle() i pdf_rect() rozpoczyna nową
ścieżkę.
void pdf_closepath (int pdf_object)
pdf_closepath_fill_stroke
Zamyka bieżącą ścieżkę, wypełnia jej obszar bieżącym kolorem wypełnienia i rysuje ścieżkę. Patrz
również:
pdf_closepath(),
pdf_stroke(),
pdf_fill(),
pdf_setgray_fill(),
pdf_setgray(),
pdf_setrbgcolor_fill() i pdf_setrgbcolor().
void pdf_closepath_fill_stroke (int pdf_object)
pdf_closepath_stroke
Połączenie pdf_closepath() i pdf_stroke(). Dodatkowo kasuje ścieżkę. Patrz również: pdf_closepath() i
pdf_stroke().
void pdf_closepath_stroke (int pdf_object)
pdf_close_image
Zamyka rysunek otwarty za pomocą funkcji
pdf_open_gif() i pdf_open_memory_image().
pdf_open_xxx().
Patrz również:
pdf_open_jpeg(),
void pdf_close_image (int pdf_object, int image)
pdf_continue_text
Umieszcza tekst przekazany w parametrze $text w kolejnym wierszu. Odstęp pomiędzy wierszami może
być regulowany za pomocą funkcji pdf_set_leading(). Patrz również: pdf_show_xy(), pdf_set_leading() i
pdf_set_text_pos().
void pdf_continue_text (int pdf_object, string text)
pdf_curveto
Rysuje krzywą Beziera od punktu bieżącego do punktu ($x3, $y3) używając jako punktów kontrolnych
($x1, $y1) i ($x2, $y2). Patrz również: pdf_moveto(), pdf_lineto() i pdf_stroke().
void pdf_curveto (int pdf_object, float x1, float y1, float x2, float y2,
float x3, float y3)
pdf_endpath
Kończy bieżącą ścieżkę, ale jej nie zamyka. Patrz również: pdf_closepath().
void pdf_endpath( int pdf_document )
pdf_end_page
Kończy stronę. Po zakończeniu strony nie może być ona już modyfikowana. Patrz również:
pdf_begin_page().
void pdf_end_page (int pdf_object)
pdf_execute_image
Wyświetla rysunek umieszczony w pliku PDF za pomocą funkcji pdf_put_image() na bieżącej stronie na
podanych współrzędnych. Rysunek może być przeskalowany podczas wyświetlania. Skala 1.0 powoduje
wyświetlanie rysunku w oryginalnej wielkości.
357
PHP – Kompendium wiedzy
Uwaga
Funkcja stanie się przestarzała w pdflib 2.01. Będzie jedynie wyświetlała ostrzeżenie.
Przykład: wielokrotne wyświetlanie rysunku
<?php
$im = ImageCreate( 100, 100 );
$col1 = ImageColorAllocate( $im, 80, 45,
ImageFill( $im, 10, 10, $col1 );
$pim = pdf_open_memory_image( $pdf, $pim
pdf_put_image( $pdf, $pim );
pdf_execute_image( $pdf, $pim, 100, 100,
pdf_execute_image( $pdf, $pim, 200, 200,
pdf_close_image( $pdf, $pim )
?>
190 );
);
1 );
2 );
pdf_fill
Wypełnia wnętrze bieżącej ścieżki za pomocą bieżącego koloru wypełnienia. Patrz również:
pdf_stroke(),
pdf_setgray_fill(),
pdf_setgray(),
pdf_setrgbcolor_fill()
i
pdf_sergbcolor().
pdf_closepath(),
void pdf_fill_stroke (int pdf_object)
pdf_fill_stroke
Wypełnia wnętrze bieżącej ścieżki za pomocą bieżącego koloru wypełnienia i rysuje bieżącą ścieżkę. Patrz
również:
pdf_closepath(),
pdf_stroke(),
pdf_fill(),
pdf_setgray_fill(),
pdf_setgray(),
pdf_setrgbcolor_fill() i pdf_sergbcolor().
void pdf_fill_stroke (int pdf_object)
pdf_get_image_height
Zwraca
wysokość rysunku pdf w
pdf_open_memory_image() i pdf_get_image_width().
pikselch.
Patrz
również:
pdf_open_image_file(),
Patrz
również:
pdf_open_image_file(),
string pdf_get_image_height (int pdf_object, int image)
pdf_get_image_width
Zwraca
szerokość rysunku pdf w
pdf_open_memory_image() i pdf_get_image_heigth().
pikselch.
string pdf_get_image_width (int pdf_object, int image)
pdf_get_parameter
Pobiera kilka z parametrów pdflib będących ciągami. Parametr funkcji $modifier określa parametr do
pobrania. Jeżeli modyfikator nie jest potrzebny, musi mieć wartość 0 lub nie podany. Patrz również:
pdf_get_value(), pdf_set_value() i pdf_set_parameter().
string pdf_get_parameter (int pdf_object, string key [, float modifier])
pdf_get_value
Pobiera kilka numerycznych parametrów pdflib. Parametr funkcji $modifier określa parametr do pobrania.
Jeżeli modyfikator nie jest potrzebny, musi mieć wartość 0 lub nie podany. Patrz również: pdf_get_parametr(),
pdf_set_value() i pdf_set_parameter().
float pdf_get_value (int pdf_object, string key [, float modifier])
Dodatek A - Funkcje
358
pdf_lineto
Rysuje linię od punktu bieżącego do punktu o współrzędnych ($x,
pdf_curveto() i pdf_stroke().
$y).
Patrz również:
pdf_moveto(),
void pdf_lineto (int pdf_object, float x, float y)
pdf_moveto
Ustawia punkt bieżący na $x i $y.
void pdf_moveto (int pdf_object, float x, float y)
pdf_open
Otwiera dokument pdf. Odpowiedni plik musi być otwarty za pomocą fopen() i deskryptor pliku
przekazany jako parametr $file. Jeżeli nie przekazane zostaną żadne parametry, dokument zostanie utworzony w
pamięci a wynikowa strona wysłana do stdout lub przeglądarki WWW.
Uwaga
Zwracana wartość jest potrzebna jako pierwszy parametr wszystkich pozostałych funkcji zapisujących pliki pdf.
Patrz również: fopen() i pdf_close().
int pdf_open( int file )
pdf_open_gif
Otwiera rysunek zapisany w pliku o nazwie
identyfikator rysunku pdf.
$filename.
Formatem pliku musi być gif. Funkcja zwraca
Uwaga
Funkcja nie powinna być już używana. Proszę używać zamiast niej funkcji pdf_open_image_file().
Patrz również: pdf_close_image(),
i pdf_put_image().
pdf_open_jpeg(), pdf_open_memory_image(), pdf_execute_image(),
pdf_place_image()
int pdf_open_gif ( int pdf_document, string filename )
Przykład: Dołączanie rysunku GIF
<?php
$im = pdf_open_gif( $pdf, "test.gif" );
pdf_place_image( $pdf, $im, 100, 100, 1 );
pdf_close_image( $pdf, $im );
?>
pdf_open_image_file
Otwiera rysunek o formacie $format, zapisany w pliku o nazwie $filename. Możliwymi formatami pliku
są: png, tiff, jpeg i gif. Funkcja zwraca identyfikator rysunku pdf. Patrz również: pdf_close_image(),
pdf_open_jpeg(), pdf_open_gif(), pdf_open_memory_image(), pdf_execute_image(), pdf_place_image() i
pdf_put_image().
int pdf_open_image_file (int PDF-document, string imagetype, string filename
[, string stringparam [, string intparam]])
Przykład: wstawianie rysunku
<?php
$im = pdf_image_file( $pdf, "png", "picture.png" );
pdf_place_image( $pdf, $im, 100, 100, 1 );
pdf_close_image( $pdf, $im );
?>
359
PHP – Kompendium wiedzy
pdf_open_jpeg
Otwiera rysunek zapisany w pliku o nazwie
identyfikator rysunku pdf.
$filename.
Formatem pliku musi być jpeg. Funkcja zwraca
Uwaga
Funkcja nie powinna być już używana. Proszę używać zamiast niej funkcji pdf_open_image_file().
Patrz
również: pdf_close_image(), pdf_open_gif(),
pdf_execute_image(), pdf_place_image() i pdf_put_image().
pdf_open_png(),
pdf_open_memory_image(),
int pdf_open_jpeg ( int pdf_document, string filename )
pdf_open_memory_image
Pobiera rysunek utworzony za pomocą funkcji PHP tworzących rysunki i udostępnia go dla dokumentu
pdf. Funkcja zwraca identyfikator rysunku pdf. Patrz również: pdf_close_image(),pdf_open_jpeg(),
pdf_open_gif(), pdf_open_png(), pdf_execute_image(), pdf_place_image() i pdf_put_image().
int pdf_open_memory_image (int pdf_object, int image)
Przykład: Dołączanie rysunku z pamięci
<?php
$im = ImageCreate( 100, 100 );
$col1 = ImageColorAllocate( $im, 80, 45, 190 );
ImageFill( $im, 10, 10, $col1 );
$pim = pdf_open_memory_image( $pdf, $pim );
ImageDestroy( $im );
pdf_place_image( $pdf, $pim, 100, 100, 1 );
pdf_close_image( $pdf, $pim )
?>
pdf_open_png
Otwiera rysunek zapisany w pliku o nazwie
identyfikator rysunku pdf.
$filename.
Formatem pliku musi być png. Funkcja zwraca
Uwaga
Funkcja nie powinna być już używana. Proszę używać zamiast niej funkcji pdf_open_image_file().
Patrz
również:
pdf_close_image(),
pdf_execute_image(), pdf_place_image()
pdf_open_gif(),
pdf_open_jpeg(),
pdf_open_memory_image(),
i pdf_put_image().
int pdf_open_png ( int pdf_document, string filename )
Przykład: dołączanie rysunku PNG
<?php
$im = pdf_open_png( $pdf, "test.png" );
pdf_place_image( $pdf, $im, 100, 100, 1 );
pdf_close_image( $pdf, $im );
?>
pdf_open_tiff
Otwiera rysunek zapisany w pliku o nazwie
identyfikator rysunku pdf.
$filename.
Formatem pliku musi być tiff. Funkcja zwraca
Uwaga
Funkcja nie powinna być już używana. Proszę używać zamiast niej funkcji pdf_open_image_file().
Patrz
również:
pdf_close_image(),
pdf_open_gif(),
pdf_open_memory_image(), pdf_execute_image(), pdf_place_image()
pdf_open_jpeg(),
pdf_open_png(),
i pdf_put_image().
int pdf_open_tiff( int pdf_document, string filename )
Dodatek A - Funkcje
360
pdf_place_image
Umieszcza rysunek na stronie na współrzędnych ($x, $y). Rysunek może być w tym czasie przeskalowany.
Patrz również: pdf_put_image().
void pdf_place_image (int pdf_object, int image, float x, float y, float scale)
pdf_put_image
Umieszcza rysunek w pliku PDF bez jego pokazywania. Zapisany rysunek może być wyświetlony za
pomocą pdf_execute_image() dowolną ilość razy. Jest to użyteczne, jeżeli ten sam rysunek jest wielokrotnie
używany w celu zmniejszenia pliku wynikowego. Użycie funkcji pdf_put_image() i pdf_execute_image() jest
zalecane dla większych rysunków (kilka KB), jeżeli są pokazane w dokumencie więcej niż raz.
Uwaga
Funkcja stanie się przestarzała w pdflib 2.01. Będzie jedynie wyświetlała ostrzeżenie.
Patrz również: pdf_put_image(), pdf_place_image() i pdf_execute_image().
pdf_rect
Rysuje prostokąt o dolnym lewym narożniku w punkcie ($x,
wysokość $height. Patrz również: pdf_stroke().
$y).
Jego szerokość wynosi
$width
a
void pdf_rect (int pdf_object, float x, float y, float width, float height)
pdf_restore
Przywraca środowisko zapisane za pomocą
Patrz również: pdf_save().
pdf_save().
Działa podobnie do polecenia postscript restore.
void pdf_restore (int pdf_object)
Przykład: zapamiętywanie i przywracanie środowiska
<?php
pdf_save( $pdf );
// wykonanie obrotów i innych transformacji
pdf_restore( $pdf );
?>
pdf_rotate
Ustawia kąt obrotu w stopniach na $angle.
void pdf_rotate (int pdf_object, float angle)
pdf_save
Zapisuje bieżące środowisko. Działa podobnie do polecenia postscript save. Funkcja jest użyteczna, gdy
chcesz przesunąć lub obrócić obiekt bez wpływania na inne obiekty. Funkcja pdf_save() powinna zawsze
posiadać swoją pdf_restore() odtwarzającą stan środowiska sprzed pdf_save(). Patrz również: pdf_restore().
void pdf_save (int pdf_object)
pdf_scale
Ustala współczynnik skalowania w obu kierunkach. Poniższy przykład powoduje przeskalowanie
współrzędnych x i y o 72. Kolejna linia będzie miała dzięki temu długość jednego cala w obu kierunkach.
void pdf_scale (int pdf_object, float x-scale, float y-scale)
Przykład: skalowanie
<?php
pdf_scale($pdf, 72.0, 72.0 );
pdf_lineto( $pdf, 1, 1 );
pdf_stroke( $pdf );
361
PHP – Kompendium wiedzy
?>
pdf_setdash
Ustawia wzór kreski na $white białych punktów i $black czarnych. Jeżeli obie wartości są 0, narysowana
zostanie ciągła linia.
void pdf_setdash (int pdf_object, float black, float white)
pdf_setflat
Ustawia parametr płaskości na wartość od 0 do 100.
void pdf_setflat (int pdf_object, float flatness)
pdf_setgray
Ustawia bieżący kolor rysowania i wypełnienia na podaną wartość szarego koloru Patrz również:
i pdf_setrgbcolor_fill().
pdf_setrgbcolor_stroke()
void pdf_setgray (int pdf_object, float gray)
pdf_setgray_fill
Ustawia bieżący kolor wypełnienia na podaną wartość szarości. Patrz również: pdf_setrgbcolor_stroke().
void pdf_setgray_fill (int pdf_object, float gray)
pdf_setgray_stroke
Ustawia bieżący kolor na podaną wartość szarości. Patrz również: pdf_setrgbcolor_stroke().
void pdf_setgray_stroke (int pdf_object, float gray)
pdf_setlinecap
Ustawia parametr linecap na wartość od 0 do 2.
void pdf_setlinecap (int pdf_object, int linecap)
pdf_setlinejoin
Ustawia parametr linejoin na wartość od 0 do 2.
void pdf_setlinejoin (int pdf_object, long linejoin)
pdf_setlinewidth
Ustawia szerokość linii na $width.
void pdf_setlinewidth (int pdf_object, float width)
pdf_setmiterlimit
Ustawia parametr miter limit na wartość większą lub równą 1.
void pdf_setmiterlimit (int pdf_object, float miter)
pdf_setrgbcolor
Ustawia bieżący kolor wypełnienia i rysowania na podaną wartość koloru RGB. Patrz również:
i pdf_setrgbcolor_fill().
pdf_setrgbcolor_stroke()
void pdf_setrgbcolor (int pdf_object, float red_value, float green_value,
float blue_value)
Dodatek A - Funkcje
362
pdf_setrgbcolor_fill
Ustawia wartość koloru RGB dla wypełnienia ścieżki. Patrz również: pdf_setrgbcolor().
void pdf_setrgbcolor_fill (int pdf_object, float red_value, float green_value,
float blue_value)
pdf_setrgbcolor_stroke
Ustawia bieżącą wartość koloru RGB do rysowania.
void pdf_setrgbcolor_stroke (int pdf_object, float red_value, float green_value,
float blue_value)
pdf_set_border_color
Ustawia kolor prostokąta otaczającego łącza i komentarze. Trzy składniki koloru muszą mieć wartości
pomiędzy 0.0 a 1.0. Patrz również: pdf_set_border_dash().
void pdf_set_border_color (int pdf_object, float red, float green, float blue)
pdf_set_border_dash
Ustawia długości czarnych i białych obszarów linii przerywanej otaczającej łącza i komentarze. Patrz
również: pdf_set_border_color().
void pdf_set_border_dash (int pdf_object, float black, float white)
pdf_set_border_style
Ustawia rodzaj i wielkość prostokąta otaczającego łącza i komentarze. Parametr
wartości solid lub dashed. Patrz również: pdf_set_border_color() i pdf_set_border_dash().
$style
może mieć
void pdf_set_border_style (int pdf_object, string style, float width)
pdf_set_char_spacing
Ustawia odstęp pomiędzy znakami. Patrz również: pdf_set_word_spacing() i pdf_set_leading().
void pdf_set_char_spacing( int pdf_object, float space )
pdf_set_duration
Ustawia czas przerwy, w sekundach, pomiędzy kolejnymi stronami. Patrz również: pdf_set_transition().
void pdf_set_duration ( int pdf_object, float duration )
pdf_set_font
Ustawia bieżący rodzaj czcionki, rozmiar czcionki i kodowanie. Jeżeli używasz pdflib 0.6, musisz
umieścić w katalogu czcionek (domyślnie ./fonts) plik Adobe Font Metrics (plik afm) dla użytej czcionki. Jeżeli
używasz PHP 3 lub pdflib w wersji późniejszej niż 2.20, parametr $encoding może przyjmować następujące
wartości: 0 — builtin, 1 — pdfdoc, 2 — macroman, 3 — macexpert lub 4 — winansi. Wartość parametru
$encoding większa od 4 lub mniejsza od 0 powoduje przyjęcie wartości winansi. Wartość ta jest zwykle dobrym
wyborem. Jeżeli używasz PHP4 i pdflib w wersji co najmniej 2.20, typ parametru $encoding został zmieniony na
ciąg. Należy użyć winansi, builtin, itd. Jeżeli ostatni parametr jest ustawiony na 1, czcionka jest wbudowywana
w dokument PDF, w przeciwnym wypadku nie jest. Wbudowywanie czcionek jest dobrym pomysłem, jeżeli jest
to rzadko wykorzystywana czcionka i nie ma pewności, że osoba oglądająca dokument będzie miała ją
zainstalowaną. Czcionka jest wbudowywana tylko raz, nawet, jeżeli funkcja pdf_set_font() będzie wywołana
kilka razy.
void pdf_set_font( int pdf_object, string font_name, float size, string encoding
[, int embed]))
363
PHP – Kompendium wiedzy
pdf_set_horiz_scaling
Ustawia skalowanie w pionie na $scale procent.
void pdf_set_horiz_scaling( int pdf_object, float scale )
pdf_set_info
Ustawia pole informacyjne dokumentu PDF. Możliwymi nazwami pól są: Subject, Title, Creator, Author,
Keywords i jedna nazwa zdefiniowana przez użytkownika. Funkcja może być wywołana przed rozpoczęciem
strony.
Uwaga
Funkcja zastępuje funkcje: pdf_set_info_keywords(), pdf_set_info_title(), pdf_set_info_subject(),
pdf_set_info_creator() i pdf_set_info_sybject().
void pdf_set_info (int pdf_object, string key, string value)
Przykład: Ustawianie informacji o dokumencie
<?php
$fd = fopen( "test.pdf", "w" );
$pdfdoc = pdf_open($fd);
pdf_set_info( $pdfdoc, "Author", "Jan Kowalski");
pdf_set_info( $pdfdoc, "Creator", "Jan Kowalski");
pdf_set_info( $pdfdoc, "Title", "Testowanie pól informacyjnych");
pdf_set_info( $pdfdoc, "Subject", "Test");
pdf_set_info( $pdfdoc, "Keywords", "Test, Pola");
pdf_set_info( $pdfdoc, "CustomField", "Cokolwiek sensownego");
pdf_begin_page($pdfdoc, 595, 842);
pdf_end_page( $pdfdoc );
pdf_close( $pdfdoc );
?>
pdf_set_leading
Ustawia odstęp pomiędzy wierszami tekstu. Jest on używany, gdy tekst jest wysyłany za pomocą funkcji
Patrz również: pdf_continue_text().
pdf_continue_text().
void pdf_set_leading( int pdf_object,float distance )
pdf_set_parameter
Ustawia parametry pdflib będące ciągami znaków. Patrz również:
pdf_get_value(), pdf_set_value()
i
pdf_get_parameter().
void pdf_set_parameter (int pdf_object, string key, string value)
pdf_set_text_matrix
Ustawia tablicę opisującą transformacje stosowane na bieżącej czcionce. Musi być przekazana tablica z
sześcioma elementami.
Uwaga
Funkcja nie jest dostępna w pdflib od wersji 2.3.
void pdf_set_text_matrix( int pdf_object, array matrix)
pdf_set_text_pos
Ustawia położenie tekstu dla następnego wywołania funkcji
pdf_show_xy().
pdf_show().
Patrz również:
pdf_show()
i
void pdf_set_text_pos (int pdf_object, float x, float y)
Dodatek A - Funkcje
364
pdf_set_text_rendering
Określa sposób rysowania tekstu. Możliwymi wartościami dla parametru $mode są: 0 — tekst wypełniony,
1 — tekst przerywany, 2 — tekst wypełniony i przerywany, 3 — niewidoczny, 4 — tekst wypełniony i dodany do
ścieżki obcinania, 5 — tekst przerywany i dodany do ścieżki obcinania, 6 — tekst przerywany i wypełniony oraz
dodany do ścieżki obcinania, 7 — dodanie do ścieżki obcinania.
void pdf_set_text_rendering( int pdf_object, int mode)
pdf_set_text_rise
Ustawia powiększenie tekstu na $rise punktów.
void pdf_set_text_rise(int pdf_object, float rise )
pdf_set_transition
Ustawia przejście pomiędzy kolejnymi stronami. Patrz również: pdf_set_duration().
void pdf_set_transition(int pdf_object, int transition)
•
•
•
•
•
•
•
•
Wartościami parametru $transition mogą być:
0 — brak
1 — dwa wiersze pokazujące się na ekranie odkrywają stronę
2 — kilka wierszy pokazujące się na ekranie odkrywają stronę
3 — prostokąt odkrywa stronę
4 — pojedynczy wiersz pokazujący się na ekranie odkrywa stronę
5 — stara strona rozmywa się aby pokazać nową stronę
6 — efekt rozmywania przesuwa się od jednej krawędzi strony do drugiej
7 — nowa strona po prostu zastępuje starą (domyślnie)
pdf_set_value
Ustawia numeryczne parametry pdflib. Patrz również:
pdf_set_parameter().
pdf_get_value(),
pdf_get_parameter()
i
void pdf_set_value (int pdf_object, string key, float value)
pdf_set_word_spacing
Ustawia odstępy pomiędzy słowami. Patrz również: pdf_set_char_spacing() i pdf_set_leading().
void pdf_set_word_spacing( int pdf_object, float space )
pdf_show
Rysuje tekst
$text
od bieżącej pozycji kursora za pomocą bieżącej czcionki. Patrz również:
i pdf_set_font().
pdf_show_xy(), pdf_show_boxed(), pdf_set_text_pos()
void pdf_show (int pdf_object, string text)
pdf_show_boxed
Rysuje tekst $text w prostokącie o lewym górnym rogu we współrzędnych ($left, $top). Rozmiar
prostokąta określają parametry $width i $height. Parametr $mode określa w jaki sposób ustawiany jest typ tekstu.
Jeżeli $width i $height mają wartości 0, $mode może być left, right lub center. Jeżeli $width lub $height są różne
od zera $mode może mieć wartości justify i fulljustify. Jeżeli parametr $feature ustawiony jest na blind, tekst nie
pokazuje się. Zwraca ilość znaków, które nie mogły być przetworzone, ponieważ nie mieściły się w prostokącie.
Patrz również: pdf_show() i pdf_show_xy().
int pdf_show_boxed (int pdf_object, string text, float left, float top,
float width, float height, string mode [, string feature])
365
PHP – Kompendium wiedzy
pdf_show_xy
Rysuje tekst $text na pozycji ($x, $y). Patrz również: pdf_show() i pdf_show_boxed().
void pdf_show_xy (int pdf_object, string text, float x, float y)
pdf_skew
Pochyla system współrzędnych o
wynosić 90 i 270 stopni.
$alpha
(x) i
$beta
(y) stopni. Parametry
$alpha
i
$beta
nie mogą
void pdf_skew (int pdf_object, float alpha, float beta)
pdf_stringwidth
Zwraca szerokość tekstu $text zapisanego bieżącą czcionką. Wymaga wcześniejszego ustawienia czcionki
za pomocą pdf_set_font(). Patrz również: pdf_set_font().
float pdf_stringwidth (int pdf_object, string text [, int font [, float size]])
Dodatek A - Funkcje
366
Dodatek B. Predefiniowane zmienne i
stałe PHP
Zmienne
Kompletną lista predefiniowanych zmiennych oraz inne użyteczne informacje można znaleźć w tabeli
będącej wynikiem działania funkcji phpinfo(). Poniższa lista nie jest wyczerpująca i nigdy taka nie miała być.
Można ją traktować jako przykład spodziewanych rodzajów zmiennych, z jakich można skorzystać w skryptach.
Zmienne Apache
Zmienne te są tworzone przez serwer Apache. Jeżeli korzystasz z innego serwera, nie gwarantuję że
dostępne będą te same funkcje. Może niektórych brakować, a będą dostępne inne, nie opisane tutaj. Wiele z tych
zmiennych jest definiowanych przez nową specyfikację CGI 1.1, więc można się spodziewać, że będą one
dostępne. Należy zauważyć, że niektóre z wymienionych zmiennych są dostępne jedynie w przypadku
uruchomienia PHP z linii poleceń.
GATEWAY_INTERFACE
Wersja specyfikacji CGI, z której korzysta serwer, na przykład CGI/1.1.
SERVER_NAME
Nazwa komputera z serwerem, na którym wykonywany jest skrypt. Jeżeli skrypt działa na serwerze
wirtualnym, będzie to nazwa zdefiniowana dla tego serwera wirtualnego.
SERVER_SOFTWARE
Ciąg identyfikujący serwer przekazywany w nagłówkach odpowiedzi na żądanie.
SERVER_PROTOCOL
Nazwa i wersja protokołu za pomocą którego wysłane zostało żądanie pobrania strony, na przykład
HTTP/1.0.
REQUEST_METHOD
Metoda żądania użyta do pobrania strony, na przykład GET, HEAD, POST lub PUT.
QUERY_STRING
Ciąg zapytania (o ile istnieje) przesłany wraz z bieżącą stroną.
DOCUMENT_ROOT
Zdefiniowany w konfiguracji serwera katalog główny dokumentów, w którym jest wykonywany bieżący
skrypt.
HTTP_ACCEPT
Zawartość nagłówka Accept: z bieżącego żądania, o ile istnieje.
HTTP_ACCEPT_CHARSET
Zawartość nagłówka Accept-Charset: z bieżącego żądania, o ile istnieje. Przykład: iso-8859-1,*,utf-8.
HTTP_ENCODING
Zawartość nagłówka Accept-Encoding: z bieżącego żądania, o ile istnieje. Przykład: gzip.
HTTP_ACCEPT_LANGUAGE
Zawartość nagłówka Accept-Language: z bieżącego żądania, o ile istnieje. Przykład: en.
HTTP_CONNECTION
Zawartość nagłówka Connection: z bieżącego żądania, o ile istnieje. Przykład: Keep-Alive.
HTTP_HOST
Zawartość nagłówka Host: z bieżącego żądania, o ile istnieje.
HTTP_REFERER
Adres strony, z której przeglądarka przeszła na bieżącą stronę. Jest to ustawiane przez przeglądarkę
użytkownika, ale nie wszystkie przeglądarki to robią.
HTTP_USER_AGENT
Zawartość nagłówka User_Agent: z bieżącego żądania, o ile istnieje. Jest to ciąg określający przeglądarkę
użytą do oglądania bieżącego dokumentu, na przykład: Mozilla/4.5[en] (X11;U;Linux 2.2.9 i586). Można użyć tej
wartości oraz funkcji get_browser() w celu przystosowania strony do możliwości przeglądarki użytej przez
użytkownika.
REMOTE_ADDR
Adres IP komputera używanego do oglądania bieżącej strony.
REMOTE_PORT
Port na komputerze klienta użyty do komunikacji z serwerem WWW.
SCRIPT_FILENAME
Bezwzględna ścieżka do wykonywanego skryptu.
SERVER_ADMIN
Zawartość dyrektywy konfiguracji Apache SERVER_ADMIN z pliku konfiguracyjnego. Jeżeli skrypt jest
uruchomiony poprzez serwer wirtualny, jest to wartość zdefiniowana dla tego serwera wirtualnego.
SERVER_PORT
Port na serwerze używany do komunikacji przez serwer WWW. Domyślnie jest to 80, jeżeli wykorzystane
jest SSL jest to port zdefiniowany do użycia przez bezpieczny HTTP.
SERVER_SIGNATURE
Ciąg zawierający wersję serwera i nazwę serwera wirtualnego, który jest dodawany do stron
wygenerowanych przez serwer, o ile opcja ta jest aktywna.
Dodatek B. Predefiniowane zmienne i stałe PHP
368
PATH_TRANSLATED
Ścieżka w systemie plików (a nie względem głównego katalogu dokumentów) do bieżącego skryptu, po
dokonaniu przekształceń ze ścieżek wirtualnych na rzeczywiste.
SCRIPT_NAME
Zawiera ścieżkę do bieżącego skryptu. Jest to użyteczna zmienna dla skryptów wskazujących na samych
siebie.
REQUEST_URI
Adres URI użyty do dostępu do bieżącej strony, na przykład, /index.html.
Zmienne środowiska
Zmienne te są importowane do przestrzeni nazw globalnych ze środowiska, w którym jest uruchamiany
analizator PHP. Wiele z nich zależy od rodzaju powłoki, a ponieważ PHP działa na wielu systemach i różnych
rodzajach powłok, zdefiniowanie kompletnej listy jest niemożliwe. Należy odszukać taką listę w dokumentacji
swojego systemu. Zmienne środowiska zawierają zmienne CGI, które zamieszczane są niezależnie od tego, czy
PHP działa jako moduł serwera, czy jako program CGI.
Zmienne PHP
Zmienne te są tworzone przez PHP. Zmienne $HTTP_*_VARS są dostępne jedynie wtedy, gdy włączona jest
opcja konfiguracji track_vars. Od PHP 4.0.3 track_vars jest zawsze włączone, niezależnie od ustawienia w pliku
konfiguracyjnym.
Jeżeli ustawiona jest dyrektywa register_globals, zmienne te będą dostępne w globalnej przestrzeni
zmiennych, oprócz wartości w tablicach $HTTP_*_VARS. Funkcja ta powinna być używana rozważnie i wyłączana o
ile jest to możliwe. Tablice $HTTP_*_VARS są bezpieczne, a ich globalne odpowiedniki są często nadpisywane
przez wartości wprowadzone przez użytkownika, co często powoduje trudne do znalezienia błędy. Jeżeli nie
możesz wyłączyć opcji register_globals, musisz się upewnić, że używane dane są bezpieczne.
argv
Tablica argumentów przekazanych do skryptu. Gdy skrypt jest uruchomiony z linii komend, pozwala to na
dostęp do argumentów tak samo jak w języku C. Jeżeli skrypt jest uruchamiany za pomocą metody GET, zmienna
zawiera ciąg zapytania.
argc
Zawiera ilość parametrów przekazanych do skryptu (jeżeli jest on uruchomiony z linii poleceń).
PHP_SELF
Nazwa pliku z wykonywanym skryptem, zapisana względem głównego katalogu dokumentów. Jeżeli PHP
jest uruchomiony z linii poleceń, zmienna ta nie jest dostępna.
HTTP_COOKIE_VARS
Tablica asocjacyjna ze zmiennymi przekazanymi do bieżącego skryptu poprzez cookie HTTP.
HTTP_GET_VARS
Tablica asocjacyjna ze zmiennymi przekazanymi do bieżącego skryptu za pomocą metody GET.
HTTP_POST_VARS
Tablica asocjacyjna ze zmiennymi przekazanymi do bieżącego skryptu za pomocą metody POST.
369
PHP – Kompendium wiedzy
HTTP_POST_FILES
Tablica asocjacyjna z informacjami na temat plików przesłanych za pomocą metody POST. Zmienna
jest dostępna w PHP od wersji 4.0.0.
$HTTP_POST_FILES
HTTP_ENV_VARS
Tablica asocjacyjna ze zmiennymi przekazanymi do bieżącego skryptu poprzez środowisko.
HTTP_SERVER_VARS
Tablica asocjacyjna ze zmiennymi przekazanymi do bieżącego skryptu z serwera HTTP. Zmienne te są
analogiczne do opisanych wcześniej zmiennych Apache.
Stałe
__FILE__
Nazwa analizowanego właśnie skryptu. Jeżeli została w dołączanym pliku, zwracana jest nazwa tego pliku
a nie pliku głównego.
__LINE__
Numer wiersza w bieżącym skrypcie. Jeżeli została w dołączanym pliku, zwracany jest numer wiersza w
tym pliku.
PHP_VERSION
Ciąg zawierający wersję używanego analizatora PHP, na przykład, 3.0.8-dev.
PHP_OS
Nazwa systemu operacyjnego, na którym działa analizator PHP, na przykład Linux.
TRUE
Wartość logiczna „prawda”.
FALSE
Wartość logiczna „fałsz”.
E_ERROR
Oznacza błąd inny niż błąd składni, gdzie nie jest możliwe kontynuowanie wykonania.
E_WARNING
Oznacza sytuację, gdy PHP wykrywa błąd, ale mimo to kontynuuje wykonywanie skryptu. Może być on
przechwycony przez skrypt. Przykładem może być nieprawidłowy wzorzec w funkcji ereg().
E_PARSE
Analizator napotkał błąd składni. Praca jest przerywana.
E_NOTICE
Sytuacja nieprawidłowa, która może, ale nie musi być błędna. Skrypt jest dalej wykonywany. Przykładem
może być użycie ciągu bez apostrofów jako indeks w tablicy asocjacyjnej lub skorzystanie z niezainicjowanej
zmiennej.
Dodatek B. Predefiniowane zmienne i stałe PHP
370
E_ALL
Wszystkie stałe E_*. Jeżeli zostanie użyta w funkcji
wszystkich problemów napotkanych przez PHP.
371
error_reporting(),
powoduje raportowanie
PHP – Kompendium wiedzy
Dodatek C. Opcje kompilacji PHP
Bazy danych
--with-adabas[=DIR]
Dołącz obsługę Adabas D. DIR jest katalogiem gdzie została zainstalowana baza Adabas, domyślnie
/usr/local.
--enable-dba=shared
Buduj DBA jako obiekt współdzielony.
--enable-dbase
Dołącz wbudowaną bibliotekę dbase. Nie potrzebne są zewnętrzne biblioteki.
--with-db2[=DIR]
Dołącz obsługę Berkeley DB2.
--with-db3[=DIR]
Dołącz obsługę Berkeley DB3.
--with-dbm[=DIR]
Dołącz obsługę DBM.
--with-dbmaker[=DIR]
Dołącz obsługę DBMaker. DIR to katalog instalacji programu DBMaker domyślnie tam, gdzie została
zainstalowana najnowsza wersja DBMaker (np. /home/dbmaker/3.6).
--with-empress[=DIR]
Dołącz obsługę Empress. DIR to katalog instalacji Empress, domyślnie $EMPRESSPATH.
--enable-filepro
Dołącz wbudowaną obsługę filePro (tylko do odczytu). Nie potrzebne są zewnętrzne biblioteki.
--with-gdbm[=DIR]
Dołącz obsługę GDBM
--with-hyperwave
Dołącz obsługę Hyperwave
--with-ibm-db2[=DIR]
Dołącz obsługę IBM DB2. DIR to katalog instalacji DB2, domyślnie /home/db2inst1/sqllib.
--with-informix[=DIR]
Dołącz obsługę Informix. DIR to katalog gdzie został zainstalowany Informix. Brak wartości domyślnej.
--with-ingres[=DIR]
Dołącz obsługę Ingres II. DIR to katalog instalacji programu Ingres, domyślnie /II/ingres.
--with-interbase[=DIR]
Dołącz obsługę InterBase. DIR to katalog instalacji programu InterBase, domyślnie /usr/interbase.
--with-ldap[=DIR]
Dołącz obsługę LDAP. DIR to katalog instalacji LDAP. Parametr ten dołącza obsługę protokołu LDAP
(Lightweight Directory Access Protocol). DIR to katalog instalacji LDAP, domyślnie /usr/local/ldap.
--with-msql[=DIR]
Dołącz obsługę mSQL. Parametrem tej opcji jest katalog instalacji mSQL, domyślnie /usr/local/Hughes.
Jest to domyślne miejsce instalacji dystrybucji mSQL 2.0. Skrypt configure automatycznie wykrywa która wersja
mSQL jest zainstalowana — PHP obsługuje obie wersje, 1.0 i 2.0, ale jeśli skompilujesz PHP z mSQL 1.0,
możesz korzystać tylko z baz danych mSQL 1.0 i odwrotnie. Patrz także: Dyrektywy konfiguracji mSQL w
dodatku D.
--with-mysql[=DIR]
Dołącz obsługę MySQL. DIR to katalog instalacji MySQL. Jeśli nie zostanie podany, użyte zostaną
wbudowane biblioteki MySQL. Ta opcja jest domyślnie włączona. Patrz także: Dyrektywy konfiguracji MySQL
w dodatku D.
--with-ndbm[=DIR]
Dołącz obsługę NDBM.
--with-oci8[=DIR]
Dołącz obsługę Oracle-oci8. Domyślnie DIR to $ORACLE_HOME.
--with-oracle[=DIR]
Dołącz obsługę bazy danych Oracle-oci7. Domyślnie DIR to $ORACLE_HOME. Zostało ono przetestowane i
powinno działać przynajmniej z wersjami Oracle 7.0 do 7.3. Parametrem jest katalog ORACLE_HOME. Nie
musisz podawać tego parametru, jeśli skonfigurowane zostało środowisko Oracle.
--with-pgsql[=DIR]
Dołącz obsługę PostgreSQL. DIR to katalog instalacji PostgreSQL, domyślnie /usr/local/pgsql. Ustaw
DIR na shared aby zbudować jako obiekt dołączany dynamicznie (dl), lub shared,DIR aby zbudować jako dl i
jednocześnie podać DIR.
--with-solid[=DIR]
Dołącz obsługę Solid. DIR to katalog instalacji Solid, domyślnie /usr/local/solid.
--with-sybase-ct[=DIR]
Dołącz obsługę Sybase-CT. DIR to katalog domowy Sybase, domyślnie /home/sybase.
--with-sybase[=DIR]
Dołącz obsługę Sybase-DB. DIR to katalog domowy Sybase, domyślnie /home/sybase.
373
PHP – Kompendium wiedzy
--with-openlink[=DIR]
Dołącz obsługę OpenLink ODBC. DIR to katalog instalacji OpenLink, domyślnie /usr/local/openlink.
--with-iodbc[=DIR]
Dołącz obsługę iODBC. DIR jest to katalog instalacji iODBC, domyślnie /usr/local. Ta opcja została
stworzona dla iODBC Driver Manager, darmowo rozpowszechnianego menedżera sterowników ODBC, który
działa na różnych odmianach Uniksa.
--with-custom-odbc[=DIR]
Dołącza obsługę niestandardowej biblioteki ODBC. Parametrem jest główny katalog biblioteki, domyślnie
/usr/local. Ta opcja jest używana tylko, gdy zdefiniowałeś CUSTOM_ODBC_LIBS przy uruchomieniu skryptu
configure. Niezbędne jest także wstawienie prawidłowego pliku odbc.h na ścieżkę include. Jeśli nie posiadasz
takiego pliku, stwórz go i dołącz stamtąd swój własny nagłówek. Nagłówek taki może wymagać pewnych
definicji zwłaszcza, jeśli jest to biblioteka wieloplatformowa. Zdefiniuj je w CFLAGS. Możesz na przykład używać
Sybase SQL Anywhere na QNX w następujący sposób:
CFLAGS=-DODBC_QNX LDFLAGS=-lunix CUSTOM_ODBC_LIBS="-ldblib -lodbc" ./configure --with-customodbc=/usr/lib/sqlany50
--with-unixODBC[=DIR]
Dołącz obsługę unixODBC. DIR to katalog instalacji unixODBC, domyślnie /usr/local.
--with-velocis[=DIR]
Dołącz obsługę Velocis. DIR to katalog instalacji Velocis, domyślnie /usr/local/velocis.
Handel elektroniczny
--with-ccvs[=DIR]
Dołącza do PHP4 obsługę CCVS. DIR to katalog instalacji CCVS.
--with-cybercash[=DIR]
Dołącza obsługę CyberCash. DIR to katalog instalacji CyberCash MCK.
--with-pfpro[=DIR]
Dołącz obsługę Verisign Payflow Pro.
Grafika
--enable-freetype-4bit-antialias-hack
Dołącz obsługę FreeType2 (eksperymentalne).
--with-gd[=DIR]
Dołącz obsługę GD (DIR to katalog instalacji GD). Ustaw DIR jako shared aby zbudować rozszerzenie
jako moduł współdzielony, lub shared,DIR aby zbudować rozszerzenie jako moduł i jednocześnie podać DIR.
--without-gd
Wyłącz obsługę GD.
Dodatek C. Opcje kompilacji PHP
374
--with-jpeg-dir[=DIR]
Katalog jpeg dla pdflib 3.x.
--with-png-dir[=DIR]
Katalog png dla pdflib 3.x.
--with-t1lib[=DIR]
Dołącz obsługę T1lib.
--with-tiff-dir[=DIR]
Katalog tiff dla pdflib 3.x.
--with-ttf[=DIR]
Dołącz obsługę FreeType.
--with-xpm-dir[=DIR]
Katalog xpm dla gd-1.8+.
Różne
--disable-libtool-lock
Unikaj blokowania (może to przerwać równoległe budowanie).
--disable-pear
Nie instaluj PEAR.
--disable-pic
Wyłącz PIC dla obiektów współdzielonych.
--disable-posix
Wyłącz funkcje POSIX.
--disable-rpath
Wyłącz przekazywanie dodatkowych ścieżek poszukiwania bibliotek.
--disable-session
Wyłącz obsługę sesji.
--enable-bcmath
Kompiluj z funkcjami matematycznymi o dowolnej dokładności. Przeczytaj plik README-BCMATH aby
uzyskać informacje na temat sposobu instalacji tego modułu. Funkcje te pozwalają operować na liczbach
wykraczających poza zakresy dozwolone przez zwykłe liczby stało i zmiennoprzecinkowe.
--enable-c9x-inline
Włącz semantykę C9x-inline.
375
PHP – Kompendium wiedzy
--enable-calendar
Włącz obsługę konwersji kalendarza.
--enable-debug
Kompiluj z symbolami dla debuggera.
--enable-discard-path
Jeśli ta opcja zostanie włączona, pliki programu CGI PHP mogą być bezpiecznie umieszczone poza
drzewem serwera WWW i użytkownicy nie będą mogli obchodzić zabezpieczeń .htaccess.
--enable-dmalloc
Włącz dmalloc.
--enable-exif
Włącz obsługę exif.
--enable-experimental-zts
Ta opcja najprawdopodobniej przerwie proces kompilacji.
--enable-fast-install[=PKGS]
Optymalizacja dla szybkiej instalacji (domyślnie yes).
--enable-force-cgi-redirect
Włącz sprawdzanie bezpieczeństwa dla wewnętrznych przekierowań serwera. Powinieneś użyć tej opcji,
jeśli używasz wersji CGI z serwerem Apache.
--enable-inline-optimization
Jeśli masz dużo pamięci i używasz gcc możesz spróbować włączyć tą opcję.
--enable-libgcc
Włącz jawne łączenie z libgcc.
--enable-maintainer-mode
Włącz reguły i zależności programu make nie przydatne (i czasem niejasne) dla zwykłego użytkownika.
--enable-memory-limit
Kompiluj z obsługą limitowania pamięci.
--enable-safe-mode
Włącz pracę w trybie bezpiecznym.
--enable-satellite
Włącz obsługę CORBA przez Satellite (wymaga ORBit).
--enable-shared[=PKGS]
Buduj biblioteki współdzielone (domyślnie yes).
Dodatek C. Opcje kompilacji PHP
376
--enable-sigchild
Włącz obsługę SIGCHLD przez PHP.
--enable-static[=PKGS]
Buduj statyczne biblioteki (domyślnie yes).
--enable-sysvsem
Włącz obsługę semaforów dla System V.
--enable-sysvshm
Włącz obsługę pamięci współdzielonej dla System V.
--enable-trans-sid
Włącz przezroczyste propagowanie identyfikatora sesji.
--with-cdb[=DIR]
Dołącz obsługę CDB.
--with-config-file-path=PATH
Ustawia ścieżkę gdzie powinien się znajdować plik php.ini. Domyślnie /usr/local/lib.
--with-cpdflib[=DIR]
Dołącz obsługę cpdflib (wymaga cpdflib >= 2). DIR to katalog instalacji cpdflib, domyślnie /usr.
--with-esoob[=DIR]
Dołącz obsługę Easysoft OOB. DIR to katalog instalacji OOB, domyślnie /usr/local/easysoft/oob/client.
--with-exec-dir[=DIR]
W trybie bezpiecznym pozwól na uruchamianie plików wykonywalnych tylko w DIR, domyślnie
/usr/local/php/bin.
--with-fdftk[=DIR]
Dołącz obsługę fdftk. DIR to katalog instalacji fdftk, domyślnie /usr/local.
--with-gnu-ld
Załóż, że kompilator C używa GNU ld [domyślnie no]
--with-icap[=DIR]
Dołącz obsługę ICAP.
--with-imap[=DIR]
Dołącz obsługę protokołu IMAP. DIR jest to katalog gdzie znajdują się pliki nagłówkowe IMAP i plik cclient.
--with-java[=DIR]
Dołącz obsługę języka Java. DIR to katalog gdzie zainstalowane jest JDK. To rozszerzenie może być
zbudowane tylko jako obiekt dynamicznie dołączany (dl).
377
PHP – Kompendium wiedzy
--with-kerberos[=DIR]
Dołącz obsługę Kerberos w protokole IMAP.
--with-mcal[=DIR]
Dołącz obsługę MCAL.
--with-mcrypt[=DIR]
Dołącz obsługę mcrypt. DIR to katalog instalacji mcrypt.
--with-mhash[=DIR]
Dołącz obsługę mhash. DIR to katalog gdzie zainstalowano mhash.
--with-mm[=DIR]
Dołącz obsługę mm do przechowywania sesji.
--with-mod_charset
Włącz transfer tablic dla mod_charset (Rosyjski Apache).
--with-pdflib[=DIR]
Dołącz obsługę pdflib 3.x/4.x. DIR to katalog instalacji pdflib, domyślnie /usr/local.
--with-readline[=DIR]
Dołącz obsługę readline. DIR to katalog instalacji readline.
--with-regex=TYPE
Typ biblioteki regex: system, apache, php.
--with-servlet[=DIR]
Dołącz obsługę serwletów. DIR to katalog instalacji JSDK. To SAPI wymaga, aby rozszerzenie Java było
zbudowane jako obiekt dołączany dynamicznie.
--with-swf[=DIR]
Dołącz obsługę swf.
--with-tsrm-pth[=pth-config]
Użyj GNU Pth.
--with-tsrm-pthreads
Użyj wątków POSIX (domyślnie).
--with-zlib-dir[=DIR]
Katalog zlib dla pdflib 3.x lub dołącz obsługę zlib.
--with-zlib[=DIR]
Dołącz obsługę zlib (wymaga zlib >= 1.0.9). DIR to katalog instalacji zlib, domyślnie /usr.
Dodatek C. Opcje kompilacji PHP
378
--without-pcre-regex
Nie dołączaj obsługi Perl Compatible Regular Expressions. Jeśli nie chcesz używać wbudowanej
biblioteki użyj opcji --with-pcre-regex=DIR, aby podać lokalizację plików nagłówkowych i bibliotek.
Sieć
--with-curl[=DIR]
Dołącz obsługę CURL.
--enable-ftp
Włącz obsługę FTP.
--disable-url-fopen-wrapper
Wyłącz wrapper adresów URL dla polecenia fopen(), który pozwala na dostęp do plików przez protokoły
HTTP lub FTP.
--with-mod-dav=DIR
Dołącz obsługę DAV poprzez moduł Apache mod_dav. DIR to katalog instalacji mod_dav (tylko jako moduł
Apache).
--with-openssl[=DIR]
Dołącz obsługę OpenSSL w SNMP.
--with-snmp[=DIR]
Dołącz obsługę SNMP. DIR to katalog instalacji SNMP, domyślnie przeszukuje wiele częstych lokalizacji
instalacji snmp. Ustaw DIR na shared aby zbudować jako obiekt dynamicznie dołączany (dl), lub shared,DIR aby
zbudować jako dl i jednocześnie podać DIR.
--enable-ucd-snmp-hack
Włącz poprawkę UCD SNMP.
--enable-sockets
Włącz obsługę gniazd.
--with-yaz[=DIR]
Dołącz obsługę YAZ (ANSI/NISO Z39.50). DIR to katalog instalacji YAZ.
--enable-yp
Dołącz obsługę YP.
Działanie PHP
--enable-magic-quotes
Włącz domyślne „magic quotes”.
379
PHP – Kompendium wiedzy
--disable-short-tags
Wyłącz możliwość używania krótkiej formy znaczników otwierających <?.
Serwer
--with-aolserver-src=DIR
Określ ścieżkę do źródłowej dystrybucji AOLserver.
--with-aolserver=DIR
Określ ścieżkę do zainstalowanego AOLserver.
--with-apache[=DIR]
Zbuduj moduł Apache. DIR to katalog bazowy Apache, domyślnie /usr/local/etc/httpd.
--with-apxs[=FILE]
Zbuduj moduł współdzielony Apache. FILE to opcjonalna ścieżka do narzędzia apxs z pakietu Apache,
domyślnie apxs.
--enable-versioning
Eksportuj tylko wymagane symbole. Przejrzyj plik INSTALL, aby uzyskać więcej informacji.
--with-fhttpd[=DIR]
Buduj moduł fhttpd. DIR to katalog ze źródłami fhttpd, domyślnie /usr/local/src/fhttpd.
--with-nsapi=DIR
Określ ścieżkę do zainstalowanego Netscape.
--with-pi3web=DIR
Buduj PHP jako moduł dla Pi3Web.
--with-roxen=DIR
Buduj PHP jako moduł Pike. DIR to katalog instalacji Roxen, zazwyczaj /usr/local/roxen/server.
--enable-roxen-zts
Buduj moduł Roxen używając Zend Thread Safety ( bezpieczne wątki Zend).
--with-zeus=DIR
Buduj PHP jako moduł ISAPI do użycia z Zeus.
Tekst i język
--with-aspell[=DIR]
Dołącz obsługę ASPELL.
Dodatek C. Opcje kompilacji PHP
380
--with-gettext[=DIR]
Dołącz obsługę GNU gettext. DIR to katalog instalacji gettext, domyślnie /usr/local.
--with-pspell[=DIR]
Dołącz obsługę PSPELL.
--with-recode[=DIR]
Dołącz obsługę redcode. DIR to katalog instalacji redcode.
XML
--with-dom[=DIR]
Dołącz obsługę DOM (wymaga libxml >= 2.0). DIR to katalog instalacji libxml, domyślnie /usr.
--enable-sablot-errors-descriptive
Włącz błędy opisowe.
--with-sablot[=DIR]
Dołącz obsługę Sablotron.
--enable-wddx
Włącz obsługę WDDX.
--disable-xml
Wyłącz obsługę wbudowanej biblioteki XML expat.
381
PHP – Kompendium wiedzy
Dodatek D. Opcje konfiguracji PHP
Ogólne dyrektywy konfiguracji
allow_url_fopen boolean
Ta opcja włącza interfejsy do funkcji fopen rozpoznające adresy URL, pozwalające na dostęp do obiektów
URL jak do plików. Domyślne interfejsy pozwalają na dostęp do zdalnych plików korzystając z protokołów ftp
lub http. Niektóre rozszerzenia, takie jak zlib, mogą rejestrować dodatkowe interfejsy. Dyrektywa ta została
wprowadzona zaraz po wyjściu wersji 4.0.3. Dla wersji 4.0.3 i wyższych możesz wyłączyć tą opcję w czasie
kompilacji używając przełącznika --disable-url-fopen-wrapper.
asp_tags boolean
Włącza możliwość użycia znaczników ASP (<% %>) razem z normalnymi znacznikami (<?php ?>).
Dotyczy to także skrótowego wyświetlania wartości zmiennych typu <%= $value %>. Obsługa znaczników ASP
została dodana w wersji 3.0.4.
auto_append_file string
Określa nazwę pliku, który jest automatycznie przetwarzany po głównym pliku. Plik jest dołączany tak,
jakby został dołączony funkcją include(), a więc używana jest opcja include_path. Specjalna wartość none
wyłącza automatyczne dołączanie. Jeśli skrypt zostanie zakończony przez exit(), nie dojdzie do dołączenia.
auto_prepend_file string
Określa nazwę pliku, który będzie automatycznie przetwarzany przed głównym plikiem. Plik jest
dołączany tak, jakby wywołana była funkcja include(), a więc używana jest opcja include_path. Specjalna
wartość none wyłącza automatyczne poprzedzanie pliku.
cgi_ext string
display_errors boolean
Określa, czy błędy powinny być wyświetlane jako część wynikowego kodu HTML czy nie.
doc_root string
Główny katalog PHP na serwerze. Używane tylko, jeśli jest to ciąg niepusty. Jeśli PHP jest
skonfigurowane do pracy w trybie bezpiecznym, pliki spoza tego katalogu nie będą udostępniane.
engine boolean
Ta dyrektywa jest przydatna tylko przy pracy z PHP w postaci modułu Apache. Jest ona używana na
witrynach, w których chce się włączać i wyłączać analizowanie plików PHP na podstawie katalogu lub na
podstawie nazwy serwera wirtualnego. Umieszczając engine off we właściwych miejscach pliku httpd.conf PHP
może być aktywne lub nieaktywne.
error_log string
Nazwa pliku, gdzie mają być zapisywane błędy. Jeśli użyta jest specjalna wartość syslog, błędy wysyłane
są do dziennika systemowego. W systemach Unix oznacza to syslog(3) a na Windows NT, dziennik zdarzeń.
Dziennik systemowy nie jest obsługiwany przez Windows 95.
error_reporting integer
Ustaw poziom raportowania. Więcej szczegółów znajduje się przy opisie funkcji error_reporting().
open_basedir string
Ogranicz pliki, które mogą być otwierane przez PHP do podanego drzewa katalogów. Jeśli skrypt próbuje
otworzyć plik, np. przez funkcje fopen() lub gzopen(), sprawdzane jest położenie pliku. Jeżeli plik znajduje się
poza podanym drzewem katalogów, PHP odmawia otwarcia takiego pliku. Wszystkie dowiązania symboliczne są
rozwiązywane, więc nie jest możliwe ominięcie tego ograniczenia przez łącza symboliczne. Wartość specjalna
„.” wskazuje, że katalog w którym znajduje się skrypt będzie uznawany jako katalog bazowy dla tej dyrektywy.
W systemie Windows, katalogi oddzielaj średnikami. Na wszystkich innych systemach, oddzielaj katalogi
dwukropkami. Jeżeli PHP pracuje jako moduł Apache, ścieżki open_basedir katalogów nadrzędnych są
automatycznie dziedziczone. Obsługa dla wielu katalogów została dodana w 3.0.7. Domyślnie PHP pozwala na
otwieranie wszystkich plików.
gpc_order string
Ustaw kolejność analizowania zmiennych GET, POST i COOKIE. Domyślne ustawienie do GPC. Ustawienie tej
dyrektywy np. na GP spowoduje, że PHP będzie całkowicie ignorował cookie i przebijał wszystkie zmienne
otrzymane metodą GET zmiennymi o tej samej nazwie otrzymanymi metodą POST.
ignore_user_abort string
Domyślnie włączona. Jeśli zostanie zmieniona na Off, skrypty będą przerywane, jak tylko będą próbowały
wysłać coś do klienta, który przerwał połączenie. Patrz również: ignore_user_abort().
include_path string
Określa listę katalogów, gdzie funkcje require(), include() i fopen_with_path() będą szukały plików.
Format jest podobny do zmiennej środowiskowej PATH: lista katalogów oddzielona dwukropkiem na systemach
Unix lub średnikiem na systemach Windows. Domyślną wartością tej dyrektywy jest „.” (tylko bieżący katalog).
isapi_ext string
log_errors boolean
Ustawia czy komunikaty o błędach skryptu mają być zapisywane do dziennika błędów serwera. W
związku z tym ta opcja jest specyficzna dla poszczególnych serwerów.
magic_quotes_gpc boolean
Ustawia stan magic_quotes dla operacji GPC (GET, POST, COOKIE). Jeśli magic_quotes są włączone,
wszystkie znaki ' (apostrof), " (cudzysłów), \ (lewy ukośnik) i znaki NULL są zamieniane na sekwencje sterujące
przez dodanie przed te znaki znaku \. Jeśli włączona jest także dyrektywa magic_quotes_sybase, wszystkie
apostrofy są zamieniane na sekwencje sterujące przez dodanie apostrofu zamiast znaku \.
magic_quotes_runtime boolean
Jeśli włączona jest dyrektywa magic_quotes_runtime, większość funkcji, które zwracają dane z dowolnych
zewnętrznych źródeł, włączając w to bazy danych i pliki tekstowe, będzie zwracała dane z apostrofami i
cudzysłowami zamienionymi na sekwencje sterujące przy pomocy znaku \. Jeśli włączona jest także opcja
magic_quotes_sybase, apostrof będą zamieniany na sekwencję strującą przy pomocy apostrofu zamiast znaku \.
383
PHP – Kompendium wiedzy
magic_quotes_sybase boolean
Jeśli włączona jest opcja magic_quotes_sybase, apostrof będzie zamieniany na sekwencję sterującą
używając apostrofu zamiast znaku \, jeśli włączona jest opcja magic_quotes_gpc i (lub) magic_quotes_runtime.
max_execution_time integer
Dyrektywa to określa maksymalny czas w sekundach wykonywania skryptu, zanim zostanie przerwany
przez analizator. Pomaga to w zapobieganiu blokowania serwera przez źle napisane skrypty. Domyślne
ustawienie to 30.
memory_limit integer
Dyrektywa ta ustawia maksymalną wielkość pamięci w bajtach, którą skrypt może sobie przydzielić.
Pomaga to w zapobieganiu przydzieleniu całej dostępnej pamięci serwera przez źle napisane skrypty.
nsapi_ext string
register_globals boolean
Ustala, czy rejestrować zmienne środowiska, GET, POST, Cookie, i serwera jako zmienne globalne. Możesz
wyłączyć tę opcję, jeśli nie chcesz zaśmiecić globalnej przestrzeni zmiennych swoich skryptów przez dane
użytkownika. Ma to największy sens, jeśli używane jest w połączeniu z opcją track_vars — w takim przypadku
do zmiennych EGCPS możliwy jest przez zmienne globalne $HTTP_ENV_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS,
$HTTP_COOKIE_VARS, i $HTTP_SERVER_VARS.
short_open_tag boolean
Ustala, czy dozwolona jest skrócona forma znacznika otwierającego PHP (<? ?>). Jeśli chcesz używać
PHP w połączeniu z XML, powinieneś wyłączyć tą opcję. Jeśli ta opcja jest wyłączona, musisz używać długiej
postaci znacznika otwierającego. (<?php ?>).
sql.safe_mode boolean
track_errors boolean
Jeśli dyrektywa ta jest włączona, ostatni komunikat błędu będzie dostępna jako zmienna globalna
$php_errormsg.
track_vars boolean
Jeśli ta dyrektywa jest włączona, zmienne środowiska, GET, POST, Cookie i serwera będą dostępne w
globalnych tablicach asocjacyjnych $HTTP_ENV_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS i
$HTTP_SERVER_VARS. Zauważ, że od PHP 4.0.3 dyrektywa track_vars jest zawsze włączona.
upload_tmp_dir string
Katalog tymczasowy używany do przechowywania plików podczas obsługiwania przesyłania plików.
Musi być to katalog z prawem zapisu dla użytkownika, jako który pracuje PHP.
user_dir string
Podstawowa nazwa katalogu używanego jako katalog domowy użytkownika dla plików PHP, na przykład
public_html.
warn_plus_overloading boolean
Jeśli dyrektywa ta jest włączona, PHP będzie wyświetlał ostrzeżenie, jeśli operator plus (+) został użyty na
ciągach. Dzięki temu łatwiej jest znaleźć skrypty, które wymagają użycia operatora sklejania ciągów (.).
Dodatek D. Opcje konfiguracji PHP
384
Dyrektywy konfiguracji poczty
SMTP string
Nazwa DND lub adres IP serwera SMTP, którego powinien użyć PHP dla Windows podczas wysyłania
poczty za pomocą funkcji mail().
sendmail_from string
Pole From: (adres nadawcy) przesyłek pocztowych wysyłanych z PHP dla Windows.
sendmail_path string
Katalog w którym znajduje się sendmail, zwykle /usr/sbin/sendmail lub /usr/lib/sendmail. Skrypt
configure próbuje samodzielnie odszukać ten program i ustawić wartość domyślną, ale jeżeli nie uda się to,
można ją samodzielnie ustawić. Systemy nie korzystające z sendmail powinny ustawić tą opcję dla jego
odpowiednika w zainstalowanym systemie poczty. Na przykład: użytkownicy Qmail zwykle ustawiają ją na
/var/qmail/bin/sendmail.
Dyrektywy konfiguracji trybu bezpiecznego
safe_mode boolean
Określa, czy PHP ma pracować w trybie bezpiecznym.
safe_mode_exec_dir string
Jeśli PHP pracuje w trybie bezpiecznym, funkcje
wykonania programów z katalogów innych niż podany.
system()
i inne wywołujące inne programy, odmówią
Dyrektywy konfiguracji debuggera
debugger.host string
Nazwa lub adres IP komputera używanego przez debugger.
debugger.port string
Numer portu używany przez debugger.
debugger.enabled boolean
Określa, czy debugger jest włączony.
Dyrektywy ładowania rozszerzeń
enable_dl boolean
Ta dyrektywa jest jedynie przydatna przy pracy PHP jako moduł Apache. Możesz włączać i wyłączać
możliwość dynamicznego ładowania rozszerzeń PHP przez funkcję dl() zależnie od katalogu lub serwera
wirtualnego. Głównym powodem wyłączania dynamicznego ładowania rozszerzeń jest kwestia bezpieczeństwa.
Używając dynamicznych rozszerzeń możliwe jest ominięcie praktycznie wszystkich ograniczeń safe_mode i
open_basedir. Domyślnie zezwalane jest dynamiczne ładowanie, z wyjątkiem pracy w trybie bezpiecznym. W
trybie bezpiecznym korzystanie z funkcji dl() jest zawsze zabronione.
PHP – Kompendium wiedzy
385
extension_dir string
Katalog, w którym PHP szuka dynamicznie dołączanych rozszerzeń.
extension string
Które dynamicznie ładowane rozszerzenia ładować przy starcie PHP.
Dyrektywy konfiguracji MySQL
mysql.allow_persistent boolean
Czy pozwalać na trwałe połączenia MySQL (persistent connections).
mysql.default_host string
Domyślny adres serwera, który będzie używany przy łączeniu się z serwerem baz danych, jeśli nie
zostanie podany żaden inny adres.
mysql.default_user string
Domyślna nazwa użytkownika, która będzie używana przy łączeniu się z serwerem baz danych, jeśli nie
zostanie podana żadna inna nazwa.
mysql.default_password string
Domyślne hasło, które będzie użyte przy łączeniu się z serwerem baz danych, jeśli nie zostanie podane
żadne inne hasło.
mysql.max_persistent integer
Maksymalna liczba stałych połączeń MySQL na każdy proces.
mysql.max_links integer
Maksymalna liczba połączeń MySQL na proces, wliczając w to połączenia stałe.
Dyrektywy konfiguracji mSQL
msql.allow_persistent boolean
Czy pozwalać na trwałe połączenia mSQL.
msql.max_persistent integer
Maksymalna liczba trwałych połączeń mSQL na każdy proces.
msql.max_links integer
Maksymalna liczba połączeń mSQL na każdy proces, wliczając w to połączenia trwałe.
Dyrektywy konfiguracji PostgreSQL
pgsql.allow_persistent boolean
Czy pozwalać na trwałe połączenia PostgreSQL.
Dodatek D. Opcje konfiguracji PHP
386
pgsql.max_persistent integer
Maksymalna liczba trwałych połączeń PostgreSQL na każdy proces.
pgsql.max_links integer
Maksymalna liczba połączeń PostgreSQL na każdy proces, wliczając w to połączenia trwałe.
Dyrektywy konfiguracji Sybase
sybase.allow_persistent boolean
Czy pozwalać na trwałe połączenia Sybase.
sybase.max_persistent integer
Maksymalna liczba trwałych połączeń Sybase na każdy proces.
sybase.max_links integer
Maksymalna liczba połączeń Sybase na każdy proces, wliczając w to połączenia trwałe.
Dyrektywy konfiguracji Sybase-CT
sybct.allow_persistent boolean
Czy pozwalać na trwałe połączenia Sybase-CT. Domyślnie włączone.
sybct.max_persistent integer
Maksymalna liczba trwałych połączeń Sybase-CT na każdy proces. Domyślą wartością jest -1, co oznacza
brak limitu.
sybct.max_links integer
Maksymalna liczba połączeń Sybase-CT na proces, włączając w to połączenia trwałe. Domyślna wartość
to -1, co oznacza brak limitu.
sybct.min_server_severity integer
Wiadomości serwera z wagą większą lub równą sybct.min_server_severity będą zgłaszane jako
ostrzeżenia. Wartość ta może być zmieniona także przez wywołanie sybase_min_server_severity(). Domyślna
wartość to 10, co powoduje raportowanie błędów o wadze „informacja” lub większej.
sybct.min_client_severity integer
Wiadomości biblioteki klienta o wadze większą lub równą sybct.min_client_severity będą zgłaszane
jako błędy. Wartość ta może być zmieniona także przez wywołanie sybase_min_client_severity(). Domyślna
wartość to 10, co praktycznie wyłącza zgłaszanie błędów.
sybct.login_timeout integer
Maksymalny czas oczekiwania na połączenie zanim zwrócony będzie błąd. Zauważ, że jeśli dojdzie do
skończenia czasu max_execution_time w trakcie oczekiwania na połączenie, twój skrypt zostanie zakończony
zanim będzie mógł podjąć jakiekolwiek działania wywoływane w przypadku nieudanego połączenia. Domyślna
wartość to jedna minuta.
387
PHP – Kompendium wiedzy
sybct.timeout integer
Maksymalny czas (w sekundach) oczekiwania na wykonanie select_db lub zapytania, po którym
zwrócony zostanie błąd. Zauważ, że jeśli dojdzie do skończenia czasu max_execution_time w trakcie oczekiwania
na połączenie, twój skrypt zostanie zakończony zanim będzie mógł podjąć jakiekolwiek działania obsługujące
błędy wykonania. Domyślnie nie ma żadnych ograniczeń.
sybct.hostname string
Nazwa komputera, który będzie wyświetlany w sp_who. Domyślną wartością jest pusty ciąg.
Dyrektywy konfiguracji Informix
ifx.allow_persistent boolean
Czy pozwalać na trwałe połączenia Informix.
ifx.max_persistent integer
Maksymalna liczba trwałych połączeń Informix na każdy proces.
ifx.max_links integer
Maksymalna liczba połączeń Informix na każdy proces, włączając w to połączenia trwałe.
ifx.default_host string
Domyślny adres komputera używany, jeśli nie podano innego w ifx_connect() lub ifx_pconnect().
ifx.default_user string
Domyślny identyfikator użytkownika używany, jeśli nie podano innego w
ifx_connect()
lub
ifx_pconnect().
ifx.default_password string
Domyślne hasło używane jeśli nie podano innego w ifx_connect() lub ifx_pconnect().
ifx.blobinfile boolean
Ustaw na TRUE jeśli chcesz zwracać kolumny blob do pliku, lub
wartość tej dyrektywy korzystając z ifx_blobinfile_mode().
FALSE
jeśli do pamięci. Możesz zmienić
ifx.textasvarchar boolean
Ustaw na TRUE jeśli chcesz w zapytaniach zwracać kolumny TEXT jako zwykłe ciągi, lub FALSE jeśli
chcesz używać identyfikatorów blob. Możesz zmienić wartość tej dyrektywy korzystając z ifx_textasvarchar().
ifx.byteasvarchar boolean
Ustaw na TRUE jeśli chcesz w zapytaniach zwracać kolumny BYTE jak zwykłe ciągi, lub FALSE jeśli chcesz
używać identyfikatorów blob. Możesz zmienić wartość tej dyrektywy korzystając z ifx_textasvarchar().
ifx.charasvarchar boolean
Ustaw na TRUE jeśli chcesz obcinać początkowe spacje z kolumn CHAR przy ich pobieraniu.
Dodatek D. Opcje konfiguracji PHP
388
ifx.nullformat boolean
Ustaw na TRUE jeśli chcesz zwracać kolumny NULL jako ciąg "NULL", lub na FALSE jeśli chcesz aby były
zwracane jako pusty ciąg. Możesz zmienić wartość tej dyrektywy korzystając z ifx_nullformat().
Dyrektywy konfiguracji BC Math
bcmath.scale integer
Liczba dziesiętnych cyfr dla wszystkich funkcji bcmath.
Dyrektywy konfiguracji możliwości przeglądarek
browscap string
Nazwa pliku opisującego możliwości przeglądarek. Zobacz także get_browser().
Dyrektywy konfiguracji Zunifikowanego ODBC
uodbc.default_db string
Źródło danych ODBC używane jeśli nie podane zostało inne w odbc_connect() lub odbc_pconnect().
uodbc.default_user string
Nazwa użytkownika używana, jeśli inna nie została podana w odbc_connect() lub odbc_pconnect().
uodbc.default_pw string
Hasło używane, jeśli inne nie zostało podane w odbc_connect() lub odbc_pconnect().
uodbc.allow_persistent boolean
Czy pozwalać na trwałych połączenia ODBC.
uodbc.max_persistent integer
Maksymalna liczba trwałych połączeń ODBC na każdy proces.
uodbc.max_links integer
Maksymalna liczba połączeń ODBC na każdy proces, włączając w to połączenia trwałe.
389
PHP – Kompendium wiedzy
Dodatek E. Zasoby Sieci
Podstawowym źródłem wiedzy na temat PHP jest oficjalna witryna WWW dostępna pod adresem
http://www.php.net. Można tam znaleźć informacje na temat list wysyłkowych, innych interesujących witryn oraz
kompletny podręcznik języka PHP. Poniższa tabela zawiera krótka listę interesujących witryn na temat PHP.
URL
Opis
Witryna poświęcona tek książce. Zawiera
http://www.php4devguide.com/
interesujące łącza i poprawki do tej książki.
Oficjalna witryna bazy danych MySQL.
http://www.mysql.com/
Świetna witryna zawierająca artykuły, przykładu
http://phpbuilder.com/
kodu inne informacje związane z programowaniem w PHP.
Witryna FastTemplate i innych bibliotek klas
http://www.thewebmasters.net/
używanych w tej książce.
Witryna poświęcona PHPLib, biblioteki klas
http://phplib.netuse.de/
używanych w tej książce w niektórych przykładach
dotyczących baz danych, sesji i autoryzacji.

Podobne dokumenty