【PHP8.x】scandir()関数の使い方
scandir関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
scandir関数は、指定されたディレクトリ内のファイルとディレクトリの一覧を取得し、配列として返す関数です。この関数は、ファイルシステムを操作する上で非常に重要な役割を果たします。具体的には、ディレクトリパスを引数として受け取り、そのディレクトリに含まれるすべてのファイルとサブディレクトリの名前を文字列の配列として返します。
scandir関数には、ソート順を指定するためのオプションの引数も用意されています。デフォルトでは、結果はアルファベット順にソートされますが、SCANDIR_SORT_DESCENDING フラグを使用することで降順にソートしたり、SCANDIR_SORT_NONE フラグを使用することでソートを行わないようにすることも可能です。ソートを行わない場合、ファイルシステムが返す順序で結果が返されます。
また、scandir関数は、カレントディレクトリを示す「.」と親ディレクトリを示す「..」をデフォルトで結果に含みます。これらを含めたくない場合は、返された配列から手動で削除する必要があります。
エラーが発生した場合、scandir関数はfalseを返します。例えば、指定されたディレクトリが存在しない場合や、アクセス権がない場合などが考えられます。そのため、戻り値をチェックして適切にエラー処理を行うことが重要です。
scandir関数は、ファイルマネージャーのようなアプリケーションや、ディレクトリ内のファイルを処理するスクリプトなど、様々な場面で利用されます。ファイルシステムを操作する上で基本となる関数の一つと言えるでしょう。
構文(syntax)
1scandir(string $directory, int $sorting_order = SCANDIR_SORT_ASCENDING, ?resource $context = null): array|false
引数(parameters)
string $directory, int $sorting_order = SCANDIR_SORT_ASCENDING, $context = null
- string $directory: ファイルやディレクトリをスキャンする対象のディレクトリパス
- int $sorting_order = SCANDIR_SORT_ASCENDING: ファイルやディレクトリの並び順を指定する定数(デフォルトは昇順)
- $context = null: ストリームコンテキストを指定する(通常はnull)
戻り値(return)
array|false
指定されたディレクトリ内のファイルおよびディレクトリ名を配列として返します。ディレクトリの読み取りに失敗した場合は false を返します。
サンプルコード
PHP scandirでファイルのみを取得する
1<?php 2 3/** 4 * 指定されたディレクトリからファイルのみを一覧で取得します。 5 * 6 * `scandir` はディレクトリも含むため `is_file` を使ってフィルタリングします。 7 * '.' や '..' といった特殊なディレクトリは `is_file` の判定で偽になるため、 8 * 結果的に除外されます。 9 * 10 * @param string $directory 調査するディレクトリのパス 11 * @return array|false ファイル名の配列。ディレクトリが存在しない等のエラー時は false 12 */ 13function getFilesOnly(string $directory): array|false 14{ 15 // scandirでディレクトリ内の要素(ファイルとサブディレクトリ)をすべて取得します。 16 // ディレクトリが存在しない、または読み取れない場合は false が返ります。 17 $items = scandir($directory); 18 19 // scandirが失敗した場合は、何もせず false を返します。 20 if ($items === false) { 21 return false; 22 } 23 24 // array_filterを使い、配列からファイルだけを抽出します。 25 // アロー関数 (fn) を使って簡潔に記述しています (PHP 7.4+)。 26 // is_fileには完全なパスが必要なため、ディレクトリ名とファイル名を連結します。 27 $files = array_filter( 28 $items, 29 fn($item) => is_file($directory . DIRECTORY_SEPARATOR . $item) 30 ); 31 32 // array_filterは元の配列のキーを維持するため、キーを0から振り直して返します。 33 return array_values($files); 34} 35 36 37// --- 以下、この関数を実際に使うための、単体で動作するサンプルコードです --- 38 39// 1. テスト用のディレクトリとファイル環境を準備します。 40$testDir = 'scandir_test_dir'; 41if (!is_dir($testDir)) { 42 mkdir($testDir); 43} 44file_put_contents($testDir . '/file1.txt', 'test data 1'); 45file_put_contents($testDir . '/file2.log', 'test data 2'); 46if (!is_dir($testDir . '/sub_dir')) { 47 mkdir($testDir . '/sub_dir'); // 比較用のサブディレクトリ 48} 49 50echo "--- ディレクトリ '{$testDir}' の中身 (scandirの素の結果) ---\n"; 51print_r(scandir($testDir)); 52echo "\n"; 53 54 55// 2. 作成した関数を実行して、ファイルのみを取得します。 56$fileList = getFilesOnly($testDir); 57 58 59// 3. 結果を表示します。 60echo "--- ファイルのみを抽出した結果 ---\n"; 61if ($fileList !== false) { 62 print_r($fileList); 63} else { 64 echo "ディレクトリの読み込みに失敗しました。\n"; 65} 66 67 68// 4. テストで作成したファイルとディレクトリを後片付けします。 69unlink($testDir . '/file1.txt'); 70unlink($testDir . '/file2.log'); 71rmdir($testDir . '/sub_dir'); 72rmdir($testDir); 73
PHPのscandir関数は、引数に指定したディレクトリパス内のファイルやサブディレクトリの名前を配列として取得する関数です。処理に成功するとファイル名などの配列を、ディレクトリが存在しないなどのエラー時にはfalseを返します。この関数が返す配列には、ファイルだけでなく、.(カレントディレクトリ)、..(親ディレクトリ)、そしてサブディレクトリもすべて含まれるという特徴があります。
このサンプルコードは、scandirの結果からファイルのみを抽出する実践的な方法を示しています。まずscandirでディレクトリ内のすべての要素を取得した後、array_filter関数を使って配列から条件に合う要素だけを絞り込みます。その条件判定にis_file関数を利用します。is_fileは指定されたパスが通常のファイルである場合にtrueを返すため、ディレクトリや.、..は自動的に除外されます。is_fileには完全なパスが必要なため、scandirで得られた要素名に元のディレクトリパスを連結して渡している点が重要です。最後に、array_filterによって歯抜けになる可能性がある配列のキー(インデックス)をarray_valuesで0から始まる連番に整え、扱いやすい形式でファイル名の配列を返します。
scandir関数は、ファイルだけでなくサブディレクトリや.(カレントディレクトリ)、..(親ディレクトリ)も含むすべての一覧を返します。このため、ファイルのみを抽出するには追加の処理が必要です。注意点として、is_file関数はファイル名を単体で渡しても正しく動作しません。サンプルコードのように、調査対象のディレクトリパスと連結し、完全なファイルパスを渡す必要があります。このとき、OS環境の違いを吸収するために、パスの区切り文字としてDIRECTORY_SEPARATOR定数を利用するのが安全です。また、scandirはディレクトリが存在しない等のエラー時にfalseを返すため、必ずその戻り値を確認する処理を記述しましょう。
PHP scandirで最終更新日時順にファイルを取得する
1<?php 2 3/** 4 * 指定されたディレクトリ内のファイルを最終更新日時でソートして取得します。 5 * 6 * scandir関数はファイル名を基準にソートしますが、この関数はファイルの最終更新日時を基準にソートします。 7 * 8 * @param string $directory 対象ディレクトリのパス。 9 * @param bool $ascending true の場合、古いファイルから新しいファイルの順(昇順)。false の場合、新しいファイルから古いファイルの順(降順)。 10 * @return array|false ソートされたファイル名の配列、またはエラーが発生した場合は false。 11 */ 12function getFilesSortedByDate(string $directory, bool $ascending = true): array|false 13{ 14 // ディレクトリの存在チェックと読み取り権限の確認 15 if (!is_dir($directory) || !is_readable($directory)) { 16 return false; 17 } 18 19 // scandir関数でディレクトリ内の全項目(ファイルとサブディレクトリ)を取得 20 $items = scandir($directory); 21 22 if ($items === false) { 23 return false; // scandirの実行に失敗した場合 24 } 25 26 $fileInfo = []; 27 foreach ($items as $item) { 28 // 特殊なディレクトリ項目 '.' (カレントディレクトリ) と '..' (親ディレクトリ) は除外 29 if ($item === '.' || $item === '..') { 30 continue; 31 } 32 33 $fullPath = $directory . DIRECTORY_SEPARATOR . $item; 34 35 // ファイルまたはディレクトリの最終更新日時(Unixタイムスタンプ)を取得 36 // @ suppresses errors for non-existent/unreadable files 37 $mtime = @filemtime($fullPath); 38 39 if ($mtime !== false) { 40 $fileInfo[] = [ 41 'name' => $item, // ファイル名またはディレクトリ名 42 'mtime' => $mtime, // 最終更新日時 43 ]; 44 } 45 } 46 47 // 最終更新日時 (mtime) を基準にソート 48 usort($fileInfo, function (array $a, array $b) use ($ascending): int { 49 if ($a['mtime'] === $b['mtime']) { 50 return 0; // 更新日時が同じ場合は順序を維持 51 } 52 // 昇順(古いものから新しいものへ)または降順(新しいものから古いものへ)で比較 53 return $ascending ? ($a['mtime'] <=> $b['mtime']) : ($b['mtime'] <=> $a['mtime']); 54 }); 55 56 // ソートされたファイル名のリストを返す 57 return array_column($fileInfo, 'name'); 58} 59 60// 関数の使用例: 61// このスクリプトがあるディレクトリを対象とします。 62$currentDirectory = __DIR__; 63 64// 最終更新日時が古いファイルから順(昇順)に取得 65$filesAscending = getFilesSortedByDate($currentDirectory, true); 66 67// 最終更新日時が新しいファイルから順(降順)に取得 68$filesDescending = getFilesSortedByDate($currentDirectory, false); 69 70// 取得した結果は $filesAscending または $filesDescending 変数に配列として格納されます。 71// 例えば、結果を表示するには以下のようにします(このコードは出力を行いません): 72// if ($filesAscending !== false) { 73// foreach ($filesAscending as $file) { 74// echo $file . "\n"; 75// } 76// } else { 77// echo "ディレクトリの読み込みに失敗しました。\n"; 78// }
PHPのscandir関数は、指定されたディレクトリ内のファイルやサブディレクトリの名前を配列として取得する機能を提供します。通常、この関数はファイル名を基準に昇順または降順でソートしますが、提供されたサンプルコードは、このscandirの機能を利用しつつ、ファイル名ではなく「最終更新日時」でファイルをソートして取得するためのものです。
getFilesSortedByDate関数は、まずscandirでディレクトリ内の全項目を取得し、その後、filemtime関数を使って各項目の最終更新日時を確認します。取得したファイル名と更新日時をペアにして一時的に保持し、usort関数を用いて最終更新日時を基準に並べ替えを行います。
引数$directoryには対象となるディレクトリのパスを指定し、$ascendingにはtrue(昇順、古いファイルから新しいファイルへ)またはfalse(降順、新しいファイルから古いファイルへ)を指定します。戻り値としては、最終更新日時でソートされたファイル名の配列が返され、ディレクトリの読み込み失敗などのエラーが発生した場合はfalseが返されます。これにより、初心者の方でも簡単にディレクトリ内のファイルを最終更新日時順に処理できるようになります。
このコードは、scandir関数がファイル名を基準にソートするのに対し、filemtimeで各ファイルの最終更新日時を取得し、usortを用いて独自の基準でソートしています。.や..といった特殊なディレクトリ項目は必ず除外する処理が必要です。また、対象ディレクトリが存在しない場合や読み取り権限がない場合には、scandirやis_dir、is_readableがfalseを返すため、適切なエラーハンドリングが重要です。@filemtimeのように@演算子でエラーを抑制していますが、本番環境ではエラー内容を把握するため、より詳細なエラーハンドリングを検討してください。ファイル数が多い場合、filemtimeの呼び出しが多数発生し、パフォーマンスに影響する可能性がある点にも注意が必要です。
PHP scandir 権限エラー処理
1<?php 2 3/** 4 * 指定されたディレクトリの内容を読み込みます。 5 * scandir() 関数が失敗した場合 (例: ディレクトリが存在しない、またはアクセス権限がない場合) の 6 * エラーハンドリングに焦点を当てています。 7 * 8 * @param string $directoryPath 走査するディレクトリのパス。 9 * @return void 10 */ 11function demonstrateScandirErrorHandling(string $directoryPath): void 12{ 13 echo "--- ディレクトリ '$directoryPath' の内容を試行 ---\n"; 14 15 // scandir() を実行し、結果をチェックします。 16 // PHPプロセスにディレクトリへの読み取り権限がない場合、 17 // scandir() は false を返し、"Permission denied" などの警告が発生します。 18 $contents = scandir($directoryPath); 19 20 if ($contents === false) { 21 // scandir() が失敗した場合のエラーハンドリング 22 echo "エラー: ディレクトリ '$directoryPath' の内容を読み込めませんでした。\n"; 23 echo "考えられる原因:\n"; 24 echo " - 指定されたディレクトリが存在しない。\n"; 25 echo " - PHPを実行しているユーザーに、そのディレクトリへの読み取り権限がない (Permission denied)。\n"; 26 echo " (例: システムの保護されたディレクトリを読み取ろうとした場合など)\n"; 27 } else { 28 // 成功した場合 29 echo "ディレクトリの内容を正常に読み込めました:\n"; 30 foreach ($contents as $item) { 31 echo " - " . $item . "\n"; 32 } 33 } 34 echo "--------------------------------------------------\n\n"; 35} 36 37// --- サンプル使用例 --- 38 39// 1. 存在するアクセス可能なディレクトリ (例: 現在のスクリプトがあるディレクトリ) 40demonstrateScandirErrorHandling('.'); 41 42// 2. 存在しないディレクトリ (scandir() は false を返し、エラーハンドリングされます) 43demonstrateScandirErrorHandling('./non_existent_folder_abc'); 44 45// 3. アクセス権限がない場合を想定した説明 46// 以下の行を有効にする場合、システムによって権限設定が必要です。 47// 例えば、Linux環境でPHPが一般ユーザーで実行されている場合、 48// `/root` ディレクトリは通常読み取り権限がないため、以下の行を実行すると 49// "Permission denied" エラーが発生し、このコードのエラーハンドリングが動作します。 50// demonstrateScandirErrorHandling('/root');
scandir関数は、PHPで指定されたディレクトリ内のファイルやサブディレクトリの一覧を取得するために使用される標準関数です。この関数には、取得したいディレクトリのパスを文字列として引数に渡します。処理が成功すると、ディレクトリ内の項目名(ファイル名やサブディレクトリ名)が格納された配列を返します。この配列には、現在のディレクトリを示す「.」と親ディレクトリを示す「..」も含まれます。
一方で、指定されたディレクトリが存在しない場合や、PHPを実行しているユーザーがそのディレクトリへの読み取り権限を持っていない場合(例えば「Permission denied」エラーが発生する状況など)には、scandir関数は処理に失敗し、戻り値としてfalseを返します。
サンプルコードでは、このscandir関数の戻り値を常にチェックし、エラーが発生した場合(falseが返された場合)に備えたエラーハンドリングの重要性を具体的に示しています。falseが返された際には、「ディレクトリが存在しない」または「読み取り権限がない」といった考えられる原因を明示するメッセージを表示することで、問題の特定と解決に役立つ情報を提供しています。このように、関数の戻り値を適切に処理することで、プログラムの堅牢性とユーザーへの説明力を高めることができます。
scandir関数を使用する際は、戻り値が成功時に配列、失敗時にfalseとなるため、必ず=== falseで厳密にエラーをチェックしてください。エラーが発生する主な原因は、指定されたディレクトリが存在しないこと、またはPHPを実行しているユーザーがそのディレクトリへの読み取り権限を持っていないことです。特に「Permission denied」という警告が表示される場合、PHPプロセスの実行ユーザー(Webサーバーのユーザーなど)に、アクセス対象のディレクトリに対する読み取り権限が付与されているかを確認し、必要に応じて権限設定を見直す必要があります。本サンプルコードのようにエラーハンドリングを適切に行うことで、プログラムの信頼性が向上します。
PHP scandir で「.」と「..」を除外する
1<?php 2 3/** 4 * 指定されたディレクトリから '.' と '..' を除いたファイルとディレクトリの一覧を取得します。 5 * 6 * @param string $directoryPath 調査するディレクトリのパス 7 * @return array ファイルとディレクトリ名の配列。ディレクトリが読み込めない場合は空の配列。 8 */ 9function getDirectoryListingWithoutDots(string $directoryPath): array 10{ 11 // is_dir() でディレクトリが存在するかを確認します。 12 if (!is_dir($directoryPath)) { 13 // ディレクトリが存在しない場合は空の配列を返します。 14 return []; 15 } 16 17 // scandir() でディレクトリの内容を取得します。 18 // この時点では結果に '.' (カレントディレクトリ) と '..' (親ディレクトリ) が含まれます。 19 $items = scandir($directoryPath); 20 21 // scandir() は失敗時に false を返すため、その場合も空の配列を返します。 22 if ($items === false) { 23 return []; 24 } 25 26 // array_diff() を使って、取得した配列から '.' と '..' の値を取り除きます。 27 $filteredItems = array_diff($items, ['.', '..']); 28 29 // array_values() で配列のキーを 0 から始まる連番にリセットして返します。 30 // これにより、後のループ処理などが扱いやすくなります。 31 return array_values($filteredItems); 32} 33 34 35// --- 以下、この関数を実際に使用するサンプルコードです --- 36 37// テスト用のディレクトリパスを定義します。 38$testDir = __DIR__ . '/sample_dir'; 39 40// 実行前の準備として、テスト用のディレクトリとファイルを一時的に作成します。 41if (!is_dir($testDir)) { 42 mkdir($testDir); 43} 44touch($testDir . '/file1.txt'); 45touch($testDir . '/file2.log'); 46if (!is_dir($testDir . '/sub_dir')) { 47 mkdir($testDir . '/sub_dir'); 48} 49 50try { 51 // 上で定義した関数を呼び出して、ディレクトリの内容を取得します。 52 $fileList = getDirectoryListingWithoutDots($testDir); 53 54 echo "ディレクトリ '{$testDir}' の内容('.' と '..' を除く):\n"; 55 56 if (empty($fileList)) { 57 echo "アイテムは見つかりませんでした。\n"; 58 } else { 59 // 取得したファイルとディレクトリの一覧を出力します。 60 foreach ($fileList as $file) { 61 echo "- {$file}\n"; 62 } 63 } 64} finally { 65 // スクリプト終了時に、作成したテスト用のファイルとディレクトリをクリーンアップします。 66 // これにより、実行環境が汚れるのを防ぎます。 67 unlink($testDir . '/file1.txt'); 68 unlink($testDir . '/file2.log'); 69 rmdir($testDir . '/sub_dir'); 70 rmdir($testDir); 71}
このPHPコードは、指定したディレクトリ内にあるファイルとサブディレクトリの一覧を取得する方法を示しています。特に、scandir関数を使って取得した一覧から、カレントディレクトリを指す . と親ディレクトリを指す .. という特殊なエントリを除外する点が重要です。
scandir関数は、引数にディレクトリのパス文字列を受け取り、その中にある要素の名前を配列として返します。しかし、この関数が返す配列には、デフォルトで . と .. が含まれてしまいます。
そこで、このサンプルコードではarray_diff関数を活用しています。array_diffは、1つ目の引数で渡された配列から、2つ目以降の引数で渡された配列に含まれる値を取り除いた、新しい配列を生成します。この性質を利用して、scandirで取得した配列から . と .. だけを正確に除去しています。
さらに、array_diffの実行後、配列のキー(インデックス)は元のまま維持されるため、歯抜けの状態になることがあります。これを整理するため、array_values関数を使ってキーを0から始まる連番に振り直しています。これにより、後のループ処理などで配列を直感的に扱いやすくなります。
また、関数のはじめにis_dirでディレクトリの存在を確認したり、scandirが失敗した場合(falseを返した場合)を考慮したりすることで、予期せぬエラーを防ぐ堅牢な作りになっています。
scandir関数は、指定ディレクトリ内のファイル名一覧を取得しますが、必ずカレントディレクトリを示す.と親ディレクトリを示す..も結果に含みます。これらが不要な場合は、サンプルコードのようにarray_diff関数で明示的に取り除くのが一般的な方法です。また、この関数はディレクトリが存在しない場合や読み取り権限がない場合にfalseを返すため、戻り値を=== falseで厳密に比較し、エラー処理を行うことが重要です。is_dirで事前にディレクトリの存在を確認しておくと、より安全なコードになります。array_diffで要素を削除すると配列のキーが歯抜けになるため、array_valuesでキーを0から振り直すことで、後のループ処理が扱いやすくなります。