Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

porucha není na vašem přijímači

PHP triky: include, require a cesty

Vkládání skriptů přes include nebo require není vždy transparentní, protože programátoři často neví, z jakého adresáře se skript načte. Pravidla jsou následující:

  1. pokud je cesta absolutní, nic se nedohledává
  2. pokud cesta začíná na ./ nebo ../, hledá se vůči aktuálnímu adresáři (neplést s adresářem s právě prováděným skriptem!)
  3. v ostatních případech:
    1. prohledají se všechny cesty z include_path relativně vztažené k aktuálnímu adresáři
    2. hledá se od adresáře s právě prováděným skriptem

„Na jistotu“ lze obecně vkládat pouze přes absolutní cesty. K tomu se užívá tato formule:

require_once dirname(__FILE__) . '/libs/TexyBase.php';

Následující trik ukazuje, jak se lze volání funkce dirname zbavit:

require_once __FILE__ . '/../libs/TexyBase.php';

Aktualizace: díval jsem se do zdrojových kódů PHP 5.3 a objevila se tam nová magická konstanta __DIR__, která nahradí volání dirname(__FILE__).

Karma body: 32. Líbil se vám článek?

Komentáře » přidat

  1. [1] veena: nový

    Supr, dík za vysvětlení těch inkludů cest a trik bez dirname. V angličtině mi to pořád nesecvakávalo. Ale ještě mi zbývají nejasnosti.

    1. prohledají se všechny cesty z include_path relativně vztažené k aktuálnímu adresáři
    Že to je relativně k aktuálnímu adresáři asi neplatí vždy, ne? V include_path taky můžou být cesty zadány trojím způsobem (absolutně, s ./, „normálně“)

    A jak je to prosím tě s tím aktuálním adresářem? Který to je, nebo podle čeho se nastaví?
    Rád bych si už konečně chtěl z hlavy dokázat představit, kde se vlastně ten soubor hledá, když ho inkluduju.

    Posláno 1. 11. 2007 v 9.27 | Odpovědět
    Na komentář reagoval [3] Jakub Vrána
    Na komentář reagoval [6] David Grudl
  2. avatar [2] Poša: nový

    Davide, jsem jen lama, ale bylo by asi vhodné u těch triků říct, jaké jsou vady stávajícího řešení (proč se tedy vlastně ten trik dělá a co přinese). Nějak mi to např. u triku s dirname chybí.

    Proč je varianta s dirname horší než navržený trik?

    Posláno 1. 11. 2007 v 9.43 | Odpovědět
  3. [3] Jakub Vrána: nový

    [1] veena: Aktuální adresář je ten, který vrací funkce getcwd(). Na webu to je obvykle adresář spuštěného skriptu, ale dá se změnit i funkcí chdir(). Každá cesta se dá vztáhnout relativně k adresáři – absolutní zůstane nezměněná.

    Posláno 1. 11. 2007 v 10.05 | Odpovědět
  4. avatar [4] Tomáš Fejfar: nový

    Jen možná ještě doplnit, že pokud includujete z nějaké asbolutní URL (http://www.example.com/foo.php), tak se nenačtou ani proměnné ani nic dalšího a použije se jen výstup. Což je sice logické, ale nedávno sem si to neuvědomil a řešil sem to půl dne.

    Posláno 1. 11. 2007 v 11.03 | Odpovědět
    Na komentář reagoval [9] Jakub Vrána
  5. avatar [5] Jan Tichý: nový

    Ahoj, co je špatného na dirname()? Subjektivně mi přijde použití dirname() čistší, než dávat název neadresářového souboru do cesty.

    Posláno 1. 11. 2007 v 11.36 | Odpovědět
    Na komentář reagoval [6] David Grudl
  6. avatar [6] David Grudl: nový

    [1] veena: Jakub to vysvětlil, jen dodám, že přímo aktuální adresář se prohledává jen tehdy, pokud jej tam include_path zavede, tedy třeba když obsahuje . (tečku).

    [5] Jan Tichý: na dirname není špatného vůbec nic, to je prostě jen taková frajeřina ;)

    Posláno 1. 11. 2007 ve 14.02 | Odpovědět
    Na komentář reagoval [9] Jakub Vrána
  7. avatar [7] Josef Průša: nový

    O kolik je includovani souboru rychlejsi, kdyz se uvede celá cesta?

    Posláno 1. 11. 2007 v 15.02 | Odpovědět
    Na komentář reagoval [8] veena
  8. [8] veena: nový

    [7] Josef Průša: + by mě zajímalo jak dlouho trvá vyzkoušení jednoho adresáře v include path. A jak jsou ty rychlosti vzhledem k rychlosti otestování pomocí funkce file_readable()

    Posláno 1. 11. 2007 v 16.09 | Odpovědět
  9. [9] Jakub Vrána: nový

    [6] David Grudl: Přímo aktuální adresář se prohledává vždy. Pokud include_path neobsahuje tečku, tak jako poslední.

    [4] Tomáš Fejfar: Proměnné se načtou v případě, že jejich definici vkládaný skript vypíše (třeba kdyby měl koncovku .txt, ale může to samozřejmě udělat i PHP skript). Pro obyčejné vložení obsahu vzdáleného souboru bez jeho vykonání je lepší použít funkci readfile().

    Posláno 1. 11. 2007 v 16.20 | Odpovědět
    Na komentář reagoval [10] David Grudl
    Na komentář reagoval [12] Tomáš Fejfar
  10. avatar [10] David Grudl: nový

    [9] Jakub Vrána: nene, pokud include_path tečku neobsahuje, aktuální adresář se neprohledává vůbec. Prohledává se adresář s aktuálně prováděným skriptem (bod c.2), ten však s include_path nijak nesouvisí.

    Posláno 1. 11. 2007 v 18.04 | Odpovědět
  11. avatar [11] Dundee: nový

    V případě, že je v includu na začátku / vyhledává se v adresáři nastaveném v doc_root?

    Nejlepší je mít jeden centrální controller, to pak starosti o to, odkud mě volající skript načetl, úplně odpadají.

    Posláno 1. 11. 2007 v 18.23 | Odpovědět
  12. avatar [12] Tomáš Fejfar: nový

    [9] Jakub Vrána: To sem nějak nepochopil. Pokud někde ve skryptu udělám echo $foo; tak potom budu moct proměnou $foo požít i v souboru, ze kterého sem includoval?

    To mi nepřijde možné. Už jen z toho principu, že při přístupu k souboru přes HTTP:// se PHPčko vykoná a vrátí se výsledek a že by se prováděla kontrola, jestli ta která http adresa není náhodou na tomtéž serveru se mi teda moc nezdá.

    Posláno 1. 11. 2007 v 18.49 | Odpovědět
    Na komentář reagoval [13] Marek Dušek
    Na komentář reagoval [17] Jan Tichý
    Na komentář reagoval [20] Dundee
  13. [13] Marek Dušek: nový

    [12] Tomáš Fejfar: Presne tak, jakmile se vklada pres ‚http://‘, cilovy webserver skript normalne zpracuje a vrati vysledek, nikoli zdrojovy kod (at se jedna fakticky o ten samy server ci nikoli).

    Moznost vkladat takto soubory se ridi direktivou ‚allow_url_fopen‘ (tedy tou, ktera hlavne ridi totez pro fci fopen()).

    (vse psano AFAIK, prirozene ;)

    PS mozna to nekomu prijde zbytecne resit, ale taky znam pripad, kdy se u pocitace sesla postupne cela kancelar a zkoumala, proc po require souboru nejsou tridy v nem pristupne, ackoli kazde ‚print 123‘ videt bylo ;)))

    Posláno 1. 11. 2007 ve 23.07 | Odpovědět
  14. [14] Vedouci: nový

    hm, a do jake míry je tohle rešení platformově nezávislé?
    (a/b/c.php vs. a\b\c.php)

    pamatuju se, že sem s tím měl kdysi problémy…

    Posláno 2. 11. 2007 ve 12.08 | Odpovědět
    Na komentář reagoval [16] David Grudl
  15. [15] jaro: nový

    Programoval som pár rokov v PHP. Keď sa však musím pre načítanie hodnôt konfiguračných premenných uchyľovať k použitiu regulárnych výrazov, buď nie je niečo v poriadku s PHP alebo bude chyba medzi monitorom a operadlom stoličky. Ináč dobrý článok :-)

    Posláno 2. 11. 2007 ve 12.37 | Odpovědět
  16. avatar [16] David Grudl: nový

    [14] Vedouci: obyčejná lomítka / jsou platformově nezávislé.

    Posláno 2. 11. 2007 ve 13.04 | Odpovědět
    Na komentář reagoval [18] Vedouci
  17. avatar [17] Jan Tichý: nový

    [12] Tomáš Fejfar: Tomáši, opravdu to tak je. Když budeš mít například ve svém skriptu následující kód:

    $foo = 'bar';
    include 'http://www.example.com/index.php';

    a v onom vzdáleném index.php budeš mít třeba něco takového:

    echo '<?php echo $foo; ?>';

    tak se Ti obsah proměnné $foo vypíše. To je hlavní důvod, proč je na spoustě serverů zakázáno allow_url_fopen respektive nově allow_url_include.

    Posláno 2. 11. 2007 ve 13.05 | Odpovědět
  18. [18] Vedouci: nový

    [16] David Grudl: no, jde o to, ze pak v kombinaci s navratovyma hodnotama php fci to pak moc nezavisle neni:

    <?php

    include $_SERVER [ ‚DOCUMENT_ROOT‘ ] . ‚kulovy/test.php‘;
    Mozna by to stalo za poznamenani ;-)

    Posláno 2. 11. 2007 ve 13.12 | Odpovědět
    Na komentář reagoval [19] David Grudl
  19. avatar [19] David Grudl: nový

    [18] Vedouci: nerozumím. Co konkrétně nefunguje?

    Jen bacha na to, že DOCUMENT_ROOT nemusí vpravo obsahovat lomítko, vlastně vůbec nemusí obsahovat očekávanou hodnotu a rozhodně bych podle něj neinkludoval. Správný postup se odvíjí od __FILE__.

    Posláno 2. 11. 2007 ve 13.47 | Odpovědět
  20. avatar [20] Dundee: nový

    [12] Tomáš Fejfar: Myslim, že Jakub to myslel trochu jinak. Říkal, že pokud includovaný skript má jako výstup definici proměnné, ta se pak dá ve volajícím skriptu vypsat.

    Např:

    <?php
    echo „$prom = ‚nejaka kravovina‘“;
    ?>

    <?php
    include („http://skrip­t.php“);
    echo $prom; //vypise ‚nejaka kravovina‘
    ?>

    Na tomhle principu je založen PHP Injection.

    Posláno 2. 11. 2007 ve 14.15 | Odpovědět
    Na komentář reagoval [23] Jan Tichý
  21. avatar [21] Mordae: nový

    require_once __FILE__ . '/../libs/TexyBase.php';

    eh… tohle funguje ale jen díky tomu, že PHP dělá realpath() na tu cestu kvůli té kontrole dvojího vkládání, případně kvůli open_basedir. Zkus to na skutečném filesystému a máš smůlu, protože hardlink ../ z něčeho, co není adresář, asi jen těžko vydoluješ.

    Posláno 2. 11. 2007 v 17.00 | Odpovědět
  22. avatar [22] Mordae: nový

    Ah a jěště se doplním. PHP má vlastní realpath(3), podle všeho, protože ten BSDčkový (alespoň ten z Glibc) tohle taky nezkousne.

    Posláno 2. 11. 2007 v 17.04 | Odpovědět
  23. avatar [23] Jan Tichý: nový

    [20] Dundee: Hmm, tohle ledaže bys měl v tom prvním skriptu jednoduché uvozovky – v opačném případě dojde už přímo v něm k substituci $prom – v lepším případě za nějakou hodnotu, v horším to vyhodí undefined variable ;).

    Posláno 2. 11. 2007 ve 22.43 | Odpovědět
  24. [24] optik: nový

    jen k rychlosti prohledavani include_path, je to pomerne rychle, zejmena na unixech, na win nicmoc, ja osobne nejradeji pouzivam include_path a jednoduchy __autoload a pak uz se s include/require vubec nezabyvam, jinak misto /
    osobne pouzivam konstatnu DIRECTORY_SEPARATOR

    Posláno 3. 11. 2007 ve 14.02 | Odpovědět
    Na komentář reagoval [25] David Grudl
    Na komentář reagoval [26] v6ak
  25. avatar [25] David Grudl: nový

    [24] optik: DIRECTORY_SEPARATOR je sice jakože čisté řešení, ale kdo ho používá důsledně? A není-li používám důsledně, pak je zbytečné ho používat vůbec.

    Třeba kód Zend_Loader ze Zend Framework:

    • na jednom řádku str_replace('_', DIRECTORY_SEPARATOR, $class);
    • o pár řádků níže: require_once 'Zend/Exception.php';
    Posláno 3. 11. 2007 v 16.58 | Odpovědět
  26. [26] v6ak: nový

    [24] optik: Pokud vím, tak lomítko je taky čisté. DIRECTORY_SEPARATOR je systémový oddělovač. Je vhodné použít str_replace s ním např. po volání realpath.

    Posláno 4. 12. 2007 v 9.20 | Odpovědět
  27. avatar [27] Luděk Pechanec: nový

    Ahoj, vytvořil jsem si dynamický stránky v PHP a používám tam klasické volání příkazu INCLUDE.
    Teď mám stránky zablokovaný, protože mi přes ně někdo posílá spamy atd. Údajně mám zabezpečit příkazy INCLUDE, POST a MAIL.

    Používám script v tomto tvaru:
    <?
    if ($stranka != "") {
    include („$stranka.php“);
    } else {
    include ‚main-center.php‘;
    }
    ?>

    Může mi někdo s tímto problémem poradit?
    díky

    Posláno 15. 1. 2008 v 11.21 | Odpovědět
    Na komentář reagoval [28] v6ak
  28. [28] v6ak: nový

    [27] Luděk Pechanec: Toto použití include je skutečně děravé a ‚hacknutelné‘, zvlášť v php5, kde přibyl pseudoprotokol da­ta.

    Posláno 18. 1. 2008 v 17.44 | Odpovědět
  29. avatar [29] Jarda: nový

    __autoload je skvělá věc, ale pokud vložený script (knihovna) z jiného adresáře používá taky __autoload, tak má pak logicky špatně cestu a script padne. A pak musím modifikovat cizí knihovnu a ten druhý __autoload smazat. Myslíte, že to jde řešit nějak elegantněji?

    Posláno 23. 2. 2008 ve 13.57 | Odpovědět
    Na komentář reagoval [30] v6ak
  30. [30] v6ak: nový

    [29] Jarda: Žeby spl_autoload?

    Posláno 23. 2. 2008 ve 14.25 | Odpovědět
  31. avatar [31] David Grudl: nový

    Díval jsem se do zdrojových kódů PHP 5.3 a objevila se tam nová magická konstanta __DIR__, která nahradí volání dirname(__FILE__).

    Posláno 24. 2. 2008 ve 14.12 | Odpovědět

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře ani hlasovat

Výtah na začátek článku na první komentář

Názory čtenářů v diskusích nejsou názory provozovatele webu, a ten za jejich obsah neodpovídá.

La Trine © 2004, 2008 David Grudl – o webu
provozuje Pachollini.

Jakékoliv užití obsahu, včetně převzetí článků nebo jejich částí, je bez předchozího písemného svolení autora zakázáno.

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.