前に「PHPにおいて、最強のファイル一覧表示は何か!? | Naokix.net」で glob 関数を思いっきりディスったので、今回は「glob 関数ってこんなに便利だよ」という話をしたいと思います。
scandirやopendir、readdirといった関数などに比べて速度の面で難点はありますが、対象ディレクトリからファイルの一覧を取得し、その中からパターンに一致したものを抜き出す処理を一文で表現できる柔軟性は見逃すことができません。
対象フォルダのファイル一覧を取得する
glob 関数はパターンにマッチするパス名を探す関数ですが、ワイルドカードを利用することでファイルの一覧を取得できます。下のソースを test.php で保存しました。
test.phpと同じ場所にtargetフォルダがあり、フォルダの中に入っているたくさんのファイルの中から目的のファイル名を探し出す状況だと思ってください。
1 2 3 4 5 6 | <?php foreach(glob("target/*.*") as $file) { $result[] = $file; } print_r($result); |
フォルダまで含めて一覧を取得したい場合は、
1 2 3 4 5 6 | <?php foreach(glob("target/*") as $file) { $result[] = $file; } print_r($result); |
とします。
取得するファイルを絞り込む
一覧だけでなく、パターンを使ってファイルを絞り込むこともできます。例えば、JPG ファイルだけを取得したいなら、
1 2 3 4 5 6 | <?php foreach(glob("target/*.jpg") as $file) { $result[] = $file; } print_r($result); |
で取得できます。複数指定することも可能で、例えば JPG と PNG ファイルを取得したいなら次のようになります。複数のパターンを指定するために使用するオプション「GLOB_BRACE」を忘れないようにしてください。
1 2 3 4 5 6 | <?php foreach(glob("target/{*.jpg,*.png}", GLOB_BRACE) as $file) { $result[] = $file; } print_r($result); |
「,(カンマ)」で区切ります。途中で半角スペースをいれるとパターンが終わったと判断されるのでいれては駄目です。上の例でいえば、「{*.jpg,(半角スペース)*.png}」と書くと JPG ファイルだけ取得する結果になるので注意してください。
パターンとしてワイルドカードや[a-z]、[1-9]などを使うことはできますが、正規表現を使うことはできません。例えば、
のようなファイルがあって test1.txt、test2.txt、test3.txt を取得したい場合、
1 2 3 4 5 6 | <?php foreach(glob("target/test[1-9].*") as $file) { $result[] = $file; } print_r($result); |
のように使うことが可能です。いくつかのサンプルをネットで探してみたのですが、ファイルの振り分けにファイルサイズや更新日時を使うような運用の仕方が多かったので、これでこと足りるのかもしれません。
フォルダをまたいでファイルを検索する
ワイルドカードを利用して、フォルダをまたいでファイルを検索することが可能です。WordPress の画像を保存するフォルダは「uploads」フォルダの下に「年」のフォルダ、その下に「月」のフォルダが作られて、その中に画像ファイルが保存されています。
ここで各月のフォルダの中に「udon.jpg」がそれぞれあるとして、これらを取得しようと思ったのなら、
1 2 3 4 5 6 | <?php foreach(glob("uploads/2015/*/udon.jpg") as $file) { $result[] = $file; } print_r($result); |
とすればよいです。
サブフォルダの中まで取得したい
再帰関数にすることで、サブフォルダの中まで取得することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php function getFiles($path) { $result = array(); foreach(glob($path . "/*") as $file) { if (is_dir($file)) { $result = array_merge($result, getFiles($file)); } $result[] = $file; } return $result; } $path = "target"; print_r(getFiles($path)); |
まずは関数を作っちゃいます。
1 | function getFiles($path) { |
ファイルの一覧を格納する配列は foreach の外側で宣言してください。
1 | $result = array(); |
フォルダかどうか判定し、
1 | if (is_dir($file)) { |
フォルダだった場合には自分自身、ここでは getFiles 関数を呼び出します。これでサブフォルダ以下のファイル一覧を取得します。さらにフォルダがある場合、再び getFiles 関数が呼ばれ、これがフォルダが現れなくなるまで繰り返されます。
1 | $result = array_merge($result, getFiles($file)); |
array_merge 関数は配列を連結する関数です。
1 | $result[] = $file; |
フォルダでない場合はファイルなので、そのまま配列の最後に追加します。最後にファイル一覧の格納された配列を返します。
おまけ
readdir 関数や DirectoryIterator 関数を使うと、「.」や「..」を取得してしまうので、ほとんどの場合このふたつを取り除く処理が必要になります。単純に If 文で比較して取り除くだけですが。glob 関数の場合、はじめから取り除いたものを取得してくれるので、この意味でもソースコードの可読性を高めてくれるメリットがあります。
Comment