Чи включають PHP шляхи відносно файлу або коду виклику?


111

У мене виникають проблеми з розумінням набору правил щодо відносних PHP включають шляхи. Якщо я запускаю файл A.PHP-, а файл A.PHP включає файл B.PHP, який включає файл C.PHP, якщо відносний шлях до C.PHP повинен бути відносно місця розташування B.PHP або до місця розташування A .PHP? Тобто, чи має значення яке файлу включається виклик, або лише те, з чого складається поточний робочий каталог - і що визначає поточний робочий каталог?


Більш точна, ніж прийнята відповідь на мій погляд: stackoverflow.com/a/23902890/1636522 .
листопад

Відповіді:


132

Це відносно основного сценарію, в цьому випадку A.php. Пам'ятайте, що include()просто вставляє код у запущений сценарій.

Тобто, чи не має значення, з якого файлу виклик включається

Немає.

Якщо ви хочете , щоб зробити цю справу, і зробити включається щодо B.php, використовуйте __FILE__константу (або __DIR__так PHP 5.2 IIRC) , який завжди вказує на буквальне поточного файлу , що рядок коду знаходиться в.

include(dirname(__FILE__)."/C.PHP");

@ Pekka- дивовижно- просто те, що я шукав. Для отримання додаткової інформації дивіться stackoverflow.com/questions/2184810/…
Ярін

7
Ви також можете використовувати саме __DIR__для цієї мети.
Нік Бедфорд

1
Ця відповідь є дещо надмірною: НЕ ПОТРІБНА include(dirname(__FILE__)."/C.PHP");, бо include("C.PHP");достатньо (Так! C.PHP може бути в тому ж каталозі, що і B.PHP) Можливо, вона не вийде лише тоді, коли у вашому проекті є два файли C.PHP.
Джонні Вонг

Щоб зробити це більш зрозумілим: це відносно як B.php, так і A.php, якщо в шляху включення немає префікса "./" або "../". Дивіться мою відповідь нижче.
Джонні Вонг

21

@Pekka завів мене там, але просто хочу поділитися тим, що я дізнався:

getcwd() повертає каталог, де знаходиться файл, який ви почали виконувати.

dirname(__FILE__) повертає каталог файлу, що містить в даний час код виконання.

Використовуючи ці дві функції, ви завжди можете побудувати включений шлях відносно того, що вам потрібно.

наприклад, якщо b.php і c.php поділяють каталог, b.php може включати c.php, як:

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

де б не називався b.php.

Насправді, це кращий спосіб встановлення відносних шляхів, оскільки додатковий код позбавляє PHP від ​​необхідності повторити ітерацію через enable_path при спробі знайти цільовий файл.

Джерела:

Різниця між getcwd () та dirname (__ FILE__)? Який я повинен використовувати?

Чому слід використовувати dirname (__ FILE__)


Я хотів би щось додати, у мене був файл під назвою csb.php, включений файл функцій з папки, а файл функцій включав файл з назвою t.php з тієї ж папки, що і файл функцій. Коли я намагався включати файл з назвою csb.php з папки t.php був, він почав включати той же csb.php, який викликав файл функцій, але коли я змінив другий csb.php на csbe.php, він почав працювати відразу. Отже, схоже, що це пріоритетно додає першу папку, а потім другу папку!
Мігель Віейра

18
  1. Якщо включити шлях не починається з ./або ../, наприклад:

    include 'C.php'; // precedence: include_path (which include '.' at first),
                     // then path of current `.php` file (i.e. `B.php`), then `.`.
  2. Якщо включати шлях починається з ./або ../, наприклад:

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

Вище .або ..вище відносно значення getcwd(), яке за замовчуванням відповідає шляху вхідного .phpфайлу (тобто A.php).

Тестовано на PHP 5.4.3 (Дата складання: 8 травня 2012 00:47:34).

(Також зауважте, що chdir()може змінити вихід getcwd().)


На закінчення, шлях A.php спочатку шукається C.php, потім шлях B.php шукається, якщо в включенні немає префікса './' або '../'. (Припустимо налаштування PHP за замовчуванням)
Джонні Вонг,

Дякуємо за те, що я використав chdir(__DIR__)для вирішення проблеми.
HartleySan

[...] getcwd(), який за замовчуванням відповідає шляху вводу .php-файлу [...] - не обов'язково відповідає дійсності. Якщо я запускаю PHP в командному рядку, то він getcwd()посилається на поточну робочу директорію оболонки, незалежно від того, який .phpфайл я викликаю. Я можу собі уявити, що якщо PHP запускається у середовищі веб-сервера, то середовище ініціалізує поточний робочий каталог у .phpфайл входу . Тестовано на macOS з PHP 7.2.2, встановленим через Homebrew.
herzbube

17

Прийнята відповідь Пекки є неповною і, загалом, хибною. Якщо файл надається як відносний шлях, називається мовна конструкціяinclude шукатиме його наступним чином.

По-перше, він пройде через шляхи змінної середовища include_path, які можна встановити за допомогою ini_set. Якщо це не вдасться, він здійснить пошук у власному каталозі виклику скрипта dirname(__FILE__)( __DIR__з php> = 5.3.) Якщо це також не вдасться, лише тоді він здійснить пошук у робочому каталозі! Просто виявляється, що за замовчуванням include_pathпочинається змінна середовища ., яка є поточною робочою каталогом. Це єдина причина, чому він шукає спочатку в поточному робочому каталозі. Дивіться http://php.net/manual/en/function.include.php .

Файли включаються залежно від заданого шляху до файлу або, якщо такого не вказано, вказаного вказати include_path. Якщо файл не знайдений у include_path, включення остаточно перевірить у власному каталозі виклику скрипта та поточному робочому каталозі, перш ніж вийти з ладу.

Отже, правильна відповідь на першу частину питання полягає в тому, що не має значення, де знаходиться включений скрипт виклику. Відповідь на останню частину запитання полягає в тому, що початковий робочий каталог, в контексті веб-сервера, - це каталог викликаного скрипту, сценарій, який включає всі інші під час роботи з PHP. У контексті командного рядка початковий робочий каталог є будь-яким, який він є, коли в запит викликається php, не обов'язково каталог, де знаходиться названий скрипт. Однак поточний робочий каталог можна змінити під час роботи за допомогою функції PHP chdir. Дивіться http://php.net/manual/en/function.chdir.php .

Цей пункт додано для коментарів до інших відповідей. Деякі згадували, що покладатися на include_pathменш надійне, і тому бажано використовувати повні шляхи, такі як ./pathабо __DIR__ . /path. Деякі пішли далеко, сказавши, що покладатися на робочий каталог .сам по собі не є безпечним, оскільки його можна змінити. Однак у деяких випадках потрібно покладатися на значення середовища. Наприклад, ви можете встановити include_pathпорожній, так що каталог виклику скрипту - це перше місце, яке він буде шукати, навіть перед поточним робочим каталогом. Код може бути вже написаний та регулярно оновлюватися із зовнішніх джерел, і ви не хочете вставляти префікс __DIR__щоразу, коли код оновлюється.


"якщо це не вдасться, він здійснить пошук у власному каталозі виклику скрипта dirname(__FILE__) (__DIR__)з php> = 5.3." " Ви впевнені? Де це документально зафіксовано? Я сподіваюся, що ви помиляєтесь, і PHP не використовує __FILE__і __DIR__для цієї мети, оскільки це негайно порушить, включаючи "побратими" сценаріїв із символічно пов'язаних ! : -o (Який, на щастя, здається, працює добре тут, у моїй установці 7.1.)
Sz.

6

Коротка відповідь: це відносно сценарію, що включає.

TFM пояснює це правильно:

Якщо файл не знайдений у файлі include_path, включити буде перевіряти в каталозі виклику скрипта та поточному робочому каталозі

Отже, якщо /app/main.php каже, include("./inc.php")що знайде /app/inc.php .

./ не є строго необхідним , але видаляє яку - або залежність від include_path.

Я б не покладався на пошук включення файлів у поточний робочий каталог у випадку, якщо хтось змінить його chdir().


Отже, якщо ви починаєте рядок із ./, чи перевіряє він спочатку каталог каталогів виклику або спочатку поточний робочий каталог?
Pacerier

2
@Denis Howe Ні, ви вже залежите від поточного робочого каталогу, якщо ваш шлях включення починається з ./. тобто chdir ("/ app / other") вийде з include("./inc.php")ладу. Таким чином, використовуйте include("inc.php")для безпечності в цьому випадку.
Джонні Вонг

@Pacerier, якщо рядок починається з ./ або ../, він перевіряє лише поточну робочу директорію. (include_path та каталог виклику скрипту (B.php) обидва ігноруються). Дивіться мою відповідь для більш детальної інформації.
Джонні Вонг

-2
dir
-> a.php
-> c.php

- dir2 
-> b.php

Щоб включити aдо bсебе, потрібноinclude("../a.php");

Щоб включити bдо cсебе, потрібноinclude("dir2/b.php");


4
@ Olli - ти не вистачаєш пункту питання - я питав про те, як визначаються відносні шляхи, коли включені ланцюги.
Ярін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.