すたらブログ

文系Webプログラマの備忘録

PHP: `file_get_contents()`にディレクトリを指定すると`Permission denied`と表示される

ファイル内容を文字列に読み込む関数にディレクトリを指定したらエラーになるのは当然ですが、エラー文にPermission deniedと表示されるので混乱してしまいました。

<?php
echo file_get_contents('foo-dir');

// エラー文
// Warning: file_get_contents(foo-dir): failed to open stream: Permission denied
?>

ちなみに、存在しないファイルを指定した場合はNo such file or directoryと表示されます。

<?php
echo file_get_contents('foo-file.txt');

// エラー文
// Warning: file_get_contents(foo-file.txt): failed to open stream: No such file or directory
?>

実際に混乱した例

SimplePieという、有名なフィード取得ライブラリがあります。
ライブラリを一つのファイルにまとめる役割のbuild/compile.phpの54行目にfile_get_contents()が使われています。
RecursiveDirectoryIteratorRecursiveIteratorIteratorでディレクトリ内を丸ごと、ディレクトリとファイルの区別なく取得した結果をひとつずつfile_get_contents()の引数に指定しているため、ここでエラーが発生します。

<?php
// Add all the files in the SimplePie directory
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(SP_PATH . '/library/SimplePie'));
foreach($files as $file_path => $info)
{
    $contents = file_get_contents($file_path);
    $compiled .= remove_header($contents) . "\n";
}
?>

エラー文にPermission deniedと表示されるため、「OSがWindowsだから発生したのか?」「パスのセパレータをバックスラッシュ(\)からスラッシュ(/)に変更すべきなのか?」など試行錯誤を重ねて、ようやく原因に気づきました。
下記のようにすればディレクトリが引数に指定されるのを防げます。

<?php
// Add all the files in the SimplePie directory
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(SP_PATH . '/library/SimplePie'));
foreach($files as $file_path => $info)
{
    // ファイルの場合のみ、file_get_contentsを実行
    if (is_file($file_path)) {
        $contents = file_get_contents($file_path);
        $compiled .= remove_header($contents) . "\n";
    }
}
?>

GitHubでプルリクエストを送りました。
https://github.com/simplepie/simplepie/pull/419

ただ、なぜこんな単純なミスが長い間放置されていたのでしょうか?
SimplePieの最新版1.3.1は2012年10月31日に公開されいますが、当時のPHPでは問題なかったのでしょうか?
…ともかく、返信を待つことにします。