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

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

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

Какой хороший способ быстро найти основную причину проблемы?

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

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

 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 варианта:

  1. используйте require __DIR__ . "/relative/path/from/current/file" 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», является частью пути include.

Вы можете проверить путь включения:

 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.

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

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

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

В таком случае единственное практическое решение – добавить каталог в ваш путь include.

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_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 для веб-сервера.

3. Симфония

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

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

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

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

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

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

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