PHP – relativní vs. absolutní cesty

Jedním z drobných úskalí webového vývoje, které ale spolehlivě zamotá hlavu drtivé většině začátečníků je relativní adresace. V menších projektech je ještě reálné pracovat s relativními cestami k souborům, ale ve větších projektech (Kdo z nás chce pořád sbírat jen drobky?) je situace reálně neudržitelná. Já jsem před lety začal používat absolutní cesty a musím přiznat, že mám konečně klid.

První zádrhel se skrývá v include/require souborů, pokud se používají relativní cesty, je nutné si pamatovat, že pokud se includuje do hloubky, tj. includované soubory includují něco dalšího, počítá se cesta vůči prvnímu scriptu, tj. tomu, který je obvykle v URL (pokud používáte PHP jako CLI, tak se vše počítá vůči scriptu, který jste spustili z příkazové řádky).

Představte si následující uspořádání souborů:

|--admin
|   |_index.php
|   |_summary.php
|--css
|   |_sprava.css
|   |_prezentace.css
|--init
|   |_configure.php
|   |_init.php
|--knihovny
|   |_auth.php
|   |_db.php
|   |_mail.php
|   |_inputs.php
|_index.php
|_read.php

V souboru index.php v kořenovém adresáři je sekvence:

<?php
  require_once './init/configure.php';
  require_once './init/init.php';
  …

Script configure.php obsahuje nějaké základní údaje, třeba konfiguraci databáze, nebo často používané vzory pro regulární výrazy. Scrip init.php se postará o natažení potředných knihoven a inicializaci připojení k databázi, může vypadat třeba takto:

<?php
  require_once './lib/auth.php';
  require_once './lib/db.php';
  require_once './lib/inputs.php';
  
  $db=new db(…);
  …
?>

Vypadá to jasně, ale při pokusu o týž postup z adresáře admin nastane problém. Require v prvním zdrojovém kódu by byl o něco delší, příklad by vypadal následovně:

<?php
  require_once './../init/configure.php';
  require_once './../init/init.php';
  …

Sekvence je zřejmá. Začátek „./“ znamená že se má začít v adresáři, kde je script, který jste spustili, tato část není povinná. Část „../“ znamená, že z aktuálního adresáře je třeba sledovat další cestu o adresář výše (tj. v tomto případě se nemá další cesta hledat v adresáři admin, ale v kořenovém adresáři). No a zbytek sekvence je snad zřejmý každému. Problém nastává v případě nataženého souboru init.php už problém nastává, protože ten se bude snažit otevítat několik dalších knihoven, ale jak jsem napsal, cestase bude odvozovat od prvního scriptu, takže PHP interpret se bude snažit otevítat soubor admin/lib/auth.php, ale ten tam přeci není.

Z této problematiky existují tři způsoby úniku, buď budou stránky soubory stránek unístěné v adresáři „www“, nebo veškeré knihovny budou nakopírovány i v adresáři admin/, což při dnešních parametrech webhostingů nepředstavuje problém, ale je to nesystémové, protože po úpravě jedné knihovny je třeba zajistit její synchronizaci na dalším místě. Poslední variantou, a při složitějším projektu jedinou reálně použitelnou, je používání absolutních cest.

Pro zjištění toho, v jakém adresáři je script uložen mi slouží triviální sekvence příkazů v PHP:

echo $config['path'] = dirname(__FILE__).'/<br>';
echo 'http://'.$_SERVER['HTTP_HOST'].str_replace('bblog/install.php','',$_SERVER['REQUEST_URI']).'<br />';

Tato sekvence mi zobrazí malinko více informací, než se potřebuji, ale s tím si už snadno poradím. Během prvního nastavovaání nové prezentace si tuto sekvenci, v souboru install.php, umístím do kořenového adresáře, do url přidám za doménu název scriptu, tj. například http://www.abecedahracek.cz/install.php a do souboru config zapíši hodnoty absolutního URL (tj. řádek, který začíná písmenky http) a absolutní cesty (na Un*xovém serveru bude tato část začínat lomítkem, na Windowsovém (asi, fakt nepoužívám Win server) písmenkem disku).

Poté už je přepis obou ukázek zdrojových kódů snad zřejmý:

<?php
  require_once './init/configure.php';
  require_once $abspath . 'init/init.php';
  …

<?php
  require_once $abspath . 'lib/auth.php';
  require_once $abspath . 'lib/db.php';
  require_once $abspath . 'lib/inputs.php';
  
  $db=new db(…);
  …
?>

Článek popisoval jen problematiku relativních a absolutních cest v kontextu souborů, ale situace adresách (URL) je identická, praktičtější je použít možností absolutního URL, protože třeba jen konfigurace mého oblíbeného FCKEditoru je s použitím relativních cest a adres docela slušně adrilanovou a neprůhlednou záležitostí.

4 komentáře u „PHP – relativní vs. absolutní cesty“

  1. No jo, na tenhle problém jsem narazil hned na začátku. Řeším to tak, že pokud je skript ve stejném adresáři, použiji
    require(„globals.php“), jinak
    ../globals.php nebo ../../globals.php atd. v případě hlubšího vnoření, atd. Při dodržení postupu to funguje OK.

  2. Dalibor Smolík: No myslím, že to fungovat nebude, buď budeš mít globals.php rozkopírovaný všude, nebo budeš vše otrocky includovat/requirovat v každém scriptu, který spouštíš, anebo to budeš mít vše udělané tak, abys vždy měl vše o stejnou úroveň. Já jsem na absolutní cesty přešel i kvůli přehlednosti.
    Hih, dokonce první verze vytahovala při načtení vše z proměnných interpretru pomocí regulárních výrazů.

  3. Je to přesně tak – globals.php mám uncludovaný ve všech skriptech. Problém to vzhledem k rozsahu systému žádný není, ale tvoje řešení prozkoumám – člověk se pořád učí. 🙂

  4. Podľa mňa je to (orem iného aj) vec názoru alebo skôr výberu. Používam oba typy uvádzania ciest; relatívne asi častejšie, keďže už niekoľkokrát som s nimi mal menej starostí. Napríklad, keď som obnovoval nejaký web, ale na inej doméne. Pri predošlom webe som mal všetky odkazy s relatívnou cestou, takže odkazom bolo v podstate jedno, na akej doméne sa nachádzajú – Vždy bol ich cieľ rovnaký.

    To boli weby, ktoré nepoužívali RS (redakčný systém) – tam to bola výhoda. Pri RS zase stačí v nastaveniach zmeniť jednu cestu a všetky ostatné sa jej prispôsobia. (Ak si to dobre pamätám.)

    Takže, buď sa niekto rozhodne pre prehľadné riešenie, ale napíše toho trošku viac, alebo si zvolí neprehľadnejšie riešenie a bude musieť trochu potrápiť svoju hlavu.

Komentáře jsou uzavřeny.