web-dev-qa-db-ja.com

PHP - ストリームを開けませんでした:そのようなファイルまたはディレクトリはありません

PHPスクリプトでは、include()require()fopen()、またはそれらの派生物(include_oncerequire_once、さらにはmove_uploaded_file()など)を呼び出すかどうかにかかわらず、エラーまたは警告が発生することがよくあります。

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

問題の根本的な原因をすばやく見つけるための良いプロセスは何ですか?

130

このエラーに遭遇する理由はたくさんあるので、最初にチェックするものの良いチェックリストがかなり役立ちます。

次の行のトラブルシューティングを行っていると考えてみましょう。

require "/path/to/file"


チェックリスト


1.タイプミスのファイルパスを確認します

  • 手動で確認する(パスを視覚的に確認する)
  • または、require*またはinclude*によって呼び出されたものを独自の変数に移動し、それをエコーし​​、コピーして、ターミナルからアクセスしてみます。

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

    次に、ターミナルで:

    cat <file path pasted>
    


2.相対パスと絶対パスの考慮事項に関して、ファイルパスが正しいことを確認します。

  • スラッシュ「/」で始まる場合は、Webサイトのフォルダーのルート(ドキュメントルート)ではなく、サーバーのルートを参照しています。
    • たとえば、Webサイトのディレクトリは/users/tony/htdocsになります
  • スラッシュで始まっていない場合は、インクルードパスに依存している(以下を参照)か、パスが相対パスになっています。相対的な場合、PHPは 現在の作業ディレクトリ 。のパスに対して相対的に計算します。
    • したがって、Webサイトのルートのパス、または入力しているファイルに対してではありません
    • そのため、常に絶対ファイルパスを使用してください

ベストプラクティス :

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

  1. require __DIR__ . "/relative/path/from/current/file"を使用します。 __DIR__マジック定数 は、現在のファイルのディレクトリを返します。
  2. SITE_ROOT定数を自分で定義します。

    • webサイトのディレクトリのルートで、ファイルを作成します。 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.インクルードパスを確認します

ファイルをインクルードするもう1つの方法は、相対的でも純粋でも絶対ではなく、 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>

許可記号表記 を見てください


5. PHP設定を確認します

上記のいずれも機能しない場合、問題はおそらく、いくつかのPHP設定がそのファイルへのアクセスを禁止していることです。

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

  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"

しかし、それでも同じ種類のエラーが発生します。

これは、(正常に)インクルードしたファイル自体に別のファイルのインクルードステートメントがあり、2番目のインクルードステートメントがそのライブラリのパスをインクルードパスに追加したことを前提としているために発生する可能性があります。

たとえば、前述のZendフレームワークファイルには、次のインクルードを含めることができます。

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

これは、相対パスによる包含でも絶対パスによる包含でもありません。 Zend frameworkディレクトリがインクルードパスに追加されていることを前提としています。

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


2. SELinux

Security-Enhanced 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コンテキストタイプをWebサイトのルートディレクトリに割り当てるには、次を実行します。

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

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

次のコンソールコマンドを実行して、これをテストおよび修正できます。

cache:clear


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

どうやら、このエラーは、Zip内の一部のファイルのファイル名に「é」などの非ASCII文字が含まれているときにZip->close()を呼び出したときにも発生する可能性があります。

考えられる解決策は、ターゲットファイルを作成する前に、ファイル名をutf8_decode()でラップすることです。

Fran Cano へのクレジットこの問題の解決策を特定して提案するために

221

(本当に良い)既存の回答に追加する

共有ホスティングソフトウェア

open_basedirは、Webサーバー構成で指定できるため、あなたを切り札にすることができます。あなたがあなた自身の専用サーバを走らせるならばこれは容易に直されるが、ドメイン毎に設定ディレクティブを設定するいくつかの共有ホスティングソフトウェアパッケージ(Plesk、cPanel、その他のような)がそこにある。ソフトウェアは設定ファイル(つまりhttpd.conf)を作成するので、ホスティングソフトウェアは再起動時にそれを上書きするだけなので、そのファイルを直接変更することはできません。

Pleskでは、提供されたhttpd.confvhost.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-dataまたはhttpdです(サーバーによって異なります)。 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のパーミッションとユーザに関するより広範な議論を読むことができます

11
Machavity

クエリパラメータを使用してスクリプトを追加する

それは私の場合でした。それは実際に 質問#4485874 にリンクしていますが、私はすぐにここでそれを説明するつもりです。
path/to/script.php?parameter=valueを要求しようとすると、UNIXではこのようなパスを使用できるため、PHPはscript.php?parameter=valueという名前のファイルを探します。
インクルードスクリプトに実際にデータを渡す必要がある場合は、それを$variable=...または$GLOBALS[]=...として宣言してください。

1
Paul Lynn
  1. exact エラーを見てください

私のコードはすべてのマシンでうまくいきましたが、これだけが問題を起こし始めました(これは私が推測していたものだった)。デバッグにエコー "document_root"パスを使用し、またエラーをよく見て、これを見つけました

警告:include( D:/MyProjects/testproject//functions/connections.php ):ストリームを開けませんでした:

問題がどこにあるのか簡単にわかります。問題は//関数の前です

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

そのため、単純にlading /をインクルードから削除するだけで問題なく動作します。興味深いのは、この動作がバージョンによって異なることです。私はラップトップ、マックブックプロとこのPCの上で同じコードを走らせます、すべてはうまくいくまでうまくいきました。これが誰かに役立つことを願っています。

  1. ファイルが存在することを確認するために、ブラウザのファイルの場所を越えてコピーします。時にはファイルが突然削除されて(私と一緒に起こった)、それは私の場合の問題でもありました。
1
Hammad Khan

その他の考えられる原因:テキストエディタ内でファイルの名前を変更したり移動したりします。私はこのエラーを投げ続けていたファイルを削除して問題を解決するまで新しいファイルを作成するまで成功せずに上記のすべてのステップを実行しました。

0
zMeadz