[PHP] scandirを効率的に使う方法

2020年1月19日

PHP テクノロジー プログラミング

とても人当たりが良いと評判ですが、気を許すと周囲のことを見下しがちな、ユゲタです。 よくないですね〜。 そんな僕は、どんなに疲れていても、常に見上げる姿勢になれるジャイアント馬場(故)さんの信念を尊敬しています。 人のことを信用することを信条にしていて、「裏切るより裏切られるほうがいいじゃないか」という名言が個人的にすごくお気に入りです。 そういや、最近作り直しているPHPフレームワークで、ファイル検索をする際に使うscandir機能で、毎回拡張子判定を行ったり、システムファイル(除外対象)を判別する処理がめんどくさいな〜と思っていた時、 もしかしたらscandorのオプションをあまり知らずに、やっぱりソート機能しかなかったのですが、他の機能と組み合わせることで、かなり簡易な記述ができることがわかりました・・・orz

scandirの使い方

これまで使っていた書き方は次のような感じで、検索したフォルダのパスを入れていて、その結果をfor分内で処理するだけでした。 // filesフォルダの中身を表示 $files = scandir("files/"); for($i=0; $i$lt;count($files); $i++){ if($files[$i] === "." || $files[$i] === ".."){continue;} echo $files[$i].PHP_EOL; } > array > ( > [0] . > [1] .. > [2] a.txt > [3] b.txt > [4] c.txt > ) phpのマニュアルサイトには、オプション機能として、第2引数にsortのON/OFFフラグがあると書いてあっただけなので、とりあえず実行テスト。 // sort $files_0 = scandir("../../",0); $files_1 = scandir("../../",1); // 昇順 print_r($files_0); > array > ( > [0] . > [1] .. > [2] a.txt > [3] b.txt > [4] c.txt > ) // 降順 print_r($files_1); > array > ( > [0] c.txt > [1] b.txt > [2] a.txt > [3] .. > [4] . > ) そして、不要なシステムファイルを除外する場合の書き方 // システムファイルの除外 $files = array_diff(scandir("files/"),array('..','.')); print_r($files); > Array > ( > [2] => a.txt > [3] => b.txt > [4] => c.txt > ) ちょっと連想配列とkey値が気になるので、下記のように配列に変換 // システムファイルの除外 $files = array_values(array_diff(scandir("files/"),array('..','.'))); print_r($files); > Array > ( > [0] => a.txt > [1] => b.txt > [2] => c.txt > ) さらに、単一階層だけでなく、複数の階層にも対応している関数は以下のように書けます。 <?php function dirToArray($dir) { $result = array(); $cdir = scandir($dir); foreach ($cdir as $key => $value) { if (!in_array($value,array(".",".."))) { if (is_dir($dir . DIRECTORY_SEPARATOR . $value)) { $result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value); } else { $result[] = $value; } } } return $result; } $files = dirToArray("dirs/"); print_r($files); > Array > ( > [a] => Array > ( > [0] => a.txt > ) > > [b] => Array > ( > [0] => b.txt > ) > > [c] => Array > ( > [0] => c.txt > ) > > ) 不要なシステムファイル判定などやらなくてもよくなる、任意の拡張子のみ抽出するスニペット <?php $all = array_diff(scandir("docs/") , array("..",".")); print_r($all); function scanFiles($path="",$exts=array()){ if(!$path || !is_dir($path)){return array();} $files = array_diff(scandir($path) , array("..",".")); // 拡張子指定無し if(!$exts){ return $files; } // 拡張子指定有り $arr = array(); $names = array(); foreach($files as $file){ $pathinfo = pathinfo($file); if(!in_array($pathinfo["extension"] , $exts)){continue;} $arr[] = $pathinfo; } return $arr; } print_r(scanFiles("docs",["html","md"])); > Array > ( > [2] => README.md > [3] => common.css > [4] => index.html > [5] => main.js > ) > Array > ( > [0] => Array > ( > [dirname] => . > [basename] => README.md > [extension] => md > [filename] => README > ) > > [1] => Array > ( > [dirname] => . > [basename] => index.html > [extension] => html > [filename] => index > ) > > ) pathinfoの情報がピンポイントで便利そうだったので、こんな感じにしてみました。 return値のdirnameには、$pathを入れたほうがいいですね。 これにさらに、ファイル名の文字列検索機能や、多重階層対応にすると、非常に強力な検索ツールになりそうです。 簡単なスニペットを目指したつもりが、まあまあな関数になっちゃいましたね。 見下しすぎました・・・

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。