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_path
relativně 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
veena #1
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.
Poša #2
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?
Jakub Vrána #3
#1 veeno, 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á.Tomáš Fejfar #4
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.
Jan Tichý #5
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.
David Grudl #6
#1 veeno, 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 Jane Tichý, na
dirname
není špatného vůbec nic, to je prostě jen taková frajeřina ;)Josef Průša #7
O kolik je includovani souboru rychlejsi, kdyz se uvede celá cesta?
veena #8
#7 Josefe Průšo, + 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()
Jakub Vrána #9
#6 Davide Grudle, Přímo aktuální adresář se prohledává vždy. Pokud include_path neobsahuje tečku, tak jako poslední.
#4 Tomáši Fejfare, 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()
.David Grudl #10
#9 Jakube Vráno, 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í.
Dundee #11
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í.
Tomáš Fejfar #12
#9 Jakube Vráno, 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á.
Marek Dušek #13
#12 Tomáši Fejfare, 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 ;)))
Vedouci #14
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…
jaro #15
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 🙂
David Grudl #16
#14 Vedouci, obyčejná lomítka
/
jsou platformově nezávislé.Jan Tichý #17
#12 Tomáši Fejfare, 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.
Vedouci #18
#16 Davide Grudle, no, jde o to, ze pak v kombinaci s navratovyma hodnotama php fci to pak moc nezavisle neni:
David Grudl #19
#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__.
Dundee #20
#12 Tomáši Fejfare, 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ř:
Na tomhle principu je založen PHP Injection.
Mordae #21
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š.
Mordae #22
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.Jan Tichý #23
#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 ;).
optik #24
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
David Grudl #25
#24 optiku, 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';
v6ak #26
#24 optiku, 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.
Luděk Pechanec #27
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
v6ak #28
#27 Luděku Pechanci, Toto použití include je skutečně děravé a ‚hacknutelné‘, zvlášť v php5, kde přibyl pseudoprotokol data.
Jarda #29
__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?
v6ak #30
#29 Jardo, Žeby spl_autoload?
David Grudl #31
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__)
.Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.