В скриптах PHP, include()
вызовы include()
, require()
, fopen()
или их производные, такие как include_once
, require_once
или даже move_uploaded_file()
, часто возникает ошибка или предупреждение:
Не удалось открыть поток: нет такого файла или каталога.
Какой хороший способ быстро найти основную причину проблемы?
Существует много причин, по которым можно столкнуться с этой ошибкой, и поэтому хороший контрольный список того, что нужно проверить, в первую очередь помогает значительно.
Давайте рассмотрим, что мы устраняем следующие проблемы:
require "/path/to/file"
или переместить все, что вызвано require*
или include*
в свою собственную переменную, эхо, скопировать его и попробовать получить доступ к нему с терминала:
$path = "/path/to/file"; echo "Path : $path"; require "$path";
Затем, в терминале:
cat <file path pasted>
/users/tony/htdocs
Лучшие практики :
Чтобы сделать ваш скрипт надежным, если вы перемещаете вещи, но при создании абсолютного пути во время выполнения у вас есть 2 варианта:
require __DIR__ . "/relative/path/from/current/file"
require __DIR__ . "/relative/path/from/current/file"
. Магическая константа __DIR__
возвращает каталог текущего файла. определите константу SITE_ROOT
самостоятельно:
config.php
в config.php
, напишите
define('SITE_ROOT', __DIR__);
в каждом файле, где вы хотите ссылаться на корневую папку сайта, SITE_ROOT
config.php
, а затем используйте константу SITE_ROOT
где бы вы ни находились:
require_once __DIR__."/../config.php"; ... require_once SITE_ROOT."/other/file.php";
Эти 2 практики также делают ваше приложение более портативным, поскольку оно не зависит от настроек ini, таких как путь включения.
Другой способ включить файлы, ни относительно, ни абсолютно абсолютно, – это полагаться на путь включения . Это часто бывает для библиотек или фреймворков, таких как структура Zend.
Такое включение будет выглядеть так:
include "Zend/Mail/Protocol/Imap.php"
В этом случае вы захотите убедиться, что папка, где находится «Zend», является частью пути include.
Вы можете проверить путь включения:
echo get_include_path();
Вы можете добавить к нему папку:
set_include_path(get_include_path().":"."/path/to/new/folder");
Возможно, что пользователь, выполняющий серверный процесс (Apache или php), просто не имеет права на чтение или запись в этот файл.
Чтобы проверить, под каким пользователем сервер работает, вы можете использовать posix_getpwuid :
$user = posix_getpwuid(posix_geteuid()); var_dump($user);
Чтобы узнать разрешения на файл, введите в терминал следующую команду:
ls -l <path/to/file>
и посмотрите на символическую символику разрешения
Если ни одно из вышеперечисленных не было выполнено, то проблема, вероятно, в том, что некоторые настройки PHP запрещают ему доступ к этому файлу.
Три параметра могут иметь значение:
phpinfo()
или используя ini_get("open_basedir")
ini_get("allow_url_include")
и установить с помощью ini_set("allow_url_include", "1")
Если ни одна из вышеперечисленных не позволяет диагностировать проблему, вот некоторые особые ситуации, которые могут произойти:
Может случиться так, что вы включаете библиотеку, например, структуру Zend, используя относительный или абсолютный путь. Например :
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
Но тогда вы все равно получаете такую же ошибку.
Это может произойти из-за того, что файл, который у вас есть (успешно) включен, сам имеет оператор include для другого файла, а второй включенный оператор предполагает, что вы добавили путь к этой библиотеке в путь include.
Например, упомянутый ранее файл фреймворка Zend может включать следующее:
include "Zend/Mail/Protocol/Exception.php"
который не является ни включением относительным путем, ни абсолютным путем. Предполагается, что каталог структуры Zend добавлен в путь include.
В таком случае единственное практическое решение – добавить каталог в ваш путь include.
Если вы используете Security-Enhanced Linux, это может быть причиной проблемы, запретив доступ к файлу с сервера.
Чтобы проверить, включен ли SELinux в вашей системе, запустите команду sestatus
в терминале. Если команда не существует, SELinux не входит в вашу систему. Если он существует, то он должен сказать вам, применяется ли оно или нет.
Чтобы проверить, являются ли политики SELinux причиной этой проблемы, вы можете временно отключить ее. Однако будьте ОСТОРОЖНЫ, так как это полностью отключит защиту. Не делайте этого на своем производственном сервере.
setenforce 0
Если у вас больше нет проблемы с выключенным SELinux, это будет основной причиной.
Чтобы решить эту проблему , вам необходимо настроить SELinux соответственно.
Будут необходимы следующие типы контекстов:
httpd_sys_content_t
для файлов, которые вы хотите, чтобы ваш сервер мог читать httpd_sys_rw_content_t
для файлов, на которые вы хотите читать и писать httpd_log_t
для файлов журнала httpd_log_t
для каталога кеша Например, чтобы назначить httpd_sys_content_t
контекста httpd_sys_content_t
корневому каталогу вашего сайта, запустите:
semanage fcontext -a -t http_sys_content_t "/path/to/root(/.*)?" restorecon -Rv /path/to/root
Если ваш файл находится в домашнем каталоге, вам также необходимо включить httpd_enable_homedirs
boolean:
setsebool -P httpd_enable_homedirs 1
В любом случае может существовать множество причин, по которым SELinux запрещает доступ к файлу в зависимости от ваших политик. Поэтому вам нужно будет узнать об этом. Ниже приведено руководство по настройке SELinux для веб-сервера.
Если вы используете Symfony и испытываете эту ошибку при загрузке на сервер, то может быть, что кеш приложения не был сброшен, поскольку загрузка app/cache
была загружена или этот кеш не был очищен.
Вы можете проверить и исправить это, выполнив следующую консольную команду:
cache:clear
Чтобы добавить (действительно хороший) существующий ответ
open_basedir
– это тот, который может пнуть вас, потому что он может быть указан в конфигурации веб-сервера. Хотя это легко исправить, если вы запускаете собственный выделенный сервер, есть некоторые пакеты хостинга для совместного использования (например, Plesk, cPanel и т. Д.), Которые будут настраивать директиву конфигурации для каждого домена. Поскольку программное обеспечение создает файл конфигурации (например, httpd.conf
), вы не можете изменить этот файл напрямую, потому что хостинг-программное обеспечение просто перезапишет его при перезапуске.
С Plesk они предоставляют место для переопределения предоставленного httpd.conf
называемого vhost.conf
. Этот файл может написать только администратор сервера. Конфигурация для Apache выглядит примерно так:
<Directory /var/www/vhosts/domain.com> <IfModule mod_php5.c> php_admin_flag engine on php_admin_flag safe_mode off php_admin_value open_basedir "/var/www/vhosts/domain.com:/tmp:/usr/share/pear:/local/PEAR" </IfModule> </Directory>
Попросите администратора вашего сервера обратиться к руководству по хостингу и веб-серверному программному обеспечению, которое они используют.
Важно отметить, что выполнение файла через ваш веб-сервер сильно отличается от выполнения командной строки или выполнения задания cron. Большая разница в том, что ваш веб-сервер имеет свой собственный пользователь и разрешения. По соображениям безопасности пользователь довольно ограничен. Apache, например, часто является apache
, www-data
или httpd
(в зависимости от вашего сервера). Задача cron или выполнение CLI имеет все права, которые пользователь запускает (т.е. запуск PHP-скрипта с правами root будет выполняться с правами root).
Много раз люди решат проблему с разрешениями, выполняя следующие действия (пример Linux)
chmod 777 /path/to/file
Это не умная идея, потому что файл или каталог теперь доступны для записи на весь мир. Если вы владеете сервером и являетесь единственным пользователем, тогда это не так уж и важно, но если вы находитесь в среде совместного размещения, которую вы только что дали всем на вашем сервере.
Что вам нужно сделать, так это определить пользователей, которым нужен доступ, и предоставить только те, к которым они имеют доступ. Как только вы узнаете, какие пользователи нуждаются в доступе, вы захотите убедиться, что
Этот пользователь владеет файлом и, возможно, родительским каталогом (особенно родительским каталогом, если вы хотите писать файлы). В большинстве общедоступных хостинговых сред это не будет проблемой, потому что ваш пользователь должен владеть всеми файлами под вашим корнем. Пример Linux приведен ниже.
chown apache:apache /path/to/file
Пользователь и только тот пользователь имеют доступ. В Linux хорошей практикой будет chmod 600
(только владелец может читать и писать) или chmod 644
(владелец может писать, но каждый может читать)
Вы можете прочитать более расширенное обсуждение разрешений Linux и Unix и пользователей здесь
Другая возможная причина: переименование и / или перемещение файлов в текстовом редакторе. Я прошел все этапы без успеха, пока не удалил файл, который продолжал бросать эту ошибку и создавал новую, которая исправила проблему.