採点されません。匿名です。 間違えることは学習の一部です。読むだけでもかまいません。

パス操作とディレクトリ走査

テクノロジ系 / 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 (先頭にドット) になる

pathinfoextension. 抜き で返す。自分で . を付けないこと

  • filenameaccess (途中まで) になる

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" を付けるのを忘れている