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í:
- pokud je cesta absolutní, nic se nedohledává
- 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!) - v ostatních případech:
- prohledají se všechny cesty z
include_pathrelativně vztažené k aktuálnímu adresáři - hledá se od adresáře s právě prováděným skriptem
- prohledají se všechny cesty z
„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';
Komentáře
» přidat
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.

#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.
#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?
#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á.#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.
#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.
#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
dirnamenení špatného vůbec nic, to je prostě jen taková frajeřina ;)#7 Josef Průša http://josef-prusa.eu nový
O kolik je includovani souboru rychlejsi, kdyz se uvede celá cesta?
#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()
#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 funkcireadfile().#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í.
#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í.
#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á.
#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 ;)))
#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…
#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
#16 David Grudl http://davidgrudl.com nový
#14 Vedouci: obyčejná lomítka
/jsou platformově nezávislé.#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:
a v onom vzdáleném index.php budeš mít třeba něco takového:
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.
#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
#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__.
#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://skript.php“);
echo $prom; //vypise ‚nejaka kravovina‘
?>
Na tomhle principu je založen PHP Injection.
#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š.
#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.#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 ;).
#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
#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:
str_replace('_', DIRECTORY_SEPARATOR, $class);require_once 'Zend/Exception.php';#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.
#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
#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 data.
#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?
#30 v6ak http://v6ak.profitux.cz/ nový
#29 Jarda: Žeby spl_autoload?
#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__).