PHPで別ファイルを読み込むときは、読み込み元ファイルの場所を基準にした絶対パスを組み立てると、実行環境によるずれを減らせます。
もっともよく使う形は次のコードです。
<?php
require __DIR__ . '/config.php';
__DIR__は「このコードが書かれているPHPファイルのディレクトリ」を表します。末尾に区切り文字は付かないため、'/config.php'の先頭にスラッシュが必要です。
この記事では、相対パスがずれる理由、__DIR__と__FILE__の違い、上の階層の指定、存在確認、安全上の注意まで解説します。
PHPの相対パスと絶対パスの違い
パスはファイルやディレクトリの場所を表す文字列です。大きく相対パスと絶対パスに分かれます。
| 種類 | 例 | 特徴 |
|---|---|---|
| 相対パス | config.php、./config.php、../config.php |
基準となるディレクトリからの位置 |
| 絶対パス | /var/www/app/config.php |
ファイルシステムの起点から場所を指定 |
Unix系OSの絶対パスは/から始まります。WindowsではC:\app\config.phpのようなドライブレター付きパスやUNCパスがあります。
URLのhttps://example.com/config.phpと、サーバー内部のファイルパスは別物です。HTMLのリンクや画像URLを作りたい場合に__DIR__をそのまま出力してはいけません。
相対パスの基準は何か
通常のローカルファイル操作で相対パスを使うと、PHPは現在の作業ディレクトリを基準に解決します。現在位置はgetcwd()で確認できます。
<?php
echo getcwd();
$contents = file_get_contents('./data/sample.txt');
CLIでPHPを実行した場合、初期の作業ディレクトリは通常、コマンドを実行したディレクトリです。
cd /var/www/app
php scripts/task.php
この場合、task.phpがscripts内にあっても、相対パスの基準が/var/www/appになる処理があります。Webサーバー、CLI、テストランナー、cronで基準が変わると「ローカルでは動くのに本番では見つからない」原因になります。
requireとincludeには探索規則がある
require 'config.php'のように明示的な相対指定を付けない場合、PHPはinclude_pathを調べ、その後に呼び出し側スクリプトのディレクトリや現在の作業ディレクトリを確認します。
一方、./config.phpや../config.phpのようにパスを明示すると、include_pathは使われません。
探索順に依存すると構成変更で別ファイルを読む可能性があるため、自分のプロジェクト内ファイルは__DIR__から組み立てると意図が明確です。
__DIR__の意味と使い方
__DIR__はPHPのマジック定数で、その記述があるファイルのディレクトリを絶対パスで返します。
<?php
echo __DIR__;
// 例: /var/www/app/src
require __DIR__ . '/config.php';
// /var/www/app/src/config.php を読み込む
__DIR__の末尾には、ルートディレクトリを除いて区切り文字が付きません。そのためファイル名との間に/を入れます。
includeされたファイル内ではどの値になるか
__DIR__は最初に実行したPHPファイルの場所ではなく、定数を書いたファイル自身の場所です。
app/
├── public/
│ └── index.php
└── src/
├── bootstrap.php
└── config.php
public/index.phpからsrc/bootstrap.phpを読み込んでも、bootstrap内の__DIR__はapp/srcを返します。
<?php
// src/bootstrap.php
require __DIR__ . '/config.php';
この性質により、bootstrap.phpがどこから呼ばれても、隣のconfig.phpを安定して指定できます。
__FILE__の意味と__DIR__との違い
__FILE__は、その記述があるPHPファイル自身のフルパスとファイル名を返します。
<?php
echo __FILE__;
// 例: /var/www/app/src/bootstrap.php
echo __DIR__;
// 例: /var/www/app/src
用途を整理すると次のようになります。
- 同じディレクトリの別ファイルを指定する:
__DIR__ - 現在のPHPファイル自身のパスをログへ出す:
__FILE__ - 古いコードでディレクトリを得る:
dirname(__FILE__)
PHP公式マニュアルでは、__DIR__はdirname(__FILE__)と同等です。新しく書くなら短い__DIR__を使えます。
同じ階層・子階層・親階層の書き方
同じディレクトリのファイル
require __DIR__ . '/config.php';
子ディレクトリのファイル
require __DIR__ . '/config/database.php';
一つ上のディレクトリのファイル
require __DIR__ . '/../config.php';
この文字列には..が残りますが、ファイルシステムは親ディレクトリとして解釈できます。
dirnameで上の階層を明示する
require dirname(__DIR__) . '/config.php';
// 2階層上のディレクトリ
$projectRoot = dirname(__DIR__, 2);
dirname($path, 2)の第2引数は、何階層分の親ディレクトリを返すかです。返り値はファイルではなくディレクトリのパスです。
パス連結でよくある間違い
区切り文字を入れ忘れる
次のコードは正しくありません。
require __DIR__ . 'config.php';
require __DIR__ . './config.php';
require __DIR__ . '../config.php';
__DIR__が/var/www/appなら、1行目は/var/www/appconfig.php、2行目は/var/www/app./config.phpになります。__DIR__の直後に/を入れてください。
URLの先頭スラッシュと混同する
Webページの/assets/app.cssはドメインルートからのURLです。一方、PHPでrequire '/config.php'と書くと、Unix系サーバーのファイルシステムのルート直下を意味します。
public_htmlやプロジェクトルートを意味するわけではありません。
スラッシュとDIRECTORY_SEPARATOR
PHPの定義済み定数DIRECTORY_SEPARATORは、実行OSのディレクトリ区切りを返します。
$path = __DIR__ . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'sample.json';
Unix系では/、Windowsでは\です。ただしPHPはWindowsでも多くの場面で/をパス区切りとして扱えるため、アプリ内の固定パスは__DIR__ . '/data/sample.json'と書く方法も一般的です。
Windows形式のバックスラッシュをダブルクォート文字列へ直接書く場合は、\nや\tなどのエスケープシーケンスと衝突します。区切り文字の問題とPHP文字列のエスケープを分けて考えてください。
realpathで正規化する
realpath()は.、..、重複した区切り、シンボリックリンクを解決し、正規化された絶対パスを返します。
$path = realpath(__DIR__ . '/../config.php');
if ($path === false) {
throw new RuntimeException('config.phpが見つかりません');
}
require $path;
対象が存在しない場合、realpath()はfalseを返します。これから作成するファイルのパスを文字列として組み立てる用途には、そのまま使えません。
ファイルが見つからないときの確認方法
パス問題は、推測せずに各値を出力すると原因を切り分けられます。
$path = __DIR__ . '/config.php';
var_dump([
'__DIR__' => __DIR__,
'__FILE__' => __FILE__,
'getcwd' => getcwd(),
'path' => $path,
'exists' => file_exists($path),
'readable' => is_readable($path),
'realpath' => realpath($path),
]);
確認順は次のとおりです。
- 連結後のパス文字列が想定どおりか
file_exists()がtrueかis_readable()がtrueか- ファイル名の大文字・小文字が一致しているか
- WebサーバーやPHP実行ユーザーに読み取り権限があるか
- open_basedirなどの実行環境制限がないか
Linuxなどではファイル名の大文字・小文字を区別します。macOSの開発環境で動いたConfig.phpとconfig.phpの不一致が、本番Linuxで失敗することがあります。
require・includeの使い分け
設定、関数、クラスなど実行に必須のファイルはrequire、読み込み失敗後も処理を続けられる任意ファイルはincludeが基本です。同じファイルの重複読み込みを避ける場合はrequire_onceまたはinclude_onceを使います。
詳しいエラーの違い、スコープ、function_exists()との関係は、PHPのrequire・include・require_onceの使い方で解説しています。
ユーザー入力をパスへ直接連結しない
URLパラメーターやフォーム値をそのままパスへ連結すると、../を使って意図しないファイルへ到達するパストラバーサルの原因になります。
次のようなコードは避けてください。
// 危険な例
$page = $_GET['page'] ?? 'home';
require __DIR__ . '/pages/' . $page . '.php';
許可する値を配列で固定し、値からファイル名へ対応付けます。
$pages = [
'home' => 'home.php',
'about' => 'about.php',
];
$page = $_GET['page'] ?? 'home';
if (!isset($pages[$page])) {
http_response_code(404);
exit;
}
require __DIR__ . '/pages/' . $pages[$page];
拡張子を付ける、basename()を通すだけでは、許可すべきファイルの制御として不十分な場合があります。読み込める候補が決まっているなら、許可リスト方式が明確です。
よくある質問
__DIR__とgetcwd()は何が違いますか?
__DIR__はそのコードが書かれたファイルのディレクトリで、基本的に実行中は変わりません。getcwd()はプロセスの現在の作業ディレクトリで、実行方法やchdir()により変わります。
__DIR__の末尾にスラッシュはありますか?
ルートディレクトリを除き、末尾のスラッシュはありません。通常は__DIR__ . '/file.php'のように連結します。
dirname(__FILE__)と__DIR__はどちらを使いますか?
同じディレクトリを得る目的なら同等です。現在のPHPでは短く読みやすい__DIR__を使えます。親階層へ移動するならdirname(__DIR__)やdirname(__DIR__, 2)が便利です。
DOCUMENT_ROOTを使えばよいですか?
$_SERVER['DOCUMENT_ROOT']はWebサーバーの公開ルートであり、CLIでは存在しないことがあります。また、アプリの設定やクラスを公開領域の外へ置く構成には合いません。ファイル自身を基準にするなら__DIR__が安定します。
書籍でPHPの基礎を体系的に学びたい人へ
この記事でパスとマジック定数を確認したあと、PHP全体を一冊の順番で復習したい場合の購入候補です。PHPの対応バージョンや関数の細かな挙動は変わることがあるため、実装時は利用環境のバージョンとPHP公式マニュアルも確認してください。
以下のリンクはアフィリエイト広告(もしもアフィリエイト経由)です。価格・在庫・送料条件は変わるため、必ずリンク先で最新情報を確認してください。
まとめ
PHPのパス指定で重要なのは、「相対パスの基準は実行方法によってずれ得る」「__DIR__はその記述があるファイルの場所」という2点です。
プロジェクト内の必須ファイルはrequire __DIR__ . '/config.php';のように指定し、上の階層はdirname(__DIR__)で表現します。見つからない場合はgetcwd()、連結後のパス、file_exists()、is_readable()を順番に確認してください。