一个人可能会遇到此错误的原因有很多,因此一份关于首先要检查的内容的良好清单有很大帮助。
假设我们正在对以下行进行故障排除:
require "/path/to/file"
清单
1。检查文件路径是否有错别字
2。检查相对路径与绝对路径注意事项的文件路径是否正确
- 如果它以正斜杠“/”开头,那么它不是指您网站文件夹的根目录(文档根目录),而是指您的服务器的根目录。
- 例如,您网站的目录可能是
/users/tony/htdocs
- 如果它不是以正斜杠开头,那么它要么依赖于包含路径(见下文),要么路径是相对的。如果是相对的,那么 PHP 将相对于current working directory 的路径进行计算。
- 因此,与您网站根目录的路径或您输入的文件无关
- 因此,请始终使用绝对文件路径
最佳实践:
为了使您的脚本在您四处移动时保持稳健,同时在运行时仍生成绝对路径,您有 2 个选项:
- 使用
require __DIR__ . "/relative/path/from/current/file"。 __DIR__ magic constant 返回当前文件的目录。
-
自己定义一个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";
这两种做法还使您的应用程序更便携,因为它不依赖于包含路径之类的 ini 设置。
3。检查您的包含路径
另一种包含文件的方法,既不是相对也不是绝对绝对,是依赖include path。库或框架(例如 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>
看看permission symbolic notation
5。检查 PHP 设置
如果以上都不起作用,那么问题可能是某些 PHP 设置禁止它访问该文件。
三个设置可能是相关的:
-
open_basedir
- 如果设置了此项,PHP 将无法访问指定目录之外的任何文件(甚至无法通过符号链接)。
- 但是,默认行为是不设置它,在这种情况下没有限制
- 这可以通过调用
phpinfo() 或使用ini_get("open_basedir") 来检查
- 您可以通过编辑 php.ini 文件或 httpd.conf 文件来更改设置
-
safe mode
-
allow_url_fopen and allow_url_include
- 这仅适用于通过网络进程(例如 http://)包含或打开文件,而不适用于尝试在本地文件系统上包含文件时
- 这可以用
ini_get("allow_url_include")检查并用ini_set("allow_url_include", "1")设置
角落案例
如果以上都不能诊断问题,这里有一些可能发生的特殊情况:
1。依赖于包含路径的库的包含
您可能会使用相对或绝对路径包含库,例如 Zend 框架。例如:
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
但是你仍然会遇到同样的错误。
这可能是因为您(成功)包含的文件本身具有另一个文件的包含语句,而第二个包含语句假定您已将该库的路径添加到包含路径。
例如,前面提到的 Zend 框架文件可能包含以下内容:
include "Zend/Mail/Protocol/Exception.php"
既不是相对路径的包含,也不是绝对路径的包含。假设 Zend 框架目录已添加到包含路径中。
在这种情况下,唯一可行的解决方案是将目录添加到包含路径中。
2。 SELinux
如果您运行的是安全增强型 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 拒绝访问文件的原因可能有多种,具体取决于您的策略。因此,您需要对此进行调查。 Here 是专门为 Web 服务器配置 SELinux 的教程。
3。 Symfony
>
如果您使用 Symfony,并且在上传到服务器时遇到此错误,则可能是应用程序的缓存尚未重置,可能是因为 app/cache 已上传,或者缓存尚未清除.
您可以通过运行以下控制台命令来测试和修复此问题:
cache:clear
4。 Zip 文件中的非 ACSII 字符
显然,当 zip 中的某些文件的文件名中包含非 ASCII 字符(例如“é”)时,调用 zip->close() 时也会发生此错误。
一种可能的解决方案是在创建目标文件之前将文件名包含在utf8_decode() 中。
感谢 Fran Cano 识别并提出解决此问题的方法