В сценариях PHP, вызывая 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 <путь к файлу вставлен>
/users/tony/htdocs
.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";
Эти две практики также делают ваше приложение более переносимым, поскольку оно не зависит от ini-параметров, таких как путь включения.
Еще один способ включения файлов, ни относительно, ни чисто абсолютно, - это полагаться на include path. Это часто используется для библиотек или фреймворков, таких как фреймворк Zend. Такое включение будет выглядеть следующим образом :
include "Zend/Mail/Protocol/Imap.php"
В этом случае вам нужно убедиться, что папка, в которой находится "Zend", является частью пути включения. Проверить путь включения можно с помощью :
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>
и посмотрите на permission symbolic notation.
Если ничего из вышеперечисленного не помогло, то проблема, вероятно, заключается в том, что некоторые настройки 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 предполагает, что вы добавили путь к этой библиотеке в путь include. Например, файл Zend framework, упомянутый ранее, может иметь следующий include :
include "Zend/Mail/Protocol/Exception.php"
что не является включением ни по относительному, ни по абсолютному пути. Предполагается, что каталог Zend framework был добавлен в путь include.
В таком случае единственным практическим решением является добавление каталога в путь include.
Если вы используете Security-Enhanced Linux, то это может быть причиной проблемы, запрещая доступ к файлу с сервера.
Чтобы проверить, включен ли SELinux в вашей системе, выполните команду sestatus
в терминале. Если команда не существует, значит, SELinux в вашей системе отсутствует. Если же она существует, то она должна сообщить вам, применяется ли 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 для веб-сервера.
Если вы используете Symfony и столкнулись с этой ошибкой при загрузке на сервер, то это может быть связано с тем, что кэш приложения не был сброшен, либо потому что app/cache
был загружен, либо потому что кэш не был очищен.
Вы можете проверить и исправить это, выполнив следующую консольную команду:
cache:clear
По-видимому, эта ошибка может возникнуть и при вызове zip->close()
, когда некоторые файлы внутри Zip-файла содержат в своем имени символы, не являющиеся ACSII, например "é".
Возможное решение - обернуть имя файла в utf8_decode()
перед созданием целевого файла.
Признательность Fran Cano за идентификацию и предложение решения этой проблемы
В дополнение к (действительно хорошему) существующему ответу
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 вы можете прочитать здесь (https://unix.stackexchange.com/questions/35711/giving-php-permission-to-write-to-files-and-folders).
Мой код работал нормально на всех машинах, но только на этот раз начали давать проблем (что б работу найти, я думаю). Используется Эхо "document_root" и путь для отладки и внимательно посмотрел на ошибки, нашел это
предупреждение: и GT; включить(D:/MyProjects/testproject//functions/connections.php): не удалось открыть поток:
Вы можете легко увидеть, где есть проблемы. Проблемы // перед функциями
$document_root = $_SERVER['DOCUMENT_ROOT'];
echo "root: $document_root";
include($document_root.'/functions/connections.php');
Так что просто удалите ладинг / включить и он должен работать нормально. Что интересно, так это поведение отличается в разных версиях. Я запускаю тот же код на ноутбук, MacBook Pro и этот компьютер, все работало нормально пока. Надеюсь, что это помогает кто-то.
Это был мой случай. Это на самом деле ссылки на вопрос #4485874, но я'м собирается вскоре объяснить это здесь.
Когда вы пытаетесь требовать путь/до/скрипта.РНР?параметр=значение
, то PHP ищет файл с именем скрипта.РНР?параметр=значение, потому, что Unix позволяет иметь пути вроде этого. Если вам действительно нужно пройти некоторые данные, чтобы включить скрипт, просто объявим его как
$переменная=...или
$Globals, так[]=...` или другим удобным для вас способом.
Акции Самба
Если у вас есть тестовый сервер Linux и работе с клиента Windows, доля Самба мешает чмод команда. Поэтому, даже если вы используете:
chmod -R 777 myfolder
со стороны Linux это полностью возможно, что группа\ВСП-данных Unix до сих пор не'т иметь право на запись. Одно рабочее решение, если ваша доля установлено, что администраторы Windows сопоставляются с корнем: с электроприводом, открытие разрешений, отключить наследование для папки с скопировать, а затем предоставить полный доступ для www-данных.
Другая возможная причина: Переименование и/или перемещение файлов в текстовом редакторе. Я безуспешно проделал все описанные выше шаги, пока не удалил файл, который продолжал выдавать эту ошибку, и создал новый, что устранило проблему.