In PHP scripts, whether calling include()
, require()
, fopen()
, or their derivatives such as include_once
, require_once
,甚至 move_uploaded_file()
,经常会遇到错误或警告:
无法打开流:没有这样的文件或目录。
什么是快速找到问题根源的好过程?
原文由 Vic Seedoubleyew 发布,翻译遵循 CC BY-SA 4.0 许可协议
可能会遇到此错误的原因有很多,因此首先检查的内容的良好清单会大有帮助。
假设我们正在对以下行进行故障排除:
清单
1.检查文件路径是否有错别字
require*
或include*
ad1ae725bc4a21f61937b7d33— 调用的任何内容移动到自己的变量中,回显它,复制它,然后尝试从终端访问它:然后,在终端中:
2. 检查相对路径与绝对路径注意事项的文件路径是否正确
/users/tony/htdocs
最佳实践:
为了使您的脚本在您四处移动时保持健壮,同时在运行时仍生成绝对路径,您有 2 个选项:
使用
require __DIR__ . "/relative/path/from/current/file"
。__DIR__
魔法常数 返回当前文件的目录。自己定义一个
SITE_ROOT
常量:config.php
config.php
中,写config.php
,然后在任何您喜欢的地方使用SITE_ROOT
常量:这两种做法还使您的应用程序更具可移植性,因为它不依赖于包含路径之类的 ini 设置。
3.检查你的包含路径
另一种包含文件的方法,既不是相对也不是绝对绝对,是依赖于 包含路径。库或框架(如 Zend 框架)通常是这种情况。
这样的包含将如下所示:
在这种情况下,您需要确保“Zend”所在的文件夹是包含路径的一部分。
您可以使用以下命令检查包含路径:
您可以使用以下命令向其中添加文件夹:
4. 检查您的服务器是否有权访问该文件
可能是,运行服务器进程(Apache 或 PHP)的用户根本没有读取或写入该文件的权限。
要检查服务器在哪个用户下运行,您可以使用 posix_getpwuid :
要找出文件的权限,请在终端中键入以下命令:
并查看 权限符号
5.检查PHP设置
如果上述方法都不起作用,那么问题可能是某些 PHP 设置禁止它访问该文件。
三个设置可能是相关的:
phpinfo()
或使用ini_get("open_basedir")
来检查ini_get("allow_url_include")
ini_set("allow_url_include", "1")
角落案例
如果以上都不能诊断问题,这里有一些可能发生的特殊情况:
1.依赖包含路径的库的包含
您可能会使用相对或绝对路径包含库,例如 Zend 框架。例如 :
但是你仍然会得到同样的错误。
这可能会发生,因为您(成功)包含的文件本身具有另一个文件的包含语句,并且第二个包含语句假定您已将该库的路径添加到包含路径。
例如,前面提到的 Zend 框架文件可能包含以下内容:
这既不是相对路径的包含,也不是绝对路径的包含。假设 Zend 框架目录已添加到包含路径。
在这种情况下,唯一实用的解决方案是将目录添加到包含路径中。
2. SELinux
如果您正在运行 Security-Enhanced Linux,那么这可能是问题的原因,即拒绝从服务器访问文件。
要检查您的系统是否启用了 SELinux ,请在终端中运行
sestatus
命令。如果该命令不存在,则 SELinux 不在您的系统上。如果它确实存在,那么它应该告诉你它是否被强制执行。要检查 SELinux 策略是否是问题的原因,您可以尝试暂时将其关闭。但是要小心,因为这将完全禁用保护。不要在您的生产服务器上执行此操作。
如果您在关闭 SELinux 时不再遇到问题,那么这就是根本原因。
要解决它,您必须相应地配置 SELinux。
以下上下文类型将是必需的:
httpd_sys_content_t
用于您希望服务器能够读取的文件httpd_sys_rw_content_t
用于您想要读写访问的文件httpd_log_t
用于日志文件httpd_cache_t
缓存目录例如,要将
httpd_sys_content_t
上下文类型分配给您的网站根目录,请运行:如果您的文件位于主目录中,您还需要打开
httpd_enable_homedirs
boolean :在任何情况下,SELinux 拒绝访问文件的原因可能有多种,具体取决于您的策略。因此,您需要对此进行调查。 这 是专门为 Web 服务器配置 SELinux 的教程。
3. Symfony
如果您使用 Symfony,并且在上传到服务器时遇到此错误,则可能是应用程序的缓存尚未重置,可能是因为
app/cache
已上传,或者缓存尚未清除。您可以通过运行以下控制台命令来测试和修复此问题:
4. Zip 文件中的非 ACSII 字符
显然,当 zip 中的某些文件的文件名中包含非 ASCII 字符(例如“é”)时,调用
zip->close()
时也会发生此错误。一个潜在的解决方案是在创建目标文件之前将文件名包装在
utf8_decode()
中。感谢 Fran Cano 确定并提出解决此问题的方法