PHP

nejen dynamicky generovanΘ strßnky

Jirka Kosek <jkj@ucw.cz>

Abstrakt

PHP je freewarov² systΘmem vhodn² pro dynamickΘ generovanφ webov²ch strßnek. Cφlem p°ednßÜky je seznßmit posluchaΦe se zßkladnφmi mo₧nostmi systΘmu -- zejmΘna se zpracovßnφm formulß°∙ a s mo₧nostmi propojenφ s r∙zn²mi databßzov²mi servery. Stranou nez∙stane ani porovnßnφ PHP s ostatnφmi technologiemi jako je CGI a ASP. V duchu celΘho seminß°e bude i struΦnß ·vaha nad intranetov²m informaΦnφm systΘmem, kter² m∙₧e b²t zcela vystaven pouze na free technologiφch jako je Linux, PHP a TeX a p°itom funkΦnostφ zdaleka p°edΦφt mnohΘ komerΦnφ systΘmy.

Konec statick²ch strßnek

Prvnφ implementace slu₧by World-Wide Web poΦφtaly s tφm, ₧e informace prezentovanΘ pomocφ HTML strßnek nebudou p°φliÜ prom∞nlivΘ v Φase, a proto byly HTML strßnky ulo₧eny v souborech. V p°φpad∞ pot°eby mohl autor strßnky jejφ text zm∞nit v souboru a od tΘ doby byla p°φstupnß novß podoba strßnky.

╚asem se p°iÜlo na to, ₧e koncept slu₧by WWW je natolik obecn², ₧e nenφ problΘm pomocφ stßvajφcφho modelu zp°φstupnit interaktivnφ slu₧by jako r∙znΘ vyhledßvacφ systΘmy apod. VÜe bylo postaveno na velice jednoduchΘm principu -- HTML strßnky ji₧ nejsou ulo₧eny v souboru, ale generovßny n∞jak²m programem, kter² umφ p°ebφrat parametry z formulß°∙ zaΦlen∞n²ch do strßnky. Proto₧e ji₧ HTML strßnky nejsou staticky umφst∞ny v souborech, ale generovßny podle pot°eby, hovo°φme o dynamicky generovan²ch strßnkßch.

Dφky dynamicky generovan²m strßnkßm se p°ed Webem objevil nov² sv∞t zp°φstup≥ovßnφ rozsßhl²ch databßzφ, podnikov²ch informaΦnφch systΘm∙ ovlßdan²ch pouze pomocφ prohlφ₧eΦe, virtußlnφch obchodnφch dom∙ apod. Dß se °φci, ₧e prohlφ₧eΦe se staly novou platformou pro provozovßnφ aplikacφ.

V poslednφ dob∞ sφlφ tlak, kter² nutn∞ vy·stφ v to, ₧e v∞tÜina strßnek dostupn²ch na Webu bude generovßna dynamicky. ╚φm je to zp∙sobeno? A¥ chceme nebo ne, dnes ji₧ hlavnφ t∞₧iÜt∞ Internetu nespoΦφvß na akademickΘ p∙d∞, ale v Φist∞ komerΦnφ oblasti. Pokud chce n∞jakß firma pomocφ svΘ webovΘ prezentace p°φpadnΘ zßkaznφky zaujmout, musφ nabφzet vφc, ne₧ jen jednou za p∙l roku aktualizovanΘ statickΘ strßnky.

U₧ivatel se na strßnky bude vracet pouze v p°φpad∞, ₧e zde Φasto najde n∞co novΘho. Pokud tedy p°i ka₧dΘ nßvÜt∞v∞ bude firemnφ strßnka dopln∞na jin²m vtipem Φi zde bude mo₧nost odpov∞d∞t na otßzku v n∞jakΘ sout∞₧i, poΦet nßvÜt∞vnφku a zejmΘna t∞ch opakovan∞ se vracejφcφch jist∞ stoupne. PodobnΘ chovßnφ Webu vÜak nelze dosßhnout pou₧itφm statick²ch strßnek, musφ se pou₧φt n∞jak² ze systΘm∙ pro dynamickΘ generovanφ strßnek.

Jestli₧e tedy p°ed rokem Φi dv∞ma bylo pro tv∙rce strßnek nezbytnΘ se nauΦit jazyk HTML, dnes je nejvyÜÜφ Φas na osvojenφ si n∞kterΘ technologie pro dynamickΘ generovßnφ strßnek. Jednou z t∞chto technologiφ je systΘm PHP s jeho₧ zßkladnφmi rysy se nynφ seznßmφme.

Dobr² den, jmenuji se PHP

Historie systΘmu PHP zaΦφnß zhruba v roce 1994, kdy Rasmus Lerdorf napsal jednoduch² systΘm pro evidenci p°φstupu ke strßnkßm. Tento systΘm se postupn∞ vyvφjel a₧ se z n∞j stal plnohodnotn² skriptovacφ jazyk s velice bohatou knihovnou funkcφ. Poslednφ verzφ PHP je 3.0, ostrß verze je k dispozici od Φervna 1998. P°ibli₧n∞ jednou za m∞sφc je uvoln∞na novß podverze, kterß obsahuje opravy chyb p°edeÜl²ch verzφ a Φasto p°idßvß podporu pro dalÜφ novΘ knihovny.

Prßce s PHP je velice jednoduchß a intuitivnφ. Na mφsto psanφ program∙, kterΘ ve v²sledku vygenerujφ HTML, pou₧φvß PHP opaΦn² p°φstup. Do HTML strßnky m∙₧eme zapsat p°φkazy PHP, jejich₧ v²sledek se po interpretaci skombinuje s okolnφm HTML k≤dem.

Syntaxe PHP je p°evß₧n∞ odvozena z jazyka C. N∞kterΘ rysy jsou p°evzaty z Perlu a z Javy -- nap°. asociativnφ pole a t°φdy. Krom∞ jednoduchΘho a mocnΘho jazyka, je velikou devizou PHP obrovskΘ mno₧stvφ zabudovan²ch funkcφ, kterΘ mimo jinΘ zahrnujφ:

Dosud nezmφn∞nou a p°itom velice podstatnou vlastnostφ PHP je jeho nezßvislost na platform∞. PHP pracuje pod operaΦnφmi systΘmy Unix, Windows 95/98/NT a Macintosh. Existujφ i projekty, kterΘ se sna₧φ o portovßnφ PHP na r∙znΘ starÜφ mainframe. Krom∞ nezßvislosti na operaΦnφm systΘmu je PHP nezßvislΘ na pou₧itΘm WWW-serveru. PHP m∙₧e spolupracovat s libovoln²m serverem, kter² podporuje rozhranφ CGI -- to dnes podporujφ snad vÜechny servery. Pokud pou₧φvßme Apache, m∙₧e b²t PHP spuÜt∞no jako jeho modul, Φφm₧ dosßhneme mnohem vyÜÜφho v²konu a v∞tÜφ bezpeΦnosti. P°ipravovanß verze PHP 3.1 bude zahrnovat i moduly ISAPI (Microsoft), NSAPI (Netscape) a WSAPI (O'Reilly) a umo₧nφ b∞h PHP jako modulu na v∞tÜin∞ WWW-server∙ pod Windows.

P°enositelnost skript∙ napsan²ch v PHP je velkou v²hodou. Pom∞rn∞ Φasto si dnes r∙znΘ firmy a instituce po°izujφ server s Windows NT. A₧ Φasem zjistφ, ₧e to z hlediska stability a v²konu nebyla nejlepÜφ volba. Pokud p°i vytvß°enφ dynamick²ch strßnek pou₧ijφ PHP, nenφ ₧ßdn² problΘm na poΦφtaΦi nainstalovat n∞jak² Unix podporujφcφ platformu Intel (Linux, FreeBSD, Solaris) a strßnky napsanΘ v PHP provozovat vesele dßl.

Lehk² ·vod do PHP

Vytvß°enφ jednoduch²ch skript∙ v PHP se p°φliÜ neliÜφ od tvorby b∞₧n²ch webov²ch strßnek. Pouze strßnky uklßdßme do soubor∙ s p°φponou php nebo php3, aby se odliÜily od strßnek, kterΘ neobsahujφ p°φkazy pro PHP. P°φkazy PHP zapisujeme mezi znaky '<?' a '?>'.

S vyu₧itφm funkce Date() nenφ problΘm na vÜech strßnkßch zobrazovat nap°φklad aktußlnφ Φas:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Ukßzka pou₧itφ funkce Date</TITLE>
</HEAD>
<BODY>
<DIV ALIGN=CENTER>
<H1>Vφtejte na naÜem serveru</H1>
<P>Prßv∞ je <?echo Date("H:i:s")?>
</DIV>
</BODY>
</HTML>

V ukßzce jsme pou₧ili p°φkaz echo, kter² slou₧φ k vypisovßnφ hodnot. V naÜe p°φpad∞ vypisujeme hodnotu vrßcenou funkcφ Date(). Tato funkce vracφ informace o aktußlnφm datu a Φase zformßtovanΘ podle zadanΘ specifikace formßtu.

V²sledek pou₧itφ funkce Date()
V²sledek pou₧itφ funkce Date()

Formulß°e jsou vstupnφ branou do interaktivnφho sv∞ta Webu. Pomocφ formulß°∙ mohou u₧ivatelΘ na strßnkßch zadßvat objednßvky, klßst dotazy na r∙znΘ databßze apod. Aby vÜak nebyl formulß° jen Φernou dφrou, musφ k n∞mu existovat skript, kter² u₧ivatelem zadanß data zpracuje a na jejich zßklad∞ poskytne u₧ivateli adekvßtnφ odezvu.

My si snadnost prßce s parametry z formulß°e ukß₧eme na jednoduchΘ aplikaci. U₧ivatel do formulß°e zadß svΘ jmΘno a sv∙j v∞k. Skript pak vyslovφ nemilosrdn² soud nad jeho v∞kem. Nejprve vytvo°φme strßnku s formulß°em:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Jednoduch² formulß°</TITLE>
</HEAD>
<BODY>
<P>Vypl≥te nßsledujφcφ ·daje
<PRE>
<FORM ACTION="obsluha.php" METHOD=POST>
JmΘno: <INPUT NAME=Jmeno>
V∞k:   <INPUT NAME=Vek>
<INPUT TYPE=Submit VALUE="Odeslßnφ formulß°e">
</FORM>
</PRE>
</BODY>
</HTML>

Strßnka s formulß°em
Strßnka s formulß°em

Takto vytvo°en² formulß° vyvolß po odeslßnφ skript obsluha.php. Tomuto skriptu je p°edßn obsah vÜech polφ formulß°e. PHP automaticky pro vÜechna pole formulß°e vyrobφ prom∞nnΘ s odpovφdajφcφm nßzvem. Ve skriptu proto m∙₧eme pou₧φvat prom∞nnΘ $Jmeno a $Vek, kterΘ obsahujφ text zadan² u₧ivatelem do polφ pro jmΘno a v∞k. Nenφ tedy problΘm napsat skript, kter² generuje r∙znΘ v²stupy prßv∞ podle obsahu formulß°ov²ch polφ.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Obsluha formulß°e</TITLE>
</HEAD>
<BODY>
<H1>V²sledek obsluhy formulß°e</H1>
<?  
    echo $Jmeno." je ";
    if ($Vek < 10):
        echo "p∞knej mlφΦnßk";
    elseif ($Vek < 20):
        echo "teenager";
    elseif ($Vek < 60):
        echo "v nejlepÜφch letech";
    elseif ($Vek < 100):
        echo "pravd∞podobn∞ prarodiΦ";
    else:
        echo "n∞kde mezi stovkou a smrtφ";
    endif
?>.
</BODY>
</HTML>

V²sledek obsluhy formulß°e
V²sledek obsluhy formulß°e

Opravdovou lah∙dkou, kterou nßm PHP nabφzφ, je snadnß spoluprßce s databßzemi. Skripty mohou pomocφ jazyka SQL (Structured Query Language) provßd∞t s ·daji v databßzφch libovolnΘ operace.

Mo₧nosti praktickΘho vyu₧itφ databßzφ jsou opravdu velmi ÜirokΘ. My si ukß₧eme jednoduch² skript, kter² u₧ivatel∙m umo₧≥uje pohodlnΘ hledßvanφ v adresß°i firem.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Prohledßvßnφ adresß°e firem</TITLE>
</HEAD>
<BODY>
<H1>Prohledßvßnφ adresß°e firem</H1>
<FORM>
Zadejte zaΦßtek nßzvu firmy: <INPUT NAME=Nazev VALUE="<?echo $Nazev?>">
<INPUT TYPE=Submit VALUE="Hledej">
</FORM>
<HR>
<?
if ($Nazev!=""):
    $spojeni = ODBC_Connect("test", "", "");
    if (!$spojeni):
        echo "Nepoda°ilo se p°ipojit k databßzi.";
    else:
        $vysledek = ODBC_Exec($spojeni, 
                    "SELECT * FROM Adresy WHERE Nazev LIKE '$Nazev%'");
        if (!$vysledek):
            echo "Chyba p°i provßd∞nφ dotazu v databßzi.";
        else: 
            echo "PoΦet nalezen²ch adres: ".ODBC_Num_Rows($vysledek);
            echo "<TABLE CELLPADDING=2 CELLSPACING=0 BORDER=1>\n";
            echo "<TR BGCOLOR=SILVER><TH>Nßzev</TH><TH>Telefon</TH></TR>\n";
            while (ODBC_Fetch_Row($vysledek)):
                echo "<TR><TD>".ODBC_Result($vysledek, "Nazev")."</TD>";
                echo "<TD>".ODBC_Result($vysledek, "Tel")."</TD></TR>\n";
            endwhile;
            echo "</TABLE>\n";
        endif;
    endif;
endif;
?>
</BODY>
</HTML>

Ukßzka spoluprßce s databßzφ
Ukßzka spoluprßce s databßzφ

Dovolte alespo≥ struΦn² komentß° k celΘmu skriptu. NßÜ p°φklad pro p°φstup k databßzi pou₧φvß standardnφ rozhranφ ODBC. Je to jedna z mo₧nostφ, kterou PHP p°i p°φstupu k databßzφm nabφzφ. Volßnφm funkce ODBC_Connect() se p°ipojφme k databßzovΘmu serveru. Funkce ODBC_Exec() slou₧φ k zadßnφ dotazu v jazyce SQL. V²sledek dotazu postupn∞ zpracovßvßme pomocφ funkcφ ODBC_Fetch_Row() a ODBC_Result(). Jak jste jist∞ vytuÜili, funkce ODBC_Num_Rows() vracφ poΦet zßznam∙, kterΘ vyhovujφ dotazu. V²sledek pak p°ehledn∞ formßtujeme pomocφ tabulky.

PHP versus CGI

PHP samoz°ejm∞ nenφ jedin²m systΘmem, kter² umo₧≥uje dynamickΘ generovßnφ webov²ch strßnek. V∙bec prvnφ technologiφ, kterß umo₧≥ovala automatickΘ generovßnφ strßnek, byly CGI-skripty, jejich₧ nßzev je odvozen z rozhranφ CGI (Common Gateway Interface). Toto rozhranφ se pou₧φvß pro p°edßvßnφ dat mezi WWW-serverem a skriptem.

V²hodou CGI-skript∙ je jejich nezßvislost na pou₧itΘm programovacφm jazyce. StaΦφ, kdy₧ dan² programovacφ jazyk umφ pracovat se standardnφm vstupem a v²stupem. CGI-skripty se tak nejΦast∞ji pφÜφ v Perlu nebo p°φkazovΘm shellu p°φpadn∞ v C/C++.

Pou₧itφ CGI-skript∙ je vÜak v porovnßnφ s PHP pom∞rn∞ t∞₧kopßdnΘ a p°inßÜφ mnohem vφce potencionßlnφch bezpeΦnostnφch rizik. Prvnφm problΘmem je u₧ samotnΘ dek≤dovßnφ dat zφskan²ch z HTML-formulß°∙. Data odesφlanß prohlφ₧eΦem jsou upravena tak, aby bezpeΦn∞ p°e₧ila p°enos pomocφ protokolu HTTP. PHP data automaticky rozk≤duje do jejich p∙vodnφ podoby. V CGI-skriptu se o p°evod musφme postarat sami nebo pou₧φt n∞jakou knihovnu, kterß tuto prßci odvede za nßs.

DalÜφ nep°φjemnostφ je pon∞kud t∞₧kopßdnΘ kombinovßnφ HTML-k≤du s k≤dem CGI-skriptu. VeÜkerΘ HTML zde musφ b²t vygenerovßno pou₧itφm p°φkazu print nebo jeho obdoby. To v²vojß°i p°inßÜφ spoustu zbyteΦnΘho psanφ.

Asi nejv∞tÜφm problΘmem CGI-skript∙, zvlßÜt∞ pro zaΦφnajφcφ v²vojß°e, je um∞nφ napsat bezpeΦn² skript, kter² neumo₧nφ jeho zneu₧itφ hackerem. CGI-skripty psanΘ v p°φkazovΘm shellu nebo v Perlu lze oÜßlit odeslßnφm vhodn²ch dat. Pokud tato data obsahujφ specißlnφ znaky, kterΘ nap°φklad v shellu ukonΦujφ p°φkazy, m∙₧e hacker spustit na serveru prakticky libovoln² program. SprßvnΘ oÜet°enφ vÜech pro shell nebezpeΦn²ch znak∙ pot°ebuje notnou dßvku zkuÜenostφ.

Poslednφ argumentem, kter² hovo°φ pro PHP, je v²kon. Pokud PHP b∞₧φ jako modul serveru, je neustßle zavedeno v pam∞ti a m∙₧e velice rychle obsluhovat vÜechny po₧adavky. Pro ka₧d² po₧adavek, kter² mß b²t obslou₧en CGI-skriptem, musφ b²t spuÜt∞n nov² proces, co₧ nenφ ·kon zrovna nejrychlejÜφ. CGI-skript m∙₧e b²t rychlejÜφ v p°φpadech, kdy provßdφ n∞jakΘ Φasov∞ nßroΦnΘ operace -- zkompilovanΘ cΘΦko je mnohem rychlejÜφ ne₧ interpretovanΘ PHP. Nic vÜak nebrßnφ tomu napsat kritickΘ rutiny v C a pomocφ PHP API je zp°φstupnit jako funkce pro skripty v PHP.

Na velice podobnΘm principu jako PHP pracujφ i dalÜφ skriptovacφ jazyky jako ASP (Active Server Pages) a ColdFusion. Jednß se vÜak o komerΦnφ a nikterak levnΘ systΘmy. Jejich dalÜφ nev²hodou je malΘ spektrum podporovan²ch platforem. Dnes pracujφ pouze ve Windows a na p°enosu do Unixu se teprve pracuje.

Za hranice Webu

Dφky velkΘ flexibilit∞ Linuxu lze s PHP provßd∞t opravdu netuÜenΘ v∞ci. NaznaΦφme alespo≥ n∞kterΘ mo₧nosti. Napsat informaΦnφ systΘm, kter² bude p°φstupn² pomocφ dynamick²ch strßnek generovan²ch pomocφ PHP, nenφ problΘm. Ale co kdy₧ pot°ebujeme n∞co vytisknout? Tiskov² v²stup souΦasn²ch prohlφ₧eΦ∙ jist∞ nelze pova₧ovat za dostaΦujφcφ. Nic nßm ale nebrßnφ v umφst∞nφ tlaΦφtka tisk p°φmo na strßnku. Stiskem tohoto tlaΦφtka m∙₧eme vyvolat skript v PHP, kter² spustφ TeX a p°edß mu po₧adovan² dokument k vysßzenφ. Perfektn∞ zformßtovan² dokument pak m∙₧eme vytisknout na sφ¥ovΘ tiskßrn∞, kterß je nejblφ₧e u₧ivateli, kter² stiskem tlaΦφtka vyvolal tisk.

V podobn²ch p°φkladech bychom mohli pokraΦovat do nekoneΦna. ProΦ? Proto₧e pom∞r v²kon/cena je u Linuxu, PHP i TeXu nekoneΦno resp. ${v²kon\over cena} = \infty$.

DalÜφ informace o PHP