Smyslem skriptů je:
  1. poskytovat různým uživatelům různé informace,
  2. vytvářet stránky, které se hýbou.

To první pořídí lépe skripty pro server, to druhé skripty na klientovi. K tvorbě skriptů lze pořídit kupříkladu rozhraní CGI, či jazyk PHP.

CGI skripty

CGI ve skutečnosti není skriptovací jazyk, ale rozhraní, které popisuje, co všechno musí program (v dosud nespecifikovaném jazyku) splnit, aby bylo rozhraní schopno z něj vykřesat platnou webovou stránku.

Zásadní informace je, že skript zahajuje výstup zásahem do hlavičky stránky. Je povinný sdělit typ dat, která pošle(!), případně může ještě poslat volitelné informace jako například zákaz cachování stránky (Pragma: no-cache), stav spojení (Status: 204 No response)...

Stejně jako v HTTP je hlavička od dat oddělena novým (prázdným) řádkem. Naučení je tedy takové, že první prázdný řádek, který skript vypíše, odděluje hlavičku od těla. Člověk mnohdy na tento prázdný řádek zapomene a diví se, proč padají pětistovkové stavy, tedy chyby na straně serveru. Kromě zapomenutého oddělovače v tyto stavy ústí i situace, kdy člověk zapomene na celou hlavičku.

Za hlavičku skript vypíše celý obsah stránky, která se má poslat klientovi (od !DOCTYPE po /HTML). Jak jsme řekli výše, programovací jazyk pro rozhraní CGI není předem specifikován, platí, že můžete použít binární program, který se má na hardwaru serveru spustit (který získáte třeba z překladače jazyka C pro prostředí používané na serveru), pokud soubor začíná sekvencí #!, má se za to, že následuje jméno interpretu (tedy třeba #!/bin/bash spustí jako interpret Bourne-again-shell v adresáři bin, jehož výuka, předpokládám, bude předmětem výkladu o UNIXu). K předvádění příkladu prvního příkladu použijeme kromě tohoto shellu ještě Pascal, jehož překladač gpc lze použít k vygenerování skriptu a který předpokládáme, že čtenář aspoň částečně zná.

Příklad:

#!/bin/bash
echo 'Content-type: text/html'
echo
echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">'
echo '<title>Pokusná stránka</title>
echo '<p>Pokus s CGI... a nic než pokus'
echo '</html>
Mimochodem sekvence #!vychází z toho, že křížkem se ve skriptovacích jazycích obvykle zahajuje komentář.
Tentýž příklad v Pascalu by vypadal asi takto:
program pokus
begin
	writeln('Content-type: text/html');
	writeln;
	writeln('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">');
	writeln('<title>Pokusná stránka</title>');
	writeln('<p>Pokus s CGI... a nic jiného');
	writeln('</HTML>'
end.
Cvičení:
  1. Spusťte alespoň jeden z výše uvedených příkladů (přímo - ne přes rozhraní CGI), prohlédněte výstup a promyslete, co a proč skript dělá.
  2. Mohli bychom v příkladu v Pascalu použít místo writeln proceduru write? Proč?

Jelikož skripty povětšinou reagují na data poslaná ve formuláři, je zejména potřeba se k těmto datům dostat. Rozhraní CGI definuje, že pošlou-li se data metodou POST, skript je najde na standardním vstupu (ze kterého se v Shellu i Pascalu čte příkazem read (pokaždé s jinou syntaxí), tudíž uvedeme-li následující příklad jen v Shellu, nikoho snad nezmateme:
Příklad:

#!/bin/bash
echo 'Content-type: text/html'
echo
echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
echo '<title>Výpis metodou POST</title>'
echo '<p>Napsal jsi: '
while read a; do echo "$a" '<br>'
done
echo '...A to je všechno.'
Pošleme-li data metodou GET, objeví se v proměnné prostředí QUERY_STRING, tedy vypsat data je v tomto případě (alespoň v shellu) ještě jednodušší, nežli s metodou POST (není mi známo, jak s proměnnými prostředí zachází Pascal, proto příklad v Pascalu bude opět chybět.

Příklad:

echo "Napsal jsi: $QUERY_STRING"
Nahradíme-li tímto řádkem while-cyklus minulého příkladu, získáme skript, který vypíše data poslaná metodou GET.

Metodu, jejíž pomocí byla data odeslána, zjistíme z proměnné prostředí REQUST_METHOD.

Příklad:

#!/bin/bash
echo 'Content-type: text/plain'
echo
read pocet <citac
pocet=`expr $pocet + 1`
echo "Jsi $pocet. návštěvník."
echo "$pocet" >citac
Příklad si trochu rozeberme. Za hlavičkou načteme ze souboru citac první řádek do proměnné počet. Tuto hodnotu následně zvýšíme o jedna (pokud byla numerická, jinak nám vyjde nesmysl). Tuto zvýšenou hodnotu vypíšeme na standardní výstup (tedy do stránky) a také do souboru citac.

PHP skripty

PHP skripty tvoří jednu z možností, jak psát skripty na straně serveru. Oproti CGI skript píšeme do stránky, nikoliv stránku do skriptu. Podotkněme ještě, že kupříkladu oproti Javascriptu se stále jedná o skripty interpretované serverem.

Striktně vzato PHP je obyčejný interpretovaný programovací jazyk z rodiny programovacího jazyka C. Syntakticky a sémanticky je poměrně blízký Javascriptu. Hned zkraje upozorněme, že jazyk je case-sensitive, tedy záleží na velikosti písmen. Tedy chceme-li programovat v PHP, stačí napsat příslušné zdrojové texty. Co je na PHP netypické, je, že v souboru zdrojového textu nemusí být jen tento zdrojový text (v jazyku PHP), ale primárně jde o webovou stránku obsahující HTML. Zdrojové kódy PHP skriptů jsou ve stránce v dobře definovaném metatagu. Tento metatag je: <?PHP ....?>. Tedy před, resp. za špičatou závorku dáme znak otazník. Tento metatag lze povětšinou zkrátit (jelikož řetězec PHP říká, že půjde o skript interpretovaný interpretem jazyka PHP; že se má použít právě tento interpret je však zpravidla jasné z názvu souboru. Proto většinou stačí PHP-skript umístit do takovéhoto metatagu: <?    ?>.

Souborům obsahujícím PHP-skripty je zpravidla potřeba přiřadit koncovku php. Pokud soubory pojmenujeme jinak, webový server neví, že se má vůbec zabývat možností, že by příslušné stránky mohly obsahovat PHP-skripty a zpravidla by takto schovaný skript nebyl zinterpretován. Záleží ovšem zejména na konfiguraci webového serveru.

První věcí, kterou budeme pomocí PHP chtít provádět, je výpis (textu, čísel...). Výpis (do zdrojového kódu stránky) zajistíme pomocí klíčového slova echo. Ovládá se (syntakticky) stejně jako return, tedy za ně klademe výraz, který se má vypsat.
Příklad:

...
<body>
<? echo "nazdar"; ?>
<? echo '10 + 15 =';
echo 10+15;
?>
...
V příkladu vidíme trojí provedení příkazu echo. Poprvé vypisujeme textový řetězec, podruhé vypisujeme aritmetický výraz (tedy také řetězec), potřetí jde o číselný výraz (jehož výsledkem je číslo). Povšimněme si, že příklad ukazuje dva skripty (vidíme dva metatagy). V prvním je jeden (samostatný) příkaz, ve druhém jsou dva příkazy (oba ukončeny středníkem stejně jako v jakémkoliv jiném jazyku z rodiny jazyku C).

Na příkladu též rovnou vidíme, jak v PHP zacházet s čísly a jak s řetězci. Jak jsme řekli na začátku, jde o jazyk podobný Javascriptu, a tedy číselné a znakové konstanty chovají velmi podobně. Čísla prostě zapíšeme do zdrojového kódu, textové řetězce ohraničujeme uvozovkami nebo apostrofy. Zda použijeme apostrofy nebo uvozovky není zcela lhostejné, za nedlouho si ukážeme rozdíl, k tomu ovšem budeme potřebovat pracovat s proměnnými:

Proměnné v PHP mají jedno velké specifikum. Jejich jméno musí začínat znakem $. Tedy platným jménem proměnné může být například $cislo nebo $a, ale ne kupříkladu vysledek. Proměnné není potřeba definovat a proměnné mohou měnit datový typ (co do nich přiřadíme, to tam budeme mít). Jinak se s proměnnými pracuje vpodstatě shodně jako v ostatních programovacích jazycích, tedy lze je předávat jako parametry funkcím a lze je používat ve výrazech (jejichž hodnotu chceme vyčíslit). Základní operátory k tomu používané jsou prakticky totožné s Javascriptem:

+
sčítání
-
odčítání
*
násobení
/
dělení
%
zbytek po dělení
.
konkatenace (slepení řetězců)
&&
a současně (konjunkce)
||
nebo (disjunkce)
!
logická negace
>
větší než
<
menší než
>=
větší nebo rovno
<=
menší nebo rovno
==
porovnání na rovnost (rovná se)
!=
porovnání na nerovnost (nerovná se)
=
přiřazení
++
inkrementace
--
dekrementace
...
...
tedy vidíme, že výrazy se chovají úplně stejně jako v jakémkoliv jiném programovacím jazyku.

Dříve či později budeme potřebovat zdrojové texty okomentovat anebo část zdrojových předmětů zakomentovat. Ani na komentářích nás ovšem nic nepřekvapí. Komentáře existují dvou druhů. Buďto komentář do konce řádku zahájený dvěma lomítky:

// tady je komentář
tady už ne.
Druhý druh komentářů je na předem neomezený počet řádků. Zahájíme sekvencí /*, ukončíme */. Tedy takto: /* Zde je komentář bez ohledu na to, zda sem umístím konec řádku nebo ne. Ovšem v komentáři se nám nesmí objevit symbol konec komentáře, tedy posloupnost hvězdička-lomeno. */

Nyní se vraťme k rozdílům mezi apostrofy a uvozovkami:
Příklad:

<?php
$titulek = 'Pokus';
$jazyk = 's PHP.';
?>
<html>
<head>
<title><?php echo $titulek; ?></title>
</head>
<body>
<?php echo "Delame pokusy $jazyk"; ?>
</body>
</html>

V příkladu vidíme tři skripty. V prvním přiřazujeme do proměnných, v dalších dvou s těmito proměnnými pracujeme. Vidíme tedy mezi řečí, že po konci skriptu se obsahy proměnných neruší, ale zůstávají takové, jak jsme je nastavili. Obsah proměnné je zrušen až poté, co je vygenerována celá stránka. Tedy pokud bychom doufali, že do další stránky budeme schopni zanést data upočítaná na jedné stránce, mýlíme se a bylo by třeba použít něco jiného.

Dále si v příkladu povšimněme třetího řádku od konce. Vidíme něco jako textový řetězec, ovšem v textovém řetězci je proměnná. Toto je právě rozdíl mezi řetězci ohraničenými uvozovkami a apostrofy. Řetězec ohraničený apostrofy se dále neinterpretuje a je ponechán přesně tak, jak byl napsán. Oproti tomu řetězec ohraničený uvozovkami podléhá interpretaci, a tedy kromě escapových sekvencí (shodných ve všech jazycích - \n, \t, \r,...) je možné do řetězce ohraničeného uvozovkami napsat jméno proměnné a tato proměnná se (při vyhodnocování řetězce) zapíše na příslušné místo. Abychom zabránili zmatení, escapové sekvence taktéž fungují jen v řetězcích ohraničených uvozovkami.

Cvičení: V minulém příkladu změňte uvozovky na apostrofy a pozorujte změnu chování skriptu.

Základní řídící struktury

Základní řídící struktury jsou totožné prakticky ve všech jazycích z rodiny jazyka C. Ani zde nás nečeká překvapení, tedy:

if(podmínka)příkaz_nebo_blok
Kód v těle cyklu se vykoná právě když je podmínka splněna. Podotkněme, že příkaz se ukončuje středníkem, blok ne.
Příklad

if($a>10) echo "$a je větší než deset!\n";
if(podmínka) příkaz_nebo_blok else jiný_příkaz_nebo_blok - není-li podmínka splněna, provedeme jiný_příkaz_nebo_blok.
if($a>10) echo "$a je větší než deset!\n";
else{	echo '$a není větší než deset!';
	$a%=10;
	// ale teď už ano!
}
Příklad ukazuje rovnou několik věcí najednou. Blok (jak jste jistě očekávali) uzavíráme do složených závorek, v řetězci vypisujeme konec řádku, kromě toho $a bude v prvním případě nahrazeno hodnotou této proměnné (kdežto v else-větvi ne). A v závěru else-větve vidíme komentář.

while(podmínka) příkaz_nebo_blok
Cyklus while snad už nikoho ani nepřekvapuje.
Příklad

$a=0;
while(++$a<= 10)
	echo "$a\n";

for(inicializace;podmínka;inkrementační_výraz)příkaz_nebo_blok
Opět to samé, jako v ostatních jazycích.
Příklad

for($a=0;$a<10;$a++)
	echo "$a\n";

do... while(podmínka)
Opakujeme cyklus, dokud je podmínka splněna. Podmínka je poprvé vyhodnocena až po prvním průchodu cyklem. Víme tedy, že takovýmto cyklem se alespoň jednou projde.

switch(výraz)/
    case hodnota: kód_vykonatelný_pro_hodnotu_hodnota...}

Tuto řídící strukturu si nastudujte samostatně, chová se stejně jako v ostatních jazycích.

Cvičení:

  1. Zkoušejte modifikovat příklad s while-cyklem. Co se stane, pokud preinkrementaci (++$a) změníme na postinkrementaci ( $a++)? A co se stane, pokud tuto inkrementaci zkusíme provést na řádku výpisu, tedy kód změníme na: echo "$a++\n";?
  2. Zkuste si podobně pohrát s příkladem na for-cyklus. Zkoušejte, co lze (a co nelze) použít jako inkrementační kód.

Další operátory a funkce

Již v sekci základních operátorů jsme si řekli, že konkatenace (slepení) řetězců se provádí operátorem tečky. Tento operátor použijeme například pokud chceme poslepovat větu z jednotlivých dílků (podobně jako je slepování slyšet u staničních rozhlasů). Tečka funguje jako jakýkoliv jiný binární operátor. Tedy například můžeme lepit takto: $veta='jedna '.'a'.' jedna '."jsou". " dve";

Druhý zajímavý operátor je ternární operátor otazníku a dvojtečky. Často se stává, že do proměnné chceme přiřadit jednu ze dvou hodnot v závislosti na nějaké podmínce. Dosud jsme problém řešili řídící strukturou if ve stylu:

if($a==1)
	$b=1;
else	$b=2;
Pro tento případ (kdy chceme v každém případě přiřazovat do téže proměnné podle nějaké podmínky) existuje ternární operátor, kdy za podmínku napíšeme otazník, za otazník napíšeme výraz, který chceme vyhodnotit (případně přiřadit) v případě, že podmínka platí. Za tento výraz napíšeme dvojtečku a zapíšeme výraz, který chceme vyhodnotit v případě, že podmínka neplatí. Tedy výše zmíněný příklad bychom zapsali asi takto: $b=($a==1?1:2); Výraz v závorce je příkladem použití zmíněného ternárního operátoru. Pokud je podmínka ($a==1) splněna, "vyhodnotíme" jedničku, jinak vyhodnotíme dvojku. Výsledek tohoto výrazu přiřadíme do proměnné b.

Pokud chceme z nějakého důvodu práci PHP-skriptu ukončit (například zjistíme, že data nám nedávají dobrý smysl a nechceme nadělat zbytečnou škodu) a chceme-li při té příležitosti ohlásit chybu, můžeme využít funkci die. Této funkci jako parametr předáme řetězec s chybovým hlášením. Tedy například máme-li vydělit dvě čísla a zjistíme-li, že jmenovatel je nulový, není moc co dělat jiného, než ohlásit chybu (a čísla nedělit). Tedy kód by mohl vypadat například takto:

if($jmenovatel==0)
	die("Nulou není zdravé dělit!");
$podil=$citatel/$jmenovatel;
//Víme, že za funkcí die skript už nepokračuje.

Chceme-li, aby PHP-skript zasahoval do hlavičky, s výhodou využijeme volání funkce header, které jako jeden textový argument dáme řetězec, který chceme přidat do hlavičky. Tedy například
header("Content-type: octet/stream");
Funkci header je potřeba zavolat ještě před tím, než server začne posílat data (tedy ještě před generováním výstupu). Jinak skript spadne s hlášením, že hlavička už byla odeslána.

Dalším problémem, na který každou chvíli narážíme, je generování náhodných (resp. pseudonáhodných) čísel. Tento problém snadno vyřešíme zavoláním funkce rand. Tato funkce bere 0 - 2 parametry. Bez parametru generuje celá čísla mezi 0 na hodnotou vracenou funkcí getrandmax(). Funkce (rand) zavolaná se dvěma parametry min a max generuje celá čísla od min do max včetně obou mezí.

Generátor můžeme chtít zinicializovat pomocí funkce srand (která bere 0 nebo 1 argument), ale není to nutné. Pokud funkci dáme argument, je to tzv. seed (česky prý překládáme jako semínko). Tuto možnost využijeme, pokud chceme ladit padající aplikaci. Pokud zadáme pevně stanovený seed, pokaždé budeme generovat tatáž čísla. Pokud nám tedy aplikace spadne, můžeme se snadno podívat, co za čísla jsme jí nagenerovali.

Cvičení:

  1. Vyrobte skript generující tisíc náhodných čísel od 0 do 10.
  2. Vytvořte stránku, která bude zobrazovat jednu z deseti zpráv náhodně podle výsledku generátoru náhodných čísel.

Definice funkcí

V PHP lze definovat funkce velmi podobně jako například v Javascriptu. Syntax (a sémantika) je prakticky shodná. Definici zahajujeme klíčovým slovem function, za ním následuje jméno funkce, kulaté závorky, v nich případně seznam formálních argumentů a za kulatými závorkami závorky složené obsahující definici těla funkce. Návratová hodnota se vrací pomocí klíčového slova return. Tedy například funkci, která vezme několik argumetů (všimněte si, že v našem případě vezme argumenty právě tři) a vrátí první z nich, bychom napsali asi takto:
function prvni($arg1,$arg2,/*...*/$argn)
{	return $arg1;
}
Všimněme si, že tato funkce může snadno vracet hodnoty různých typů (v závislosti na tom jakého typu je první argument).

Cvičení: Napište si funkci, která bude vracet hodnoty různých typů nezávisle na parametrech. Ne že by taková funkce měla být k něčemu dobrá, ale je užitečné si uvědomit, že i to se může při programování v PHP snadno stát.

Podobně jako v Pascalu je i v PHP třeba funkce napřed definovat a pak až použít. V PHP je ovšem tento princip doveden do absurdního tvaru: Je třeba, aby před zavoláním funkce interpret přes definici dané funkce "přeběhl". Tedy pokud máme plochou funkční strukturu (nemáme jednu funkci definovanou uvnitř druhé), znamená to opravdu totéž, co v Pascalu. PHP nám umožňuje vložit definici jedné funkce do těla funkce jiné. V takovém případě je ona "vnitřní" funkce definována až poté, co interpret přes její definici proběhne. Zkusme si situaci vysvětlit na následujícím příkladu se jmény jen náhodně se podobajícími jménům jisté postavy v jistém filmu:

        function f()
        {       function g()
                {       echo "Je tam pan Vrana?\n";
                }
        }
	f();
        g();
Tento příklad bez potíží proběhne a vypíše: "Je tam pan Vrána?" Ovšem pokud bychom volání funkce f zrušili, skript spadne, jelikož funkce g nebude definována. My ovšem můžeme příklad ještě poněkud upravit:
        function f()
        {       function g()
                {       echo "Je tam pan Vrana?\n";
                }
        }
        function h()
	{
	        function g()
        	{       echo "Nejsem Vrana, jsem Kralik!\n";
	        }
	}
        h();
        g();
Tento příklad také úspěšně proběhne a vypíše: "Nejsem Vrana, jsem Kralik!" Ovšem pokud bychom mezi volání funkcí h a g vložili ještě volání funkce f, skript spadne, jelikož jednou definované funkce je zakázáno předefinovávat. PHP konečně nepodporuje přetěžování funkcí (dvě funkce téhož jména lišící se nějakým způsobem v parametrech). Proč tomu tak je, objasní následující odstavce:

Funkce se za jistých okolností mohou zavolat s méně parametry, než kolik jsme jich definovali. U některých parametrů můžeme říci, že mohou být implicitní. Uděláme to tak, že do nich v definici funkce přiřadíme implicitní hodnotu: function implicitni($a=1){} Tuto funkci půjde zavolat jak s jedním parametrem, tak bez parametru. Zavoláme-li funkci implicitni bez parametru, v těle funkce bude tato situace neodlišitelná od situace, kdy do dané proměnné dosadíme implicitní hodnotu, tedy jedničku.

Příklad:

function implicitni($a=1)
{	if($a!=1)
		echo "Funkci jsme zavolali s parametrem!";
	else	echo "Funkci jsme budto zavolali bez parametru, nebo s parametrem 1!";
}
implicitni(10);// Vypise: "Funkci jsme zavolali s parametrem!"
implicitni();// Vypise: "Funkci jsme zavolali bez parametru, nebo s..."
implicitni(1);// "Funkci jsme zavolali... s parametrem 1!"

Cvičení: Co se stane, pokud nedáme jako implicitní parametry ty poslední, ale například ty počáteční (function f($a=1,$b,$c){})?

Pole

Podobně jako kupříkladu v Pascalu můžeme přístupovat k polím, tedy entitám obsahujícím seznam prvků setříděný dle nějakého indexu. Jelikož PHP je interpretovaný jazyk, není potřeba předem upozorňovat na to, co budeme ve které proměnné skladovat, což speciálně platí i pro pole. Chceme-li použít proměnnou typu pole, prostě do ní přiřadíme výsledek funkce array asi takto: $pole=array(); a ještě k tomu můžeme jako argumenty zadat jednotlivé prvky pole, čili například takto:
$pole=array("jedna","dve","tri","ctyri","pet");
Pak získáme pole již zinicializované (tak, že první prvek má index 0) a k jednotlivým jeho položkám přistupujeme pomocí operátoru hranatých závorek: $pole[0] tedy bude mít hodnotu "jedna". Povšimněte si, že v jednom poli můžeme skladovat proměnné různých typů. Pro tuto vlastnost mě sice nenapadá rozumné využití, ale potřeba takovou možnost očekávat při čtení cizího kódu. Oproti mnoha jazykům je novinkou tzv. asociativní pole, které neindexujeme čísly, ale řetězci. Chceme-li vyrobit asociativní pole, postupujeme takto:
$garaz=array(prvni=>'Audi', druhe => 'Mercedes');
Jak bylo napsáno, toto pole není indexováno čísly, ale pomocí řetězců: $garaz[prvni] (jméno prvku můžeme dát do uvozovek nebo apostrofů, tedy též $garaz['prvni'] nebo $garaz["prvni"]). Vypisovat obsahy proměnných již umíme, činíme tak pomocí klíčového slova echo.

Taktéž si všimněte, že můžeme udělat děravé pole a navíc pole hybridní (kdy některé prvky budou indexovány asociativně, tedy řetězcem, kdežto jiné budou indexovány číslem). Například můžeme k předešlému příkladu s auty připojit řádek: $garaz[1000]='Zigulik'; V tom případě by nebyl definován žádný prvek s indexem menším než 1000.

S poli lze provádět i některé další lumpárny. Například lze přidat k poli: $garaz[]='Skodovka'; v našem příkladu na pokračování definuje prvek s indexem 1001 (protože zatím poslední prvek měl index 1000) a příslušným způsobem ho zinicializuje.

Prvek v poli lze taktéž zrušit zavoláním funkce unset, které jako parametr předáme rušený prvek. Tedy například: unset($garaz[1000]); zrušíme Žigulík.

Pokud máme v poli takový nepořádek, že už se v něm sami nevyznáme, můžeme dát pole "setřepat", tedy nechat vyrobit pole, ve kterém budou jednotlivé prvky indexovány od nuly bez chybějících indexů. Toto nám umožňuje funkce array_values, které jako parametr předáme setřásané pole. Funkce nám vrátí nové pole. Funkci bychom tedy mohli využít například takto: $nova_garaz=array_values($garaz);
Prvky jsou funkcí array_values seřazeny v pořadí, v jakém byly přidávány.

Cvičení: Jakým způsobem se dostaneme k hodnotě 8 v následujícím poli? $a=array(0 => 0, 1 => 1, "pepicek" => 7, 8);
Nápověda: Pokud nevíte, podívejte se do slidů.

Funkce print_r a var_dump

Snadno se může stát (a většině z nás se také stane), že ztratíme orientaci v obsazích vlastních proměnných. Z nějakého důvodu nebude fungovat to, co by dle našeho názoru fungovat mělo. Například nebude definován prvek pole s námi očekávaným indexem. Pokud se chceme podívat, co se s proměnnou děje, můžeme k tomu použít funkce print_r nebo var_dump. Obě funkce se ovládají podobně, ta druhá podává poněkud obsáhlejší informace. Je ovšem potřeba dát pozor na to, že výstup těchto funkcí by měl být prohlížen jako holý text (protože se v něm mohou vyskytovat znaky 62, tedy > - postačí jen si nechat vypsat pole). Tedy příklad:

<? header('Content-type: text/plain');
$a=array('Mercedes','Rolls-Royce',"pepicek"=>"Skodovka","Zigulik");
print_r($a);
echo "Tohle byla funkce print_r, ted pojede var_dump:\n";
var_dump($a);
?>
Výstup bude vypadat asi takto:
Array
(
    [0] => Mercedes
    [1] => Rolls-Royce
    [pepicek] => Skodovka
    [2] => Zigulik
)
Tohle byla funkce print_r, ted pojede var_dump:
array(4) {
  [0]=>
  string(8) "Mercedes"
  [1]=>
  string(11) "Rolls-Royce"
  ["pepicek"]=>
  string(8) "Skodovka"
  [2]=>
  string(7) "Zigulik"
}

Přístup k datům zaslaným pomocí formuláře

Jelikož PHP je jazyk navrhovaný speciálně pro interakci s HTML, byl by velmi vhodný nějaký interface, který by nám zpřístupnil údaje zaslané prostřednictvím webových formulářů. Ačkoliv jsme si již ukázali poměrně rozsáhlou část PHP, dosud není jasné jakým způsobem skriptu předávat vstup. To napravíme v této kapitole.

Jednou (a zároveň nejjednodušší) možností, jak se dostat k datům zaslaným prostřednictvím formuláře, je tzv. globální resoluce. Ta odkazuje k tomu, že pro prvek formuláře daného jména PHP vytvoří proměnnou stejného jména (ovšem se znakem $ na začátku). Tedy pokud ve formuláři máme například: <input type=text name=pepicek>, při zapnuté globální resoluci ve skriptu můžeme použít proměnnou $pepicek a v ní bude hodnota, kterou jsme ve formuláři do příslušného textového políčka vyplnili. Tato globální resoluce se nezřídka považuje za bezpečnostní riziko (jelikož se snadno může stát, že nebude existovat nějaká proměnná, na kterou se budeme ptát, případně se někdo může tímto způsobem pokusit změnit obsahy již existujících proměnných). Proto bývá většinou vypnuta a je potřeba použít jiný způsob.

Jinou metodou je naparsovat si řetězec zaslaný metodou GET. K tomuto řetězci se dostaneme prostřednictvím užitečného asociativního pole $_SERVER konkrétně přístupem k položce QUERY_STRING. Řetězec poslaný na server metodou GET (tedy část URI za otazníkem, který následuje za jménem skriptu) tak získáme jako $_SERVER['QUERY_STRING']. Pokud bychom byli masochisti, můžeme si tento řetězec naparsovat.

V dalším způsobu přístupu k submitnutým datům je potřeba rozlišit, zda data přišla metodou GET nebo POST. Podle toho používáme dvě z následujících čtyř asociativních polí: $_GET, $_POST, $HTTP_GET_VARS, $HTTP_POST_VARS. Druhé dvě možnosti fungovaly v PHP verze 4, první dvě se používají ve verzích 3 a 5 (v době používání verze 4 se v $_GET a $_POST našly chyby a tato asociativní pole bylo důrazně nedoporučeno používat, v PHP 5 naopak zmizela pole $HTTP_GET_VARS a $HTTP_POST_VARS. Pokud budeme používat PHP verze 5, budeme tedy používat první dvě jmenovaná asociativní pole a výklad na ně tedy nadále omezíme.

Jak jsme řekli, jde o asociativní pole indexovaná jmény jednotlivých prvků formuláře. Příslušné hodnoty pak jsou hodnotami pole. Tedy chceme-li přiřadit do proměnné $pepicek obsah výše uvedeného stejnojmenného textového pole, uděláme to takto: $pepicek=$_GET['pepicek'];
Pole $_POST funguje úplně stejně, jen je třeba myslet na to jakou metodou data na server posíláme.

Teď už sice víme, jak se dostat k uživatelem zadaným datům, ale je třeba dát pozor na předčasnou radost. Uživatelé totiž nejsou dobráci a snadno nám mohou poslat řetězec, kterým nám budou chtít uškodit. Konkrétně mohou mít ambice koukat na obsahy našich proměnných (a to zejména těch obsahující přístupová jména a hesla). Taktéž (až se budeme učit o práci s MySQL) mohou chtít ukončit jeden SQLský dotaz a zahájit jiný (začínající pokud možno příkazem drop). Pokud nám přijde řetězec, je vhodné jej tzv. oescapovat, tedy deaktivovat všechny potenciálně nebezpečné znaky. Zejména se jedná o ASCII-znaky 39 (apostrof) a 92 (zpětné lomítko, backslash alias zvrhlítko). Před každý z nich tak budeme chtít pro jistotu umístit jednou znak 92 (\). Buďto použijeme nějakou již existující funkci (kterou si najdeme v manuálu k PHP), nebo si ji vyrobíme sami například na způsob toho, jak je uvedena na roscripts.com:

<?php
function escape_string($str) {
	if ($str !== null) {
		$str = str_replace(array('\\','\''),array('\\\\','\\\''),$str);
		$str = "'".$str."'";
	} else {
		$str = "null";
	}
	return $str;
}
?>
Příklad nám ukazuje použití funkce str_replace. Tato funkce bere tři parametry. Třetí je řetězec, ve kterém chceme nahrazovat. První parametr je pole určující které podřetězce budeme nahrazovat, druhý parametr je pole stejné délky a říká čím budeme nahrazovat. Tedy znak \ nahradíme dvěma takovými a znak ' nahradíme posloupností \'. Z existujících knihovních funkcí řetězec "obrní" například funkce mysql_escape_string. Této funkci se jako parametr předá řetězec a funkce nám vrátí takový řetězec, který lze bez obav poslat funkcím pracujícím s MySQL. Pozor, pro jiné účely takový řetězec v pořádku být nemusí.

Příklad:

$text=mysql_escape_string($text);
Příklad ukazuje použití funkce mysql_escape_string. Jako parametr jí dáváme proměnnou $text, výsledek přiřadíme do téže proměnné.

Nyní již sice víme, jak se dostat k datům z prvků formuláře, nevíme však, co máme čekat od jednotlivých datových typů ve formuláři. Přesněji víme to u textového políčka. V zásadě je to jednoduché - vrací se nám hodnota atributu value. Z této informace je jasné, co čekat od textového políčka, políčka na heslo a prvku hidden. Pro checkboxy a radiobuttony si situaci raději rozeberme podrobněji. U checkboxů je situace jednodušší: Pokud checkbox není zatržen, vrátí se prázdný řetězec. Pokud checkbox zatržen je, vrátí se nám obsah jeho atributu value. Pokud není atribut value nastaven, vrací se řetězec "on".

Radiobutton je z těchto prvků asi nejzrádnější, ačkoliv v něm platí totéž, co pro checkbox. Tedy máme-li radiobutton sestávající z několika možností, je nám vrácen atribut value pro příslušnou možnost. Pokud atribut value nedefinujeme, vrátí se nám hodnota on. Asi je jasné, že bude legrační, pokud zapomeneme radiobuttonu definovat atribut value pro více než jednu možnost (takové možnosti pak od sebe neodlišíme).

Příklad:

<form action="nic.php">
<input type="text" name="text1">
<input type="checkbox" name="chkbox">
<input type="radio" name="televize" value="prvni">
<input type="radio" name="televize" value="druhy">
<input type="radio" name="televize">
</form>
Skript může následně získat hodnoty takto:
$text=$_GET["text1"];
$chkbox=$_GET["chkbox"];
$televize=$_GET["televize"];
V jednotlivých proměnných potom bude:
$text
vyplněný obsah textového políčka
$chkbox
nic nebo hodnota on (jelikož jsme nespecifikovali atribut value),
$televize
nic (pokud není vybráno nic), prvni, druhy nebo on podle toho, který z těch tří prvků je vybrán. Všimněme si, že třetímu jsme nedefinovali atribut value, proto, pokud je vybrán, bude vrácena hodnota on stejně jako v případě checkboxu.

Cvičení: Vyzkoušejte si zasílání dat na server pomocí formulářů pro různé typy vstupních prvků (text, radio, select a podobně).

Přijetí souboru z formuláře

Zatím jsme se poměrně důsledně vyhýbali zpracování jednoho prvku formuláře, a to souboru. Soubor lze nahrát metodou POST, ovšem je zapotřetí udělat to rafinovaně. Vše začíná už u příslušného formuláře, který nám bude odesílání zajišťovat. Tomu je potřeba nastavit atribut enctype na hodnotu multipart/form-data. Formulář by pak mohl vypadat asi takto:

<form enctype="multipart/form-data" action="skript.php" method=POST>
Tady se nahraje soubor: <input type=file name=soubor>
<input type=submit>
</form>
PHP nám nahrané soubory zpřístupní v asociativním poli $_FILES (v PHP verze 4 se jmenovalo $HTTP_POST_FILES). Toto pole je opět indexováno jmény prvků ve formuláři (tedy v našem případě bychom hledali položku "soubor". Každý prvek tohoto asociativního pole (tedy například $_FILES[soubor]) je též asociativní pole několika prvků a můžeme v něm najít zejména:
tmp_name
jméno (včetně cesty) pod kterým soubor najdeme nahraný dočasně na serveru (z tohoto umístění je smazán po konci skriptu),
name
jméno pod kterým byl uložen na odesílajícím stroji,
size
velikost,
type
typ (MIME - kupříkladu image/png).

Napřed (před zpracováním souboru) je vhodné se ujistit, zda byl soubor opravdu nahrán (zda nedošlo k chybě). To uděláme zavoláním funkce is_uploaded_file, které jako parametr dáme jméno souboru (který má existovat ve filesystému), tedy:
is_uploaded_file($_FILES[jmeno_prvku_formulare][tmp_name]); Funkce vrací true, pokud je soubor nahrán, false jinak.

Chceme-li soubor zpracovat, chceme jej buďto přečíst (což se budeme učit za nedlouho (a v takovém případě použijeme jako jméno souboru $_FILES[jmeno_html_prvku][tmp_name]) anebo jej chceme okopírovat na stálé místo (kde nebude po konci skriptu smazán). V tom případě můžeme použít funkci copy(odkud,kam); Jméno odkud bude odkazovat opět k tmp_name.

Elementární práce se soubory

Fundamentální práci se soubory můžeme provést podobně, jako v Pascalu:

Příklad (odesílající formulář):

<FORM submit="skript_zapis.php">
<input type="text" name="textik">
<input type="submit">
</form>

Příklad (zapíšeme na konec souboru):

$soub=fopen("soubor.txt","a");
puts($soub,$textik);
fclose($soub);

Příklad (vypíšeme soubor):

$soub=fopen("soubor.txt","r");
if($soub)
{
        $puvobs=fread($soub , filesize ($filen));
        fclose($soub);
}
$soub=fopen($filen,"rw+") or die("<b>Nelze otevřít soubor!</b>");
fputs($soub, "<span class=\"jmeno\">$jmeno</span><br>");
fputs($soub, "<span class=\"obsah\">$text</span><p>");
fwrite($soub, $puvobs);
fclose($soub);

Spojení s MySQL-serverem

PHP je výkonný skriptovací jazyk, který mimo jiné umožňuje komunikovat s databázemi (jelikož většina skriptů, které potřebujeme, beztak reprezentují jen nějakou manipulaci s databázemi). My si popíšeme rozhraní, kterého lze využít při spolupráci s MySQL-serverem. MySQL se používá zejména proto, že je poměrně jednoduchý. Použití MySQL v PHP není samozřejmé, musí být zapnuta podpora jeho interpretace.

Od PHP verze 6 byla podpora MySQL přepsána na tzv. MySQL Improved. Tato implementace je objektová (operuje s třídou mysqli reprezentující jedno připojení k databázi). Jelikož jsme se objekty dosud nezabývali (a budeme se o nich bavit jen okrajově, jelikož objekty v PHP nejsou příliš vzorem toho, jak by měly objekty vypadat), budeme využívat funkce volající jednotlivé metody třídy mysqli. Služeb serveru tedy využíváme pomocí zvláštních funkcí. Těmto funkcím zadáváme jako argumenty řetězce obsahující SQL-dotazy, například select * from telef;

$conn=mysqli_connect("adresa_stroje_s_db","login","heslo");
nebo $conn=mysqli_connect("adresa","login","heslo","databaze"); připojí "skript" k serveru dle zadaných údajů. Funkce bere čtyři parametry, z nichž čtvrtý je implicitní (tedy není třeba jej nastavovat). Pokud jej nastavíme, rovnou vybereme databázi, se kterou budeme pracovat (pak nemusíme volat mysqli_select_db). Nejspíše se používá připojení k místnímu stroji, jelikož připojení po síti bývá zakázané). Funkce vrací objekt popisující připojení. Tento objekt reprezentuje naše spojení a je třeba jej předávat téměř všem následujícím funkcím (podobně jako pracujeme-li se soubory, předáváme objekt popisující otevřený soubor).

mysqli_close($conn); odpojí od serveru - konec SQL,

mysqli_select_db($conn,"jmeno_databaze"); vybere databázi,

$vysledek=mysqli_query($conn,"pozadavek"); provede požadavek, výsledkem je objekt popisující odpověď (SQL-serveru). Tento objekt je osazen metodami a atributy umožňujícími nám získat o odpovědi konkrétní informace:

$pocet=mysqli_num_rows($vysledek);
zjistí počet serverem vrácených řádek, ekvivalentně tuto informaci získáme:
$pocet=$vysledek->num_rows;
tedy přečteme objektu reprezentujícímu odpověď atribut num_rows

$asoc_pole=mysqli_fetch_assoc($vysledek);
odebere z odpovědi serveru první řádek a vytvoří z něj asociativní pole. Prvky pole jsou indexovány názvy sloupců (které odpověď obsahuje). Při dalším zavolání zpracuje (tedy vydá) další řádek odpovědi (jde tedy o funkci dotyčný objekt postupně destruující). Jde o ekvivalent zavolání metody fetch_assoc objektu reprezentujícímu odpověď:
$asoc_pole=$vysledek->fetch_assoc();

$pole=mysqli_fetch_array($vysledek);
odebere z odpovědi serveru první řádek a vytvoří z něj pole (neasociativní, tedy prvky jsou indexovány přirozenými čísly - od nuly včetně). Ekvivalentní zavolání metody fetch_array objektu reprezentujícímu odpověď:
$pole=$vysledek->fetch_array();

$prvek=mysqli_fetch_field($vysledek);
odebere z odpovědi serveru jeden prvek. Ekvivalentní zavolání metody fetch_field objektu reprezentujícímu odpověď:
$prvek=$vysledek->fetch_field();

Příklad: Chceme z tabulky adresy v databázi zakaznici získat všechny prvky jmeno a setříděné podle abecedy vypsat do tabulky (s jedním sloupcem):

<table>
<caption>Jména zákazníků</caption>
<tr><th>Jmeno
<?
@$conn=mysqli_connect("localhost","root","heslo","zakaznici");
$r=mysqli_query($conn,"select jmeno from adresy order by jmeno;");
$num_rows=mysqli_num_rows($r);
for($i=0;$i<$num_rows;$i++)
	echo "<tr><td>".mysqli_fetch_assoc($r)["jmeno"];
mysqli_close($conn);
?>
V příkladu vidíme (kromě toho, co vidět máme) na prvním řádku skriptu (volání funkce mysql_connect) využití unárního prefixního operátoru zavináče (česky "obchodní a" - @). Tento operátor lze použít k potlačení chybového hlášení. Pokud tedy matně tušíme, že bychom neradi návštěvníkům webu prozradili přihlašovací údaje od databáze (jelikož pak by se mohli zbytečně snažit naši databázi přijít osobně navštívit). Toto by se snadno mohlo stát, jen nám databáze vypadne, přesněji jen funkce mysql_connect z nějakého důvodu selže (interpret by mohl ohlásit chybu na příslušném řádku a jeho obsah vypsat). Proto jsme před její volání dali operátor zavináče, který říká, že i když v následujícím výrazu dojde k chybě, chybové hlášení se má potlačit (ovšem skript spadne tak jako tak).

Často se stává, že z odpovědi od serveru potřebujeme sestrojit pole, jehož prvky jsou jednotlivé řádky. Prvky tohoto pole tedy budou opět pole, tentokrát asociativní (abychom v rámci řádku mohli hledat podle názvu položky). Problém vyřešíme asi takto:

function result($res)
{       $result=array();
        for($i=mysqli_num_rows($res);$i>0;$i--)
                $result[]=$res->fetch_assoc();
        return $result;
}

Cvičení: Jak byste řešení modifikovali, aby byly jednotlivé řádky reprezentovány jako pole (neasociativní), tedy abychom k nim mohli přistupovat indexem požadovaného sloupce?

Cvičení:

  1. Představte si, že máte v tabulce sloupec castka jehož hodnoty chcete posčítat (select sum(castka) ... ) Jak bude vypadat volání funkce mysql_result v takovém případě?
  2. Vyzkoušejte si fungování operátoru zavináče (@). Tvořte kód, který budete shazovat na různých místech a sledujte, kdy operátor hlášení potlačí a kdy ne.
  3. Souvislý příklad Kafomat: Vybavte kafomat stránkou, na které bude možné si objednat. Z cvičení HTML jim máte formulář, nyní vyrobte PHP-skripty, které budou příslušné údaje ukládat do databáze. Taktéž vytvořte administrační rozhraní, které umožní majiteli kafomatu vyřizovat přijaté objednávky.

Cookies

Cookies lze použít k uschování informace na straně klienta. Můžeme si tak v principu ukládat data na disk klienta. To by nám v zásadě umožňovalo rozmigrovat si data po discích našich návštěvníků, má to však jeden háček: K těmto datům se nedostaneme, dokud dotyčný návštěvník znovu nepřijde. Cookies se tedy používají ke zrádnému šmírování nebohých uživatelů. Ovládají se až nečekaně jednoduše. Cookie se dá buďto zanést, nebo číst. Sám od sebe se může cookie zkazit (expiruje a klient jej nadále nepoužívá a nejspíše ho v rámci úspory místa na disku smaže). Každý cookie vypadá trochu jako HTML-atribut, tedy má jméno a jemu přiřazenou hodnotu.

Začneme tím jednodušším, tedy přístupem ke Cookies. Ten se děje přes asociativní pole $_COOKIE. Toto pole je (jistě k našemu nemalému překvapení) indexováno jmény příslušných cookies. Tedy pokud jsme zanesli cookie se jménem user, jeho hodnotu zjistíme jako $_COOKIE[user]. Snadno se ovšem může stát, že nevíme, zda je cookie nastaven. K tomu použijeme obecnou funkci pracující nad poli isset, které předáme prvek pole a funkce rozhodne, zda je prvek pole definován nebo ne. Zeptali bychom se tedy isset($_COOKIE['user']).

Těžké není ani nastavování cookies. Ovládá se jednou (byť zběsile vyhlížející) funkcí:
setcookie($jmeno,$hodnota,$cas_expirace,$cesta,$domena,$secure,$httponly)
Parametrů je úctyhodné množství, ale od druhého (včetně) jsou implicitní a tedy jich lze vyplnit libovolné (nenulové) množství. Smysl a význam parametrů je tento:

$jmeno
identifikátor cookie - pod tímto jménem si o něj budeme říkat,
$hodnota
hodnota, kterou jménu přiřadíme,
$cas_expirace
čas v sekundách (od stvoření světa), kdy cookie expiruje (současný čas zjistíme zavoláním funkce time(),
$cesta
omezení používání cookie pro zadanou cestu (například jen pro mé stránky)
$domena
omezení používání cookie pro zadané domény (cookie se použije, pokud je námi nastavená doména podřetězcem DNS-jména stroje, na který přistupujeme),
$secure
boolský parametr odpovídající na otázku: "Má se cookie použít pouze pro HTTPS (a nikoliv HTTP)?"
$httponly
boolský parametr omezující použití pouze na HTTP, pomocí různých pokoutných spojení se k němu tedy nedostaneme.

Pozor, funkce setcookie musí být zavolána před začítkem vypisování těla stránky (tedy před doctypem)!

Příklad:

<?
$jmeno=$_GET["jmeno"];
setcookie("jmeno",$jmeno,time()+3600);
?>
Takto jsme nastavili cookie, který jménu jmeno přiřadí obsah proměnné $jmeno, která nám byla zaslána formulářem metodou GET. Tento cookie se zkazí za hodinu (3 600 sekund od teď). Pokud bychom čas nenastavili (nebo jej nastavili na nulu), cookie platí do konce session. Pokud bychom chtěli cookie smazat, nastavíme mu čas expirace v minulosti. Implicitní hodnoty pro doménu a adresář jsou jméno současného stroje a současný adresář.
Nazdar, <?
if(isset($_COOKIE["jmeno"]))
	echo "ze ty jsi ".$_COOKIE["jmeno"]."!? Vidis, my tu vsechno pozname,";
?>
takze k veci...
Tady zkusíme uživatele identifikovat podle dříve zaneseného cookie.

Cvičení: Do souvislého příkladu Kafomat implementujte identifikaci uživatele pomocí cookies (pokud uživatele neznáte, zobrazte mu registrační formulář, kde musí oznámit své jméno, pod kterým ho buďto najdete v databázi, nebo do ní zanesete. Cookie používejte ke sledování učiněných objednávek.

Sessions

Session představuje možnost jak udržovat nepříliš persistentní údaje po dobu jedné návštěvy jednoho konkrétního návštěvníka. Session je třeba zahájit (voláním funkce session_start) a na běžící session je třeba (voláním též funkce) upozorňovat na každé stránce (kde session budeme používat). Funkci session_start je třeba zavolat ještě před výpisem HTML (před doctypem).

Session se ovládá jako (asociativní) pole $_SESSION, do kterého si můžeme ukládat hodnoty vcelku libovolného typu pod klíči, které chceme. Můžeme tedy počítat, kolikrát člověk během současné návštěvy kliknul, nebo si v tomto poli můžeme pamatovat přihlašovací údaje. Pole $_SESSION se zkrátka používá jako jakékoliv jiné (asociativní) pole.

Příklad

<?
session_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<title>Kontrola</title>
<p>
Vy jste <? echo (isset($_SESSION['byltu'])?"tu uz byl, tak to tu znate...":
"jste ted prisel, takze vitejte!");
$_SESSION['byltu']=true; //udelame si boolskou promennou, ktera je budto true, nebo neexistuje.
?>

V příkladu si všimněme využití ternárního operátoru otazník - dvojtečka. Tedy pokud je v poli $_SESSION nastaven prvek byltu, vypíšeme řetězec před dvojtečkou, jinak vypíšeme ten za dvojtečkou.

Pokud chceme session explicitně ukončit, můžeme po zavolání funkce session_start stejným způsobem zavolat funkci session_destroy. Tato funkce se taktéž volá bez parametrů.

Cvičení: Do souvislého příkladu Kafomat přidejte sessiony. Využijte je k počítání položek, které člověk během současné session objednal (a jejich počet při vhodných příležitostech vypisujte).

HTTP autentizace

Pokud chceme uživatele autentizovat (přihlásit, abychom jim povolili nějakým způsobem speciální přístup), můžeme s výhodou využít cookies, resp. session (podle okolností). Session nám umožní propasírovat vždy na klienta jméno a heslo, Cookies můžeme použít podobně (nastavíme jeden na jméno, druhý na heslo), což ovšem není příliš bezpečné (cookies se porůznu ukládají na disk). Proto můžeme na nějakou dobu vygenerovat cookie, o kterém si poznamenáme, že ho drží tento uživatel a pokud nám někdo tento cookie předloží, budeme mít za to, že jde o dotyčného uživatele.

Zbývá maličkost: Jak dostat přihlašovací údaje z klienta k nám. K tomuto buďto můžeme použít již známé HTML-formuláře, anebo můžeme nasadit HTTP-autentizaci podle RFC 2617.Nás bude tato autorizace zajímat v souvislosti s využitím v rámci PHP. Jak tedy tuto autorizaci použijeme:

Druhů autentizace je několik, my si ukážeme napřed tzv. Basic Authentication:

Pokud se klient chce autentizovat, objevíme v již známém asociativním poli $_SERVER prvky PHP_AUTH_USER a PHP_AUTH_PW. Tyto prvky obsahují (v tomto pořadí) přihlašovací jméno a heslo. Přihlašovací stránku tedy můžeme pojmout například takto:

<?
if(!isset($_SERVER['PHP_AUTH_USER']))
{       header('Status: 401 Unauthorized');
        header('WWW-Authenticate: Basic realm="Jmeno aplikace"');
        echo 'Tak takhle by to neslo!';//toto se zobrazi pri zruseni.
}else{  echo ' <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">';
        echo '<title>Chranena stranka</title>';
        echo '<p>Zde bychom mohli provest overeni jmena a hesla. Tyto udaje jsou:<p>';
        echo '<em>Jmeno:</em> '.$_SERVER['PHP_AUTH_USER'].' <em>Heslo:</em> ';
        echo $_SERVER['PHP_AUTH_PW'];
}
?>
Existují i další typy autentizací, nicméně nám bude pro začátek stačit ta základní (například Digest zřejmě není zdaleka vždy podporována).

Cvičení: Do souvislého příkladu Kafomat přidejte přihlašování. Jména a hesla udržujte v MySQL-databázi a kontrolujte.