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

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

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

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

12 ответов

Решение

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

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

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.

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

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 Framework, используя относительный или абсолютный путь. Например:

require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"

Но тогда вы все равно получаете такую ​​же ошибку.

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

Например, упомянутый ранее файл 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 Тип контекста в корневой каталог вашего сайта, запустите:

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() перед созданием целевого файла.

Кредиты Fran Cano для определения и предложения решения этой проблемы

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

Shared Hosting Software

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, 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 и пользователей здесь

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

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

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

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

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

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

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

Samba Shares

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

chmod -R 777 myfolder

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

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

Например:

      $file = fopen(date('Y-m-d_H:i:s'), 'w+');

Дам:

fopen(2022-06-01_22:53:03): Не удалось открыть поток: Нет такого файла или каталога в ...

винда не любит :в именах файлов, а также ряд других символов.

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

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

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

Следующие настройки PHP в php.ini если установлен в несуществующий каталог, также может поднять

Предупреждение PHP: Неизвестно: не удалось открыть поток: В разрешении отказано в Неизвестном в строке 0

sys_temp_dir
upload_tmp_dir
session.save_path

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

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

$thePathOfMyPicture = "/Users/misstugba/Desktop/"; использовать с функцией

      if(move_uploaded_file($_FILES["file"]["tmp_name"],$thePathOfMyPicture.$_FILES["file"]["name"])){
echo "image uploaded successfully";

}

Для меня я получил эту ошибку, потому что я пытался прочитать файл, который требовал HTTP-аутентификации, с именем пользователя и паролем. Надеюсь, что это поможет другим. Может быть еще один угловой случай.

Редактировать

Вы можете проверить, присутствует ли этот тип аутентификации, проверив заголовки:

      $file_headers = get_headers($url);
if (!$file_headers) echo 'File headers missing';
else if (strpos($file_headers[0], '401 Unauthorized') > -1) echo '401 Unauthorized';

В PHP запустите Apache, затем напишите имя БД и пароль, если они существуют в вашей среде (.env).

Если вы запускаете консольные сценарии CLI, добавьте в 1 строку

      #!/usr/bin/env php
<?php
require_once('common/autoload.php');
Другие вопросы по тегам