_

V dnešním článku bych odbočil od středně pokročilých PHP skriptů a návodů, a vrátil se na chvíli k samotným začátkům většiny z nás, a to prvnímu použití funkce include. Existuje mnoho konstrukcí, kterými můžeme stránky poskládat z více souborů, a já vám popíši všechny jejich výhody a nevýhody. Pokusím se jít úplně od začátku, od prvního neandrtálského řešení až po šikovnou sekvenci podmínek s ošetřením všech potencionálních chyb a nedostatků.

Nezapomeňte se podívat na druhý díl

Předpokládejme includování stránek podle proměnné $_GET['page'] a odkazy například ve tvaru index.php?page=kontakt. Jako nejjednodušší řešení lze vytvořit posloupnost několika podmínek :

if ($_GET['page'] == 'kontakt') {
    include "./inc/kontakt.php";
} else if ($_GET['page'] == 'kniha-navstev') {
    include "./inc/kniha-navstev.php";
} else {
    include "./inc/uvod.php";
}

Jako první nedostatek bych zmínil absenci chybové stránky. Při zavolání adresy například index.php?page=tohle-neexistuje je načtena úvodní stránka. Lepší, než kdyby se zhroutil celý vesmír, ovšem my se chceme posunout dál. Proto můžeme vytvořit podmínku, která bude hned jako první, postará se o načtení úvodu při nulové hodnotě proměnné a chybovou stránku 404 zavolá až pod else. Nesprávně bývá uváděno porovnání if ($_GET['page'] == '') předcházející dalšímu testování proměnné $_GET['page'], a právě zde narážíme na další chybu : nedefinovaná proměnná totiž nemá hodnotu empty nýbrž null, tudíž musíme porovnávat s hodnotou null. Upravený zápis by mohl vypadat nějak takto :

if ($_GET['page'] === null) { // špatně : if ($_GET['page'] == '') 
    include "./inc/uvod.php";
} else if ($_GET['page'] == 'kontakt') {
    include "./inc/kontakt.php";
} else if ($_GET['page'] == 'kniha-navstev') {
    include "./inc/kniha-navstev.php";
} else {
    include "./inc/404.php";
}

Tohle řešení je ovšem stále čiré zlo. Jestliže máme například 20 podstránek, neustálé opakování if / elseif … je cesta do pekel. A zde přichází konstrukce switch, kterou implementujeme namísto zbytečných podmínek. Nezapomeneme ani na hodnotu false a chybová stránka 404 zůstane pod default.

switch($_GET['page']) {
    case false :
        include "./inc/uvod.php";
    break;
    case 'kontakt' :
        include "./inc/kontakt.php";
    break;
    case 'kniha-navstev' :
        include "./inc/kniha-navstev.php";
    break;
    default:
        include "./inc/404.php";
    break;
}

Mnohem lepší řešení než předchozí uvedené, ale to stále nestačí. Zde zmíním další nedostatek, který první a třetí zápis obsahuje : jestliže nastavíme úroveň výpisu chybových hlášek  error_reporting(E_ALL), zmíněné konstrukce vypisují chybu typu notice. Navíc stejně jako sekvence podmínek musíme i ve switchi neustále přidávat další řádky, tři s každou novou podstránkou. Naštěstí ale přichází v pravou chvíli spásná funkce file_exists, díky které zkrouhneme desítky zbytečných řádků do jednoho if / else. Hodnotě proměnné přidáme koncovku *.php, zkontrolujeme, zda-li daný soubor existuje, pokud ano, includujeme :

$filename = $_GET['page'].".php";
if (file_exists("./inc/$filename")) {
    include "./inc/$filename";
} else {
    include "./inc/uvod.php";
}

Jako základ stačí, ale my se přece nebudeme spokojení s žádným ořezaným řešením, že =o) Výše uvedená konstrukce opět nemyslí na chybová hlášení typu notice: undefined index, stejně tak na error 404 při nesmyslné hodnotě proměnné. Také cesty k souborům, které jsme do teď uváděli relativní konečně zapíšeme absolutními cestami. Zapomněl jsem ještě zdůraznit umístění všech includovaných souborů v podadresáři, čímž ošetříme zacyklení typu index.php?page=index.

Nejdříve otestujeme proměnnou funkcí isset, v případě hodnoty false načteme úvodní stránku. Až uvnitř bude kontrola přes file_exists, načteme požadovaný soubor nebo 404ku. Vnořenou podmínku můžeme jednoduše zapsat pomocí ternárního operátoru, a tak bude dynamické načítání stránek vypadat ve finále třeba takto :

if (isset($_GET['page'])) {
    include file_exists("./inc/{$_GET['page']}.php") == true ? 
        dirname(__FILE__)."/inc/{$_GET['page']}.php" : 
        dirname(__FILE__)."/inc/404.php";
} else {
    include dirname(__FILE__)."/inc/uvod.php";
}

Unikátní titulek pro každou stránku, řešení problémů

Bohužel, dynamická změna obsahu nestačí, je také vhodné tisknout každé podstránce unikátní titulek, keywords či description. Jestliže i hlavičku a patičku stránek máme v dalších souborech, můžeme předpokládat strukturu stránek podobnou následující:

include dirname(__FILE__).'/header.php';

if (isset($_GET['page'])) {
    include file_exists("./inc/{$_GET['page']}.php") == true ? 
        dirname(__FILE__)."/inc/{$_GET['page']}.php" : 
        dirname(__FILE__)."/inc/404.php";
} else {
    include dirname(__FILE__)."/inc/uvod.php";
}

include dirname(__FILE__).'/footer.php';

Pro náš účel použijeme asociativní pole, kde každé hodnotě proměnné přiřadíme řetězec, který následně vytiskneme do titulku respektive do keywords / description. Podmínka bude stejná jako pro funkci include, akorát bude jen vypisovat konkrétní položky pole. Funkci definujeme ještě před načtením souboru header.php, ve kterém ji zavoláme.

function titulek() {
    $title = array(
        'kontakt' => 'Kontakt',
        'kniha-navstev' => 'Kniha návštěv'
    );

    if (isset($_GET['page'])) {
        echo file_exists("./inc/{$_GET['page']}.php") == true ? 
            "Můj web | ".$title[$_GET['page']] :
            "Můj web | Soubor nenalezen";
    } else {
        echo "Můj web | Úvod";
    }
}
echo '<title>';
titulek();
echo '</title>';

To by bylo snad vše, co jsem na srdci měl, a pro ty z vás, kteří by si chtěli stáhnout těch pár souborů, na kterých jsem toto testoval nabízím zip archív ke stažení.

Ukázka: download