无法打开流:没有这样的文件或目录

在PHP脚本中,无论是调用include()require()fopen()还是其派生词,如include_oncerequire_oncemove_uploaded_file() ,都会遇到错误或警告:

无法打开流:没有这样的文件或目录。

什么是快速找到问题根源的好过程?


有很多原因可能会导致这个错误,因此一个很好的核对清单首先要检查什么会有相当大的帮助。

让我们考虑一下,我们正在解决以下问题:

require "/path/to/file"


清单


1.检查文件路径是否有错别字

  • 要么手动检查(通过目视检查路径)
  • 或者将require*include*所调用的任何东西移动到它自己的变量中,然后回显,复制它,然后尝试从终​​端访问它:

    $path = "/path/to/file";
    
    echo "Path : $path";
    
    require "$path";
    

    然后,在终端中:

    cat <file path pasted>
    

  • 2.检查文件路径关于相对与绝对路径考虑是否正确

  • 如果它是以正斜杠“/”开头的,那么它不是指您的网站文件夹(文档根目录)的根目录,而是指您服务器的根目录。
  • 例如,您网站的目录可能是/users/tony/htdocs
  • 如果它不是以正斜杠开始,那么它要么依赖于包含路径(参见下文),要么路径是相对的。 如果它是相对的,那么PHP将相对于当前工作目录的路径进行计算。
  • 因此,不是相对于您网站根目录的路径,也不是您输入的文件
  • 出于这个原因,总是使用绝对文件路径
  • 最佳实践:

    为了使脚本在您移动时保持健壮,同时仍然在运行时生成绝对路径,您有两种选择:

  • 使用require __DIR__ . "/relative/path/from/current/file" require __DIR__ . "/relative/path/from/current/file"__DIR__魔术常量返回当前文件的目录。
  • 自己定义一个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.检查你的包含路径

    包含文件的另一种方式,既不是相对也不是绝对的,是依靠包含路径。 对于像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文件来更改设置
  • 安全模式
  • 如果启用了此限制,则可能适用。 但是,这在PHP 5.4中已被删除。 如果您仍然使用支持安全模式升级到仍受支持的PHP版本的版本。
  • allow_url_fopen和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"
    

    但是,你仍然会遇到同样的错误。

    这可能是因为您已经(成功)包含的文件本身具有另一个文件的include语句,并且第二个include语句假定您已将该库的路径添加到包含路径。

    例如,之前提到的Zend框架文件可能包含以下内容:

    include "Zend/Mail/Protocol/Exception.php" 
    

    这既不是相对路径的包容,也不是绝对路径。 假设Zend框架目录已被添加到包含路径中。

    在这种情况下,唯一可行的解​​决方案是将目录添加到包含路径中。


    2. SELinux

    如果您正在运行安全增强型Linux,则可能会导致问题,原因是拒绝从服务器访问文件。

    要检查系统上是否启用SELinux ,请在终端中运行sestatus命令。 如果该命令不存在,那么SELinux不在您的系统上。 如果它确实存在,那么它应该告诉你它是否被强制执行。

    要检查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可能会拒绝访问文件,这可能有多种原因。 所以你需要对此进行调查。 这里有一个关于配置SELinux的Web服务器的教程。


    Symfony

    如果您正在使用Symfony,并且在上传到服务器时遇到此错误,则可能是应用程序的缓存未被重置,原因可能是app/cache已上载,或缓存未被清除。

    您可以通过运行以下控制台命令来测试和解决此问题:

    cache:clear
    


    4. Zip文件中的非ACSII字符

    很明显,这个错误也可能发生在调用zip->close()时,zip中的某些文件的文件名中有非ASCII字符,例如“é”。

    潜在的解决方案是在创建目标文件之前将文件名包装在utf8_decode()

    感谢Fran Cano为此问题确定并提出解决方案


    添加到(真的很好)现有的答案

    共享主机软件

    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服务器执行文件与命令行或cron作业执行完全不同。 最大的区别是您的Web服务器拥有自己的用户和权限。 出于安全原因,用户相当受限制。 例如,Apache通常是apachewww-datahttpd (取决于您的服务器)。 cron作业或CLI执行具有运行它的用户拥有的任何权限(即以root身份运行PHP脚本将以root权限执行)。

    很多时候,人们会通过执行以下操作来解决权限问题(Linux示例)

    chmod 777 /path/to/file
    

    这不是一个聪明的想法,因为文件或目录现在是世界可写的。 如果你拥有服务器并且是唯一的用户,那么这不是什么大不了的事情,但是如果你在一个共享主机环境中,你刚刚给你的服务器访问权限上的每个人。

    你需要做的是确定需要访问的用户,并只给予他们访问权限。 一旦您知道哪些用户需要访问,您需要确保这一点

  • 该用户拥有该文件并可能拥有父目录 (如果要写入文件,尤其是父目录)。 在大多数共享主机环境中,这不会成为问题,因为您的用户应该拥有根目录下的所有文件。 一个Linux例子如下所示

    chown apache:apache /path/to/file
    
  • 用户,并且只有该用户才有权访问。 在Linux中,一个好的做法是chmod 600 (只有所有者可以读写)或chmod 644 (所有者可以写,但每个人都可以读)

  • 你可以在这里阅读更多关于Linux / Unix权限和用户的讨论


    另一个可能的原因:在文本编辑器中重命名和/或移动文件。 我经历了上述所有步骤,直到我删除了不断抛出此错误的文件并创建了一个修复了问题的新文件。

    链接地址: http://www.djcxy.com/p/11879.html

    上一篇: Failed to open stream : No such file or directory

    下一篇: Fatal error: Can't use function return value