Є багато причин, чому можна зіткнутися з цією помилкою, і тому хороший перелік того, що перевірити спочатку, значно допомагає.
Розглянемо, що ми усуваємо проблеми з наступного рядка:
require "/path/to/file"
Контрольний список
1. Перевірте шлях файлу на помилки
- або перевірити вручну (візуально перевіривши шлях)
або перемістити все, що викликається, require*
або include*
до його власної змінної, повторити її, скопіювати та спробувати отримати доступ до нього з терміналу:
$path = "/path/to/file";
echo "Path : $path";
require "$path";
Потім у терміналі:
cat <file path pasted>
2. Перевірте, чи правильний шлях до файлу щодо відносних та абсолютних міркувань шляху
- якщо він починається з нахилу "/" вперед, тоді він не посилається на корінь папки вашого веб-сайту (корінь документа), а на корінь вашого сервера.
- наприклад, може бути каталог вашого веб-сайту
/users/tony/htdocs
- якщо він не починається прямою косою рисою, то він або спирається на шлях включення (див. нижче), або шлях відносний. Якщо він відносний, то PHP буде обчислюватися відносно шляху поточної робочої директорії .
- таким чином, не відносно шляху кореня вашого веб-сайту або до файлу, де ви вводите текст
- з цієї причини завжди використовуйте абсолютні шляхи до файлів
Кращі практики :
Щоб зробити ваш сценарій надійним у випадку, якщо ви переміщуєте речі, при цьому все ще генеруючи абсолютний шлях під час виконання, у вас є 2 варіанти:
- використання
require __DIR__ . "/relative/path/from/current/file"
. __DIR__
Постійна магія повертає каталог поточного файлу.
визначте SITE_ROOT
константу себе:
- у корені каталогу вашого веб-сайту створіть файл, наприклад
config.php
в config.php
, пишіть
define('SITE_ROOT', __DIR__);
у кожному файлі, де ви хочете посилатися на кореневу папку сайту, включіть config.php
, а потім використовуйте SITE_ROOT
константу, куди вам подобається:
require_once __DIR__."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
Ці 2 практики також роблять вашу програму більш портативною, оскільки вона не покладається на такі настройки, як шлях включення.
3. Перевірте свій включений шлях
Ще один спосіб включення файлів, ні відносно, ні абсолютно абсолютно, - покладатися на шлях включення . Це часто трапляється для бібліотек або фреймворків, таких як Zend Framework.
Таке включення буде виглядати приблизно так:
include "Zend/Mail/Protocol/Imap.php"
У цьому випадку ви хочете переконатися, що папка, де знаходиться "Zend", є частиною шляху включення.
Ви можете перевірити шлях включення за допомогою:
echo get_include_path();
Ви можете додати до нього папку за допомогою:
set_include_path(get_include_path().":"."/path/to/new/folder");
4. Перевірте, чи має ваш сервер доступ до цього файлу
Можливо, все разом, що користувач, який запускає серверний процес (Apache або PHP), просто не має дозволу читати або записувати в цей файл.
Щоб перевірити, під яким користувачем працює сервер, ви можете використовувати posix_getpwuid :
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
Щоб дізнатися дозволи на файл, введіть у терміналі таку команду:
ls -l <path/to/file>
і подивіться на символічні позначення дозволу
5. Перевірте налаштування PHP
Якщо жодне з вищезгаданого не спрацювало, можливо, проблема полягає в тому, що деякі параметри PHP забороняють йому доступ до цього файлу.
Три налаштування можуть бути відповідні:
- open_basedir
- Якщо цей параметр встановлено, PHP не зможе отримати доступ до жодного файлу за межами вказаного каталогу (навіть через символічне посилання).
- Однак поведінка за замовчуванням полягає в тому, що вона не встановлюється, і в цьому випадку обмежень немає
- Це можна перевірити, зателефонувавши
phpinfo()
або скориставшисьini_get("open_basedir")
- Ви можете змінити налаштування, відредагувавши файл php.ini або файл httpd.conf
- безпечний режим
- якщо це ввімкнено, можливі обмеження. Однак це було видалено в PHP 5.4. Якщо ви все ще перебуваєте на версії, яка підтримує безпечний режим оновлення до версії PHP, яка все ще підтримується .
- enable_url_fopen і enable_url_include
- це стосується лише включення або відкриття файлів через мережевий процес, наприклад http: // не при спробі включення файлів у локальну файлову систему
- це можна перевірити
ini_get("allow_url_include")
і встановити за допомогоюini_set("allow_url_include", "1")
Кутові шафи
Якщо жодне з перерахованого вище не дозволило діагностувати проблему, ось які особливі ситуації можуть трапитися:
1. Включення бібліотеки, що спирається на шлях включення
Може статися, що ви включаєте бібліотеку, наприклад, рамку Zend, використовуючи відносний або абсолютний шлях. Наприклад :
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
Але тоді ви все-таки отримуєте таку ж помилку.
Це може статися тому, що у файл, який ви (успішно) включили, є сам оператор include для іншого файлу, а цей другий оператор include передбачає, що ви додали шлях до цієї бібліотеки до шляху включення.
Наприклад, рамковий файл Zend, згаданий раніше, може містити таке:
include "Zend/Mail/Protocol/Exception.php"
що не є ні включенням відносним шляхом, ні абсолютним шляхом. Передбачається, що до контуру включення додати каталог Zend Framework.
У такому випадку єдиним практичним рішенням є додати каталог до шляху включення.
2. SELinux
Якщо ви працюєте з Linux-Enhanced Linux, то це може бути причиною проблеми, заборонивши доступ до файлу з сервера.
Щоб перевірити, чи ввімкнено SELinux у вашій системі, запустіть sestatus
команду в терміналі. Якщо команди не існує, SELinux відсутній у вашій системі. Якщо він існує, то він повинен повідомити, чи застосовується він чи ні.
Щоб перевірити, чи є причиною проблеми політики SELinux , спробуйте її тимчасово вимкнути. Однак будьте обережні, оскільки це повністю вимкне захист. Не робіть цього на виробничому сервері.
setenforce 0
Якщо у вас більше немає проблем із вимкненим SELinux, то це є першопричиною.
Для її вирішення доведеться відповідно налаштувати SELinux.
Необхідні наступні типи контексту:
httpd_sys_content_t
для файлів, які ви хочете, щоб ваш сервер міг читати
httpd_sys_rw_content_t
для файлів, до яких потрібно отримати доступ для читання та запису
httpd_log_t
для журнальних файлів
httpd_cache_t
для каталогу кеша
Наприклад, щоб призначити httpd_sys_content_t
тип контексту кореневому каталогу вашого веб-сайту, запустіть:
semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root
Якщо ваш файл знаходиться в домашньому каталозі, вам також потрібно буде ввімкнути httpd_enable_homedirs
булевий:
setsebool -P httpd_enable_homedirs 1
У будь-якому випадку можуть бути різні причини, через які SELinux забороняє доступ до файлу, залежно від політики. Тож вам потрібно буде довідатися про це. Ось підручник спеціально щодо налаштування SELinux для веб-сервера.
3. Симфонія
Якщо ви користуєтесь Symfony і відчуваєте цю помилку під час завантаження на сервер, можливо, кеш програми не було скинуто, тому app/cache
що він завантажений, або кеш не очищений.
Ви можете перевірити та виправити це, виконавши таку команду консолі:
cache:clear
4. Не символи ACSII всередині Zip-файлу
Мабуть, ця помилка може статися і під час виклику, zip->close()
коли деякі файли всередині zip мають у своєму імені файли не ASCII символи, наприклад, "é".
Потенційне рішення полягає в обгортанні імені файла utf8_decode()
перед створенням цільового файлу.
Подяка Фран Кано за виявлення та пропозицію вирішення цього питання