web-dev-qa-db-ja.com

インクルードパス解決はrequire_onceでどのように機能しますか?

奇妙な状況に遭遇したとき、私はPHPでWebアプリを書いていました。私の問題を説明するために、この構造のWebアプリを考えてみましょう。

/
    index.php
    f1/
        f1.php
    f2/
        f2.php

これらのファイルの内容:

index.php:

<?php require_once("f1/f1.php"); ?>

f1.php:

<?php require_once("../f2/f2.php"); ?>

f2.php:空白

ブラウザでindex.phpを開こうとすると、次のエラーが発生します。

Warning: require_once(../f2/f2.php) [function.require-once]: 
failed to open stream: No such file or directory in /var/www/reqtest/f1/f1.php on line 2
Fatal error: require_once() [function.require]: 
Failed opening required '../f2/f2.php' (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/reqtest/f1/f1.php on line 2

私が見逃している明らかなものはありますか?インクルードパスはPHPでどのように機能しますか?


この質問をする前に、私は実験して調べようとしました。次のように、別のテストを設定しました。

/
    index.php
    f1/
        f1.php
        f2.php

index.php:

<?php require_once("f1/f1.php"); ?>

f1.php:

<?php require_once("f2.php"); ?>

f2.php:空白

驚いたことに(そしてまったく混乱して)、これはうまくいきました!

では、パス解決の背後にある秘密は何ですか?

PS私が見た この質問 、しかしそれは私がここで述べた2番目のケースにまだ答えていません。

17
jrharshath

別のファイルをインクルードすると、作業ディレクトリはインクルードファイルがある場所に残ります。

あなたの例は意図したとおりに機能しています。

編集: 2番目の例は。 (実際のディレクトリ)はインクルードパスにあります(エラーメッセージを参照してください)。

Edit2: 2番目の例では、関心のある重要なポイントは次の行です。

<?php require_once("f2.php"); ?>

最初は、現在の作業ディレクトリ(/var/www/req_path_test)が、f2.phpが見つかりません。

フォールバックとして、include_pathでf2.phpを見つけようとします('.:/usr/share/php:/usr/share/pear')、 で始まります '。' (これは実際のファイルに関連しており、含むファイルではありません)。

したがって、「。/f2.php」は機能し、requireは失敗しません。

12
Karsten

Index.phpを開くと、作業ディレクトリはこのファイルが存在するフォルダーに設定されます。また、含まれているf1.php内では、この作業ディレクトリは変更されません。

次のように、現在含まれているファイルを基準にして、絶対パスを使用してファイルを含めることができます。

require_once(dirname(__FILE__).'/../../test/file.php')

ただし、これらのファイルにクラスが含まれている場合は、オートローダーの使用を検討することをお勧めします。

4

PHPドキュメント PHPインクルード から

ファイルは、指定されたファイルパスに基づいてインクルードされます。指定されていない場合は、include_pathが指定されます。ファイルがinclude_pathに見つからない場合、includeは、失敗する前に、呼び出し元のスクリプト自体のディレクトリと現在の作業ディレクトリを最終的にチェックインします。

ファイルパスが指定されていない場合、つまりrequire_once( "f2.php");

1日include_pathがチェックされます

2位。呼び出し元のスクリプト自身のディレクトリがチェックされます

3位。最後に、現在の作業ディレクトリがチェックされます

ファイルが見つからない場合PHPファイルインクルードに警告をスローし、requireに致命的なエラーをスローします

パスが定義されている場合(絶対(Windowsではドライブ文字または\で始まる、Unix/Linuxシステムでは/で始まる)、または現在のディレクトリからの相対パス(。または..で始まる))、include_pathは完全に無視されます。たとえば、ファイル名が../で始まる場合、パーサーは親ディレクトリを調べて、要求されたファイルを見つけます。

で始まるファイルを含める/必要とする場合。または..または./次に、PHPのパーサーは、現在の作業ディレクトリである親ディレクトリ、つまりrequire_once( "../ f2/f2.php")を検索し、phpは呼び出し元のスクリプトindex.phpとしてルートディレクトリをチェックします。そのディレクトリにあります。

これで、PHPスクリプトにインクルードパスが定義されていないため、常に呼び出し元のスクリプトにフォールバックしてから、現在の作業ディレクトリにフォールバックします。

// Check your default include path, most likely to be C:\xampp\php\PEAR
echo get_include_path();

// To set include path
set_include_path ( string $new_include_path ) : string

現在の作業ディレクトリは、メインの呼び出しスクリプトindex.phpから派生しています。

// The Current Working Directory can be checked
echo getcwd();

必要なファイル「../f2/f2.php」がf1.phpからのものである最初の例では

あなたのコードは次の理由で機能しません-

  1. ファイル名が../で始まるため、指定されたパスはPHPによって無視されます。
  2. f1 /呼び出し元のスクリプト自体のディレクトリも無視されます。
  3. パーサーディレクトリは、親ディレクトリを調べて、要求されたファイルを見つけます。現在の作業ディレクトリはルートディレクトリです。これは、作業スクリプトindex.phpを開始した場所です。ファイルがこのディレクトリにありません。間違ったパスが指定されています。

したがって、致命的なエラーが発生します

2番目の例では、ディレクトリを変更し、f1.phpからrequire_once( "f2.php")を変更しました。

あなたのコードは次の理由で機能します-

  1. 今回はrequire( "f2.php")先頭の../または./はありません今回PHP include_pathをチェックしますが、ファイルとファイルを定義していないため、そこにありますデフォルトのプリセットinclude_pathには存在しません。
  2. 今回は、呼び出しスクリプトf1.phpのディレクトリはf1 /です。ファイル( "f2.php")がこのディレクトリにある必要があります。 PHP今回は、このディレクトリ内のファイルをチェックして見つけます。
  3. PHPは、ファイルが見つかったときに作業ディレクトリをチェックする必要はありません。

したがって、コードは正常に機能します!

通常あなたの古い構造で

<?php require_once("f2/f2.php"); ?>

の代わりに

<?php require_once("../f2/f2.php"); ?>

動作するはずです。私の知る限り、phpは最初のスクリプトからパスを取ります

0
user207675

サーバーのPHP構成で open_basedir 設定が有効になっているようです。これにより、ディレクトリ構造内の上のフォルダにファイルを含める(および開く)ことができなくなります。 (つまり、.. /を使用してフォルダー構造を上に移動することはできません)。

0
Emil Vikström