【问题标题】:PHP - Failed to open stream : No such file or directoryPHP - 无法打开流:没有这样的文件或目录
【发布时间】:2016-08-03 06:53:30
【问题描述】:

在 PHP 脚本中,无论是调用include()require()fopen(),还是它们的派生类,例如include_oncerequire_once,甚至是move_uploaded_file(),都经常会遇到错误或警告:

打开流失败:没有这样的文件或目录。

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

【问题讨论】:

  • 我已经清理了这篇文章中的离题 cmets。请在元中保持元讨论。但是,请注意,关于规范问题可行性的讨论已经一遍又一遍地进行。参见示例here
  • 我遇到了同样的问题,唯一有效的解决方案是:-1转到要包含的文件,右下角,属性,复制完整路径例如:C:/.... ..../file.php 2- 包含它。实际上我看到这个问题得到了回答,并且答案得到了验证,但是对我来说在某些情况下没有用,直到我找到了上述方法。
  • @Rash 感谢您的贡献。不幸的是,您的解决方案是错误的,因为它会提到绝对路径名,这是错误的。这是错误的原因,因为当您将项目复制到其他地方或将其移动到计算机中时,一切都会中断。

标签: php require fopen include-path


【解决方案1】:

在 PHP 中,启动 Apache,然后写入您的数据库名称和密码(如果您的环境中存在)(.env)。

【讨论】:

    【解决方案2】:

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

    例如,我将上传一张图片。但我收到了这个错误。我要做的第一件事是右键单击图像并获取信息。

    $thePathOfMyPicture = "/Users/misstugba/Desktop/"; 与函数一起使用

    if(move_uploaded_file($_FILES["file"]["tmp_name"],$thePathOfMyPicture.$_FILES["file"]["name"])){
    echo "image uploaded successfully";
    

    }

    【讨论】:

      【解决方案3】:

      对我来说,我收到了这个错误,因为我试图读取一个需要 HTTP 身份验证的文件,并带有用户名和密码。希望对其他人有所帮助。可能是另一个极端情况。

      编辑

      您可以通过检查标头来检查是否存在这种类型的身份验证:

      $file_headers = get_headers($url);
      if (!$file_headers) echo 'File headers missing';
      else if (strpos($file_headers[0], '401 Unauthorized') > -1) echo '401 Unauthorized';
      

      【讨论】:

      • 您能分享一下您使用的确切线路吗?它使用了includerequire 还是fopen
      • @VicSeedoubleyew $fp = fopen($file, 'wb');不,我没有使用 include 或 require。您可以使用 URL 进行复制:12345:12345@datatransfer.cj.com/datatransfer/files/products.zip
      • 好的,谢谢。 fopen 是从 HTTP 位置读取的推荐方式吗?
      • 我不知道它是否被推荐,但它似乎完全有效。你可能比我知道的更多
      • 我已经好几年没用过PHP了,所以我说不出来。我只是想知道解决您的情况是添加用户名和密码,还是使用其他功能
      【解决方案4】:

      php.ini中的以下PHP设置如果设置为不存在的目录也可以引发

      PHP 警告:未知:无法打开流:权限被拒绝 第0行未知

      sys_temp_dir
      upload_tmp_dir
      session.save_path
      

      【讨论】:

        【解决方案5】:

        Samba 分享

        如果您有一台 Linux 测试服务器并使用 Windows 客户端工作,则 Samba 共享会干扰 chmod 命令。所以,即使你使用:

        chmod -R 777 myfolder
        

        在 Linux 方面,完全有可能 Unix Group\www-data 仍然没有写入权限。如果您的共享设置为将 Windows 管理员映射到 root,则一种可行的解决方案:从 Windows,打开权限,禁用带有副本的文件夹的继承,然后授予对 www-data 的完全访问权限。

        【讨论】:

          【解决方案6】:

          一个人可能会遇到此错误的原因有很多,因此一份关于首先要检查的内容的良好清单有很大帮助。

          假设我们正在对以下行进行故障排除:

          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 将相对于current working directory 的路径进行计算。
            • 因此,与您网站根目录的路径或您输入的文件无关
            • 因此,请始终使用绝对文件路径

          最佳实践:

          为了使您的脚本在您四处移动时保持稳健,同时在运行时仍生成绝对路径,您有 2 个选项:

          1. 使用require __DIR__ . "/relative/path/from/current/file"__DIR__ magic constant 返回当前文件的目录。
          2. 自己定义一个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 设置禁止它访问该文件。

          三个设置可能是相关的:

          1. open_basedir
            • 如果设置了此项,PHP 将无法访问指定目录之外的任何文件(甚至无法通过符号链接)。
            • 但是,默认行为是不设置它,在这种情况下没有限制
            • 这可以通过调用phpinfo() 或使用ini_get("open_basedir") 来检查
            • 您可以通过编辑 php.ini 文件或 httpd.conf 文件来更改设置
          2. safe mode
            • 如果启用此功能,可能会受到限制。但是,这已在 PHP 5.4 中删除。如果您仍在使用支持安全模式的版本,请升级到 PHP 版本 still being supported
          3. 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-&gt;close() 时也会发生此错误。

          一种可能的解决方案是在创建目标文件之前将文件名包含在utf8_decode() 中。

          感谢 Fran Cano 识别并提出解决此问题的方法

          【讨论】:

          • 我认为在这里提及selinux 可能是个好主意。您将至少需要 httpd_sys_content_t(Apache 使用的只读目录和文件)对包含文件的权限。
          • 非常感谢您的建议。由于我对 SELinux 不熟悉,所以我做了一些阅读并试图回答这个案例。如果不正确,请随时反馈或提出一些修改建议。再次感谢您的评论!
          • chcon 是临时的,不会在restorecon 或重新启动后继续存在。您可能需要使用semanage 来更改文件的上下文。这是一个很好的simple tutorial for web site
          • 另一种可能添加:真实路径缓存:lyte.id.au/2014/05/01/what-the-hell-php
          • @chrishiestand 非常感谢!那篇文章真的很有趣!您还记得导致该错误的事件过程是什么吗?是不是最初用户没有对文件的读取权限,然后它被更改了,但缓存仍然认为它不可读,所以它在文件打开时抛出了这个错误?
          【解决方案7】:
          1. 查看确切错误

          我的代码在所有机器上都运行良好,但只有在这台机器上开始出现问题(我猜它曾经工作过)。使用 echo "document_root" 路径进行调试,也仔细查看了错误,发现了这个

          警告: 包括(D:/MyProjects/testproject//functions/connections.php): 无法打开流:

          您可以轻松查看问题所在。问题是 // 在函数之前

          $document_root = $_SERVER['DOCUMENT_ROOT'];
          echo "root: $document_root";
          include($document_root.'/functions/connections.php');
          

          所以只需从 include 中删除 ladding / 它应该可以正常工作。有趣的是这种行为在不同的版本上是不同的。我在笔记本电脑、Macbook Pro 和这台 PC 上运行相同的代码,一切都运行良好,直到。希望这对某人有所帮助。

          1. 在浏览器中复制文件位置以确保文件存在。有时文件会被意外删除(发生在我身上),这也是我的问题。

          【讨论】:

          • 这与下面清单的第 1 步有何不同?
          • 第 2 步是一项额外检查,与第 1 步无关。只需在浏览器中导航到建议的路径,然后查看是否在那里看到文件(在 Windows 资源管理器中没有,但在浏览器中)。
          【解决方案8】:

          添加带有查询参数的脚本

          这就是我的情况。它实际上链接到question #4485874,但我很快就会在这里解释它。
          当您尝试要求 path/to/script.php?parameter=value 时,PHP 会查找名为 script.php?parameter=value 的文件,因为 UNIX 允许您使用这样的路径。
          如果您确实需要将一些数据传递给包含的脚本,只需将其声明为$variable=...$GLOBALS[]=... 或其他您喜欢的方式。

          【讨论】:

            【解决方案9】:

            添加到(非常好的)现有答案

            共享主机软件

            open_basedir 是一个让你难以理解的方法,因为它可以在 Web 服务器配置中指定。如果您运行自己的专用服务器,这很容易解决,但也有一些共享托管软件包(如 Plesk、cPanel 等)将在每个域的基础上配置配置指令。由于软件会构建配置文件(即httpd.conf),因此您无法直接更改该文件,因为托管软件会在重新启动时覆盖它。

            使用 Plesk,它们提供了一个位置来覆盖提供的 httpd.conf,称为 vhost.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
            

            这不是一个聪明的主意,因为文件或目录现在是全局可写的。如果您拥有服务器并且是唯一的用户,那么这没什么大不了的,但如果您在共享托管环境中,您只是为服务器上的每个人提供了访问权限。

            您需要做的是确定需要访问权限的用户并仅授予他们访问权限。一旦您知道哪些用户需要访问权限,您需要确保

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

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

            你可以read a more extended discussion of Linux/Unix permissions and users here

            【讨论】:

              猜你喜欢
              • 2015-11-13
              • 1970-01-01
              • 1970-01-01
              • 2020-08-11
              • 2011-05-27
              相关资源
              最近更新 更多