搜尋

首頁  >  問答  >  主體

PHP - 無法開啟流:沒有這樣的檔案或目錄

<p>在PHP 腳本中,無論是呼叫<code>include()</code>、<code>require()</code>、<code>fopen()</code>或其衍生類,例如<code> include_once</code>、<code>require_once</code>,甚至<code>move_uploaded_file()</code>,經常會遇到錯誤或警告:< /p> <blockquote> <p>無法開啟流:沒有這樣的檔案或目錄。 </p> </blockquote> <p>快速找到問題根本原因的好流程是什麼? </p>
P粉145543872P粉145543872461 天前590

全部回覆(2)我來回復

  • 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 權限和用戶

    #

    回覆
    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>#

    回覆
    0
  • 取消回覆