include()
、require()
、fopen()
还是它们的衍生函数 include_once
、require_once
甚至是 move_uploaded_file()
,通常会遇到以下错误或警告:
Failed to open stream : No such file or directory.
有什么好的方法能快速找出问题的根本原因呢?
include()
、require()
、fopen()
还是它们的衍生函数 include_once
、require_once
甚至是 move_uploaded_file()
,通常会遇到以下错误或警告:
Failed to open stream : No such file or directory.
有什么好的方法能快速找出问题的根本原因呢?
有很多原因会导致出现这个错误,因此一个好的检查清单可以极大地帮助解决问题。
让我们考虑一下我们正在排除以下行:
require "/path/to/file"
or move whatever is called by require*
or include*
to its own variable, echo it, copy it, and try accessing it from a terminal:
$path = "/path/to/file";
echo "Path : $path";
require "$path";
Then, in a terminal:
cat <file path pasted>
/users/tony/htdocs
最佳实践:
为了使您的脚本在移动文件位置时更加健壮,并且仍然在运行时生成绝对路径,您有两个选择:
require __DIR__ . "/relative/path/from/current/file"
. The __DIR__
magic constant returns the directory of the current file.define a SITE_ROOT
constant yourself :
config.php
in config.php
, write
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 :
require_once __DIR__."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
另一种包含文件的方式,既不是相对路径也不是纯绝对路径,是依赖于包含路径。这通常适用于像Zend框架这样的库或框架。
这样的包含看起来像这样:
include "Zend/Mail/Protocol/Imap.php"
echo get_include_path();
你可以使用以下代码将文件夹添加到其中:
set_include_path(get_include_path().":"."/path/to/new/folder");
可能是因为运行服务器进程(Apache或PHP)的用户根本没有权限读取或写入该文件。
要检查服务器在哪个用户下运行,您可以使用 posix_getpwuid:
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
要查看文件的权限,请在终端中输入以下命令:
ls -l <path/to/file>
并查看权限符号表示法
如果以上方法都不起作用,那么问题可能是某些PHP设置禁止访问该文件。
有三个设置可能会影响:
phpinfo()
或使用ini_get("open_basedir")
来检查此设置。ini_get("allow_url_include")
进行检查,并使用ini_set("allow_url_include", "1")
进行设置。如果以上方法都不能诊断问题,以下是一些可能发生的特殊情况:
有时您会使用相对或绝对路径来引入库,例如Zend框架。例如:
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
include "Zend/Mail/Protocol/Exception.php"
如果您正在运行安全增强型 Linux(SELinux),可能会因为服务器拒绝访问文件而导致问题。
要检查系统是否启用了 SELinux,请在终端中运行 sestatus
命令。如果该命令不存在,则表示您的系统上没有 SELinux。如果存在,则应告诉您它是否已强制执行。
要检查 SELinux 策略是否是问题的原因,可以尝试暂时关闭它。但是要小心,因为这将完全禁用保护。不要在生产服务器上执行此操作。
setenforce 0
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拒绝访问文件可能有多种原因,具体取决于您的策略。因此,您需要进行查询。这里是一个专门介绍为Web服务器配置SELinux的教程。
如果您正在使用Symfony,并在上传到服务器时遇到此错误,则可能是应用程序的缓存尚未重置,原因是app/cache
已被上传或者缓存没有被清除。
您可以通过运行以下控制台命令来测试和修复此问题:
cache:clear
显然,当压缩包中的某些文件名包含非ASCII字符(例如“é”)时,在调用zip->close()
时也可能会出现此错误。
一个潜在的解决方案是在创建目标文件之前使用utf8_decode()
包装文件名。
感谢Fran Cano识别并提出了解决此问题的方法。
selinux
可能是个好主意。至少您需要在所包含的文件上拥有 httpd_sys_content_t
权限(Apache 使用的只读目录和文件)。 - bansi在这个已经很好的答案基础上,需要补充的是:
open_basedir
是一个可能会让你困扰的问题,因为它可以在Web服务器配置中指定。如果您运行自己的专用服务器,则可以轻松解决此问题,但是有一些共享主机软件包(例如Plesk、cPanel等)会按域配置一个配置指令。由于软件生成配置文件(即 httpd.conf
),因此您无法直接更改该文件,因为主机软件在重新启动时会覆盖它。
对于Plesk,他们提供了一个名为vhost.conf
的地方来覆盖提供的httpd.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>
请让您的服务器管理员查阅所使用的主机和Web服务器软件的手册。
需要注意的是,通过 Web 服务器执行文件与通过命令行或 cron job 执行完全不同。最大的区别在于,您的 Web 服务器具有自己的用户和权限。出于安全原因,该用户的权限非常受限制。例如,Apache 经常是 apache
、www-data
或 httpd
(取决于您的服务器)。cron job 或 CLI 执行拥有运行它的用户所具有的所有权限(例如,以 root 身份运行 PHP 脚本将以 root 的权限执行)。
很多时候人们会通过以下方式解决权限问题(Linux 示例):
chmod 777 /path/to/file
这不是个明智的做法,因为该文件或目录现在是全世界可写的。如果您拥有服务器并且是唯一的用户,则此事无关紧要,但如果您在共享托管环境中,则刚刚赋予了所有人访问权限。
您需要做的是确定需要访问的用户,并仅授予他们访问权限。一旦确定哪些用户需要访问,您将希望确保:
那些用户拥有该文件以及可能的父目录(特别是如果您想写入文件,则需要父目录)。在大多数共享托管环境中,这不会是问题,因为您的用户应该拥有根目录下的所有文件。以下是Linux示例:
chown apache:apache /path/to/file
用户,只有该用户才能访问。在Linux中,一个好的做法是chmod 600
(只有所有者可以读写)或chmod 644
(所有者可以写但每个人都可以读)
我的代码在所有机器上都能正常运行,但在这台机器上开始出现问题(我想以前似乎是可以工作的)。使用echo命令来调试"document_root"路径,并仔细查看错误信息,发现了这个:
警告: include(D:/MyProjects/testproject//functions/connections.php): 打开流失败:
你可以很容易地看出问题所在。问题出在functions之前的“//”符号。
$document_root = $_SERVER['DOCUMENT_ROOT'];
echo "root: $document_root";
include($document_root.'/functions/connections.php');
所以只需从包含中简单地删除/符号,它就应该正常工作。有趣的是这种行为在不同版本上是不同的。我在笔记本电脑、Macbook Pro和这台电脑上运行相同的代码,一切都运行良好,直到出现问题。希望这能帮助到某个人。
2. 复制并粘贴文件位置到浏览器中,以确保该文件存在。有时文件会意外删除(这也发生在我的情况下),这也是我的问题所在。
Samba分享
如果你有一台Linux测试服务器并且你从Windows客户端进行工作,Samba分享会影响到chmod命令。因此,即使你使用了:
chmod -R 777 myfolder
在Linux系统中,Unix组\www-data可能仍然没有写权限。一种可行的解决方案是,如果您的共享设置为将Windows管理员映射到root,则可以从Windows打开权限设置,在副本中禁用继承,然后授予www-data完全访问权限。
除了其他优秀的答案,当我在Windows上编写一个简单的脚本时,我忽略了一件事情:当尝试使用Windows不支持的字符打开文件时,将显示此错误。
例如:
$file = fopen(date('Y-m-d_H:i:s'), 'w+');
将会得到:
fopen(2022-06-01_22:53:03):无法打开流:在...中没有这个文件或目录
Windows不喜欢在文件名中使用:
,还有一些其他字符。
这是我的情况。实际上,它链接到问题#4485874,但我将在此简要解释。
当您尝试要求path/to/script.php?parameter=value
时,PHP会查找名为script.php?parameter=value
的文件,因为UNIX允许您拥有此类路径。
如果您确实需要向已包含的脚本传递某些数据,请将其声明为$variable=...
或$GLOBALS[]=...
或其他您喜欢的方式。
php.ini
中,如果设置为不存在的目录,也会引发以下警告:
PHP Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0
sys_temp_dir
upload_tmp_dir
session.save_path
对我来说,我遇到了这个错误是因为我试图读取一个需要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';
include
、require
还是 fopen
? - Vic Seedoubleyew