BOM付きUTF-8のPHPファイルからBOMだけを一度に削除するスクリプト | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

あまりUTF-8の環境でPHPを動かすということがなかったのではまったんですが、BOM(Byte Order Mark)ありのUTF-8で保存したPHPって動作に問題が出るんですね・・・。

要はBOMの先頭バイトが邪魔をしてPHPスクリプトと認識してくれなかったり、文字化けを起すような弊害が出てきます。


じゃあ、事前にBOM付きのUTF-8をBOMなしのUTF-8に変換すればいいとiconvコマンドで変換しようとしても


$ iconv -f UTF-8 -t EUC-JP hoge.php
iconv: 位置 0 で不正な入力シーケンスがありました

と、iconvコマンドはBOM付きのUTF-8に対応していない模様・・・。

nkfコマンドもうまくBOMを取り除くということが出来ませんでした。

vimコマンドでは


:set nobomb

として保存することでBOMを取り除くことができます。

ただし、大量にBOM付きのPHPコードが合った場合、ちまちまやってられないので、BOMを取り除くPHPスクリプトを書いてみました。



UTF-8(BOMあり)からBOMだけを取り除くPHPスクリプト


ファイルの先頭に来るBOMコードは0xEFBBBFとなるため、該当ファイルからそれを除去して同じパス上に保存するという動作をします。


<?php

$target_dir = "/var/www/html/";

if (is_dir($target_dir)) {
    if ($dh = opendir($target_dir)) {
        while (($file = readdir($dh)) !== false) {
            $path_parts = pathinfo($file);
// 拡張子がphpのファイルのみが対象
            if ($file != '.' && $file != '..' && ($path_parts['extension'] == 'php')) {
                $path = $target_dir . $file;

// kccコマンドでUTF-8のファイルかどうか判断
                $cmd = `kcc -c $path`;
                list($fname, $enc) = explode(':', $cmd);

                if (trim($enc) == 'data') {
                    $contents = file_get_contents($path);

// BOMありの場合
                    if (preg_match("/^efbbbf/", bin2hex($contents[0] . $contents[1] . $contents[2])) === 1) {

// 先頭3バイトのBOMコードを除去して同名で保存
                        $contents = substr($contents, 3);
                        file_put_contents($path, $contents);
                   }
                }
            }
        }closedir($dh);
    }
}


対象は拡張子が.phpのファイルのみとしていますが、違えばお好みで変更できます。

また、kccコマンドでUTF-8のファイルかどうか判別(厳密にkccコマンドではUTF-8コードかを判別できず、結果はdataと返ってきます)をしていますが、全てがBOM付きUTF-8のファイルだということであれば、特にその条件判定は必要ないかもしれません。

ツールを使ってPHPファイルを保存した場合、意図しないところで勝手にBOMが挿入されてたりもするのですが、大量に保存してしまったPHPファイルを再度保存しなおすのは手間となるので、こういったスクリプトで一気に除去してしまえば便利かもしれません。