1. ホーム
  2. php

[解決済み] PHP - ストリームを開くのに失敗しました : そのようなファイルまたはディレクトリがありません。

2022-02-18 19:45:45

質問

PHPスクリプトでは include() , require() , fopen() またはその派生物である include_once , require_once , あるいは move_uploaded_file() というエラーや警告に遭遇することがよくあります。

ストリームを開くのに失敗しました:そのようなファイルまたはディレクトリがありません。

問題の根本的な原因を素早く見つけるために、何か良いプロセスはありますか?

どのように解決するのですか?

このエラーに遭遇する理由はさまざまなので、最初に何を確認すべきかのチェックリストが非常に役に立ちます。

次のような行のトラブルシューティングを行う場合を考えてみましょう。

require "/path/to/file"


チェックリスト


1. ファイルパスに誤字がないか確認する

  • 手動で確認する(パスを目視で確認する)か
  • で呼び出されたものを移動させるか require* または include* を自分の変数にコピーし、それをechoし、コピーして、ターミナルからアクセスしてみてください。

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

    次に、ターミナルで

    cat <file path pasted>
    
    


2. ファイルパスが正しいかどうか、相対パスと絶対パスについて考慮すること

  • フォワードスラッシュ "/"で始まっている場合は、ウェブサイトのフォルダーのルート(ドキュメントルート)ではなく、サーバーのルートを指していることになります。
    • 例えば、あなたのウェブサイトのディレクトリは、次のようになります。 /users/tony/htdocs
  • がフォワードスラッシュで始まっていない場合、インクルードパスに依存しているか(下記参照)、パスが相対パスであるかのどちらかです。相対パスである場合、PHP は 現在の作業ディレクトリ .
    • したがって、Web サイトのルートのパスや、入力中のファイルからの相対パスではありません。
    • そのため、ファイルパスは常に絶対パスを使用します。

ベストプラクティス:

実行時に絶対パスを生成しつつ、スクリプトを移動した場合に備えて堅牢にするために、2つのオプションがあります。

  1. 使用 require __DIR__ . "/relative/path/from/current/file" . その __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の設定がそのファイルへのアクセスを禁止していることが原因だと思われます。

3つの設定に関連する可能性があります。

  1. オープンベースドア
    • この設定をすると、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"

でも、そうすると、やはり同じようなエラーが出てしまいます。

これは、インクルードが成功したファイル自体に、別のファイルのインクルード文があり、その2番目のインクルード文が、インクルードパスにそのライブラリのパスを追加したものと仮定しているために起こり得ます。

例えば、先ほどのZend frameworkのファイルでは、以下のようなincludeが可能です。

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

は相対パスによるインクルージョンでも絶対パスによるインクルージョンでもない。これは、Zend framework ディレクトリがインクルードパスに追加されていることを想定しています。

このような場合、唯一の現実的な解決策は、そのディレクトリをインクルードパスに追加することです。


2. SELinux

Security-Enhanced 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を設定するための特別なチュートリアルです。


3. シンフォニー

Symfonyを使用していて、サーバーにアップロードするときにこのエラーが発生する場合、アプリのキャッシュがリセットされていない可能性があります。 app/cache がアップロードされているか、キャッシュがクリアされていない。

以下のコンソールコマンドを実行することで、テストと修正を行うことができます。

cache:clear


4. Zipファイル内の非ACSII文字

どうやら、このエラーは zip->close() のような非 ASCII 文字がファイル名に含まれている場合、zip ファイルを作成することができます。

解決策としては、ファイル名を utf8_decode() を作成してから、ターゲットファイルを作成します。

クレジット フラン・カノ この問題を特定し、解決策を提案してくれた