PHP - Kompendium, nauka, informatyka, Tworzenie stron www


Spis Treści


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:

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 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.

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 ODBC-ODBC 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 blake@intechra.net.


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

0x01 graphic

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

0x01 graphic

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.

Rysunek 1.3. Dodawanie mapowania dla rozszerzenia w IIS

0x01 graphic

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

0x01 graphic

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>

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 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. 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 --with-PAKIET. Aby dodać funkcję do PHP należy użyć jednej z poniższych form:

--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-linux-gnulibc2.1 --withunixODBC=/usr/local/unixODBC --disable-debug --enabletrack-vars -- enable-fin-funcs --with-snmp=/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 -with-apxs, 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.

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

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 Win32

www.php.net/extra/win32build.zip

Obsługa BCMath

www.php.net/version4/downloads/number.tar.gz

Zastępnik pliku resolv.lib

www.php.net/version4/downloads/bindlib_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 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

0x01 graphic

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++

0x01 graphic

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.

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

0x01 graphic

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:

error_reporting = E_ALL & ~E_NOTICE ; Pokaż wszystkie błędy oprócz informacji

display_errors = On ; Wypisuj błędy (jako część wynikowego HTML)

log_errors = Off ; Zapisuj błędy do pliku błędów

error_log = 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 = E_ALL ; Pokaż wszystkie błędy

display_errors = Off ;

log_errors = On ; Zapisuj błędy

error_log = /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 admin@server.net

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.

Rysunek 1.8. Elastyczność konfiguracji z zastosowaniem php.ini oraz plików konfiguracyjnych Apache

0x01 graphic

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ł 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

$aStr1 = "To jest zwykły ciąg.";

print( "$aStr1<br>" );

$aStr2 = "Thatcher";

print( "$aStr2<br>" );

$aStr3 = "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:

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

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, 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

Definicja

HOSTNAME

Nazwa komputera serwera.

HOSTTYPE

Typ komputera, na przykład i386.

PATH

Systemowa ścieżka serwera.

OSTYPE

System operacyjny działający na serwerze, na przykład Linux.

Tabela 2.4. Zmienne generowane przez PHP

Zmienna

Definicja

PHP_SELF

Nazwa pliku z wykonywanym skryptem.

HTTP_COOKIE_VARS

Tablica asocjacyjna zmiennych przekazanych do skryptu poprzez cookie HTTP.

HTTP_GET_VARS

Tablica asocjacyjna zmiennych przekazanych do skryptu za pomocą metody GET.

HTTP_POST_VARS

Tablica asocjacyjna zmiennych przekazanych do skryptu za pomocą metody POST.

Tabela 2.5. Operatory arytmetyczne

Operator

Nazwa

Przykład

Wynik

+

Dodawanie

$a + $b

Suma $a i $b

-

Odejmowanie

$a - $b

Różnica $a i $b

*

Mnożenie

$a * $b

Iloczyn $a i $b

/

Dzielenie

$a / $b

Iloraz $a i $b

%

Reszta z dzielenia

$a % $b

Reszta z dzielenie $a przez $b

Tabela 2.6. Operatory bitowe

Operator

Nazwa

Przykład

Wynik

&

Iloczyn bitowy

$a & $b

Bity ustawione w $a i $b są ustawione

|

Suma bitowa

$a | $b

Bity ustawione w $a lub $b są ustawione

^

Różnica symetryczna

$a ^ $b

Bity ustawione w $a lub $b, ale nie w obu na raz są ustawione

~

Negacja

~$a

Bity ustawione nie są teraz ustawione i odwrotnie

<<

Przesunięcie w lewo

$a << $b

Przesunięcie bitów w $a w lewo o $b kroków

>>

Przesunięcie w prawo

$a >> $b

Przesunięcie bitów w $a w prawo o $b kroków

Tabela 2.7. Operatory porównania

Operator

Nazwa

Przykład

Wynik

==

Równy

$a == $b

True, jeżeli $a jest równe $b

===

Identyczny

$a === $b

True, jeżeli $a jest równe $b i są one tych samych typów

!=

Różny

$a != $b

True, jeżeli $a jest różne od $b

<

Mniejszy

$a < $b

True, jeżeli $a jest mniejsze od $b

>

Większy

$a > $b

True, jeżeli $a jest większe od $b

<=

Mniejszy lub równy

$a <= $b

True, jeżeli $a jest mniejsze lub równe $b

>=

Większy lub równy

$a >= $b

True, jeżeli $a jest większe lub równe $b

Tabela 2.8. Operatory zwiększania i zmniejszania

Operator, przykład

Nazwa

Wynik

$a++

Postinkrementacja

Zwraca $a, a następnie zwiększa $a o jeden

++$a

Preinkrementacja

Zwiększa $a o jeden i zwraca $a

$a--

Postdekrementacja

Zwraca $a, a następnie zmniejsza $a o jeden

--$a

Predekrementacja

Zmniejsza $a o jeden i zwraca $a

Tabela 2.9. Operatory logiczne

Operator

Nazwa

Przykład

Wynik

and

Iloczyn logiczny

$a and $b

True, jeżeli $a i $b mają wartość True

or

Suma logiczna

$a or $b

True, jeżeli $a lub $b mają wartość True

xor

Różnica symetryczna

$a xor $b

True, jeżeli $a lub $b mają wartość True, ale nie razem

!

Negacja

!$a

True, jeżeli $a nie jest True

&&

Iloczyn logiczny

$a && $b

True, jeżeli $a i $b mają wartość True

||

Suma logiczna

$a || $b

True, jeżeli $a lub $b mają wartość True

Tabela 2.10. Operatory przypisania

Operator

Przykład

Wynik

=

$a = $b

Przypisuje wartość $b do $a.

+=

$a += $b

Przypisuje wartość ($a+$b) do $a. Jest to identyczne z $a=$a+$b.

-=

$a -= $b

Przypisuje wartość ($a-$b) do $a. Jest to identyczne z $a=$a-$b.

*=

$a *= $b

Przypisuje wartość ($a*$b) do $a. Jest to identyczne z $a=$a*$b.

/=

$a /= $b

Przypisuje wartość ($a/$b) do $a. Jest to identyczne z $a=$a/$b.

.=

$a .= $b

Przypisuje wartość ($a.$b) do $a. Jest to identyczne z $a=$a.$b.

%=

$a %= $b

Przypisuje wartość ($a%$b) do $a. Jest to identyczne z $a=$a%$b.

|=

$a |= $b

Przypisuje wartość ($a|$b) do $a. Jest to identyczne z $a=$a|$b.

&=

$a &= $b

Przypisuje wartość ($a&$b) do $a. Jest to identyczne z $a=$a&$b.

^=

$a ^= $b

Przypisuje wartość ($a^$b) do $a. Jest to identyczne z $a=$a^$b.

<<=

$a <<= $b

Przypisuje wartość ($a<<$b) do $a. Jest to identyczne z $a=$a<<$b.

>>=

$a >>= $b

Przypisuje wartość ($a>>$b) do $a. Jest to identyczne z $a=$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>" );

?>

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>" );

?>

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 if organizuje przepływ sterowania poprzez tworzenie rozgałęzień na podstawie wyrażeń logicznych.

Wydruk 2.13. Przykład użycia if, else i elseif

<?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 );

?>

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.

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 )

{

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>

</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 include() 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.

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.

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 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 );

$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.


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>

<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 $Colors[] i $adress[] będzie zawierać zero lub więcej wartości.

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()

{

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

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ściowych elementów formularza

0x01 graphic

Rysunek 3.2. Wynik przesłania formularza wielowartościowego do displayall.phtml

0x01 graphic

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>

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 )

print( "'$aCode1' jest poprawnym kodem pocztowym<br>" );

else

print( "'$aCode1' nie jest poprawnym kodem pocztowym<br>" );

if ( ereg( $aCodeFormat, $aCode2 ) == True )

print( "'$aCode2' jest poprawnym kodem pocztowym<br>" );

else

print( "'$aCode2' nie jest poprawnym kodem pocztowym<br>" );

if ( ereg( $aCodeFormat, $aCode3 ) == True )

print( "'$aCode3' jest poprawnym kodem pocztowym<br>" );

else

print( "'$aCode3' nie jest poprawnym kodem pocztowym<br>" );

if ( ereg( $aCodeFormat, $aCode4 ) == True )

print( "'$aCode4' jest poprawnym kodem pocztowym<br>" );

else

print( "'$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>" );

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 = "support@intechra.net";

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 = "blake@intechra.net";

$aEmail2 = "john";

$aEmail3 = "nobody@invalidhost.com";

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>" );

?>

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:

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];

$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 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"

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>

<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

0x01 graphic

Rysunek 3.4. Wyświetlanie bez filtrowania

0x01 graphic

Rysunek 3.5. Wyświetlanie ze strip_tags()

0x01 graphic

Rysunek 3.6. Wyświetlanie z htmlentities()

0x01 graphic

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, NUL 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

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

0x01 graphic

Rysunek 3.8. Wyświetlanie przefiltrowane przez strip_tags(), strip_slashes() i nl2br()

0x01 graphic

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.


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.

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>

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”.


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:

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>

<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ć

// 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 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ł 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>" );

}

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

$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.

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.

Rysunek 6.1. Komponenty aplikacji PHP korzystającej z PHP

PHP Application - aplikacja PHP

Driver Manager - zarządca sterowników

Database Driver - sterownik do bazy danych

DBMS - SZRBD

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.

Rysunek 6.2.

Dodajemy sterownik OOB

PHP Application - aplikacja PHP

Driver Manager - zarządca sterowników

The OOB driver - sterownik OOB

OOB Client - klient OOB

Network - sieć

OOB Server - serwer OOB

Driver Manager - zarządca sterowników

Database Driver - sterownik do bazy danych

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.

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 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

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

{

var $Host = "208.129.36.163";

var $Database = "mydb";

var $User = "root";

var $Password = "";

}

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.

Rysunek 6.3. Dynamicznie generowany formularz do wprowadzania danych

0x01 graphic

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.

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 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”.


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

0x01 graphic

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();

?>

<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

0x01 graphic

Rysunek 7.3. Wynik działania skryptu z wydruku 7.2

0x01 graphic

Możliwe jest wyświetlenie bieżącego identyfikatora sesji wypisując na ekran zawartość zmiennej $PHPSESSID. 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";.

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 SID, 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-trans-sid. 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

<?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>

</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).

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.

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

<?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>

Rysunek 7.4. Wynik działania skryptu mysession.php

0x01 graphic

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";

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 mysess_open() 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.

<?php

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:

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";

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; // język aplikacji

$lang = "pl"; // domyślnie polski

$sess->register("lang");

global $cur; // waluta aplikacji

$cur = "PLN"; // domyślnie złotówki

$sess->register("cur");

global $cart;

$cart = new Shop_Cart; // utworzenie obiektu wózka na zakupy

// zdefiniowanego w local.inc

$sess->register("cart"); // 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:

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ż 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:

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ł 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

0x01 graphic

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

0x01 graphic

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 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 )

{

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 $acttype 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

<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++;

}

?>

</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

0x01 graphic

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.

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ść, 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

0x01 graphic

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) NOT NULL,

SurName varchar(30) NOT NULL,

password varchar(20) NOT NULL,

PRIMARY KEY (FirstName, 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' )";

$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>

</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>

</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ł 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:

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

Dodatkowe informacje na temat Browscap

W czasie pisania książki podejmowane były dodatkowe ulepszenia do istniejącej w PHP funkcji get_browser(). Odkryłem, że plik browser.ini dostępny z firmy cyScape (wspomnianej już wcześniej) wymaga kilku zmian aby działał z PHP 4.0 z poprawką 2. Pierwszą z nich jest dodanie pustej linii na końcu pliku. Bez dodatkowego znaku końca linii w trakcie uruchamiania PHP generowany jest błąd składni.

Drugim, o wiele bardziej skomplikowany problem jest związany z samą struktura pliku. Typowo, plik browscap.ini jest zwykłym plikiem konfiguracyjnym w którym każda sekcja reprezentuje określoną przeglądarkę. Każda z sekcji odwołuje się do sekcji wyższego rzędu, więc zdefiniowana jest pewnego rodzaju struktura. Tym sposobem w sekcji opisującej nową przeglądarkę zdefiniowane są tylko nowe możliwości a istniejące wcześniej znajdują cię w opisie starszej przeglądarki. Problem wynika z tego, że w czasie odczytu pliku PHP konwertuje jego zawartość na małe litery. Konwersja ta powoduje, że PHP nie potrafi odszukać nadrzędnej sekcji, ponieważ nie wszystkie nazwy zapisane są małymi literami. Aby rozwiązać ten problem wykonałem prosty skrypt konwertujący wszystkie linie pliku browscap.ini na małe litery:

<?php

$aArray = file( "./browscap.ini" );

$aNewFile = fopen( "./browscap.ini", "w" );

foreach( $aArray as $aLine )

{

$aNewFile = strtolower( $aLine );

fputs( $aNewFile, $aNewLine );

}

fclose ($aNewFile );

?>

Skutkiem ubocznym takiej zmiany jest to, że wszystkie wywołania funkcji get_browser() muszą zawierać wywołanie funkcji strtolower(). Jednak po wprowadzeniu takich zmian funkcja get_browser() działa tak, jak się tego spodziewamy.

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().

Aby użyć funkcji get_browser() należy ściągnąć z sieci plik browscap.ini, który jest dostępny z wielu witryn w Sieci. W czasie pisania książki plik był dostępny bez żadnych opłat z witryny http://www.cyscape.com/browscap. Po jego ściągnięciu i zainstalowaniu w serwerze WWW, należy zmienić plik php.ini. Odszukaj opcję konfiguracji browscap i zmień ją na pełną ścieżkę do pliku browscap.ini. Po 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 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.

Rysunek 9.2. Wynik działania skryptu z wydruku 9.1 wykonywanego w przeglądarce Netscape 4.7

0x01 graphic

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>" );

}

?>

</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

0x01 graphic

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 możliwość przesyłania plików do serwera (przeglądarki zgodne z RFC 1867).

Boolean

getFontColor()

Sprawdza, czy przeglądarka potrafi wyświetlać kolorowy tekst.

Boolean

getFontSize()

Sprawdza, czy przeglądarka potrafi wyświetlać różne wielkości tekstu.

Boolean

getFrames()

Sprawdza, czy przeglądarka obsługuje ramki.

java.lang.String

getFullversion()

Zwraca kompletną wersje przeglądarki zawierającą wyższą i niższą część numeru oraz litery, o ile występują.

Boolean

getGold()

Sprawdza, czy jest to wersja Gold przeglądarki Netscape Navigator.

Boolean

getHDML()

Zwraca True, jeżeli obsługuje HDML (poprzednik WAP).

java.lang.String

getIPAddr()

Zwraca adres IP klienta.

Boolean

getJavaApplets()

Sprawdza, czy przeglądarka obsługuje applety Java.

Boolean

getJavaScript()

Sprawdza, czy przeglądarka obsługuje JavaScript.

double

getJavaScriptVer()

Zwraca numer wersji JavaScript obsługiwanego przez przeglądarkę.

java.lang.String

getLanguage()

Zwraca wybrany przez użytkownika język.

int

getMajorver()

Zwraca wyższą część numeru wersji przeglądarki.

double

getMinorver()

Zwraca niższą część numeru wersji przeglądarki.

java.lang.String

getMinorverlet()

Zwraca literę niższej części numeru przeglądarki, o ile występuje.

Boolean

getMouseOver()

Sprawdza, czy przeglądarka obsługuje efekt JavaScript, mouseover.

Boolean

getMSN()

Sprawdza, czy użytkownik korzysta z sieci Microsoft Network (MSN).

java.lang.String

getOSDetails()

Zwraca szczegóły na temat systemu operacyjnego (OS) systemu użytkownika.

Boolean

getPDA()

Zwraca True, jeżeli przeglądarką jest urządzeniem PDA na przykład PalmPilot.

java.lang.String

getPlatform()

Zwraca bardziej ogólne dane (w porównaniu do getOSDetails()) na temat platformy użytkownika.

Boolean

getPNG()

Sprawdza, czy przeglądarka obsługuje format rysunków PNG (Potrable Network Graphics).

Boolean

getProxy()

Sprawdza, czy użytkownik jest połączony poprzez serwer Proxy.

Boolean

getSSL()

Sprawdza, czy przeglądarka obsługuje protokół SSL (Secure Socket Layer).

Boolean

getSSLActive()

Sprawdza, czy użytkownik jest połączony poprzez aktywne połączenie SSL.

java.lang.String

getSSLCipherSuite()

Zwraca zestaw szyfrowania SSL dla bieżącej sesji. Dostępny jedynie w przypadku aktywnej sesji SSL.

int

getSSLKeySize()

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.

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 files@my.domain.com.

<?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>

<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ł 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 kodu.

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 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.

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

Opcja

Domyślnie

Opis

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>

<?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()

0x01 graphic

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

1

E_ERROR

2

E_WARNING

4

E_PARSE

8

E_NOTICE

16

E_CORE_ERROR

32

E_CORE_WARNING

64

E_COMPILE_ERROR

128

E_COMPILE_WARNING

256

E_USER_ERROR

512

E_USER_WARNING

1024

E_USER_NOTCE

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()

0x01 graphic

Rysunek 10.3. Wynik działania drugiego skryptu error_reporting()

0x01 graphic

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\php4-devguide\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\php4-devguide\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\php4-devguide\site\ch10\error_reporting.phtml on line 12

[06-Dec-2001 20:54:49] PHP Warning: Undefined offset: 3 in c:\helion\php4-devguide\site\ch10\error_reporting_2.phtml on line 17

[06-Dec-2001 20:54:51] PHP Warning: Undefined offset: 3 in c:\helion\php4-devguide\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\php4-devguide\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().

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, "app_errors@intechra.net",

"From: error_logger@myhost.com\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";

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( "<table border=\"1\"><tr><td>" );

print( "<b>$aErrorType</b>: <i>$aErrorStr</i><br>" );

print( "w pliku $aFile linia $aLine<br>" );

print( "</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()

0x01 graphic

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.

Rysunek 10.5. Użycie funkcji zdefiniowanej dla assert()

0x01 graphic

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;

MAIL=mydebug@intechra.net;IP=myserver.com:5400;

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 (mydebug@intechra.net)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++ )

{

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: mydebug@host.com\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";

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

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

0x01 graphic

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 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ł 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ę:

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>

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;

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:

<?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;

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;

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.

Rysunek 11.1. Wykorzystanie nowych funkcji finansowych

0x01 graphic

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ć.

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/php-4.0.1.p12/ext/java/php_java.jar:/home/blake/bhawk/lib/bhawk4j.jar:/home/blake/bhawk:/home/blake/java/numberspeller.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.

Rysunek 11.2. Przykładowy plik RTF modułu Scrooge

0x01 graphic

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. 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.

Rysunek 11.3. Wynik przetworzenia przykładowego pliku RTF na kod HTML

nie potrafię uruchomić tego przykładu

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

{

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

0x01 graphic

Rysunek 11.5. Przykład użycia serwera Cloanto, wyświetlana waluta: forinty węgierskie

0x01 graphic

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ę.

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. 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ł 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ą:

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 );

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 require(). 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

<!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.

Rysunek 12.1. Łączenie HTML i kodu PHP przy użyciu include()

0x01 graphic

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" );

}

}

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( "<h2>$aTitle</h2>" );

print( "<h4>autor: $aAuthor</h4>" );

print( "<p>$aSynopsis</p>" );

print( "<a href=\"full_story.phtml?news_id=$aNewsID\">pełny tekst...</a>" );

print( "<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.

Rysunek 12.2. Przykładowa aplikacja z pierwszym arkuszem stylów

0x01 graphic

Rysunek 12.3. Przykładowa aplikacja z pierwszym arkuszem stylów

0x01 graphic

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.

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 ";

}

$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

0x01 graphic

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}

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' => 'sample_1.tpl',

'copyright' => 'copyright.tpl',

'body' => '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' => 'Lepszy przykład',

'BODY_COLOR' => 'white',

'YEARS' => $aYears,

'PAGE_HEADER' => 'Lepszy przykład',

'PAGE_CONTENT' => $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.

Rysunek 12.5. Wynik działania zagnieżdżonych szablonów FastTemplate

0x01 graphic

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.

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" => "ft_news_base.tpl",

"body" => "ft_news_body.tpl",

"item" => "ft_news_item.tpl",

"copyright" => "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" => $aYears,

"TITLE" => "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" => $aTitle,

"NEWS_AUTHOR" => $aAuthor,

"NEWS_SYNOPSIS" => $aSynopsis,

"FULL_STORY_URL" => $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. 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' );

?>

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.

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.


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

0x01 graphic

Rysunek 13.2. Plik CSV w Excelu

0x01 graphic

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">

</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 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.

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)

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 );

$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.

Rysunek 13.4. Przykładowy plik strefy DNS

0x01 graphic

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 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></wddxPacket>

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;

// 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

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.

Rysunek 13.5.

Przykład wykorzystania danych WDDX na kliencie

0x01 graphic

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'; // *nix

$aTraceCmd = '/usr/sbin/traceroute -n'; // *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;

}

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( "phpPing: " . phpPing ( 'www.php.net' ) . "<br><br>" );

print( "phpTrace: <ul>" . phptrace( 'www.php.net' ) . "</ul><br>" );

print( "phpPageCheck: " );

print( phpPageCheck( 'http://www.php.net/' ) ? "OK" : "NOT OK" );

print( "<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.

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ł 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.

Strona WWW składająca się z kilku plików szablonów

Page header - nagłówek strony

navigation - panel nawigacji

footer - stopka

HTML base page - Podstawowa strona HTML

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' => 'merch_base2.tpl',

'header' => 'merch_header.tpl',

'navi' => 'merch_navi.tpl',

'footer' => 'merch_footer.tpl',

'cat_header' => $aCategoryHeader,

'body' => 'merch_body.tpl'

) );

$aTPL->assign( array( 'TITLE' => 'Katalog towarów: Ubrania',

'CATEGORY_SPECIALS' => 'Sprzedajemy koszulki Intechra!',

'PRODUCT_NAME' => 'Koszulka Intechra',

'PRODUCT_DESCRIPTION' => 'Świetna koszulka z logo Intechra LLC!',

'PRODUCT_PRICE' => '14.95 zł',

'COPYRIGHT_YEARS' => '2001',

'HREF_HOME' => 'index.phtml',

'HREF_CART' => 'cart.phtml',

'HREF_CONTACT' => 'contact.phtml',

'HREF_COMPANY_INFO' => 'company.phtml'

) );

$aTPL->parse( 'PAGE_HEADER', 'header' );

$aTPL->parse( 'CAT_HEADER', 'cat_header' );

$aTPL->parse( 'LEFT_NAVI', 'navi' );

$aTPL->parse( 'BODY', 'body' );

$aTPL->parse( 'PAGE_FOOTER', 'footer' );

$aTPL->parse( 'BASE', 'base' );

$aTPL->FastPrint( '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.

Rysunek 14.2. Strona wygenerowana przez skrypt z wydruku 14.7.

0x01 graphic

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>

Rysunek 14.3. Strona wygenerowana przy użyciu nowego szablonu „base”

0x01 graphic

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.

Rysunek 14.4. Arkusz stylu pokazujący możliwość modyfikacji znaczników <body>, <td> i <h3>

0x01 graphic

Rysunek 14.5. Inny arkusz stylu pokazujący możliwość modyfikacji znaczników <body>, <td> i <h3>

0x01 graphic

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.

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

0x01 graphic

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.

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

0x01 graphic

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') );

$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">

</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' => $aPartnerBase,

'header' => 'merch_header.tpl',

'navi' => 'merch_navi.tpl',

'footer' => $aPartnerFooter,

'cat_header' => $aCategoryHeader,

'body' => 'merch_body.tpl'

) );

$aTPL->assign( array( 'TITLE' => 'Katalog produktów: Ubrania',

'CATEGORY_SPECIALS' => 'Sprzedanemy koszulki Intechra!',

'PRODUCT_NAME' => 'Koszulka Intechra',

'PRODUCT_DESCRIPTION' => 'Świetna koszulka z logo Intechra LLC!',

'PRODUCT_PRICE' => '14.95 zł',

'COPYRIGHT_YEARS' => '2000',

'HREF_HOME' => 'index.phtml',

'HREF_CART' => 'cart.phtml',

'HREF_CONTACT' => 'contact.phtml',

'HREF_COMPANY_INFO' => 'company.phtml'

) );

$aTPL->parse( 'PAGE_HEADER', 'header' );

$aTPL->parse( 'CAT_HEADER', 'cat_header' );

$aTPL->parse( 'LEFT_NAVI', 'navi' );

$aTPL->parse( 'BODY', 'body' );

$aTPL->parse( 'PAGE_FOOTER', 'footer' );

$aTPL->parse( 'BASE', 'base' );

$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

0x01 graphic

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.

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

0x01 graphic

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ę.

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 = "intl_head_{$Lang}.gif";

$aNaviImg = "intl_nav_{$Lang}.gif";

$aNaviMap = "intl_map_{$Lang}.tpl";

$aBodyTpl = "body_{$Lang}.tpl";

$aTPL->define( array( 'base' => 'intl_base.tpl',

'body' => $aBodyTpl,

'navimap' => $aNaviMap ) );

$aTPL->assign( array( 'HREF_HOME' => "intl.phtml?Lang=$Lang",

'HREF_LINKS' => "links.phtml?Lang=$Lang",

'HREF_ABOUT' => "about.phtml?Lang=$Lang",

'HREF_CONTACT' => "contact.phtml?Lang=$Lang",

'HEADER_IMG' => $aHeaderImg,

'NAV_IMG' => $aNaviImg,

'HREF_ENU' => $PHP_SELF . "?Lang=enu",

'HREF_POL' => $PHP_SELF . "?Lang=pol",

'HREF_DEU' => $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.

Rysunek 14.12. Witryna międzynarodowa w języku angielskim

0x01 graphic

Rysunek 14.13. Witryna międzynarodowa w języku polskim

0x01 graphic

Rysunek 14.14. Witryna międzynarodowa w języku niemieckim

0x01 graphic

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.


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

0x01 graphic

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

0x01 graphic

Wydruk 15.1. Implementacja modelu danych katalogu produktów

CREATE TABLE mcMerchants

(

merchant_id int not null,

name varchar(50) not null,

created_date datetime not null,

internal_status int not null,

addtl_handling float default 0.0 not null,

mgr_email varchar(25) not null,

mgr_username varchar(30) not null,

mgr_password varchar(30) not null,

mgr_name varchar(50) not null,

primary key ( merchant_id ),

index( name ),

index( mgr_username )

);

CREATE TABLE mcCategories

(

merchant_id int not null,

category_id int not null,

name varchar(50) not null,

created_date datetime not null,

deleted tinyint default 0 not null,

primary key ( merchant_id, category_id ),

index( name )

);

CREATE TABLE mcProducts

(

merchant_id int not null,

product_id int not null,

category_id int not null,

name varchar(200) not null,

descr text not null,

has_image_file tinyint default 0 not null,

external_id varchar(100) not null,

ship_weight float not null,

price float not null,

created_date datetime not null,

deleted tinyint default 0 not null,

primary key ( merchant_id, product_id ),

index( name )

);

CREATE TABLE mcProductsToCategories

(

merchant_id int not null,

category_id int not null,

product_id int not null,

primary key ( merchant_id, category_id, product_id )

);

CREATE TABLE mcProductsOptions

(

merchant_id int not null,

product_id int not null,

option_id int not null,

name varchar(100) not null,

sort_type tinyint default 0 not null,

primary key ( merchant_id, product_id, option_id ),

index( name )

);

CREATE TABLE mcProductsOptionsValues

(

merchant_id int not null,

product_id int not null,

option_id int not null,

value_id int not null,

name varchar(100) not 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ą:

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 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>

<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" => "mgmt_app_base.tpl",

"body" => "mgmt_body.tpl",

"footer" => "mgmt_footer.tpl",

"page_body" => "mgmt_cats_ovr.tpl",

"cat_table" => "mgmt_cats_table.tpl",

"cat_item" => "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( "EXISTING_CATEGORIES" => "" ) );

}

$aTPL->assign( array( "TITLE" => "Zarządzanie katalogiem towarów",

"MERCHANT_NAME" => 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 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ądzania kategoriami katalogu produktów

0x01 graphic

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" );

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( "base" => "mgmt_app_base.tpl",

"body" => "mgmt_body.tpl",

"footer" => "mgmt_footer.tpl",

"page_body" => "mgmt_cat_add.tpl" ) );

$aTPL->assign( array( "TITLE" => "Zarządzanie katalogiem produktów",

"MERCHANT_NAME" => GetMerchantName( $aDB, $aMerchantID ),

"FORM_ACTION" => $PHP_SELF,

"ERRORS" => $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 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ądzania produktami

0x01 graphic

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" => "mgmt_app_base.tpl",

"body" => "mgmt_body.tpl",

"footer" => "mgmt_footer.tpl",

"page_body" => "mgmt_prods_ovr.tpl",

"prod_table" => "mgmt_prods_table.tpl",

"prod_item" => "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" => $aProdID,

"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" => "Zarządzanie katalogiem produktów",

"MERCHANT_NAME" => 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:

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,

// 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ę.

Rysunek 15.5. Główna strona katalogu produktów

0x01 graphic

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" => "mgmt_app_base.tpl",

"body" => "mgmt_body.tpl",

"footer" => "mgmt_footer.tpl",

"page_body" => "mgmt_main.tpl",

"cat_body" => "mgmt_main_body.tpl",

"cat_item" => "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" => "Brak dostępnych produktów." ) );

}

$aTPL->assign( array("TITLE" => "Zarządzanie katalogiem produktów",

"MERCHANT_NAME" => 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";

}

}

$aTPL = new FastTemplate( "." );

$aDB = new mgmt_db();

$aTPL->define( 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" ) );

$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" => $aProdName,

"CAT_NAME" => $aCatName,

"PROD_EID" => $aProdEID,

"PROD_PRICE" => number_format( $aProdPrice, 2 ).'zł',

"PROD_DESCR" => $aProdDescr,

"IMAGE_FILE" => $aImageFile

) );

$aTPL->parse( "ITEM_LIST", ".prod_item" );

}

}

else

{

$aTPL->assign( array("ITEM_LIST" => "Nie ma produktów dla wybranego kryterium."));

}

$aTPL->assign( array( "TITLE" => "Zarządzanie katalogiem produktów",

"MERCHANT_NAME" => 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”.

Rysunek 15.6. Lista dla kategorii (kategoria ubrania)

0x01 graphic

Rysunek 15.7. Alfabetyczna lista produktów

0x01 graphic

Rysunek 15.8. Lista wyników wyszukiwania (szukanie „pol”)

0x01 graphic

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ł 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 $Host = "localhost";

var $Database = "mydb";

var $User = "root";

var $Password = "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.

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 FastTemplate( "." );

$aDB = new mgmt_db();

$aCatDB = new mgmt_db();

$aTPL->define( 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" => $aProdName,

"CAT_NAME" => $aCatName,

"PROD_EID" => $aProdEID,

"PROD_PRICE" => '$' . number_format( $aProdPrice, 2 ),

"PROD_DESCR" => $aProdDescr,

"IMAGE_FILE" => $aImageFile

) );

$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ę.

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.

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ł 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 webmaster@server.com

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.

Rysunek 17.1. Zależności w aplikacji handlu elektronicznego

0x01 graphic

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 --with-cybercash. 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.

  2. Zmiana uprawnień do pliku instalatora w taki sposób, aby można było go uruchomić: chmod +x install-mck-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 --with-cybercash=/ś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 zainicjowaną przez sprzedawcę. Komunikat ten jest obsługiwany jedynie przez procesor Paymentech (wykorzystując opcję Electronic Check Payment — ECP).

checkreturn

Zwraca pieniądze na konto czekowe klienta.

mauthcapture

Autoryzuje i przechwytuje rozpoczętą przez sprzedawcę transakcję za pomocą karty kredytowej. Jest używany jedynie dla głównych procesorów przechwytujących.

mauthonly

Autoryzuje rozpoczętą przez sprzedawcę sprzedaż za pomocą karty kredytowej. Jest używany dla końcowych procesorów przechwytujących.

postauth

Przechwytuje płatność kartą kredytową autoryzowaną za pomocą mauthonly lub checkauth.

query

Odpytuje bazę transakcji.

retry

Ponawia oczekującą transakcję dla podanego zamówienia.

return

Zwraca pieniądze na kartę kredytową klienta.

void

Unieważnia transakcję.

merchant-check-payment

Sprawdza i autoryzuje zainicjowaną przez sprzedawcę płatność w systemie PayNow.

check-query

Odszukuje w bazie danych PayNow danych na temat określonych rachunków.

check-update-status

Uaktualnia serwer rachunków za pomocą zmian przeprowadzonych w bramce.

check-query-order-status

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

Wymagane

order-id

Unikalny identyfikator transakcji.

amount

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).

card-number

Numer karty kredytowej obciążanej tą transakcją.

card-exp

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).

card-name

Nazwa właściciela karty kredytowej.

card-address

Adres zamieszkania właściciela karty kredytowej. UWAGA: pole jest wymagane w przypadku kart AVS i Discover.

card-city

Miejscowość w której mieszka właściciel karty. UWAGA: pole jest wymagane w przypadku kart AVS i Discover.

card-zip

Kod pocztowy miejscowości, w której mieszka właściciel karty. Prawidłowymi zapisami są „22091”, „20191-1448,”, „NW3 5RJ” i „113 192”. UWAGA: pole jest wymagane w przypadku kart AVS i Discover.

card-state

Stan w którym mieszka właściciel karty. UWAGA: pole jest wymagane w przypadku kart AVS i Discover.

card-country

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.

MErrCode

Numer błędu odpowiadający komunikat błędu przekazanego w MErrMsg.

merch-txn

Numer używany przez bramkę do identyfikacji przeprowadzanej transakcji. Pole to występuje zawsze.

order-id

Identyfikator zamówienia do którego należy przetwarzana transakcja. Pole to występuje zawsze.

cust-txn

Numer transakcji używany przez portfel CyberCash do identyfikacji 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.

MSWErrMsg

Komunikat błędu przy użyciu nieaktualnej wersji portfela lub serwera płatności. Pole to nie zawsze występuje.

addnl-response-data

Dodatkowe dane transakcji zwracane przez bramkę. UWAGA: Jeżeli 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.

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 = ""; /* tutaj identyfikator sprzedawcy. */

$merchant_key = ""; /* tutaj klucz sprzedawcy. */

$payment_url = "http://cr.cybercash.com/cgi-bin/";

$auth_type = "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( "blake@intechra.net", "Ponowna próba płatności ($aCustomerID)",

"Czy chcesz jeszcze raz zapłacić??", "From: support@intechra.net\r\n" );

$tpl->define( array( base => "a_base.tpl",

footer => "c_footer.tpl",

body => "s_paid_already.tpl"

) );

$tpl->assign( array( TITLE => "Płatność Intechra.Net",

URL => $aInternalURL,

THEDATE => date( "l, j F Y" ),

ORDERID => $aOrderID,

HIDDENID => $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 );

$aMaxID = $aRow["MAX_ID"];

}

else

{

$aMaxID = 0;

}

$aCurID = $aMaxID + 1;

$aOrderID = "INT-" . date( "Ymd" ) . "-" . sprintf( "%06d", $aFamilyID ) .

"-" . sprintf( "%04d", $aCurID );

$aOrderDetails = array( "Order-ID" => $aOrderID,

"Amount" => "usd 39.00",

"Card-Number" => $CCNum,

"Card-Address" => $CCAddr,

"Card-City" => $CCCity,

"Card-State" => $CCState,

"Card-Zip" => $CCZip,

"Card-Exp" => $CCExpDate,

"Card-Name" => $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( "blake@intechra.net",

"Płatność dla Intechra.net zrealizowana ($aCustomerID)",

"Płatność zakończona sukcesem", "From: support@intechra.net\r\n" );

$aSQL = "update orders set ISPAID = 1 where ( ID = $aCustomerID )";

$aDB->SetSQL( $aSQL );

$tpl->define( array( base => "a_base.tpl",

footer => "c_footer.tpl",

body => "s_paid_ok.tpl"

) );

$tpl->assign( array( TITLE => "Płatności Intechra.net",

URL => $aInternalURL,

THEDATE => date( "l, j F Y" ),

ORDERID => $aOrderID,

HIDDENID => $ID

) );

AddSiteVars( $tpl, $aHiddenID );

$tpl->parse( FOOTER, "footer" );

$tpl->parse( BODY, "body" );

$tpl->parse( PAGE, "base" );

$tpl->FastPrint( PAGE );

}

else

{

mail( "blake@intechra.net",

"Płatność dla Intechra.net nieudana ($ ($aCustomerID)",

"Płatność nieudana", "From: support@intechra.net\r\n" );

$tpl->define( array( base => "a_base.tpl",

footer => "c_footer.tpl",

body => "s_paid_fail.tpl"

) );

$tpl->assign( array( TITLE => "Płatności Intechra.net",

HIDDENID => $ID

) );

$tpl->parse( FOOTER, "footer" );

$tpl->parse( BODY, "body" );

$tpl->parse( PAGE, "base" );

$tpl->FastPrint( PAGE );

}

?>

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.

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.


Dodatek A. Funkcje

function_exists

Szuka w liście zdefiniowanych funkcji nazwy przekazanej w $function_name. Zwraca True, jeżeli znaleziono podaną nazwę funkcji, w przeciwnym wypadku zwraca False.

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 func_get_args() do zrealizowania funkcji ze zmienna liczbą argumentów. Funkcja została dodana w PHP 4.

func_get_args

Zwraca tablicę, w której każdy element zawiera odpowiedni argument z listy argumentów funkcji. Funkcja func_get_args() generuje ostrzeżenie w wypadku wywołania jej spoza definicji funkcji.

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 func_get_arg() do zrealizowania funkcji ze zmienna liczbą argumentów. Funkcja została dodana w PHP 4.

func_num_args

Zwraca liczbę argumentów przekazanych do bieżącej funkcji. Funkcja func_num_args() generuje ostrzeżenie w przypadku wywołania jej z poza funkcji.

int func_num_args( void )

<?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 func_get_arg() do zrealizowania funkcji ze zmienna liczbą argumentów. Funkcja została dodana w PHP 4.

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 getallheaders() działa jedynie, gdy PHP pracuje jako moduł Apache.

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:

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 $ip_address. W przypadku wystąpienia błędu funkcja zwraca $ip_address. Patrz również: gethostbyname().

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ą $hostname. Patrz również: gethostbyname(), gethostbyaddr(), checkdnserr(), getmxrr() oraz man named(8).

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

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 $name według pliku /etc/protocols. Patrz również: getprotobynumber().

int getprotobyname( string name )

getprotobynumber

Zwraca nazwę protokołu skojarzonego z protokołem $number według pliku /etc/protocols. Patrz również: getprotobyname().

int getprotobynumber( string name )

getrandmax

Zwraca maksymalną wartość, jaka może być zwrócona przez funkcję rand(). Patrz również: rand(), srand(), mt_rand(), mt_srand() oraz mt_getrandmax().

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 = getrusage();

echo $dat["ru_nswap"]; # ilość stronicowań

echo $dat["ru_majflt"]; # ilość błędów strony

echo $dat["ru_utime.tv_sec"]; # użyty czas użytkownika (sekundy)

echo $dat["ru_utime.tv_usec"]; # użyty czas użytkownika (mikrosekundy)

Więcej szczegółów na temat getrusage można znaleźć w podręczniku systemowym pod hasłem getrusage(2).

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.

array gettimeofday( void )

gettype

Zwraca typ zmiennej PHP $var. Możliwe zwracane wartości zamieszczone są poniżej:

boolean

integer

double

string

array

object

resource

user function

unknown type

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 korzysta z pliku konfiguracji, należy spróbować odczytać wartość zmiennej konfiguracji cfg_file_path. Jeżeli jest to możliwe, oznacza to, że jest używany plik konfiguracji.

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 $class_name. Patrz również: get_class_vars(), get_object_vars().

array get_class_methods( string class_name )

get_class_vars

Zwraca tablicę z nazwami właściwości zdefiniowanych w klasie określonej przez $class_name. Patrz również: get_class_methods(), get_object_vars().

array get_class_vars( string class_name )

get_current_user

Zwraca nazwę właściciela bieżącego skryptu PHP. Patrz również getmyuid(), getmypid(), getmyinode() oraz getlastmod().

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);

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>

<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 $obj. Patrz również: get_class(), is_subclass_of().

string get_parent_class( object obj )

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.

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 )

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().

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

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"); //Data w przeszłości

header("LastModified: " .. gmdate("D, d M y H:i:s"); // Czas GMT

header("Cache-Control: no-cache, must-revalidate"); // zawsze zmodyfikowane HTTP/1.1

header("Pragme: no-cache"); // 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 False. Patrz również: header().

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 hexdec() 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().

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 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 powoduje konwersję zarówno cudzysłowów jak i apostrofów. ENT_NOQUOTES powoduje, że zarówno cudzysłowy jak i apostrofy pozostają niezmienione.

string htmlspecialchars( string string [, int quote_style])

Wykonywane są następujące konwersje:

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, zwraca 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().

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 $destination_id. Zwracaną wartością jest ilość skopiowanych obiektów. Patrz również: hw_mv().

int hw_Cp( int conection, array object_id_array, int destination_id

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. Dane ze znaczników BODY i HEAD są zapamiętywane w rekordzie obiektu. Parz również: hw_Document_Attributes(), hw_Document_Size() i hw_DocumentSetContent().

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 hw_Document_Attributes(). W celu zachowania zgodności akceptowana jest również nazwa hw_DocumentSize, ale jej stosowanie nie jest zalecane.

int hw_Document_Size( int hw_document )

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

Zwraca ciąg zawierający ostatni komunikat błędu lub ciąg No Error. Jeżeli funkcja się nie udała, zwraca False. 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 )

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ż: hw_ChildrenObj() i hw_GetChildCollObj().

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 )

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 $objectID. Obiekt ten może być dokumentem lub zakotwiczeniem. Patrz również: hw_GetAnchors().

array hw_GetSrcByDestObj( int connection, int objectID )

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 )

hw_InsColl

Wstawia nową kolekcję z atrybutami zawartymi w tablicy $object_array, do kolekcji o identyfikatorze $objectID.

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 $parentID. 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().

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 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.

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 hw_OutputDocument(), ale jest to postać przestarzała.

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)

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().

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 = array(

1 => 'Eric',

5 => 'Filip',

7 => '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()

<?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, ibase.dateformat i ibase.timeformat. Parametr $columntype został dodany w PHP 4.0. Ma on znaczenie jedynie w wersjach InterBase 6 i wyższych.

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:

Wszystkie pozycje daty i czasu zawierają następujące atrybuty:

icap_list_alarms

Zwraca tablicę z identyfikatorami zdarzeń które wyślą alarm o podanej godzinie. Funkcja icap_list_alarms() wymaga podania daty i czasu oraz strumienia kalendarza. Zwracana jest tablica identyfikatorów zdarzeń z aktywnym alarmem o podanej godzinie.

int icap_list_alarms (int stream_id, array date, array time)

Wszystkie pozycje z datą i czasem zawierają następujące atrybuty:

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:

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:

Wszystkie pozycje daty i czasu zawierają następujące atrybuty:

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 False w przypadku wystąpienia błędu, True w przypadku powodzenia operacji.

int ifxus_close_slob (int bid)

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 False w przypadku wystąpienia błędu i True w przeciwnym wypadku.

int ifxus_free_slob (int bid)

ifxus_open_slob

Otwiera obiekt slob. Parametr $bid powinien być identyfikatorem istniejącego obiektu. Tryby: 1 = LO_RDONLY, 2 = LO_WRONLY, 4 = LO_APPEND, 8 = LO_RDWR, 16 = LO_BUFFER, 32 = LO_NOBUFFER. Zwraca False w przypadku wystąpienia błędu a w przeciwnym wypadku identyfikator nowego obiektu slob.

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 $content zawiera dane do zapisania. Zwraca False w przypadku wystąpienia błędu, w przeciwnym przypadku ilość zapisanych bajtów.

int ifxus_write_slob (long bid, string content)

ifx_affected_rows

Parametr $result_id powinien być identyfikatorem wyniku zwracanym przez funkcję ifx_query() lub ifx_prepare(). 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 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 SELECT. Tryb 0 oznacza przechowywanie blobów w pamięci, natomiast 1, przechowywanie ich w pliku.

void ifx_blobinfile_mode (int mode)

ifx_byteasvarchar

Ustawia domyślny tryb zapytaniach SELECT. Tryb 0 powoduje zwracanie identyfikatora blob, natomiast 1, zwracanie pola varchar z danymi tekstowymi.

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");

ifx_copy_blob

Tworzy kopię podanego obiektu blob. Parametr $bid jest identyfikatorem obiektu blob. Zwraca False w przypadku błędu, a w przeciwnym wypadku identyfikator nowego obiektu blob.

int ifx_copy_blob (int bid)

ifx_create_blob

Tworzy obiekt blob. Zwraca False w przypadku błędu, a w przeciwnym wypadku identyfikator nowego obiektu blob.

int ifx_create_blob (int type, int mode, string param)

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));

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);

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 $bid. W przypadku wystąpienia błędu zwraca False, w przeciwnym wypadku True.

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)

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,

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 0 powoduje zwracanie identyfikatorów blob, natomiast tryb 1 powoduje zwracanie zawartości jako tekstu.

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])

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ż: ImageColorSet() i ImageColorsForIndex().

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)

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 ImageCreate(), natomiast $col jest identyfikatorem koloru zwracanym przez ImageColorAllocate(). Zwracany jest identyfikator nowego (lub bieżącego, jeżeli nie podano nowego koloru) koloru przezroczystego.

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);

?>

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 vic@zymsys.com)

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 ImageCreateFromJPEG() 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.

int ImageCreateFromJPEG (string filename)

Przykład: Obsługa błędu w czasie tworzenia rysunku (podziękowania dla vic@zymsys.com)

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 ImageCreateFromPNG() 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 vic@zymsys.com)

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;

}

ImageDashedLine

Rysuje na rysunku $im linię przerywaną z $x1, $y1 do $x2, $y2 (lewy górny róg to 0,0) o kolorze $col. Patrz również: ImageLine().

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 $im rozpoczynając od współrzędnych $x, $y (lewy górny róg to 0,0) kolorem $col.

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 $border. Punkt rozpoczęcia wypełniania to $x, $y (lewy górny róg to 0,0), kolor wypełnienia to $col.

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 ImageLoadFont().

int imagefontheight (int font)

ImageFontWidth

Zwraca szerokość znaku w pikselach dla określonej czcionki. Patrz również: ImageFontHeiht() i ImageLoadFont().

int ImageFontWidth (int font)

ImageGammaCorrect

Stosuje korekcję gamma na rysunku $im na podstawie wartości gamma wejściowej $inputgamma i wyjściowej $outputgamma.

int imagegammacorrect (int im, float inputgamma, float outputgamma)

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 $interlace jest 0, przeplot nie zostanie zastosowany. Funkcja zwraca bieżącą wartość bitu przeplotu dla rysunku.

int imageinterlace (int im [, int interlace])

ImageJPEG

Tworzy plik JPEG na podstawie rysunku $im. Parametr $im jest identyfikatorem zwracanym przez funkcję ImageCreate(). 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.

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 w bajtach

Typ danych C

Opis

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 — xxx

char

Tablica danych znakowych, jeden bajt na piksel w każdym znaku, razem (znaki*szerokość*wyskokość) bajtów

Patrz również: ImageFontWidth() i ImageFontHeight().

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)

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 $x1, $y1 i prawego dolnego $x2, $y2. Lewy górny róg rysunku ma współrzędne 0,0.

int ImageRectangle (int im, int x1, int y1, int x2, int y2, int col)

ImageSetPixel

Rysuje na rysunku $im piksel w kolorze $col na współrzędnych $x, $y (lewy górny róg to 0,0). Patrz również: ImageCreate() i ImageColorAllocate().

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)

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);

?>

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 quoted-printable. 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 imap_alerts(), 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.

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: me@my.host\r\n"

."To: you@your.host\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)

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 $flags jest maską bitową zawierającą jedną lub więcej wartości:

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.

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:

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";

$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().

int imap_deletemailbox (int imap_stream, string mbox)

imap_errors

Zwraca tablicę wszystkich komunikatów błędów IMAP wygenerowanych od ostatniego wywołania imap_errors() lub od początku skryptu. Po wywołaniu imap_errors() stos błędów jest czyszczony.

array imap_errors (void)

imap_expunge

Usuwa przesyłki zaznaczone jako usunięte przez imap_delete(), imap_mail_move() lub imap_setflag_full(). Zwraca True.

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:

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:

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

bytes

Ilość bajtów

ifdisposition

TRUE jeżeli jest to ciąg rozmieszczenia

disposition

Ciąg rozmieszczenia

ifdparameters

TRUE jeżeli istnieje tablica dparameters

dparameters

Tablica parametrów rozmieszczenia

ifparameters

TRUE jeżeli istnieje tablica parametrów

parameters

Tablica parametrów MIME

parts

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:

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);

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:

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 imap_getmailboxes(), ale zwraca jedynie skrzynki, do których użytkownik posiada subskrypcję.

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: remail, date, Date, subject, Subject, in_reply_to, message_id, newsgroups, followup_to, references.

imap_header( void )

Dostępne są następujące znaczniki wiadomości:

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'.

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 $ref i $pattern znajduje się przy opisie imap_getmailboxes().

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);

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

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: " . $check->Date ."<br>\n" ;

print "Driver: " . $check->Driver ."<br>\n" ;

print "Mailbox: " . $check->Mailbox ."<br>\n" ;

print "Messages: ". $check->Nmsgs ."<br>\n" ;

print "Recent: " . $check->Recent ."<br>\n" ;

print "Unread: " . $check->Unread ."<br>\n" ;

print "Deleted: " . $check->Deleted ."<br>\n" ;

print "Size: " . $check->Size ."<br>\n" ;

} else {

print "imap_check() 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"]="musone@afterfive.com";

$envelope["to"]="musone@darkstar";

$envelope["cc"]="musone@edgeglobal.com";

$part1["type"]=TYPEMULTIPART;

$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 US-ASCII, 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?= <keld@dkuug.dk>";

$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)

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:

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);

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:

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ą:

array imap_rfc822_parse_adrlist (string address, string default_host)

Przykład: imap_rfc822_parse_adrlist()

$address_string =

"Hartmut Holzgraefe <hartmut@cvs.php.net>, postmaster@somedomain.net, 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";

}

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 RFC822 (http://www/faqs.org/rfcs/rfc2045.html), na podstawie skrzynki pocztowej, hosta i danych osobistych.

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)

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 $reverse jest 1, sortowanie jest odwrotne.

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:

Opcje są maską bitową z następującymi wartościami:

imap_status

Zwraca obiekt zawierający dane statusu.

object imap_status (int imap_stream, string mailbox, int options)

Dozwolonymi znacznikami są:

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());

$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ę imap_delete() lub imap_move(). Zwraca True w przypadku powodzenia i False w przypadku błędu.

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)

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 False w przypadku niepowodzenia, natomiast w przypadku sukcesu, poprzednią wartość opcji.

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(), ini_restore() i ini_set().

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 $haystack. Zwraca True, jeżeli ciąg zostanie znaleziony w tablicy i False, jeżeli nie zostanie znaleziony.

bool in_array (mixed needle, array haystack)

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 False gdy nie istnieje. Jeżeli zmienna została usunięta za pomocą unset(), funkcja isset() zwraca False.

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 False, gdy nią nie jest. Patrz również: is_float(), is_int(), is_integer(), is_string() i is_object().

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)

is_double

Zwraca True, jeżeli parametr $var jest liczbą double, w przeciwnym wypadku zwraca False. Patrz również: is_bool(), is_int(), is_integer(), is_string(), is_array() i is_object().

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_long(). Patrz również: is_bool(), is_float(), is_integer(), is_string(), is_array() i is_object().

bool is_int (mixed var)

is_integer

Alias do is_long(). Patrz również: is_bool(), is_float(), is_integer(), is_string(), is_array() i is_object().

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 False. Patrz również: is_bool(), is_float(), is_integer(), is_string(), is_array() i is_object().

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)

is_object

Zwraca True, jeżeli $var jest obiektem, w przeciwnym wypadku zwraca False. Patrz również: is_bool(), is_int(), is_integer(), is_float(), is_string() i is_array().

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 False. Patrz również: is_bool(), is_int(), is_integer(), is_float(), is_real(), is_object() i is_array().

bool is_string (mixed var)

is_subclass_of

Zwraca True, jeżeli $obj jest obiektem klasy, która jest klasą pochodną po $superclass, w przeciwnym wypadku zwraca False. Patrz również: get_class(), get_parent_class().

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ą 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 (angielski-gregoriań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)

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 = cytryna

c = jabłko

b = banan

a = 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().

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 = pomarańcza

b = banan

c = jabłko

d = 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"]="jonj@here.and.now";

$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";

}

?>

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 False. 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.

int ldap_connect ([string hostname [, int port]])

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 False w przypadku błędu. Funkcja ldap_delete() usuwa pozycję z katalogu LDAP określoną przez $dn.

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ą 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 True 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.

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:

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 False w przypadku błędu. Funkcja ldap_get_dn() jest używana do sprawdzenia DN pozycji wyniku.

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, False. 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).

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

// 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 ldap_get_values_len() 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.

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)

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 ldap_next_attribute() 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().

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 ldap_read() 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().

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 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:

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 False w przypadku błędu. Funkcja ldap_unbind() odłącza od katalogu LDAP.

int ldap_unbind (int link_identifier)

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:

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ż: symlink() do tworzenia łącz symbolicznych oraz readlink() i linkinfo().

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ę 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. list() jest używane do przypisywania wartości do listy zmiennych przy pomocy jednej operacji.

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ą:

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 i-node

liczba dowiązań

identyfikator właściciela

identyfikator grupy

typ urządzenia, jeżeli jest to urządzenie z i-node *

rozmiar w bajtach

czas ostatniego dostępu

czas ostatniej modyfikacji

czas ostatniej zmiany

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 $to. Można podać wielu odbiorców umieszczając średnik pomiędzy adresami przekazanymi w parametrze $to.

bool mail (string to, string subject, string message [, string additional_headers

[, string additional_parameters]])

Przykład: wysyłanie poczty

mail("rasmus@lerdorf.on.ca", "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.

Przykład: Wysyłanie wiadomości z dodatkowymi nagłówkami

mail("nobody@aol.com", "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 <mary@u.college.edu>" . ", " ; //zwróć uwagę na przecinek

$recipient .= "Kelly <kelly@u.college.edu>" . ", ";

$recipient .= "ronabop@php.net";

/* 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 <birthday@php.net>\n";

$headers .= "X-Sender: <birthday@php.net>\n";

$headers .= "X-Mailer: PHP\n"; // klient poczty

$headers .= "X-Priority: 1\n"; // wiadomość ważna!

$headers .= "Return-Path: <birthday@php.net>\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: birthdayarchive@php.net\n"; // CC

$headers .= "bcc: birthdaycheck@php.net, birthdaygifts@php.net"; // 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)

mcal_date_valid

Zwraca True, jeżeli podany rok, miesiąc i dzień jest prawidłową datą lub False, gdy nie jest to data prawidłowa.

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ść 1 — publiczna lub 0 — prywatna. Zwraca True.

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

[, 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:

Wszystkie pozycje zawierające datę i czas są obiektem zawierającym:

mcal_fetch_event

Pobiera zdarzenie ze strumienia kalendarza określonego przez $id.

object mcal_fetch_event (int mcal_stream, int event_id [, int options])

Zwraca obiekt zdarzenia zawierający następujące atrybuty:

Wszystkie pozycje zawierające datę i czas są obiektem zawierającym:

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])

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 True w przypadku powodzenia a False w przypadku błędu.

int mcal_store_event (int mcal_stream)

mcal_time_valid

Zwraca True, jeżeli podana godzina, minuta i sekunda tworzą prawidłowy czas, False gdy jest to czas nieprawidłowy.

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])

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])

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])

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])

Patrz również mcrypt_cbc(), mcrypt_cfb() i mcrypt_ofb().

mcrypt_encrypt

Szyfruje dane i zwraca ich zaszyfrowaną postać.

string mcrypt_encrypt (string cipher, string key, string data, string mode

[, string iv])

Przykład: mcrypt_encrypt()

<?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 $td, w bajtach.

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)

mcrypt_enc_is_block_algorithm_mode

Zwraca 1, gdy tryb jest używany przez algorytm blokowy, w przeciwnym przypadku zwraca 0 (na przykład, 0 dla stream a 1 dla cbc, cfb, ofb).

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 $td. Jeżeli test się uda, zwraca 0. W przypadku błędu zwraca 1.

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)

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)

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>";

}

?>

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 $lib_dir można podać miejsce, gdzie są zapisane moduły trybów.

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 $lib_dir można 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,

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])

Patrz również: mcrypt_cbc(), mcrypt_cfb() i mcrypt_ecb().

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.

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 <lphilips@verity.com>. 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 $object zdefiniowana jest metoda $method_name. W przeciwnym przypadku zwraca False.

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)

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 0 gdy obowiązuje czas letni lub na -1 (domyślnie) gdy nie wiadomo jaki czas obowiązuje.

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 date ("M-d-Y", mktime (0,0,0,12,32,1997));

echo date ("M-d-Y", mktime (0,0,0,13,1,1997));

echo date ("M-d-Y", mktime (0,0,0,1,1,1998));

echo date ("M-d-Y", mktime (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);

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 msql_pconnect(). Patrz również: msql_connect() i msql_pconnect().

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. 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).

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:

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)

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 msql_dbname() do odczytania tego znacznika wyniku.

int msql_list_dbs (void)

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 msql(). Do pobrania wyniku na podstawie znacznika powinna zostać użyta funkcja msql_table_name().

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)

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().

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])

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 mssql_fetch_array() i prawie tak samo szybka jak mssql_fetch_row() — różnica jest nieznaczna. Patrz również: mssql_fetch_array() i mssql_fetch_row().

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)

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 mssql_pconnect() 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()).

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(). Patrz również: mt_rand(), mt_srand(), rand(), srand() i getrandmax().

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 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 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().

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 mysql_dbname(). Nie jest to jednak zalecane.

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])

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)) {

echo "ID użytkownika: ".$row["user_id"]."<br>\n";

echo "ID użytkownika: ".$row[0]."<br>\n";

echo "Pełna nazwa : ".$row["fullname"]."<br>\n";

echo "Pełna nazwa : ".$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:

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";

}

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 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 $result jest identyfikatorem zapytania, a $field_index jest numerem kolejnym pola.

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;

$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

...

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 mysql_db_query(). 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().

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 mysql_pconnect() 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.

resource mysql_pconnect ([string hostname [:port] [:/path/to/socket]

[, string username [, string password]]])

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])

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

[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 <BR> wstawionymi przed wszystkimi znakami nowej linii. Patrz również: htmlspecialchars(), htmlentities() 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_start() i ob_end_flush().

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 False, jeżeli buforowanie wyjścia nie jest aktywne. Patrz również: ob_start() i ob_get_length().

string ob_get_contents (void)

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, thies@thieso.net (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)) {

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>";

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ż: OCINumCols(), OCIColumnName() i OCIColumnSize().

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, thies@thieso.net (980219) */

$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ą:

OCIFetchStatement

Pobiera wszystkie wiersze wyniku do tablicy zdefiniowanej przez użytkownika. Funkcja OCIFetchStatement() zwraca ilość pobranych wierszy.

int OCIFetchStatement (int stmt, array &variable)

Przykład: OCIFetchStatement()

<?php

/* przykład OCIFetchStatement, mbritton@verinet.com (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 ) ) {

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 $onoff na 0 aby wyłączyć wyjście debugera, 1 aby je włączyć.

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 "<HTML><PRE>";

$db = "";

$c1 = ocilogon("scott","tiger",$db);

$c2 = ocilogon("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";

}

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);

?>

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 $type 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.

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

/* 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">

* ...

*/

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";

}

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 (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 OCIesult() zwraca wszystko poza typami abstrakcyjnymi (ROWID, LOB, FILE) w postaci ciągów.

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

UPDATE

DELETE

INSERT

CREATE

DROP

ALTER

BEGIN

DECLARE

UNKNOWN

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>";

}

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)

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

Tryb binarny

longreadlen

Wynik

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

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

Zwraca listę kolumn i uprawnień do nich dla podanej tablicy. Zwraca identyfikator wyniku ODBC lub False 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:

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

TABLE_OWNER

TABLE_NAME

COLUMN_NAME

DATA_TYPE

TYPE_NAME

PRECISION

LENGTH

SCALE

RADIX

NULLABLE

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 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:

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 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

PKTABLE_OWNER

PKTABLE_NAME

PKCOLUMN_NAME

FKTABLE_QUALIFIER

FKTABLE_OWNER

FKTABLE_NAME

FKCOLUMN_NAME

KEY_SEQ

UPDATE_RULE

DELETE_RULE

FK_NAME

PK_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.

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

DATA_TYPE

PRECISION

LITERAL_PREFIX

LITERAL_SUFFIX

CREATE_PARAMS

NULLABLE

CASE_SENSITIVE

SEARCHABLE

UNSIGNED_ATTRIBUTE

MONEY

AUTO_INCREMENT

LOCAL_TYPE_NAME

MINIMUM_SCALE

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ń INSERT, UPDATE i DELETE funkcja zwraca ilość zmienionych wierszy. Dla wyrażeń SELECT zwraca ilość zwracanych wierszy.

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)

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

TABLE_OWNER

TABLE_NAME

COLUMN_NAME

KEY_SEQ

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

PROCEDURE_OWNER

PROCEDURE_NAME

COLUMN_NAME

COLUMN_TYPE

DATA_TYPE

TYPE_NAME

PRECISION

LENGTH

SCALE

RADIX

NULLABLE

REMARKS

Wynik jest posortowany według kolumn 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 False w przypadku błędu.

int odbc_procedures (int connection_id [, string qualifier [, string owner [, string name]]])

Wynik zawiera następujące kolumny:

PROCEDURE_QUALIFIER

PROCEDURE_OWNER

PROCEDURE_NAME

NUM_INPUT_PARAMS

NUM_OUTPUT_PARAMS

NUM_RESULT_SETS

REMARKS

PROCEDURE_TYPE

Argumenty $owner, $proc i $column mogą zawierać wzorzec przeszukiwania (% zastępuje zero lub więcej znaków i _ zastępuje jeden znak).

odbc_result

Zwraca zawartość pola. Parametr $field może być liczbą określającą numer pola lub ciągiem zawierającym nazwę pola.

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 $connection_id. Zwraca True w przypadku pomyślnego wykonania operacji lub False w przypadku błędu.

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);

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

COLUMN_NAME

DATA_TYPE

TYPE_NAME

PRECISION

LENGTH

SCALE

PSEUDO_COLUMN

Wynik jest uporządkowany według kolumny SCOPE.

odbc_statistics

Odczytuje statystyki na temat tablicy i indeksów. Zwraca identyfikator wyniku ODBC lub False w przypadku błędu.

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

TABLE_OWNER

TABLE_NAME

NON_UNIQUE

INDEX_QUALIFIER

INDEX_NAME

TYPE

SEQ_IN_INDEX

COLUMN_NAME

COLLATION

CARDINALITY

PAGES

FILTER_CONDITION

Wynik jest uporządkowany według kolumn: NON_UNIQUE, TYPE, INDEX_QUALIFIER, INDEX_NAME i 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

TABLE_OWNER

TABLE_NAME

GRANTOR

GRANTEE

PRIVILEGE

IS_GRANTABLE

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_OWNER

TABLE_NAME

TABLE_TYPE

REMARKS

Wynik jest uporządkowany według: TABLE_TYPE, 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). 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 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

LOG_CONS

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 ... LOG_LOCAL7

Zarezerwowane.

LOG_LPR

Podsystem drukarki.

LOG_MAIL

Podsystem poczty.

LOG_NEWS

Podsystem USENET.

LOG_SYSLOG

Komunikaty generowane przez syslogd.

LOG_USER

Komunikaty generowane przez programy użytkownika.

LOG_UUCP

Podsystem UUCP.

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 $column z kursora $cursor. Zwracana nazwa zapisana jest wielkimi literami.

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:

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)

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 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 */

?>

OrbitObject

Klasa pozwalająca na dostęp do obiektu CORBA. Parametr $id powinien być ciągiem zawierającym Interoperable Object Reference (IOR) identyfikujący zdalny obiekt.

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 $string. Funkcja jest odwrotnością chr(). Patrz również: chr().

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ć 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:

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, port, user, pass, path, query i fragment.

array parse_url (string url)

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, $y-coor) i promieniu $radius. Patrz również: pdf_arc() i pdf_stroke().

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)

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_xxx(). Patrz również: pdf_open_jpeg(), pdf_open_gif() i pdf_open_memory_image().

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.

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, 190 );

ImageFill( $im, 10, 10, $col1 );

$pim = pdf_open_memory_image( $pdf, $pim );

pdf_put_image( $pdf, $pim );

pdf_execute_image( $pdf, $pim, 100, 100, 1 );

pdf_execute_image( $pdf, $pim, 200, 200, 2 );

pdf_close_image( $pdf, $pim )

?>

pdf_fill

Wypełnia wnętrze bieżącej ścieżki za pomocą bieżącego koloru wypełnienia. Patrz również: pdf_closepath(), pdf_stroke(), pdf_setgray_fill(), pdf_setgray(), pdf_setrgbcolor_fill() i pdf_sergbcolor().

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 pikselch. Patrz również: pdf_open_image_file(), pdf_open_memory_image() i pdf_get_image_width().

string pdf_get_image_height (int pdf_object, int image)

pdf_get_image_width

Zwraca szerokość rysunku pdf w pikselch. Patrz również: pdf_open_image_file(), pdf_open_memory_image() i pdf_get_image_heigth().

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])

pdf_lineto

Rysuje linię od punktu bieżącego do punktu o współrzędnych ($x, $y). Patrz również: pdf_moveto(), pdf_curveto() i pdf_stroke().

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 $filename. Formatem pliku musi być gif. Funkcja zwraca identyfikator rysunku pdf.

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_jpeg(), pdf_open_memory_image(), pdf_execute_image(), pdf_place_image() i pdf_put_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 );

?>

pdf_open_jpeg

Otwiera rysunek zapisany w pliku o nazwie $filename. Formatem pliku musi być jpeg. Funkcja zwraca identyfikator rysunku pdf.

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_png(), pdf_open_memory_image(), pdf_execute_image(), pdf_place_image() i pdf_put_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 $filename. Formatem pliku musi być png. Funkcja zwraca identyfikator rysunku pdf.

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_jpeg(), pdf_open_memory_image(), pdf_execute_image(), pdf_place_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 $filename. Formatem pliku musi być tiff. Funkcja zwraca identyfikator rysunku pdf.

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_jpeg(), pdf_open_png(), pdf_open_memory_image(), pdf_execute_image(), pdf_place_image() i pdf_put_image().

int pdf_open_tiff( int pdf_document, string filename )

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, $y). Jego szerokość wynosi $width a wysokość $height. Patrz również: pdf_stroke().

void pdf_rect (int pdf_object, float x, float y, float width, float height)

pdf_restore

Przywraca środowisko zapisane za pomocą pdf_save(). Działa podobnie do polecenia postscript restore. Patrz również: pdf_save().

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 );

?>

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ż: pdf_setrgbcolor_stroke() i pdf_setrgbcolor_fill().

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ż: pdf_setrgbcolor_stroke() i pdf_setrgbcolor_fill().

void pdf_setrgbcolor (int pdf_object, float red_value, float green_value,

float blue_value)

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 $style może mieć wartości solid lub dashed. Patrz również: pdf_set_border_color() i pdf_set_border_dash().

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]))

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 pdf_continue_text(). Patrz również: 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(). Patrz również: pdf_show() i pdf_show_xy().

void pdf_set_text_pos (int pdf_object, float x, float y)

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ć:

pdf_set_value

Ustawia numeryczne parametry pdflib. Patrz również: pdf_get_value(), pdf_get_parameter() i pdf_set_parameter().

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ż: pdf_show_xy(), pdf_show_boxed(), pdf_set_text_pos() i pdf_set_font().

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])

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 $alpha (x) i $beta (y) stopni. Parametry $alpha i $beta nie mogą wynosić 90 i 270 stopni.

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 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.

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.

HTTP_POST_FILES

Tablica asocjacyjna z informacjami na temat plików przesłanych za pomocą metody POST. Zmienna $HTTP_POST_FILES jest dostępna w PHP od wersji 4.0.0.

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.

E_ALL

Wszystkie stałe E_*. Jeżeli zostanie użyta w funkcji error_reporting(), powoduje raportowanie wszystkich problemów napotkanych przez PHP.


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.

--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-custom-odbc=/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.

--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.

--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).

--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 c-client.

--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).

--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.

--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”.

--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.

--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.


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 \.

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 (.).

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 system() i inne wywołujące inne programy, odmówią wykonania programów z katalogów innych niż podany.

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.

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.

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.

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 FALSE jeśli do pamięci. Możesz zmienić wartość tej dyrektywy korzystając z ifx_blobinfile_mode().

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.

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.


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

http://www.php4devguide.com/

Witryna poświęcona tek książce. Zawiera interesujące łącza i poprawki do tej książki.

http://www.mysql.com/

Oficjalna witryna bazy danych MySQL.

http://phpbuilder.com/

Świetna witryna zawierająca artykuły, przykładu kodu inne informacje związane z programowaniem w PHP.

http://www.thewebmasters.net/

Witryna FastTemplate i innych bibliotek klas używanych w tej książce.

http://phplib.netuse.de/

Witryna poświęcona PHPLib, biblioteki klas używanych w tej książce w niektórych przykładach dotyczących baz danych, sesji i autoryzacji.

Znak o kodzie zero (przyp. tłum.)

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.

6

Spis Treści

5

PHP - Kompendium wiedzy

10

Wstęp

22

Rozdział 1 - Kompilacja i instalowanie PHP

38

Rozdział 2 - Język

56

Rozdział 3 - Formularze i cookie

60

Rozdział 4 - Operacje na plikach

66

Rozdział 5 - Wysyłanie plików przez formularz

78

Rozdział 6 - Współpraca z bazami danych

94

Rozdział 7 - Sesje i stan aplikacji

104

Rozdział 8 - Uwierzytelnianie

114

Rozdział 9 - Niezależność od przeglądarki

130

Rozdział 10 - Uruchamianie

144

Rozdział 11 - Ponowne wykorzystanie kodu

158

Rozdział 12 - Oddzielanie kodu HTML od PHP

174

Rozdział 13 - Fajny PHP

188

Rozdział 14 - Witryny oparte o szablony

204

Rozdział 15 - Witryny oparte o bazę danych

210

Rozdział 16. Generowanie statycznych stron HTML w oparciu o dynamiczne dane

220

Rozdział 17. Witryny handlu elektronicznego

366

Dodatek A - Funkcje

370

Dodatek B. Predefiniowane zmienne i stałe PHP

380

Dodatek C. Opcje kompilacji PHP

388

Dodatek D. Opcje konfiguracji PHP



Wyszukiwarka

Podobne podstrony:
informatyka tworzenie stron www kurs wydanie iii radoslaw sokol ebook
informatyka tworzenie stron www ilustrowany przewodnik wydanie ii aleksandra tomaszewska ebook
Podstawy tworzenia stron WWW w języku HTML, wrzut na chomika listopad, Informatyka -all, INFORMATYKA
php i mysql tworzenie stron www vademecum profesjonalisty [helion] CONZDUWNFQFYUVVHCKLSSSQE7VYZR7HO
PHP Tworzenie stron WWW Szybki start
PHP i MySQL Tworzenie stron WWW Wydanie drugie Vademecum profesjonalisty
%5bpl+book%5d+fr+przechowywanie+i+wyszukiwanie+danych +z+ksi%b9%bfki+ php+i+mysql +tworzenie+stron+w
PHP i MySQL Tworzenie stron WWW Vademecum profesjonalisty Wydanie czwarte phmsv4
PHP i MySQL Tworzenie stron WWW Wydanie drugie Vademecum profesjonalisty phms2v
PHP i MySQL Tworzenie stron WWW Vademecum profesjonalisty Wydanie trzecie
PHP i MySQL Tworzenie stron WWW Wydanie drugie Vademecum profesjonalisty
rozdział tworzenie internetowej?zy?nych z php i mysql tworzenie stron www vademecum profesjonalisty
PHP i MySQL Tworzenie stron WWW VP Wyd3
PHP Tworzenie stron WWW Szybki start phpszs
PHP i MySQL Tworzenie stron WWW Wydanie drugie Vademecum profesjonalisty phms2v
PHP i MySQL Tworzenie stron WWW Vademecum profesjonalisty Wydanie trzecie 2
PHP Tworzenie stron WWW Szybki start phpszs
PHP i MySQL Tworzenie stron WWW Wydanie drugie Vademecum profesjonalisty phms2v

więcej podobnych podstron