简体   繁体   English

PHP - 无法打开 stream:没有这样的文件或目录

[英]PHP - Failed to open stream : No such file or directory

In PHP scripts, whether calling include() , require() , fopen() , or their derivatives such as include_once , require_once , or even, move_uploaded_file() , one often runs into an error or warning:在 PHP 脚本中,无论是调用include()require()fopen()还是它们的派生词,例如include_oncerequire_once ,甚至是move_uploaded_file() ,都经常遇到错误或警告:

Failed to open stream: No such file or directory.无法打开 stream:没有这样的文件或目录。

What is a good process to quickly find the root cause of the problem?什么是快速找到问题根源的好过程?

There are many reasons why one might run into this error and thus a good checklist of what to check first helps considerably.可能会遇到此错误的原因有很多,因此首先检查的内容的良好清单会大有帮助。

Let's consider that we are troubleshooting the following line:假设我们正在对以下行进行故障排除:

require "/path/to/file"


Checklist清单


1. Check the file path for typos 1.检查文件路径是否有错别字

  • either check manually (by visually checking the path)手动检查(通过目视检查路径)
  • or move whatever is called by require* or include* to its own variable, echo it, copy it, and try accessing it from a terminal:或者将require*include*调用的任何内容移动到它自己的变量中,回显它,复制它,然后尝试从终​​端访问它:

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

    Then, in a terminal:然后,在终端中:

     cat <file path pasted>


2. Check that the file path is correct regarding relative vs absolute path considerations 2. 检查相对路径与绝对路径注意事项的文件路径是否正确

  • if it is starting by a forward slash "/" then it is not referring to the root of your website's folder (the document root), but to the root of your server.如果它以正斜杠“/”开头,那么它不是指您网站文件夹的根目录(文档根目录),而是指您的服务器的根目录。
    • for example, your website's directory might be /users/tony/htdocs例如,您网站的目录可能是/users/tony/htdocs
  • if it is not starting by a forward slash then it is either relying on the include path (see below) or the path is relative.如果它不是以正斜杠开头,那么它要么依赖于包含路径(见下文),要么路径是相对的。 If it is relative, then PHP will calculate relatively to the path of the current working directory .如果是相对的,那么 PHP 会相对于当前工作目录的路径进行计算。
    • thus, not relative to the path of your web site's root, or to the file where you are typing因此,与您网站根目录的路径或您输入的文件无关
    • for that reason, always use absolute file paths因此,请始终使用绝对文件路径

Best practices :最佳实践:

In order to make your script robust in case you move things around, while still generating an absolute path at runtime, you have 2 options :为了使您的脚本在您四处移动时保持健壮,同时在运行时仍生成绝对路径,您有 2 个选项:

  1. use require __DIR__ . "/relative/path/from/current/file"使用require __DIR__ . "/relative/path/from/current/file" require __DIR__ . "/relative/path/from/current/file" . require __DIR__ . "/relative/path/from/current/file" The __DIR__ magic constant returns the directory of the current file. __DIR__魔术常量返回当前文件的目录。
  2. define a SITE_ROOT constant yourself :自己定义一个SITE_ROOT常量:

    • at the root of your web site's directory, create a file, eg config.php在您网站目录的根目录下,创建一个文件,例如config.php
    • in config.php , writeconfig.php中,写

      define('SITE_ROOT', __DIR__);
    • in every file where you want to reference the site root folder, include config.php , and then use the SITE_ROOT constant wherever you like :在您要引用站点根文件夹的每个文件中,包含config.php ,然后在您喜欢的任何地方使用SITE_ROOT常量:

       require_once __DIR__."/../config.php"; ... require_once SITE_ROOT."/other/file.php";

These 2 practices also make your application more portable because it does not rely on ini settings like the include path.这两种做法还使您的应用程序更具可移植性,因为它不依赖于包含路径之类的 ini 设置。


3. Check your include path 3.检查你的包含路径

Another way to include files, neither relatively nor purely absolutely, is to rely on the include path .另一种包含文件的方法,既不是相对也不是绝对绝对,是依赖于 包含路径 This is often the case for libraries or frameworks such as the Zend framework.库或框架(如 Zend 框架)通常是这种情况。

Such an inclusion will look like this :这样的包含将如下所示:

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

In that case, you will want to make sure that the folder where "Zend" is, is part of the include path.在这种情况下,您需要确保“Zend”所在的文件夹是包含路径的一部分。

You can check the include path with :您可以使用以下命令检查包含路径:

echo get_include_path();

You can add a folder to it with :您可以使用以下命令向其中添加文件夹:

set_include_path(get_include_path().":"."/path/to/new/folder");


4. Check that your server has access to that file 4. 检查您的服务器是否有权访问该文件

It might be that all together, the user running the server process (Apache or PHP) simply doesn't have permission to read from or write to that file.可能是,运行服务器进程(Apache 或 PHP)的用户根本没有读取或写入该文件的权限。

To check under what user the server is running you can use posix_getpwuid :要检查服务器在哪个用户下运行,您可以使用posix_getpwuid

$user = posix_getpwuid(posix_geteuid());

var_dump($user);

To find out the permissions on the file, type the following command in the terminal:要找出文件的权限,请在终端中键入以下命令:

ls -l <path/to/file>

and look at permission symbolic notation并查看权限符号


5. Check PHP settings 5.检查PHP设置

If none of the above worked, then the issue is probably that some PHP settings forbid it to access that file.如果上述方法都不起作用,那么问题可能是某些 PHP 设置禁止它访问该文件。

Three settings could be relevant :三个设置可能是相关的:

  1. open_basedir open_basedir
    • If this is set PHP won't be able to access any file outside of the specified directory (not even through a symbolic link).如果设置了这个,PHP 将不能访问指定目录之外的任何文件(甚至不能通过符号链接)。
    • However, the default behavior is for it not to be set in which case there is no restriction但是,默认行为是不设置它,在这种情况下没有限制
    • This can be checked by either calling phpinfo() or by using ini_get("open_basedir")这可以通过调用phpinfo()或使用ini_get("open_basedir")来检查
    • You can change the setting either by editing your php.ini file or your httpd.conf file您可以通过编辑 php.ini 文件或 httpd.conf 文件来更改设置
  2. safe mode安全模式
    • if this is turned on restrictions might apply.如果启用此功能,可能会应用限制。 However, this has been removed in PHP 5.4.但是,这已在 PHP 5.4 中删除。 If you are still on a version that supports safe mode upgrade to a PHP version that is still being supported .如果您仍在使用支持安全模式的版本,请升级到仍受支持的 PHP 版本。
  3. allow_url_fopen and allow_url_include allow_url_fopen 和 allow_url_include
    • this applies only to including or opening files through a network process such as http:// not when trying to include files on the local file system这仅适用于通过网络进程(例如 http://)包含或打开文件,而不适用于尝试在本地文件系统上包含文件时
    • this can be checked with ini_get("allow_url_include") and set with ini_set("allow_url_include", "1")这可以用ini_get("allow_url_include")检查并用ini_set("allow_url_include", "1")设置


Corner cases角落案例

If none of the above enabled to diagnose the problem, here are some special situations that could happen :如果以上都不能诊断问题,这里有一些可能发生的特殊情况:


1. The inclusion of library relying on the include path 1.依赖包含路径的库的包含

It can happen that you include a library, for example, the Zend framework, using a relative or absolute path.您可能会使用相对或绝对路径包含库,例如 Zend 框架。 For example :例如 :

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

But then you still get the same kind of error.但是你仍然会得到同样的错误。

This could happen because the file that you have (successfully) included, has itself an include statement for another file, and that second include statement assumes that you have added the path of that library to the include path.这可能会发生,因为您(成功)包含的文件本身具有另一个文件的包含语句,并且第二个包含语句假定您已将该库的路径添加到包含路径。

For example, the Zend framework file mentioned before could have the following include :例如,前面提到的 Zend 框架文件可能包含以下内容:

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

which is neither an inclusion by relative path, nor by absolute path.这既不是相对路径的包含,也不是绝对路径的包含。 It is assuming that the Zend framework directory has been added to the include path.假设 Zend 框架目录已添加到包含路径。

In such a case, the only practical solution is to add the directory to your include path.在这种情况下,唯一实用的解决方案是将目录添加到包含路径中。


2. SELinux 2. SELinux

If you are running Security-Enhanced Linux, then it might be the reason for the problem, by denying access to the file from the server.如果您正在运行 Security-Enhanced Linux,那么这可能是问题的原因,即拒绝从服务器访问文件。

To check whether SELinux is enabled on your system, run the sestatus command in a terminal.要检查您的系统上是否启用了 SELinux ,请在终端中运行sestatus命令。 If the command does not exist, then SELinux is not on your system.如果该命令不存在,则 SELinux 不在您的系统上。 If it does exist, then it should tell you whether it is enforced or not.如果它确实存在,那么它应该告诉你它是否被强制执行。

To check whether SELinux policies are the reason for the problem, you can try turning it off temporarily.要检查 SELinux 策略是否是问题的原因,您可以尝试暂时将其关闭。 However be CAREFUL, since this will disable protection entirely.但是要小心,因为这将完全禁用保护。 Do not do this on your production server.不要在您的生产服务器上执行此操作。

setenforce 0

If you no longer have the problem with SELinux turned off, then this is the root cause.如果您在关闭 SELinux 时不再遇到问题,那么这就是根本原因。

To solve it , you will have to configure SELinux accordingly.要解决它,您必须相应地配置 SELinux。

The following context types will be necessary :以下上下文类型将是必需的:

  • httpd_sys_content_t for files that you want your server to be able to read httpd_sys_content_t用于您希望服务器能够读取的文件
  • httpd_sys_rw_content_t for files on which you want read and write access httpd_sys_rw_content_t用于您希望对其进行读写访问的文件
  • httpd_log_t for log files用于日志文件的httpd_log_t
  • httpd_cache_t for the cache directory httpd_cache_t用于缓存目录

For example, to assign the httpd_sys_content_t context type to your website root directory, run :例如,要将httpd_sys_content_t上下文类型分配给您的网站根目录,请运行:

semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root

If your file is in a home directory, you will also need to turn on the httpd_enable_homedirs boolean :如果您的文件位于主目录中,您还需要打开httpd_enable_homedirs布尔值:

setsebool -P httpd_enable_homedirs 1

In any case, there could be a variety of reasons why SELinux would deny access to a file, depending on your policies.在任何情况下,SELinux 拒绝访问文件的原因可能有多种,具体取决于您的策略。 So you will need to enquire into that.因此,您需要对此进行调查。 Here is a tutorial specifically on configuring SELinux for a web server. 是专门为 Web 服务器配置 SELinux 的教程。


3. Symfony 3. Symfony

If you are using Symfony, and experiencing this error when uploading to a server, then it can be that the app's cache hasn't been reset, either because app/cache has been uploaded, or that cache hasn't been cleared.如果您正在使用 Symfony,并且在上传到服务器时遇到此错误,则可能是应用程序的缓存尚未重置,可能是因为app/cache已上传,或者该缓存尚未清除。

You can test and fix this by running the following console command:您可以通过运行以下控制台命令来测试和修复此问题:

cache:clear


4. Non ACSII characters inside Zip file 4. Zip 文件中的非 ACSII 字符

Apparently, this error can happen also upon calling zip->close() when some files inside the zip have non-ASCII characters in their filename, such as "é".显然,当 zip 中的某些文件的文件名中包含非 ASCII 字符(例如“é”)时,调用zip->close()也会发生此错误。

A potential solution is to wrap the file name in utf8_decode() before creating the target file.一个潜在的解决方案是在创建目标文件之前将文件名包装在utf8_decode()中。

Credits to Fran Cano for identifying and suggesting a solution to this issue感谢Fran Cano确定并提出解决此问题的方法

To add to the (really good) existing answer添加到(非常好的)现有答案

Shared Hosting Software共享主机软件

open_basedir is one that can stump you because it can be specified in a web server configuration. open_basedir是一个可以难倒你的工具,因为它可以在 Web 服务器配置中指定。 While this is easily remedied if you run your own dedicated server, there are some shared hosting software packages out there (like Plesk, cPanel, etc) that will configure a configuration directive on a per-domain basis.虽然如果您运行自己的专用服务器,这很容易解决,但有一些共享托管软件包(如 Plesk、cPanel 等)将在每个域的基础上配置配置指令。 Because the software builds the configuration file (ie httpd.conf ) you cannot change that file directly because the hosting software will just overwrite it when it restarts.因为软件构建了配置文件(即httpd.conf ),所以您不能直接更改该文件,因为托管软件会在重新启动时覆盖它。

With Plesk, they provide a place to override the provided httpd.conf called vhost.conf .使用 Plesk,它们提供了一个地方来覆盖提供的名为vhost.confhttpd.conf Only the server admin can write this file.只有服务器管理员可以写入此文件。 The configuration for Apache looks something like this 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>

Have your server admin consult the manual for the hosting and web server software they use.让您的服务器管理员查阅他们使用的托管和 Web 服务器软件的手册。

File Permissions文件权限

It's important to note that executing a file through your web server is very different from a command line or cron job execution.请务必注意,通过 Web 服务器执行文件与命令行或 cron 作业执行非常不同。 The big difference is that your web server has its own user and permissions.最大的不同是您的 Web 服务器有自己的用户和权限。 For security reasons that user is pretty restricted.出于安全原因,该用户受到很大限制。 Apache, for instance, is often apache , www-data or httpd (depending on your server).例如,Apache 通常是apachewww-datahttpd (取决于您的服务器)。 A cron job or CLI execution has whatever permissions that the user running it has (ie running a PHP script as root will execute with permissions of root). cron 作业或 CLI 执行具有运行它的用户所拥有的任何权限(即以 root 身份运行 PHP 脚本将以 root 权限执行)。

A lot of times people will solve a permissions problem by doing the following (Linux example)很多时候人们会通过执行以下操作来解决权限问题(Linux 示例)

chmod 777 /path/to/file

This is not a smart idea, because the file or directory is now world writable.这不是一个聪明的主意,因为文件或目录现在是世界可写的。 If you own the server and are the only user then this isn't such a big deal, but if you're on a shared hosting environment you've just given everyone on your server access.如果您拥有服务器并且是唯一的用户,那么这没什么大不了的,但是如果您在共享托管环境中,您只是为服务器上的每个人提供了访问权限。

What you need to do is determine the user(s) that need access and give only those them access.您需要做的是确定需要访问权限的用户并仅授予他们访问权限。 Once you know which users need access you'll want to make sure that一旦您知道哪些用户需要访问权限,您需要确保

  1. That user owns the file and possibly the parent directory (especially the parent directory if you want to write files).该用户拥有该文件,并且可能拥有父目录(如果您想写入文件,尤其是父目录)。 In most shared hosting environments this won't be an issue, because your user should own all the files underneath your root.在大多数共享主机环境中,这不是问题,因为您的用户应该拥有您根目录下的所有文件。 A Linux example is shown below下面显示了一个 Linux 示例

     chown apache:apache /path/to/file
  2. The user, and only that user, has access.该用户并且只有该用户具有访问权限。 In Linux, a good practice would be chmod 600 (only owner can read and write) or chmod 644 (owner can write but everyone can read)在 Linux 中,一个好的做法是chmod 600 (只有所有者可以读写)或chmod 644 (所有者可以写但每个人都可以阅读)

You can read a more extended discussion of Linux/Unix permissions and users here您可以在此处阅读有关 Linux/Unix 权限和用户的更详细讨论

  1. Look at the exact error查看确切的错误

My code worked fine on all machines but only on this one started giving problem (which used to work find I guess).我的代码在所有机器上都运行良好,但只有这台机器开始出现问题(我猜它曾经工作过)。 Used echo "document_root" path to debug and also looked closely at the error, found this使用 echo "document_root" 路径进行调试,还仔细查看了错误,发现了这个

Warning: include( D:/MyProjects/testproject//functions/connections.php ): failed to open stream:警告:包括( D:/MyProjects/testproject//functions/connections.php ):未能打开流:

You can easily see where the problems are.您可以轻松查看问题所在。 The problems are // before functions问题是 // 在函数之前

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

So simply remove the lading / from include and it should work fine.因此,只需从 include 中删除 ladding / 它应该可以正常工作。 What is interesting is this behaviors is different on different versions.有趣的是这种行为在不同的版本上是不同的。 I run the same code on Laptop, Macbook Pro and this PC, all worked fine untill.我在笔记本电脑、Macbook Pro 和这台 PC 上运行相同的代码,一切都运行良好,直到。 Hope this helps someone.希望这可以帮助某人。

  1. Copy past the file location in the browser to make sure file exists.复制过去浏览器中的文件位置以确保文件存在。 Sometimes files get deleted unexpectedly (happened with me) and it was also the issue in my case.有时文件会被意外删除(发生在我身上),这也是我的问题。

Samba Shares桑巴股份

If you have a Linux test server and you work from a Windows Client, the Samba share interferes with the chmod command.如果您有一台 Linux 测试服务器并且使用 Windows 客户端工作,那么 Samba 共享会干扰chmod命令。 So, even if you use:所以,即使你使用:

chmod -R 777 myfolder

on the Linux side it is fully possible that the Unix Group\www-data still doesn't have write access.在 Linux 方面,完全有可能 Unix Group\www-data 仍然没有写访问权限。 One working solution if your share is set up that Windows admins are mapped to root: From Windows, open the Permissions, disable Inheritance for your folder with copy, and then grant full access for www-data.如果您的共享设置为将 Windows 管理员映射到 root,则一种可行的解决方案:从 Windows,打开权限,禁用带有副本的文件夹的继承,然后授予对 www-data 的完全访问权限。

Add script with query parameters添加带有查询参数的脚本

That was my case.那是我的情况。 It actually links to question #4485874 , but I'm going to explain it here shortly.它实际上链接到问题 #4485874 ,但我将很快在这里解释它。
When you try to require path/to/script.php?parameter=value , PHP looks for file named script.php?parameter=value , because UNIX allows you to have paths like this.当您尝试要求path/to/script.php?parameter=value时,PHP 会查找名为script.php?parameter=value的文件,因为 UNIX 允许您拥有这样的路径。
If you are really need to pass some data to included script, just declare it as $variable=... or $GLOBALS[]=... or other way you like.如果您确实需要将一些数据传递给包含的脚本,只需将其声明为$variable=...$GLOBALS[]=...或您喜欢的其他方式。

The following PHP settings in php.ini if set to non-existent directory can also raise php.ini中的以下 PHP 设置如果设置为不存在的目录也可以引发

PHP Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0 PHP 警告:未知:无法打开流:第 0 行的未知中的权限被拒绝

sys_temp_dir
upload_tmp_dir
session.save_path

PHP - Failed to open stream : No such file or directory in mac PHP - 无法打开流:mac中没有这样的文件或目录

For example I will upload a picture.例如,我将上传一张图片。 But I am getting this error.但我收到了这个错误。 First thing i will do right click on the image and get info.我要做的第一件事是右键单击图像并获取信息。

$thePathOfMyPicture = "/Users/misstugba/Desktop/"; use with function与功能一起使用

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

} } 在此处输入图像描述

Another possible cause: Renaming and/or moving files while in a text editor. 另一个可能的原因:在文本编辑器中重命名和/或移动文件。 I went through all the steps above without success until I deleted the file that kept throwing this error and created a new one, which fixed the issue. 我经历了上述所有步骤,但没有成功,直到删除了不断抛出该错误的文件并创建了一个新文件,该文件便解决了该问题。

For me I got this error because I was trying to read a file which required HTTP auth, with a username and password.对我来说,我收到了这个错误,因为我试图使用用户名和密码读取需要 HTTP 身份验证的文件。 Hope that helps others.希望对其他人有所帮助。 Might be another corner case.可能是另一个极端案例。

Edit编辑

You can check if this type of authentication is present by inspecting the headers:您可以通过检查标头来检查是否存在这种类型的身份验证:

$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)中存在)。

Aside from the other excellent answers, one thing I overlooked on Windows while writing a simple script: This error will be shown when trying to open a file with characters that Windows does not support in file names.除了其他出色的答案之外,我在编写简单脚本时在 Windows 上忽略了一件事:尝试打开文件名中包含 Windows 不支持的字符的文件时会显示此错误。

For example:例如:

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

Will give:会给:

fopen(2022-06-01_22:53:03): Failed to open stream: No such file or directory in ... fopen(2022-06-01_22:53:03):无法打开流:...中没有这样的文件或目录

Windows does not like : in file names, as well as a number of other characters. Windows 不喜欢文件名中的:以及一些其他字符。

In PHP scripts, whether calling include() , require() , fopen() , or their derivatives such as include_once , require_once , or even, move_uploaded_file() , one often runs into an error or warning:在PHP脚本中,无论是调用include()require()fopen()还是它们的派生类,例如include_oncerequire_once ,甚至move_uploaded_file() ,都会经常出现错误或警告:

Failed to open stream : No such file or directory.无法打开流:没有这样的文件或目录。

What is a good process to quickly find the root cause of the problem?有什么好的方法可以快速找到问题的根本原因?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM