PHP inclut-il des chemins relatifs au fichier ou au code appelant?

111

J'ai du mal à comprendre le jeu de règles concernant les chemins d'inclusion relatifs PHP. Si j'exécute le fichier A.PHP- et que le fichier A.PHP inclut le fichier B.PHP qui inclut le fichier C.PHP, le chemin relatif de C.PHP doit-il être en relation avec l'emplacement de B.PHP, ou avec l'emplacement de A .PHP? Autrement dit, quel est le fichier à partir duquel l'inclusion est appelée ou quel est le répertoire de travail actuel et qu'est-ce qui détermine le répertoire de travail actuel?

Yarin
la source
Réponse plus précise que la réponse acceptée à mon avis: stackoverflow.com/a/23902890/1636522 .
feuille du

Réponses:

132

C'est relatif au script principal, dans ce cas A.php. N'oubliez pas que le include()code insère simplement dans le script en cours d'exécution.

Autrement dit, quel est le fichier à partir duquel l'inclusion est appelée

Non.

Si vous voulez que ce soit important, et faire une inclusion relative à B.php, utilisez la __FILE__constante (ou __DIR__depuis PHP 5.2 IIRC) qui pointera toujours vers le fichier courant littéral dans lequel se trouve la ligne de code.

include(dirname(__FILE__)."/C.PHP");
Pekka
la source
@ Pekka- génial- exactement ce que je cherchais. Pour plus d'informations, voir stackoverflow.com/questions/2184810/…
Yarin
7
Vous pouvez également utiliser __DIR__dans ce but précis.
Nick Bedford
1
Cette réponse est un peu exagérée: PAS BESOIN include(dirname(__FILE__)."/C.PHP");, car cela include("C.PHP");suffit (Oui! C.PHP peut être dans le même répertoire que B.PHP) Cela peut échouer uniquement lorsqu'il y a deux fichiers C.PHP dans votre projet.
Johnny Wong
Pour être plus clair: il est relatif à la fois à B.php et A.php s'il n'y a pas de préfixe "./" ou "../" dans le chemin d'inclusion. Voir ma réponse ci-dessous.
Johnny Wong
21

@Pekka m'a amené là-bas, mais je veux juste partager ce que j'ai appris:

getcwd() renvoie le répertoire dans lequel réside le fichier que vous avez commencé à exécuter.

dirname(__FILE__) renvoie le répertoire du fichier contenant le code en cours d'exécution.

En utilisant ces deux fonctions, vous pouvez toujours créer un chemin d'inclusion relatif à ce dont vous avez besoin.

par exemple, si b.php et c.php partagent un répertoire, b.php peut inclure c.php comme:

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

peu importe d'où b.php a été appelé.

En fait, c'est la manière préférée d'établir des chemins relatifs, car le code supplémentaire libère PHP de la nécessité d'itérer à travers le include_path pour tenter de localiser le fichier cible.

Sources:

Différence entre getcwd () et dirname (__ FILE__)? Lequel dois-je utiliser?

Pourquoi utiliser dirname (__ FILE__)

Yarin
la source
Je voudrais ajouter quelque chose, j'avais un fichier appelé csb.php, inclus un fichier de fonctions d'un dossier, et le fichier de fonctions comprenait un fichier nommé t.php du même dossier que le fichier de fonctions, quand j'ai essayé d'inclure un fichier nommé csb.php du dossier t.php était, il a commencé à inclure le même csb.php qui appelait le fichier de fonctions, mais quand j'ai changé le deuxième csb.php en csbe.php, il a commencé à fonctionner tout de suite. Donc, il semble qu'il priorise le premier dossier, puis le deuxième dossier d'inclusion!
Miguel Vieira
18
  1. Si include path ne commence pas par ./ou ../, par exemple:

    include 'C.php'; // precedence: include_path (which include '.' at first),
                     // then path of current `.php` file (i.e. `B.php`), then `.`.
  2. Si include path commence par ./ou ../, par exemple:

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

Le .ou ..au-dessus est relatif à getcwd(), qui par défaut est le chemin du .phpfichier d' entrée (c.-à-d.A.php ).

Testé sur PHP 5.4.3 (Date de build: 8 mai 2012 00:47:34).

(Notez également que cela chdir()peut changer la sortie de getcwd().)

Johnny Wong
la source
Pour conclure, le chemin de A.php est d'abord recherché pour C.php, puis le chemin de B.php est recherché s'il n'y a pas de préfixe './' ou '../' dans l'inclusion. (Supposons le paramètre PHP par défaut)
Johnny Wong
Merci de m'avoir aidé chdir(__DIR__)à résoudre le problème.
HartleySan
[...] getcwd(), qui par défaut est le chemin du fichier .php d'entrée [...] - pas nécessairement vrai. Si j'exécute PHP sur la ligne de commande, getcwd()fait référence au répertoire de travail actuel du shell, quel que soit le .phpfichier que j'appelle. Je peux imaginer, cependant, que si PHP est exécuté dans un environnement de serveur Web, l'environnement initialise le répertoire de travail actuel dans le .phpfichier d' entrée . Testé sur macOS avec PHP 7.2.2 installé via Homebrew.
herzbube
17

La réponse acceptée de Pekka est incomplète et, dans un contexte général, trompeuse. Si le fichier est fourni comme chemin relatif, la construction de langage appelée includele recherchera de la manière suivante.

Tout d'abord, il passera par les chemins de la variable d'environnement include_path, qui peut être définie avec ini_set. Si cela échoue, il cherchera dans le propre répertoire du script appelant dirname(__FILE__)( __DIR__avec php> = 5.3.) Si cela échoue également, alors seulement il cherchera dans le répertoire de travail! Il s'avère simplement que, par défaut, la variable d'environnement include_pathcommence par ., qui est le répertoire de travail actuel. C'est la seule raison pour laquelle il recherche d'abord dans le répertoire de travail actuel. Voir http://php.net/manual/en/function.include.php .

Les fichiers sont inclus en fonction du chemin d'accès au fichier donné ou, si aucun n'est indiqué, du chemin d'inclusion spécifié. Si le fichier n'est pas trouvé dans include_path, include va finalement archiver le propre répertoire du script appelant et le répertoire de travail actuel avant d'échouer.

Donc, la bonne réponse à la première partie de la question est qu'il importe où se trouve le script d'appel inclus. La réponse à la dernière partie de la question est que le répertoire de travail initial , dans un contexte de serveur web, est le répertoire du script appelé, le script qui inclut tous les autres tout en étant manipulé par PHP. Dans un contexte de ligne de commande, le répertoire de travail initial est ce qu'il est lorsque php est appelé à l'invite, pas nécessairement le répertoire où se trouve le script appelé. Le répertoire de travail actuel , cependant, peut être modifié au moment de l'exécution avec la fonction PHP chdir. Voir http://php.net/manual/en/function.chdir.php .

Ce paragraphe est ajouté pour commenter d'autres réponses. Certains ont mentionné que s'appuyer sur include_pathest moins robuste et qu'il est donc préférable d'utiliser des chemins complets tels que./path ou __DIR__ . /path. Certains sont allés jusqu'à dire que se fier au répertoire de travail .lui-même n'est pas sûr, car il peut être modifié. Cependant, parfois, vous devez vous fier aux valeurs d'environnement. Par exemple, vous pouvez vouloir définir include_pathvide, de sorte que le répertoire du script appelant soit le premier endroit où il effectuera la recherche, même avant le répertoire de travail actuel. Le code peut être déjà écrit et mis à jour régulièrement à partir de sources externes et vous ne souhaitez pas réinsérer le préfixe __DIR__chaque fois que le code est mis à jour.


la source
"si cela échoue, il recherchera dans le propre répertoire du script appelant dirname(__FILE__) (__DIR__)avec php> = 5.3.)" Êtes-vous sûr? Où est-il documenté? J'espère que vous avez tort, et PHP ne pas utiliser __FILE__et __DIR__à cette fin, car cela briser rapidement , y compris les scripts de « frères et sœurs » de liens symboliques les! : -o (Ce qui, heureusement, semble fonctionner correctement ici, sur ma configuration 7.1.)
Sz.
6

Réponse courte: c'est relatif au script d'inclusion.

TFM l' explique correctement:

Si le fichier n'est pas trouvé dans include_path, include archivera le répertoire du script appelant et le répertoire de travail actuel

Donc, si /app/main.php ditinclude("./inc.php") cela trouvera /app/inc.php .

le ./ n'est pas strictement nécessaire mais supprime toute dépendance sur include_path.

Je ne me fierais pas à la recherche de fichiers d'inclusion dans le répertoire de travail actuel au cas où quelqu'un le changerait avec chdir().

Denis Howe
la source
Donc, si vous démarrez la chaîne avec ./, vérifie-t-elle d'abord le répertoire du script appelant ou le répertoire de travail actuel?
Pacerier
2
@Denis Howe Non, vous dépendez déjà du répertoire de travail actuel si votre chemin d'inclusion commence par ./. ie chdir ("/ app / other") fera include("./inc.php")échouer. Ainsi, utilisez include("inc.php")pour être en sécurité dans ce cas.
Johnny Wong
@Pacerier si la chaîne commence par ./ ​​ou ../, il ne vérifie que le répertoire de travail courant. (include_path et le répertoire du script appelant (B.php) sont tous deux ignorés). Voir ma réponse pour plus de détails.
Johnny Wong
-2
dir
-> a.php
-> c.php

- dir2 
-> b.php

À inclure adansbvous devezinclude("../a.php");

Pour inclure bdans cvous devezinclude("dir2/b.php");

Olli
la source
4
@ Olli- vous manquez le point de la question - je vous demandais comment les chemins relatifs sont déterminés lorsque les inclusions sont chaînées.
Yarin le