2008年4月21日月曜日

PHP の include によりファイルが検索される場所

include 関数を利用している PHP ファイルがある。このファイルを別の環境に移したら動かなくなってしまった。 (+_+) 原因は何だろう?

 

include はどこからファイルを探すのか?

言語リファレンス > 制御構造 > include によると、

ファイルのインクルードは、指定されたパスから行います。パスを指定しない場合は、 include_path の設定を利用します。…

パス (絶対パスあるいは相対パスのいずれでも) を指定した場合は include_path は無視されます。たとえば ../ ではじまるファイル名を指定した場合は、 親ディレクトリからそのファイルを探します。

上記 include_path とは、

PHP は、インクルードするファイルを探す際に インクルードパスの各エントリを個別に調べます。 まず最初のパスを調べ、見つからなければ次のパスを調べ、…… というように、ファイルが見つかるか warning あるいは error が発生するまで続けます。

(PHP: コア php.ini ディレクティブに関する説明 – Manual より)

include_path を調べるには、phpinfo 、または get_include_path を利用する。 XAMPP を使っているなら、以下の URL にアクセス。

http://localhost/xampp/phpinfo.php

 

include を試してみる

Image3右図のようにファイル構成で include の挙動を確認する。実行した環境は、XAMPP を利用しており、phpinfo() を見ると include_path

D:\xampp\php\pear\

と表示される。 右図のルートとなる www フォルダは、PDT で testphp プロジェクト内に作成した。

各ファイルの内容は以下の通り。

  • www/index.php
<?php
include ("include/a.php");
?>
  • www/include/a.php
<?php
print "include/a.php"."<br>";
include("b.php");
?>
  • www/include/b.php
<?php
print "include/b.php"."<br>";
?>

これで www/index.php を実行すると、

include/a.php
include/b.php

と表示された。

 

include でファイルを探しにいく場所を順に考える

上記の実行される流れを考える。最初に www/index.php にアクセスしたので current working directory

www

include する側のファイルとされる側を矢印で示すと、

  • www/index.php → include/a.php、
  • include/a.php → include/b.php

という関係。

ところで、マニュアルには次のように書かれていた。

ファイルのインクルードは、指定されたパスから行います。パスを指定しない場合は、 include_path の設定を利用します。…

つまり、include/a.php において

“b.php”

を include するとき、パスが指定されていないので最初に include_path である

D:\xampp\php\pear\

に b.php がないか検索される。その後 www/include/ 内を検索。

上記の場合は include_path に b.php がなく、www/include/ に b.php があるので www/include/b.php が実行される。

 

相対パスによって指定するとそのディレクトリから検索される

ところで、先ほどのドキュメントには、以下のように書かれていた。

パス (絶対パスあるいは相対パスのいずれでも) を指定した場合は include_path は無視されます。たとえば ../ ではじまるファイル名を指定した場合は、 親ディレクトリからそのファイルを探します。

上記における www/include/a.php で include している部分を include("./b.php"); に変更して実行したら、以下のエラーが表示された。

include/a.php
Warning: include(./b.php) [function.include]: failed to open stream: No such file or directory in D:\xampp\htdocs\testphp\www\include\a.php on line 3
Warning: include() [function.include]: Failed opening './b.php' for inclusion (include_path='.;D:\xampp\php\pear\') in D:\xampp\htdocs\testphp\www\include\a.php on line 3

これは、

./

を付けたことによって current working directory から検索されるため。

www/b.php

は存在しないので上記のようなエラーが表示された。b.php を www に置いたら、エラーは表示されない。

 

意図しないファイルを include してしまう

さて、ここで www/include/

config.php

を作成する。ファイルの内容は "config.php" と文字列を表示するのみ。

これを include/a.php から include して動作を確かめる。 include/a.php の include を include("config.php") と変更した。

実行するとなぜか "config.php" と表示されなかった。

include("config.php") をブレークポイントにしてデバッグしたところ、config.php の include で以下のような表示がされている。

Image5

www/include/config.php を include しているつもりが、include_path (D:\xampp\php\pear\) 内の Config.php を include してしまっている。これは先ほどの説明にあったように、

include_path が最初に検索される

のが理由。 include_path 内にあるファイルと同名のファイルを include をするときは注意が必要。

 

意図しない include をしないための対策

config.php の内容が実行されるには、3 つの方法がある。

  • config.php を myconfig.php のように名称を変え、pear\Config.php とバッティングしないようにする。
  • config.php を current working directory に置き、相対パスで呼出すようにする。www/config.php に置き、include/a.php では、include("./config.php") とする。
  • www/include/config.php の場所は変えず、include/a.php の include の呼出しを次にようにする。

include(dirname(__FILE__) . "/config.php");

include しているファイルから見て相対的な位置で include できるように記述すればよい。(参考: PHP の include, require で相対パスを指定して読み込む場合のメモ - hoge256ブログ)

 

環境を変えたら動作しなかった理由

最初の問題に戻る。環境を変えたら動かなくなった理由は、問題なく動いていた環境では PEAR がインストールされていなかったために、

include("config.php")

の記述により、自分が作成した config.php が include されたていた。

しかし、環境を XAMPP に変更したことにより include_path に PEAR が設定され、include("config.php") の記述により PEAR の Config.php が呼出されたために挙動がおかしくなった。

パタッ(o_ _)o~†