Czy ścieżki dołączania PHP są względne w stosunku do pliku czy kodu wywołującego?

111

Mam problem ze zrozumieniem zestawu reguł dotyczących względnych ścieżek dołączania PHP. Jeśli uruchomię plik A.PHP- i plik A.PHP zawiera plik B.PHP, który zawiera plik C.PHP, czy względna ścieżka do C.PHP powinna odnosić się do lokalizacji B.PHP, czy do lokalizacji A .PHP? To znaczy, czy ma znaczenie, z którego pliku jest wywoływane dołączenie, czy tylko jaki jest bieżący katalog roboczy - i co określa bieżący katalog roboczy?

Yarin
źródło
Moim zdaniem dokładniejsza niż akceptowana odpowiedź: stackoverflow.com/a/23902890/1636522 .
liść

Odpowiedzi:

132

Jest względna w stosunku do głównego skryptu, w tym przypadku A.php. Pamiętaj, że include()po prostu wstawia kod do aktualnie uruchomionego skryptu.

To znaczy, czy ma znaczenie, z którego pliku jest wywoływane dołączenie

Nie.

Jeśli chcesz, aby miało to znaczenie i wykonaj dołączenie względem B.php, użyj __FILE__stałej (lub __DIR__od PHP 5.2 IIRC), która zawsze będzie wskazywać na dosłowny plik bieżący, w którym znajduje się wiersz kodu.

include(dirname(__FILE__)."/C.PHP");
Pekka
źródło
@ Pekka- niesamowite- właśnie to, czego szukałem. Więcej informacji można znaleźć na stronie stackoverflow.com/questions/2184810/…
Yarin
7
Możesz również użyć __DIR__do tego dokładnego celu.
Nick Bedford
1
Ta odpowiedź jest nieco przesadzona: BRAK POTRZEBY include(dirname(__FILE__)."/C.PHP");, ponieważ include("C.PHP");wystarczy (tak! C.PHP może znajdować się w tym samym katalogu co B.PHP) Może się nie powieść tylko wtedy, gdy w Twoim projekcie są dwa pliki C.PHP.
Johnny Wong
Aby było jaśniej: jest względne zarówno w stosunku do B.php, jak i A.php, jeśli nie ma przedrostka „./” lub „../” w ścieżce dołączania. Zobacz moją odpowiedź poniżej.
Johnny Wong
21

@Pekka mnie tam doprowadził, ale chcę się tylko podzielić tym, czego się nauczyłem:

getcwd() zwraca katalog, w którym znajduje się plik, który zacząłeś wykonywać.

dirname(__FILE__) zwraca katalog pliku zawierającego aktualnie wykonywany kod.

Korzystając z tych dwóch funkcji, zawsze możesz zbudować ścieżkę dołączania względem tego, czego potrzebujesz.

np. jeśli b.php i c.php współdzielą katalog, b.php może zawierać c.php, na przykład:

include(dirname(__FILE__).'/c.php');

bez względu na to, skąd dzwoniono do b.php.

W rzeczywistości jest to preferowany sposób ustanawiania ścieżek względnych, ponieważ dodatkowy kod uwalnia PHP od konieczności iteracji po ścieżce include_path podczas próby zlokalizowania pliku docelowego.

Źródła:

Różnica między getcwd () a dirname (__ FILE__)? Którego powinienem użyć?

Dlaczego powinieneś używać dirname (__ FILE__)

Yarin
źródło
Chciałbym coś dodać, miałem plik o nazwie csb.php, zawierał plik funkcji z folderu, a plik funkcji zawierał plik o nazwie t.php z tego samego folderu co plik funkcji. plik o nazwie csb.php z folderu t.php, zaczął zawierać ten sam csb.php, który wywołał plik functions, ale kiedy zmieniłem drugi csb.php na csbe.php, od razu zaczął działać. Wygląda więc na to, że nadaje priorytet pierwszemu folderowi, a następnie drugiemu folderowi dołączania!
Miguel Vieira
18
  1. Jeśli ścieżka dołączenia nie zaczyna się od ./lub ../, na przykład:

    include 'C.php'; // precedence: include_path (which include '.' at first),
                     // then path of current `.php` file (i.e. `B.php`), then `.`.
  2. Jeśli dołączona ścieżka zaczyna się od ./lub ../, na przykład:

    include './C.php';  // relative to '.'
    
    include '../C.php'; // also relative to '.'

Znak .lub ..powyżej odnosi się do getcwd(), co oznacza domyślną ścieżkę do .phppliku wejściowego (tj A.php.).

Przetestowano na PHP 5.4.3 (data kompilacji: 8 maja 2012 00:47:34).

(Należy również pamiętać, że chdir()może to zmienić wyjście getcwd().)

Johnny Wong
źródło
Podsumowując, ścieżka A.php jest najpierw przeszukiwana pod kątem C.php, a następnie ścieżka B.php jest przeszukiwana, jeśli nie ma przedrostka „./” lub „../” w dołączeniu. (Przyjmij domyślne ustawienia PHP)
Johnny Wong
Dziękuję za podpowiedź, aby użyć chdir(__DIR__)do rozwiązania problemu.
HartleySan
[...] getcwd(), która jest domyślną ścieżką do wpisu pliku .php [...] - niekoniecznie prawda. Jeśli uruchomię PHP w wierszu poleceń, wówczas getcwd()odwołuje się do bieżącego katalogu roboczego powłoki, niezależnie od tego, który .phpplik wywołuję. Mogę sobie jednak wyobrazić, że jeśli PHP jest uruchamiane w środowisku serwera WWW, to środowisko inicjuje bieżący katalog roboczy do .phppliku wejściowego . Testowane na macOS z PHP 7.2.2 zainstalowanym przez Homebrew.
herzbube
17

Przyjęta odpowiedź Pekki jest niepełna i, w ogólnym kontekście, myląca. Jeśli plik jest podany jako ścieżka względna, wywoływana konstrukcja języka includebędzie go szukać w następujący sposób.

Najpierw przejdzie przez ścieżki zmiennej środowiskowej include_path, którą można ustawić za pomocą ini_set. Jeśli to się nie powiedzie, przeszuka katalog własny skryptu wywołującego dirname(__FILE__)( __DIR__z php> = 5.3). Jeśli to również się nie powiedzie, tylko wtedy przeszuka katalog roboczy! Po prostu okazuje się, że domyślnie zmienna środowiskowa include_pathzaczyna się od ., czyli aktualnego katalogu roboczego. Jest to jedyny powód, dla którego szuka najpierw w bieżącym katalogu roboczym. Zobacz http://php.net/manual/en/function.include.php .

Pliki są dołączane na podstawie podanej ścieżki do pliku lub, jeśli nie została podana, określonej ścieżki include_path. Jeśli plik nie zostanie znaleziony w include_path, funkcja include sprawdzi w końcu własny katalog skryptu wywołującego i bieżący katalog roboczy, zanim zakończy się niepowodzeniem.

Tak więc prawidłowa odpowiedź na pierwszą część pytania jest taka, że ​​ma znaczenie, gdzie znajduje się dołączony skrypt wywołujący. Odpowiedź na ostatnią część pytania jest taka, że początkowy katalog roboczy, w kontekście serwera WWW, jest katalogiem wywoływanego skryptu, skryptu, który zawiera wszystkie pozostałe, podczas gdy jest obsługiwany przez PHP. W kontekście wiersza poleceń początkowy katalog roboczy jest tym, czym jest, gdy php jest wywoływany po znaku zachęty, niekoniecznie katalogiem, w którym znajduje się wywołany skrypt. Bieżący katalog roboczy, jednak może ulec zmianie w czasie wykonywania z funkcji PHP chdir. Zobacz http://php.net/manual/en/function.chdir.php .

Ten akapit został dodany w celu skomentowania innych odpowiedzi. Niektórzy wspominali, że poleganie na include_pathjest mniej niezawodne, dlatego lepiej jest używać pełnych ścieżek, takich jak ./pathlub __DIR__ . /path. Niektórzy posunęli się nawet do stwierdzenia, że ​​poleganie na samym katalogu roboczym .nie jest bezpieczne, ponieważ można go zmienić. Jednak czasami trzeba polegać na wartościach środowiskowych. Na przykład możesz chcieć ustawić include_pathpusty, aby katalog skryptu wywołującego był pierwszym miejscem, które będzie przeszukiwał, nawet przed bieżącym katalogiem roboczym. Kod może być już napisany i regularnie aktualizowany ze źródeł zewnętrznych i nie chcesz ponownie wstawiać prefiksu za __DIR__każdym razem, gdy kod jest aktualizowany.


źródło
"Jeśli to się nie powiedzie, przeszuka katalog skryptu wywołującego dirname(__FILE__) (__DIR__)z php> = 5.3.)" Czy na pewno? Gdzie to jest udokumentowane? Mam nadzieję, że się mylisz, a PHP nie używa __FILE__i __DIR__do tego celu, ponieważ spowodowałoby to natychmiastowe zerwanie dołączania skryptów "rodzeństwa" z dowiązanych symbolicznie ! : -o (Co na szczęście wydaje się działać dobrze tutaj, na mojej konfiguracji 7.1.)
Sz.
6

Krótka odpowiedź: dotyczy skryptu włączającego.

TFM wyjaśnia to poprawnie:

Jeśli plik nie zostanie znaleziony w ścieżce include_path, funkcja include sprawdzi katalog skryptu wywołującego i bieżący katalog roboczy

Tak więc, jeśli /app/main.php mówi, include("./inc.php")że znajdzie /app/inc.php .

./ nie jest to bezwzględnie konieczne, ale usuwa zależność include_path.

Nie polegałbym na znajdowaniu plików dołączanych w bieżącym katalogu roboczym na wypadek, gdyby ktoś zmienił go za pomocą chdir().

Denis Howe
źródło
Więc jeśli zaczynasz łańcuch od ./, czy najpierw sprawdza on katalog skryptu wywołującego, czy też bieżący katalog roboczy?
Pacerier,
2
@Denis Howe Nie, już jesteś uzależniony od bieżącego katalogu roboczego, jeśli ścieżka dołączania zaczyna się od ./. tzn. chdir ("/ app / other") zakończy się include("./inc.php")niepowodzeniem. Dlatego include("inc.php")w tym przypadku użyj, aby być bezpiecznym.
Johnny Wong,
@Pacerier jeśli ciąg zaczyna się od ./ lub ../, sprawdza tylko bieżący katalog roboczy. (ścieżka_włączania i katalog skryptu wywołującego (B.php) są ignorowane). Zobacz moją odpowiedź po więcej szczegółów.
Johnny Wong,
-2
dir
-> a.php
-> c.php

- dir2 
-> b.php

Aby uwzględnić aw btrzebainclude("../a.php");

Aby uwzględnić bw ctrzebainclude("dir2/b.php");

Olli
źródło
4
@ Olli - nie rozumiesz sedna pytania - pytałem o to, w jaki sposób wyznaczane są ścieżki względne, gdy dołączone są łańcuchy.
Yarin