PHPスクリプトでは、include()
、require()
、fopen()
、あるいはそれらの派生形であるinclude_once
、require_once
、さらにはmove_uploaded_file()
を呼び出しているかどうかにかかわらず、しばしばエラーや警告が発生します。
Failed to open stream : No such file or directory.
問題の根本的な原因を素早く見つけるための良いプロセスは何でしょうか?
このエラーが発生する理由は様々なので、最初に何をチェックすべきかの良いチェックリストがあればかなり役立ちます。 以下の行をトラブルシューティングすることを考えてみましょう。
require "/path/to/file"
とします。
チェックリスト
require*
やinclude*
で呼び出されるものを自分の変数に移し、それをエコー、コピーして、ターミナルからアクセスしてみます。
$path = "/path/to/file";
echo "Path : $path";
require "$path";
次に、ターミナルで
cat /users/tony/htdocs
であるとします。require _DIR__ . "/relative/path/from/current/file"
を使用する。magicconst-docs] はカレントファイルのディレクトリを返します。SITE_ROOT
定数を定義する。config.php
というファイルを作成します。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の設定に依存しないので、アプリケーションの移植性も高くなります。インクルードパス]includepath-docsに依存するという方法もありますが、これは相対的にも絶対的にもありません。これは、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>
と入力し、permission symbolic notationを見てください。
上記のいずれもうまくいかなかった場合は、PHPの設定でそのファイルへのアクセスが禁止されていることが問題となります。 以下の3つの設定が考えられます。 1.open_basedir.
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"
しかし、それでも同じようなエラーが発生します。 これは、インクルードした(成功した)ファイルの中に、別のファイルのためのinclude文があり、その2番目のinclude文は、そのライブラリのパスをincludeパスに追加したと仮定しているために起こります。 例えば、先ほどのZendフレームワークのファイルは、以下のようなinclude :
include "Zend/Mail/Protocol/Exception.php"
これは、相対パスによるインクルードでも、絶対パスによるインクルードでもありません。これは、Zend framework ディレクトリがインクルード・パスに追加されていることを想定しています。
このような場合、唯一の現実的な解決策は、そのディレクトリをインクルードパスに追加することです。
Security-Enhanced Linuxを使用している場合は、サーバーからのファイルへのアクセスを拒否することで問題を解決している可能性があります。
SELinuxが有効になっているかどうかを確認するには、ターミナルでsestatus
コマンドを実行してください。このコマンドが存在しない場合は、SELinuxがシステムに搭載されていないことになります。存在する場合は、それが適用されているかどうかを教えてくれるはずです。
SELinuxポリシーが問題の原因であるかどうかを確認するには、SELinuxを一時的にオフにしてみることができます。ただし、これは保護を完全に無効にしてしまうため、注意が必要です。本番サーバーではこのようなことをしないでください。
setenforce 0
SELinuxをオフにしても問題が発生しない場合は、これが根本的な原因です。 **この問題を解決するには、SELinuxを適切に設定する必要があります。 以下のようなコンテキストタイプが必要になります。
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の設定に関するチュートリアルがあります。 参考にしてください。
Symfonyを使用していて、サーバーにアップロードする際にこのエラーが発生する場合、アプリのキャッシュがリセットされていない可能性があります(app/cache
がアップロードされているか、キャッシュがクリアされていないため)。
以下のコンソールコマンドを実行することで、この問題をテストし、解決することができます。
cache:clear
と表示されます。
このエラーは、ZIPファイルのファイル名に"é"などの非ASCII文字が含まれている場合、zip->close()
の呼び出し時にも発生するようです。
解決策としては、ターゲットファイルを作成する前に、ファイル名を utf8_decode()
でラップすることが考えられます。
この問題を特定し、解決策を提案してくれたFran Canoに感謝します。
既存の回答(本当に良い)に追加すると
open_basedirは、Webサーバーの設定で指定できるため、困ってしまうことがあります。自分で専用サーバーを運用している場合は簡単に解決できますが、共有ホスティングソフトウェアパッケージ(PleskやcPanelなど)の中には、ドメインごとに設定ディレクティブを設定するものがあります。このソフトウェアは設定ファイル(例:
httpd.conf`)を構築するので、ホスティングソフトウェアが再起動したときに上書きされてしまうため、そのファイルを直接変更することはできません。
Pleskでは、vhost.conf
という、提供されたhttpd.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>
サーバー管理者には、使用しているホスティングソフトやウェブサーバーソフトのマニュアルを参照してもらってください。
ウェブサーバーでファイルを実行することは、コマンドラインやクーロンジョブの実行とは大きく異なることに注意してください。大きな違いは、ウェブサーバーには独自のユーザーとパーミッションがあるということです。セキュリティ上の理由から、そのユーザーはかなり制限されています。例えば、Apacheはしばしばapache
、www-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のパーミッションとユーザーについてのより詳しい説明はこちら](https://unix.stackexchange.com/questions/35711/giving-php-permission-to-write-to-files-and-folders)