パス操作とディレクトリ走査
テクノロジ系 / file-io (read / write / CSV / paths / upload概念)
パス操作とディレクトリ走査
Lesson 14 / Chapter 5
__DIR__ と __FILE__
// /Users/you/proj/app/index.php というファイル内で... echo __FILE__; // /Users/you/proj/app/index.php (このファイル自身) echo __DIR__; // /Users/you/proj/app (このファイルが入っているディレクトリ)
__FILE__: 実行中の PHP ファイルの 絶対パス__DIR__: それをdirnameした結果 (= 親ディレクトリ)
→ どこから呼ばれても 「自分自身からの相対パス」 を組める。file-io トピックで何度も登場。
パスを分解する 3 つ + α
$path = '/var/www/app/config/db.yaml'; dirname($path); // /var/www/app/config (ディレクトリ部分) basename($path); // db.yaml (ファイル名 + 拡張子) basename($path, '.yaml'); // db (拡張子を剥がす) pathinfo($path); // [ // 'dirname' => '/var/www/app/config', // 'basename' => 'db.yaml', // 'extension' => 'yaml', // 'filename' => 'db', // ]
dirname= 「親ディレクトリ」だけbasename= 「最後の/以降」 (= ファイル名)pathinfo= 全部入りの 連想配列 (拡張子・拡張子無しの名前まで)
pathinfo を実戦で使う
<?php
$info = pathinfo('/var/www/logs/access.2026-05-19.log');
echo $info['dirname']; // /var/www/logs
echo $info['basename']; // access.2026-05-19.log
echo $info['filename']; // access.2026-05-19
echo $info['extension']; // log| キー | 中身 |
|---|---|
dirname | ディレクトリ部分 |
basename | ファイル名 (拡張子付き) |
filename | ファイル名 (拡張子なし) |
extension | 拡張子 (. なし) |
→ アップロードファイルの拡張子検証 (ch06) でも pathinfo($name, PATHINFO_EXTENSION) がよく出る。
realpath で絶対パスに正規化
echo realpath('./tests/../tests/data/hello.txt');
// /Users/you/proj/.../tests/data/hello.txt
// ↑ ".." や "./" を解決し、シンボリックリンクも展開して 絶対パスを返す
echo realpath('does_not_exist.txt'); // false- 相対パス /
.//..// シンボリックリンクを 全部解決 - 実在しないパスには
falseを返す (= 存在チェック代わり にも使える) - セキュリティ上重要: ユーザー入力のパスは
realpathで正規化してから 許可ディレクトリ配下か検証する
scandir でディレクトリ一覧
<?php $dir = __DIR__ . '/tests/data/sample'; $files = scandir($dir); print_r($files); // [ // '.', ← カレントディレクトリを示す特殊エントリ // '..', ← 親ディレクトリを示す特殊エントリ // 'a.txt', // 'b.txt', // 'c.txt', // ]
scandirは./..を含む ことに必ず注意- 普通は除いて使う:
array_diff($files, ['.', '..']) - 並び順は デフォルトで昇順 (
SCANDIR_SORT_ASCENDING)。明示的にソートしたければsort()を後段で
scandir + 除外 + ソートのテンプレ
<?php
$dir = __DIR__ . '/tests/data/sample';
$files = array_values(array_diff(scandir($dir), ['.', '..']));
sort($files); // 明示的にアルファベット順
foreach ($files as $f) {
echo $f . "\n";
}array_diffで...を除く (array_valuesでキーを 0 から振り直す)sortで明示ソート (環境差・PHP バージョン差を消す)- 必要なら
is_file/is_dirでファイルとサブディレクトリを切り分け
→ ログ集計バッチ・テンプレートエンジンの 一覧取得などで頻出パターン。
このチャプターでできるようになること
✅ __DIR__ / __FILE__ の違いを言える
✅ dirname / basename / pathinfo で パスを分解できる
✅ pathinfo の 4 つのキー (dirname / basename / filename / extension) を言える
✅ realpath の役割 (絶対パス化 + 存在チェック) を言える
✅ scandir の戻り値から . / .. を除いて ソートする定型が書ける
→ ドリルへ
考えてみよう
既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。
ドリル 01 — pathinfo でパスを分解する
問題
以下のパス文字列を pathinfo で分解し、4 つの要素 (dirname / basename / filename / extension) を コロン + 半角スペース 区切りで 1 行ずつ出力してください。
$path = '/var/www/logs/access.2026-05-19.log';
期待される出力:
dirname: /var/www/logs basename: access.2026-05-19.log filename: access.2026-05-19 extension: log
採点
php scripts/grade.php topics/file-io/ch05-paths/drill/01-path-info/
ヒント
$info = pathinfo($path);
echo "dirname: {$info['dirname']}\n";
echo "basename: {$info['basename']}\n";
echo "filename: {$info['filename']}\n";
echo "extension: {$info['extension']}\n";| キー | 中身 |
|---|---|
dirname | ディレクトリ部分 (/var/www/logs) |
basename | ファイル名 (拡張子付き) (access.2026-05-19.log) |
filename | ファイル名 (拡張子なし) (access.2026-05-19) |
extension | 拡張子 (log — 先頭の . は付かない) |
つまづいたら
extensionが.log(先頭にドット) になる
→ pathinfo の extension は . 抜き で返す。自分で . を付けないこと
filenameがaccess(途中まで) になる
→ pathinfo は 「最後の . より前」 を filename とする。仕様通りなのでこれが正解
ドリル 02 — scandir でディレクトリ一覧
問題
__DIR__ . '/tests/data/sample' 配下のファイル名を、. と .. を除いた 上で 昇順 にソートして 1 行ずつ出力してください。
tests/data/sample/ の中身 (このリポジトリにコミット済み):
apple.txt banana.txt cherry.txt
期待される出力:
apple.txt banana.txt cherry.txt
採点
php scripts/grade.php topics/file-io/ch05-paths/drill/02-list-dir/
ヒント
$dir = __DIR__ . '/tests/data/sample';
$files = array_values(array_diff(scandir($dir), ['.', '..']));
sort($files);
foreach ($files as $f) {
echo $f . "\n";
}scandir($dir)はディレクトリ内のエントリ名を配列で返す- 戻り値には 必ず
.(カレント)・..(親) が含まれる のでarray_diffで除く array_valuesで キーを 0 から振り直す (array_diffは元のキーを保つため、後段のsort不要な順序ズレを防ぐ)sort($files)で 明示的に昇順 (PHP / OS 環境差を消す)
つまづいたら
- 出力の先頭に
...が混ざる
→ array_diff(scandir($dir), ['.', '..']) でカレント・親エントリを除く
- 順序がバラバラ
→ sort($files) を明示的に呼ぶ。scandir のデフォルトは昇順だが、OS / ファイルシステム差で揺れることもある
- 出力が 1 行に詰まる
→ echo の末尾に "\n" を付けるのを忘れている