適当な思いつきで書くブログ

UbuntuやPerlやJavaScriptやVimやZshやShellScriptやMySQLと戯れている中で適当な思いつきでやってみたことを書いています。

不正なハンドラがreaddir()に渡されたときの返り値がPHP5.2と5.3で異なり下手すると無限ループする(というか、した)でござる

<?php
$handle = opendir('/path/to/dir');
while (false !== ($file = readdir($handle))) {
    $files[] = $file;
}

上記のようにopendir()でディレクトリハンドラを開き、readdir()に渡して/path/to/dir内のファイル名を$filesにpushするような処理があるとします。

本来これは作法の悪いソースで、ループさせる前にopendir()の返り値がfalseでないかチェックする必要があります。

<?php
if ($handle = opendir('/path/to/dir')) {
    while (false !== ($file = readdir($handle))) {
        $files[] = $file;
    }
}


しかしPHP5.2の場合、万が一/path/to/dirが開けなくてもreaddir()がfalseを返すため、ループは行なわれません。

$ php -r "var_dump(readdir(opendir(NULL)));"
PHP Warning:  readdir(): supplied argument is not a valid Directory resource in Command line code on line 1
bool(false)

(上記はPHP Version => 5.2.6環境)


しかし、PHP5.3から/path/to/dirが開けなかった場合、readdir()はNULLを返すようになりました。
そのため上記のようなソースではfalse !== NULLが真となり無限ループに落ち入ります。

$ php -r "var_dump(readdir(opendir(NULL)));"
PHP Warning:  readdir() expects parameter 1 to be resource, boolean given in Command line code on line 1
PHP Stack trace:
PHP   1. {main}() Command line code:0
NULL  // NULLが返ってくる

(上記はPHP Version => 5.3.4環境)


PHP5.2以前の時代のソースを5.3環境で利用する場合はご注意ください。

謝辞

社長++