2016/10/18 20:46:49

PHPでファイル一覧を取得する

php-logo
目次(クリックするとジャンプします)
  • 1:readdir関数をつかって取得する
  • 1.1:ディレクトリハンドルを取得する
  • 1.2:エントリを取得する為にループ処理を行う
  • 1.3:ハンドルをクローズする。
  • 2:補足・ハマりポイント
  • 2.1:存在しないディレクトリの場合
  • 2.2:厳密比較演算子を使う必要性
  • 2.3:ハンドルを巻き戻す
  • 3:まとめ

readdir関数をつかって取得する

PHPでファイル一覧を得るにはいつくかの方法がありますが、readdir関数を使うのが動作速度などの条件からして良いのではないかと思います。

コードは以下のようになります。

ディレクトリハンドルを取得する

順番としてはまずopendir関数でファイルの一覧を得たいディレクトリのハンドルを得ます。ハンドルとは認識番号のようなもので、そのディレクトリを表す特別な変数です。

$dir = "/home/mino/";
$handle = opendir($dir);

ハンドルのことをresource(リソース)と呼び、ディレクトリハンドルはstream(ストリーム)と呼ばれます。

エントリを取得する為にループ処理を行う

このハンドルをreaddir関数に与えてファイル名またはディレクトリ名を得ます。PHPではこれらをエントリといいます。

$fileName = readdir($handle)

ハンドルにはreaddirに与えると一回あたり一個のエントリを返します。ハンドルから得られるエントリをすべて得るにはディレクトリにあるエントリ分処理を繰り返す必要があります。

繰り返しにはwhileを使うのが定石です。

while (false !== ($fileName = readdir($handle))) {
    if(is_file($dir . $fileName)){
        echo $fileName . "n";
    } 
}

処理を繰り返すたびにハンドルは次のエントリに進みます。最後のエントリまで進むと自動的には巻き戻りません。そのため最後のエントリの次には進むエントリがないのでfalseを吐きます。

この段階でwhileの条件が満たないことになりループが終了します。

ハンドルをクローズする。

最後にハンドルを閉じます。ハンドルを閉じないとハンドルが開きっぱなしになり、メモリを使います(はず)。

closedir($handle);

補足・ハマりポイント

存在しないディレクトリの場合

存在しないディレクトリをopendirに与えた場合、

<?php

$dir = "/notexist/dir/";
$handle = opendir($dir);
var_dump($handle);

PHP Warningエラーが出てfalseを吐きます。

PHP Warning:  opendir(/notexist/dir): failed to open dir: No such file or directory in notexistdir.php on line 4
bool(false)

この状態を検知せずにwhileに渡した場合、

$fileName = readdir($handle)

falseではなくnullを吐きますので、

false !== ($fileName = readdir($handle))

は永久に真になりwhile無限ループになる恐れがあります。

PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in list.php on line 7
PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in list.php on line 7
PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in list.php on line 7
PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in list.php on line 7
PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in list.php on line 7
PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in list.php on line 7
PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in list.php on line 7
PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in list.php on line 7

ぐぬぬ…。

もし未知のディレクトリを探すような場合にはハンドルが正常に取れているかどうかを確かめる手段を講じたほうが良いようです。

厳密比較演算子を使う必要性

whileの条件に厳密否定比較演算子 !==を使う必要があります。これはエントリが0(ファイル名やディレクトリ名が0というのはありえる)の場合、否定比較演算子!=では型変換が行われるので0falseとなり予期しないループの終了がありえます。

//これではエントリが0だった場合ループが終了する
false != ($fileName = readdir($handle))

肯定比較演算子を使った以下の例でも間違いでは無いようですが、比較には厳密比較演算子をつかうのが良いようなのでできる限り型変換無しで評価できる方が良いかと思いマス。

//一応エントリがある場合はtureに型変換されるが…
ture == ($fileName = readdir($handle))

ハンドルを巻き戻す

最後のエントリまで行くと巻き戻らないとか説明しましたが、実際試してみると、最後のエントリまで進んでfalseを吐いたあとにもう一度エントリを得ようとしてみても、処理は進まず何も取得できません

$ php list.php

1回めの処理
.bashrc
.profile
.bash_history
.vt_locations
.viminfo
.bash_logout
2回めの処理

//最初の処理の分しか出力されていない

もう一度取得したい時にはハンドルを巻き戻す処理が必要です。これにはrewinddir関数を使います。

$ php list.php

1回めの処理
.bashrc
.profile
.bash_history
.vt_locations
.viminfo
.bash_logout
2回めの処理
.bashrc
.profile
.bash_history
.vt_locations
.viminfo
.bash_logout

//2回目も出力されている

わ〜い。

まとめ

  • ディレクトリハンドルを得る -> opendir関数
  • エントリ(ファイル名)を得る -> readdir関数
  • whileで繰り返し処理を行いエントリを1つずつ得る
  • file識別にはis_fileを使う
  • 条件式には厳密比較演算子を使うようにする
  • ハンドルをクローズする -> closedir関数
  • 再度エントリを得たい時はハンドルを巻き戻す -> rewinddir関数