可能会遇到此错误的原因有很多,因此首先检查哪些内容的良好清单会很有帮助。
让我们假设我们正在对以下行进行故障排除:
require "/path/to/file"
清单
1.检查文件路径是否有拼写错误
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.
- 例如,您网站的目录可能是
/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.
- 因此,与网站根目录的路径或您正在键入的文件的路径无关
- 因此,请始终使用绝对文件路径
最佳实践:
为了使您的脚本在移动内容时保持健壮,同时仍然在运行时生成绝对路径,您有 2 个选项:
- use
require __DIR__ . "/relative/path/from/current/file"
. The __DIR__魔法常数返回当前文件的目录。
-
定义一个SITE_ROOT
不变的自己:
- 在网站目录的根目录中,创建一个文件,例如
config.php
-
in config.php
, write
define('SITE_ROOT', __DIR__);
-
在要引用站点根文件夹的每个文件中,包括config.php
,然后使用SITE_ROOT
无论你喜欢什么地方都保持不变:
require_once __DIR__."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
这两种做法还使您的应用程序更加可移植,因为它不依赖于 ini 设置(例如包含路径)。
3.检查你的包含路径
另一种包含文件的方法(既不是相对也不是纯粹绝对)是依赖于包含路径。对于诸如 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>
看看权限符号表示法
5.检查PHP设置
如果上述方法均不起作用,则问题可能是某些 PHP 设置禁止它访问该文件。
三个设置可能相关:
-
open_basedir
- 如果设置了此选项,PHP 将无法访问指定目录之外的任何文件(甚至无法通过符号链接访问)。
- 但是,默认行为是不设置,在这种情况下没有限制
- 这可以通过调用来检查phpinfo()或通过使用
ini_get("open_basedir")
- 您可以通过编辑 php.ini 文件或 httpd.conf 文件来更改设置
-
safe mode
- 如果打开此功能,可能会受到限制。然而,这在 PHP 5.4 中已被删除。如果您仍在使用支持安全模式的版本,请升级到 PHP 版本仍在支持中.
-
allow_url_fopen and allow_url_include
- 这仅适用于通过网络进程(例如 http://)包含或打开文件,不适用于尝试包含本地文件系统上的文件
- 这可以通过检查
ini_get("allow_url_include")
并设置为ini_set("allow_url_include", "1")
极端情况
如果上述方法均无法诊断问题,则可能会发生以下一些特殊情况:
1.依赖include路径的库的包含
您可能会使用相对或绝对路径包含一个库,例如 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
context 类型到您的网站根目录,运行:
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,并且在上传到服务器时遇到此错误,则可能是应用程序的缓存尚未重置,因为app/cache
已上传,或者缓存尚未清除。
您可以通过运行以下控制台命令来测试并修复此问题:
cache:clear
4. Zip 文件中的非 ASCII 字符
显然,调用时也会发生此错误zip->close()
当 zip 内的某些文件的文件名中包含非 ASCII 字符(例如“é”)时。
一个可能的解决方案是将文件名包装在utf8_decode()
在创建目标文件之前。
致谢弗兰卡诺用于确定此问题并提出解决方案