【PHP】フォルダのすべてのファイルパスを取得するあれこれ

2020年4月19日

PHPのプログラムでファイルを一括編集する機会があったのでフォルダ(ディレクトリ)の中のファイルパスをすべて配列で取得するプログラムを何パターンかまとめていく。

全階層ファイルパスをひとつの配列で取得

まずフォルダ内のディレクトリ・ファイルを取得する関数glob()を使う。

/Test/ – test1.php
– test_dir1 – test2.php
– test3.php
– test_dir2 – test4.php
– test_dir2-2 – test5.php

とする。

$root = './Test/*';  //正規表現で一致したもののみ取得できる。
$paths = glob($root);
var_dump($paths);

結果

array(3)
{
[0]=> string(16) “./Test/test1.php"
[1]=> string(16) “./Test/test_dir1"
[2]=> string(16) “./Test/test_dir2"
}

このままでは2階層以降のファイルパスが取得できない。そのため、ディレクトリを取得した場合再帰的に処理を行う必要がある。

関数を作成する

$root = '../Test';
$paths = globAllPath($root);
print_r($paths);


function globAllPath($root)
{
//正規表現がめんどうだからフォルダ名を引数に渡したらすべて取得できるように
  $root = $root. '/*';
  $paths = glob($root);

  foreach ($paths as $path) {
    if (is_dir($path)) {
       $paths[$path] = globAllPath($path);
    }
  }
  return $paths;
}

結果は次のようになる。

Array(
[0] => ../Test/test1.php
[1] => ../Test/test_dir1
[2] => ../Test/test_dir2

[../Test/test_dir1] => Array (
[0] => ../Test/test_dir1/test2.php
[1] => ../Test/test_dir1/test3.php
)
[../Test/test_dir2] => Array (
[0] => ../Test/test_dir2/test4.php
[1] => ../Test/test_dir2/test_dir2-2

[../Test/test_dir2/test_dir2-2] => Array (
[0] => ../Test/test_dir2/test_dir2-2/test5.php )
)
)

無事、全てのファイル パスを配列に収めることができた。

キー値にはディレクトリを入れてどこのファイルなのかがわかるようにしている。

でもなんか気持ち悪い、、。ファイル名だけを取得したいのにもかかわらずディレクトリ名も残っているのでそれを消してみる。

関数を修正(追記:ディレクトリと同じ構造の多次元配列)

function globAllPath($root)
{
  $root = $root. '/*';
  $paths = glob($root);

  $i = 0;
  foreach ($paths as $path) {
    if (is_dir($path)) {
       $paths[$path] = globAllPath($path);
       //ディレクトリをリストから外す
       unset($paths[$i]);
    }
    ++$i;
  }
  return $paths;
}

結果はこうなる。
(追記)こちらはディレクトリごとに(ディレクトリと同じ構造で)配列を形成するプログラムとなった。

array(3) {
[0]=> string(16) “./Test/test1.php"
[“./Test/test_dir1"]=> array(2) {
[0]=> string(26) “./Test/test_dir1/test2.php"
[1]=> string(26) “./Test/test_dir1/test3.php"
}
[“./Test/test_dir2"]=> array(2) {
[0]=> string(26) “./Test/test_dir2/test4.php"
[“./Test/test_dir2/test_dir2-2"]=> array(1) {
[0]=> string(38) “./Test/test_dir2/test_dir2-2/test5.php"
}
}
}

unset()関数でフォルダだった場合にその値をnullにさせている。

unset()に対する引数は $i インデックスで渡すことができた。

追記:すべての階層のフォルダを単配列で取得する

できあがった配列はどうしても多次元配列になってしまうので、それを1次元の配列に戻す関数を使うことにする。

取り出してきた先ほどの多次元の配列をあらためて単配列に戻す。

多次元配列を単配列へ変換する

参考:https://php-fan.org/array.html

こんな関数を見つけた。

//多次元配列から単配列へ変換
function arrayFlatten($array){
	$result = array();
		foreach($array as $val){
			if(is_array($val)){
				$result = array_merge($result, arrayFlatten($val));
			}else{
				$result[]=$val;
			}
		}
	return $result;
}

美しすぎる。

この関数に先ほどの $paths を引数に渡してみると

array(5) {
[0]=> string(16) “./Test/test1.php"
[1]=> string(26) “./Test/test_dir1/test2.php"
[2]=> string(26) “./Test/test_dir1/test3.php"
[3]=> string(26) “./Test/test_dir2/test4.php"
[4]=> string(38) “./Test/test_dir2/test_dir2-2/test5.php"
}

きれいに単配列に変換することができた。

まとめ

次の記事では取得したファイルパスの中身(ソースコード)をすべて取得するプログラムを作成するのでそのために単配列でファイルパスをまとめた。

<?php
//すべてを同じ階層の配列に格納する
$root = './Test';
$paths = globAllPath($root);

$paths = arrayFlatten($paths);

var_dump($paths);

//ファンクション群..

この流れで準備しておく。

次はすべてのファイルのソースコードを配列として受け取るプログラムに挑戦!

(ちょっと最後は手抜き感あったのでひとつのファンクションでフラットに作れたらプログラム追記します笑)