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

Translate to English… Ins Deutsche übersetzen…

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 (nedoporučuju používat)

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

PHP 5.3 má novou magickou konstantu __DIR__, která nahradí volání dirname(__FILE__):

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

napsáno 1. 11. 2007 | shlédnuto 7350x | nahoru

Komentáře RSS 2.0 komentářů » přidat

#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 [6] David Grudl
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 Jakub Vrána http://php.vrana.cz/ 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
avatar

#4 Tomáš Fejfar http://blog.red-pill.cz 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
avatar

#5 Jan Tichý http://www.phpguru.cz/ 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
avatar

#6 David Grudl http://davidgrudl.com 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
avatar

#7 Josef Průša http://josef-prusa.eu 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 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 Jakub Vrána http://php.vrana.cz/ 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 [12] Tomáš Fejfar
avatar

#10 David Grudl http://davidgrudl.com 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
avatar

#11 Dundee http://blog.milde.cz 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
avatar

#12 Tomáš Fejfar http://blog.red-pill.cz 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

#13 Marek Dušek http://www.stringdata.cz 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 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 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
avatar

#16 David Grudl http://davidgrudl.com 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
avatar

#17 Jan Tichý http://www.phpguru.cz/ 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 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
avatar

#19 David Grudl http://davidgrudl.com 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
avatar

#20 Dundee http://blog.milde.cz 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ý
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
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
avatar

#23 Jan Tichý http://www.phpguru.cz/ 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 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 [26] v6ak
avatar

#25 David Grudl http://davidgrudl.com 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 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
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 v6ak http://v6ak.profitux.cz/ 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
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 v6ak http://v6ak.profitux.cz/ nový

#29 Jarda: Žeby spl_autoload?

Posláno 23. 2. 2008 ve 14.25 | Odpovědět
avatar

#31 David Grudl http://davidgrudl.com 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.

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á.

phpFashion © 2004, 2012 David Grudlo webu

Pokud není uvedeno jinak, podléhá obsah těchto stránek licenci Creative Commons BY-NC-ND Creative Commons License BY-NC-ND

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