PHPにはファイル署名とMIMEタイプと拡張子を組み合わせた辞書が組み込まれています。この辞書は finfo 関数を用いることでいい感じに使えます。これを利用することで拡張子のないファイルの拡張子を補完できます。これができると拡張子の誤ったファイル群や拡張子なしで保存したファイル群を GUI 上で楽に使うための準備をしやすくなります。
具体的なスクリプトは次です。
<?php foreach(glob('/tgt_dir_path/*') as $filePath){ // finfo を使って拡張子を得られるようにすると宣言 $finfo = finfo_open(FILEINFO_EXTENSION); // ファイルの中身からあるべき拡張子を取得 $ext = $finfo->file($filePath); if (! preg_match("/\.{$ext}$/i", $filePath)) { // 正規表現のiフラグは大文字小文字を無視するフラグ // もしファイル末尾の拡張子がファイルの中身にそぐう拡張子でない場合は // 拡張子を付け足したファイルとして名前を変更 rename($filePath, $filePath.'.'.$ext); } }
tgt_dir_path
の所に変更したファイル群のあるディレクトリのパスを入れてphp スクリプトファイル名
で実行できます。
finfo はファイル情報機能の中に含まれている機能です。この機能ではファイルのマジックナンバー(ファイルの先頭から始まるバイトにあるファイルの種類固有のバイトコード)からファイルを識別でき、識別結果から色々なことができます。
このスクリプトではその機能の内の拡張子の取得を用いて、ファイル名末尾に拡張子が見当たらなければ末尾に拡張子を追加、としています。単純なスクリプトですが割とうまく動作します。
ちなみにマジックナンバーによる識別は完璧ではありません。たまたま先頭のバイトが一致したテキストファイルが最たる例です。SJISエンコードで”公開フラグ”という文字列を先頭に含むテキストファイルがDOS実行ファイルと解釈されるなんて話もあります。
<?php $finfo = finfo_open(); $txt = finfo_buffer($finfo,mb_convert_encoding("公開フラグ ほげほげ", 'SJIS-win')); var_dump($txt); // string(34) "DOS executable (COM, 0x8C-variant)"
Online PHP editor | output for 2EVYU#公開フラグがDOS実行ファイル扱いされる例
PHPのドキュメントも次の様に説明しています。
このモジュールの関数は、ファイル内の特定の位置から
magic バイトシーケンスを見つけることで、
ファイルの content type とエンコーディングを推測します。
これは完全な手法ではありませんが、経験上かなりうまく動作しています。