PHP致命错误:打开所需文件失败。

70

我从Apache得到以下错误:

[Sat Mar 19 23:10:50 2011] [warn] mod_fcgid: stderr: PHP致命错误:require_once() [function.require]: 打开'/common/configs/config_templates.inc.php'失败(include_path='.:/usr/share/pear:/usr/share/php'),位于/home/viapics1/public_html/common/configs/config.inc.php的第158行

我并不是Apache的专家,但文件config.inc.php和config_templates.inc.php都在那里。我还尝试导航到我放置在common/configs/下的test.html页面,因此我认为这里没有权限问题。我还将config_templates.inc.php的权限设置为给予所有人读取、写入和执行权限。目前不确定该怎么做,我检查了是否有/usr/share/php目录,并发现没有,但当我运行yum install php时,它说已经安装了最新版本。有什么想法吗?

7个回答

109

这实际上不是一个与Apache相关的问题,甚至也不是一个与PHP相关的问题。 为了理解这个错误,您需要区分虚拟服务器上的路径和文件系统中的路径。

require操作符用于文件。但是像这样的路径

                          /common/configs/config_templates.inc.php

该路径仅存在于虚拟HTTP服务器上,而在文件系统中不存在此路径。正确的文件系统路径应为

/home/viapics1/public_html/common/configs/config_templates.inc.php

在哪里

/home/viapics1/public_html

这个部分被称为文档根目录,它连接虚拟世界和真实世界。幸运的是,web服务器通常有一个配置变量,其中包含了文档根目录,并与PHP共享。因此,如果您将代码更改为以下内容,则可以轻松访问文档根目录:

require_once $_SERVER['DOCUMENT_ROOT'].'/common/configs/config_templates.inc.php';

它可以在任何目录下的任何文件中使用!

更新:最终我写了一篇文章,解释了在文件系统和Web服务器上相对路径和绝对路径之间的区别,并详细说明了此问题并包含了一些实用的解决方案。例如,在从命令行运行脚本时,这样一个方便的变量是不存在的。在这种情况下,可以使用“单一入口点”技术来解决。您也可以参考上面的文章获取详细信息。


1
@Al Katawazi 不对,在你的 PHP 代码中。你正在处理 PHP 代码中的一个文件。而且你必须使用正确的地址。 - Your Common Sense
抱歉,这不是解决方法。我已经更新了代码,看起来像这样:<?php require_once($_SERVER['DOCUMENT_ROOT'].'/common/configs/config.inc.php'); 但我仍然得到完全相同的错误。有趣的是,当我在URL中放入一个X时,它会回拼出整个URL,就像这样:Failed opening required '/home/viapics1/public_htmlX/common/configs/config.inc.php',这一切都非常奇怪,可能有某种全局覆盖吗?真正奇怪的是,这个应用程序在另一台服务器上运行良好,但当移动到新服务器时,我开始遇到这个问题。非常感谢迄今为止的帮助。 - Al Katawazi
@Al Katawazi 我已经编辑了第二部分(使用 __FILE__),现在试一下。如果失败,请发布它的错误消息。 - Your Common Sense
@Al Katawazi,这是另一个错误。你需要以类似的方式进行更正。 - Your Common Sense
dirname(FILE)是一个好习惯,即使不是所有情况都需要它。 - m3nda
显示剩余3条评论

11

如果您正在运行SELinux,则可能需要使用以下命令授予httpd读取/home目录的权限:

 sudo setsebool httpd_read_user_content=1

我需要从/home目录运行这个命令吗? - jayaprakash R
你不需要将 /home 标记为用户内容,因为它应该已经被标记为用户内容了。 - user1533634

5
你可以使用PHP常量__DIR__来解决这个问题。最初的回答中提到了这一点。
require_once __DIR__ . '/common/configs/config_templates.inc.php';

这是文件的目录。如果在一个include内使用,返回的是被包含文件的目录。这相当于dirname __FILE__。该目录名称没有尾随斜杠,除非它是根目录。 1

对于OP来说,这样做行不通。因为它会导致/home/viapics1/public_html/common/configs/common/configs/config_templates.inc.php这样的结果。__DIR__常量并不是一个能解决文件名问题的魔法棒。就像任何工具一样,它必须在理解的基础上使用。 - undefined

4
运行 php -f /common/configs/config_templates.inc.php 命令,以验证文件中的 PHP 语法是否有效。

错误信息清楚地表明文件不存在,那么重新运行 PHP 来确认它不存在有什么意义呢?OP 有一个前导斜杠,将路径转换为绝对路径。它应该至少是没有前导斜杠的相对路径。 - Marc B
2
“错误信息清楚地表明文件不存在。”并不是这样。同样的错误信息可能来自于包含路径设置、文件权限设置或安全模式设置。(我还猜想它可能来自语法错误,取决于错误报告设置,但经过一些测试,看起来PHP总是显示实际的语法错误。) - Alex Howansky
你错了。你提到的每种情况都有自己独特的错误信息,除了语法错误。人们可以轻松区分“解析错误”和“文件未找到错误”。你的假设都是错误和误导性的。多积累一些 PHP 经验吧。 - Your Common Sense
1
我的error_log包含堆栈跟踪,其中包含这些不同条件的相同文本。例如,这是刚刚从我的日志中提取的一行(路径已模糊化),用于不存在的文件:“PHP致命错误:require():在/path/to/test.php的第4行打开所需的“sub/include.php”(include_path ='.:/usr/local/lib/php')”而对于具有错误权限的现有文件,这是一个:“PHP致命错误:require():在/path/to/test.php的第4行打开所需的“sub/include.php”(include_path ='.:/usr/local/lib/php')”。坏的include_path也是如此。 - Alex Howansky
检查文件权限,伙计。failed to open stream: Permission denied是一个错误消息,表示权限不足。 - Your Common Sense
请仔细阅读。每种情况下堆栈跟踪行中的文本都相同(并且与OP发布的措辞完全匹配),堆栈跟踪行紧随错误行在error_log中。因此,如果您只是观察尾部,您会看到相同的消息。无论如何,这并不是非常相关的。如果您不喜欢答案,请将其投票否决。您不需要变得正义和傲慢。 - Alex Howansky

2

如果有人需要帮助,我在昨晚遇到了一个很少见的错误。具体来说,我使用require_once方法,只指定文件名而没有路径,因为所需的文件位于同一目录中。

某个时刻,我开始收到“无法打开所需文件”的错误。经过一段时间的苦恼之后,我终于注意到了一个PHP警告消息,紧接着是致命错误输出,指示“无法打开流:权限被拒绝”,但更重要的是,告诉我它尝试打开的文件路径。然后我意识到,我在其他地方创建了该文件的副本(所有权不可访问Apache),它也在PHP“include”搜索路径中,并且在我想要它被选中的文件夹之前。噢!


0

你可以在 php.ini 中设置包含路径

include_path = ".:/home/viapics1/public_html"


-7

我遇到完全相同的问题,我三次检查了包含路径,还检查了pear是否已安装,一切看起来都没问题(但不使用绝对路径),但仍然出现错误。在疯狂地研究了几个小时后,我意识到我的脚本中有这样的代码:

include_once "../Mail.php";

而不是(它的行为等价性):
include_once ("../Mail.php");

嗯,括号没有丢失,但是在我的脚本这一行上没有生成错误,这对我来说很奇怪,可能是我以愚蠢的方式接收到了这个信息。

7
因为include_once是一种语言结构,而不是“真正的”函数,所以括号是可选的。不确定为什么加上括号可以解决你的问题。 - Mike Hedman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接