PHP-Не удалось открыть поток:Нет такого файла или директории

php require fopen include-path


В сценариях PHP, независимо от того, вызывается ли метод include() , require() , fopen() или их производные, такие как include_once , require_once или даже move_uploaded_file() , часто встречается ошибка или предупреждение:

Не удалось открыть поток:Нет такого файла или каталога.

Что является хорошим процессом,чтобы быстро найти первопричину проблемы?




Answer 1 Vic Seedoubleyew


Причин,по которым можно столкнуться с этой ошибкой,множество,и поэтому хороший контрольный список того,что нужно проверить в первую очередь,значительно помогает.

Рассмотрим,что мы диагностируем следующую строку:

require "/path/to/file"


Checklist


1.Проверьте путь к файлу на наличие опечаток

  • либо проверьте вручную (визуально проверяя путь).
  • или переместите все, что вызывается с помощью require* или include* в свою собственную переменную, отобразите его, скопируйте и попробуйте получить доступ к нему из терминала:

    $path = "/path/to/file";
    
    echo "Path : $path";
    
    require "$path";

    Потом,в терминале:

    cat <file path pasted>


2.Проверьте,что путь к файлу корректен относительно соображений относительного и абсолютного пути.

  • если он начинается с прямой косой черты "",то это относится не к корню папки вашего сайта (корень документа),а к корню вашего сервера.
    • например, каталог вашего сайта может быть /users/tony/htdocs
  • если он не начинается с косой черты, то он либо полагается на путь включения (см. ниже), либо путь является относительным. Если это относительно, то PHP будет рассчитывать относительно пути текущего рабочего каталога .
    • таким образом,не по отношению к пути к корню вашего сайта,или к файлу,в котором вы печатаете
    • по этой причине всегда используйте абсолютные пути к файлам

Передовые практики :

Для того,чтобы сделать ваш скрипт надежным в случае,если вы перемещаете вещи вокруг,в то же время генерируя абсолютный путь во время выполнения,у вас есть 2 варианта :

  1. использование require __DIR__ . "/relative/path/from/current/file" . __DIR__ постоянная магия возвращает каталог текущего файла.
  2. определите константу 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,такие как включенный путь.


3.Проверьте включенный путь

Другой способ включения файлов, ни относительный, ни сугубо абсолютный, заключается в использовании пути включения . Это часто имеет место для библиотек или фреймворков, таких как фреймворк Zend.

Такое включение будет выглядеть следующим образом:

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 запрещают ему доступ к этому файлу.

Может быть релевантно три параметра :

  1. open_basedir
    • Если этот параметр установлен,PHP не сможет получить доступ ни к одному файлу вне указанной директории (даже через символическую ссылку).
    • Однако,поведение по умолчанию заключается в том,что оно не должно быть установлено,и в этом случае нет никаких ограничений
    • Это можно проверить, вызвав phpinfo() или используя ini_get("open_basedir")
    • Вы можете изменить настройки либо отредактировав ваш php.ini файл,либо httpd.conf файл.
  2. безопасный режим
    • если это включено, ограничения могут применяться. Однако это было удалено в PHP 5.4. Если вы все еще используете версию, которая поддерживает безопасный режим, обновите ее до версии PHP, которая все еще поддерживается .
  3. allow_url_fopen и allow_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 предполагает,что вы добавили путь к этой библиотеке в путь include.

Например,упомянутый выше файл Zend framework может иметь следующую включённую версию :

include "Zend/Mail/Protocol/Exception.php" 

который не является ни относительным,ни абсолютным включением.Предполагается,что к пути включения был добавлен каталог Zend framework.

В таком случае,единственным практическим решением будет добавление каталога в ваш включаемый путь.


2.SELinux

Если вы используете Security-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 контекста 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

Если вы используете Symfony и сталкиваетесь с этой ошибкой при загрузке на сервер, возможно, кэш приложения не был сброшен, либо потому, что app/cache был загружен, либо этот кэш не был очищен.

Вы можете протестировать и исправить это,выполнив следующую консольную команду:

cache:clear


4.Не ACSII символы внутри Zip файла

По-видимому, эта ошибка также может возникать при вызове zip->close() когда в некоторых файлах внутри zip-файла есть не-ASCII-символы в имени файла, например «é».

Потенциальное решение - обернуть имя файла в utf8_decode() перед созданием целевого файла.

Кредиты Фран Кано для выявления и предложения решения этой проблемы




Answer 2 Machavity


Чтобы добавить к (действительно хорошему)существующему ответу

Программное обеспечение общего хостинга

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

Это не очень умная идея,потому что файл или каталог теперь доступен для записи.Если вы владеете сервером и являетесь единственным пользователем,то это не так уж и важно,но если вы находитесь на общем хостинге,то вы только что предоставили доступ всем,кто находится на вашем сервере.

Что вам нужно сделать,так это определить пользователей,которым нужен доступ,и дать доступ только тем пользователям,которым он нужен.Как только вы узнаете,каким пользователям нужен доступ,вы захотите убедиться,что

  1. Этот пользователь владеет файлом и, возможно, родительским каталогом (особенно родительским каталогом, если вы хотите записывать файлы). В большинстве сред общего хостинга это не будет проблемой, потому что ваш пользователь должен владеть всеми файлами под вашим корнем. Пример Linux показан ниже

    chown apache:apache /path/to/file
  2. Пользователь и только этот пользователь имеет доступ. В Linux хорошей практикой будет chmod 600 (только владелец может читать и писать) или chmod 644 (владелец может писать, но каждый может читать)

Вы можете прочитать более подробное обсуждение разрешений Linux / Unix и пользователей здесь




Answer 3 Hammad Khan


  1. Посмотрите на точную ошибку

Мой код отлично работал на всех машинах,но только на этой стал давать проблему (которая раньше работала найти,я думаю).Использовал эхо-путь "document_root" для отладки,а также внимательно посмотрел на ошибку,обнаружил следующее

Предупреждение: include ( D: /MyProjects/testproject//functions/connections.php ): не удалось открыть поток:

Вы можете легко увидеть,где проблемы.Проблемы есть/перед функциями

$document_root = $_SERVER['DOCUMENT_ROOT'];
echo "root: $document_root";
include($document_root.'/functions/connections.php');

Поэтому просто уберите накладку из комплекта поставки и она должна работать нормально.Что интересно,так это то,что такое поведение отличается на разных версиях.Я запускаю один и тот же код на ноутбуке,Macbook Pro и этом компьютере,и все работает отлично до сих пор.Надеюсь,это кому-то поможет.

  1. Скопируйте в браузере местоположение файла,чтобы убедиться в его существовании.Иногда файлы удаляются неожиданно (это случилось со мной),и это также было проблемой в моем случае.



Answer 4 Paul Lynn


Добавить скрипт с параметрами запроса

Это был мой случай. Это на самом деле ссылка на вопрос # 4485874 , но я собираюсь объяснить это здесь в ближайшее время.
Когда вы пытаетесь path/to/script.php?parameter=value , PHP ищет файл с именем script.php?parameter=value , потому что UNIX позволяет вам иметь такие пути.
Если вам действительно нужно передать некоторые данные во включенный скрипт, просто объявите его как $variable=... или $GLOBALS[]=... или другим способом, который вам нравится.




Answer 5 Stephan Brunker


Акции Самбы

Если у вас есть тестовый сервер Linux, и вы работаете с клиентом Windows, общий ресурс Samba мешает работе команды chmod . Итак, даже если вы используете:

chmod -R 777 myfolder

На стороне Linux вполне возможно,что Unix Group\www-данные все еще не имеют доступа на запись.Одно из рабочих решений,если ваш ресурс настроен так,что администраторы Windows сопоставляются с root:Из Windows откройте Permissions (Разрешения),отключите Inheritance (Наследование)для вашей папки с копией,а затем предоставьте полный доступ для www-data.