UTF-8でプログラムを書いていると、Windowsのメモ帳などが勝手に付けてくれるBOM(Byte Order Mark)が邪魔をしてうまく動かないということが時々起こります。
PHPでは特にこの問題が表面化しやすく、リダイレクトなど、HTTPヘッダを出力しようとすると、すでに本文出力してるぞってエラーが出てくるわけです。
そういうときは何らかの方法でBOMを除去するわけですが、そもそもBOMの入ったファイルを見つけなければ話にならないわけです。
そこで、BOM付きファイルを探し出すのをPHPで作ってみました。
<?php
// 初期ディレクトリ
$initial_directory = __DIR__;
header('Content-type: text/plain');
s($initial_directory.'/');
function s($target_dir)
{
chdir($target_dir);
$files = glob('*');
if (!is_array($files) || count($files) == 0) {
return;
}
foreach ($files as $file) {
$path = $target_dir.$file;
if (is_dir($path)) {
s($path.'/');
} elseif (filesize($path) >= 3) {
$contents = file_get_contents($path);
if (hasbom($contents)) {
// 出力
echo "$path\n";
}
}
}
}
function hasbom($contents)
{
return preg_match('/^efbbbf/', bin2hex($contents[0].$contents[1].$contents[2])) === 1;
}
特定のディレクトリ以下のすべてのファイルを走査して、BOMコードで始まるファイルを列挙していきます。
globのパターンを変更してPHPファイルだけを対象にするというのもよいでしょう。
なんでもかんでもBOM除去していいってわけでもないので、とりあえず表示だけしています。
あとは出てきたファイルを、必要に応じてテキストエディタなどでBOMなしにして保存しなおせばよいわけです。
BOM除去していいテキストファイルしかないとわかっているときは、ファイルを列挙せずにすぐBOM除去して書き戻したほうが便利でしょう。
その場合は、出力部分を以下のコードに入れ替えます。
file_put_contents($path, substr($contents, 3));
今回のプログラムは、PHP5.6と7.1で動作確認済みです。