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


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

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

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

5 108

5 ответов:

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

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". Элемент __DIR__ магической константы возвращает каталог текущего файла.
  2. определение 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 практики также делают ваше приложение более портативным, потому что оно не зависит от ini настройки Как включить путь.


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

3 установки смогли быть уместны :

  1. функции
    • если это установлено, PHP не сможет получить доступ к любому файлу за пределами указанного каталога (даже через символическую ссылку).
    • однако поведение по умолчанию для него не должно быть установлено, и в этом случае нет никаких ограничений
    • это можно проверить, позвонив по телефону phpinfo() и с помощью ini_get("open_basedir")
    • вы можете изменить настройки, либо путем редактирования РНР.ini-файл или ваш httpd.conf file
  2. безопасный режим
    • если это включено, могут применяться ограничения. Однако это было удалено в PHP 5.4. Если вы все еще находитесь на версии, которая поддерживает безопасный режим обновления до версии PHP, которая является все еще поддерживается.
  3. опция allow_url_fopen и allow_url_include
    • это относится только к включению или открытие файлов через сетевой процесс, такой как http: / / not при попытке включить файлы в локальную файловую систему
    • это можно проверить с помощью ini_get("allow_url_include") и ini_set("allow_url_include", "1")


случаев углу

если ни один из вышеперечисленных методов не позволяет диагностировать проблему, вот некоторые особые ситуации, которые могут произойти:


1. Включение библиотеки, опираясь на путь

может случиться так, что вы включаете библиотеку, например Zend framework, используя относительный или абсолютный путь. Например :

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. Селинукс

если вы работаете с усиленной безопасностью 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 boolean:

setsebool -P httpd_enable_homedirs 1

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


3. Symfony

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

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

cache:clear


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

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

потенциальное решение заключается в том, чтобы обернуть имя файла в utf8_decode() перед созданием целевой файл.

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

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

Программное Обеспечение Для Совместного Хостинга

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 будет выполняться с разрешениями корень.)

много раз люди будут решать проблему разрешений, делая следующее (пример Linux)

chmod 777 /path/to/file

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

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

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

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

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

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

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

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

  1. посмотреть точно

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

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

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

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

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

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