Heim  >  Fragen und Antworten  >  Hauptteil

PHP – Stream kann nicht geöffnet werden: Keine solche Datei oder kein solches Verzeichnis

<p>Ob Sie in einem PHP-Skript <code>include()</code>, <code>require()</code>, <code>fopen()</code> oder seinen abgeleiteten Klassen, wie <code> include_once</code>, <code>require_once</code> oder sogar <code>move_uploaded_file()</code>, werden Sie häufig auf Fehler oder Warnungen stoßen: < /p> <blockquote> <p>Stream kann nicht geöffnet werden: Keine solche Datei oder kein solches Verzeichnis. </p> </blockquote> <p>Was ist ein gutes Verfahren, um schnell die Grundursache eines Problems zu finden? </p>
P粉145543872P粉145543872393 Tage vor522

Antworte allen(2)Ich werde antworten

  • P粉362071992

    P粉3620719922023-08-24 12:18:48

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

    共享托管软件

    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 服务器软件的手册。

    文件权限

    需要注意的是,通过 Web 服务器执行文件与命令行或 cron 作业执行有很大不同。最大的区别是您的网络服务器有自己的用户和权限。出于安全原因,该用户受到很大限制。例如,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(所有者可以写入,但每个人都可以读取)

    您可以阅读有关 Linux 的更广泛的讨论/此处的 Unix 权限和用户

    Antwort
    0
  • P粉268654873

    P粉2686548732023-08-24 00:48:10

    可能会遇到此错误的原因有很多,因此首先检查哪些内容的良好清单会很有帮助。

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

    require "/path/to/file"


    清单


    1。检查文件路径是否有拼写错误

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

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

      然后,在终端中:

      cat <file path pasted>


    2。检查相对与绝对路径注意事项的文件路径是否正确

    最佳实践:

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

    1. 使用 require __DIR__ 。 “/相对/路径/来自/当前/文件”__DIR__ 魔术常量 返回当前文件的目录。
    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";

    这 2 种做法还使您的应用程序更具可移植性,因为它不依赖于包含路径等 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 设置禁止它访问该文件。

    三个设置可能相关:

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

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

    发生这种情况的原因是您(成功)包含的文件本身具有另一个文件的包含语句,而第二个包含语句假定您已将该库的路径添加到包含路径中。

    例如,前面提到的 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 拒绝访问文件的原因可能有多种,具体取决于您的策略。所以你需要对此进行调查。 此处 是专门为 Web 服务器配置 SELinux 的教程。


    3。交响乐

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

    您可以通过运行以下控制台命令来测试并修复此问题:

    cache:clear


    4。 Zip 文件中的非 ACSII 字符

    显然,当 zip 中的某些文件的文件名中包含非 ASCII 字符(例如“é”)时,调用 zip->close() 时也会发生此错误。

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

    感谢 Fran Cano 确定了此问题并提出了解决方案< /p>

    Antwort
    0
  • StornierenAntwort