PHPスクリプトでは、include()
、require()
、fopen()
、またはそれらの派生物(include_once
、require_once
、さらにはmove_uploaded_file()
など)を呼び出すかどうかにかかわらず、エラーまたは警告が発生することがよくあります。
ストリームを開けませんでした:そのようなファイルまたはディレクトリはありません。
問題の根本的な原因をすばやく見つけるための良いプロセスは何ですか?
このエラーに遭遇する理由はたくさんあるので、最初にチェックするものの良いチェックリストがかなり役立ちます。
次の行のトラブルシューティングを行っていると考えてみましょう。
require "/path/to/file"
または、require*
またはinclude*
によって呼び出されたものを独自の変数に移動し、それをエコーし、コピーして、ターミナルからアクセスしてみます。
$path = "/path/to/file";
echo "Path : $path";
require "$path";
次に、ターミナルで:
cat <file path pasted>
/users/tony/htdocs
になりますベストプラクティス :
実行時に絶対パスを生成しながら移動する場合にスクリプトを堅牢にするために、2つのオプションがあります。
require __DIR__ . "/relative/path/from/current/file"
を使用します。 __DIR__
マジック定数 は、現在のファイルのディレクトリを返します。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設定に依存しないため、アプリケーションの移植性を高めます。
ファイルをインクルードするもう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");
サーバープロセス(ApacheまたはPHP)を実行しているユーザーには、そのファイルに対する読み取りまたは書き込みのアクセス許可がまったくない可能性があります。
サーバーが実行しているユーザーを確認するには、 posix_getpwuid を使用します。
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
ファイルの権限を確認するには、ターミナルで次のコマンドを入力します。
ls -l <path/to/file>
許可記号表記 を見てください
上記のいずれも機能しない場合、問題はおそらく、いくつかのPHP設定がそのファイルへのアクセスを禁止していることです。
3つの設定が関連する可能性があります。
phpinfo()
を呼び出すか、ini_get("open_basedir")
を使用して確認できます。ini_get("allow_url_include")
で確認でき、ini_set("allow_url_include", "1")
で設定できます上記のいずれでも問題の診断が有効になっていない場合、次のような特別な状況が発生する可能性があります。
相対パスまたは絶対パスを使用して、Zendフレームワークなどのライブラリを含めることがあります。例えば :
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
しかし、それでも同じ種類のエラーが発生します。
これは、(正常に)インクルードしたファイル自体に別のファイルのインクルードステートメントがあり、2番目のインクルードステートメントがそのライブラリのパスをインクルードパスに追加したことを前提としているために発生する可能性があります。
たとえば、前述のZendフレームワークファイルには、次のインクルードを含めることができます。
include "Zend/Mail/Protocol/Exception.php"
これは、相対パスによる包含でも絶対パスによる包含でもありません。 Zend frameworkディレクトリがインクルードパスに追加されていることを前提としています。
このような場合、唯一の実用的な解決策は、インクルードパスにディレクトリを追加することです。
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を設定するためのチュートリアルです。
Symfonyを使用していて、サーバーへのアップロード時にこのエラーが発生した場合、app/cache
がアップロードされたか、キャッシュがクリアされていないため、アプリのキャッシュがリセットされていない可能性があります。
次のコンソールコマンドを実行して、これをテストおよび修正できます。
cache:clear
どうやら、このエラーは、Zip内の一部のファイルのファイル名に「é」などの非ASCII文字が含まれているときにZip->close()
を呼び出したときにも発生する可能性があります。
考えられる解決策は、ターゲットファイルを作成する前に、ファイル名をutf8_decode()
でラップすることです。
Fran Cano へのクレジットこの問題の解決策を特定して提案するために
(本当に良い)既存の回答に追加する
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はしばしばApache
、www-data
またはhttpd
です(サーバーによって異なります)。 cronジョブまたはCLIの実行には、それを実行しているユーザーが持っている権限がすべて含まれています(つまり、rootとしてPHPスクリプトを実行すると、rootの権限で実行されます)。
多くの場合、次のようにしてパーミッションの問題を解決します(Linuxの例)。
chmod 777 /path/to/file
これは賢い考えではありません。ファイルまたはディレクトリは現在、世界で書き込み可能であるためです。サーバーを所有していて唯一のユーザーであれば、これはそれほど大きな問題ではありませんが、共有ホスティング環境にいる場合は、サーバー上の全員にアクセスを許可したばかりです。
あなたがする必要があるのは、アクセスを必要とするユーザーを決定し、それらのユーザーにのみアクセスを許可することです。どのユーザーがアクセスを必要としているかがわかったら、それを確認する必要があります。
そのユーザはファイル とおそらく親ディレクトリ を所有します(特にファイルを書きたい場合は親ディレクトリ)。ほとんどの共有ホスティング環境では、これは問題になりません。あなたのユーザはあなたのルートの下にあるすべてのファイルを所有するべきだからです。以下にLinuxの例を示します。
chown Apache:apache /path/to/file
ユーザー、そしてそのユーザーだけがアクセスできます。 Linuxでは、良いやり方はchmod 600
(所有者だけが読み書きできます)またはchmod 644
(所有者は書くことができますが誰でも読むことができます)でしょう。
それは私の場合でした。それは実際に 質問#4485874 にリンクしていますが、私はすぐにここでそれを説明するつもりです。path/to/script.php?parameter=value
を要求しようとすると、UNIXではこのようなパスを使用できるため、PHPはscript.php?parameter=value
という名前のファイルを探します。
インクルードスクリプトに実際にデータを渡す必要がある場合は、それを$variable=...
または$GLOBALS[]=...
として宣言してください。
私のコードはすべてのマシンでうまくいきましたが、これだけが問題を起こし始めました(これは私が推測していたものだった)。デバッグにエコー "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の上で同じコードを走らせます、すべてはうまくいくまでうまくいきました。これが誰かに役立つことを願っています。
その他の考えられる原因:テキストエディタ内でファイルの名前を変更したり移動したりします。私はこのエラーを投げ続けていたファイルを削除して問題を解決するまで新しいファイルを作成するまで成功せずに上記のすべてのステップを実行しました。