PHPプロ!TIPS+

関数とバイナリセーフ

関数の中にはバイナリデータを正しく扱うことが出来る関数(バイナリセーフ)とそうではない関数があります。これを把握しておかないと、思わぬところでバグを発生させかねません。今回はその中でも正規表現によるマッチングに焦点を当てます。

正規表現によるマッチング関数にpreg_matcheregがあります。前者はPerl互換性、後者はPHPのPOSIX互換性正規表現関数です。これらは入力値をフィルターするときにしばしば用いられます。しかし、eregには落とし穴が存在します。

その落とし穴とは「ereg関数はバイナリセーフではない」ということです。例えば、ユーザ入力をフィルタリングするスクリプトを考えてみましょう。

if (ereg('^[0-9A-Za-z_]+$', $_POST['login_id'])) {
// 正しい入力に対する処理
}

ここでの目的はポストされたlogin_idが半角英数、アンダーバーのみで構成されているか確認することです。一見、何の問題もないように思われます。しかし、$_POST['login_id']にヌルバイト文字(\0)を入れられると、このフィルタリングは意味を持たなくなります。ためしに

$_POST['login_id'] = "abc\0 -** 1 **-";

としてみて下さい。ereg関数はtrueを返し、if内部のスクリプトが実行されたと思います。この原因はereg関数がヌルバイト文字の直前までしかマッチングを行わないことにあります。つまり、バイナリセーフな関数ではないため、ヌルバイト文字で文字列が終了したとみなしてしまいます。このような場合にはeregではなくpreg_matchを用いて下さい。

ただし、これはmb_ereg系には当てはまりません。名前は似ていますが、これらはバイナリセーフな関数です。また、preg系の関数ではその代わりになりえません。

以上の様に、入力値に対してバイナリセーフではない関数を用いる場合には注意が必要です。特に正規表現関数の使い所には気を付けて下さい。

他のバイナリセーフではない関数の一部

ereg_replace(), eregi(), eregi_replace(),
split(), spliti(),
include(), include_once(), require(), require_once()
fopen(), file_get_contents(), readfile(), basename()

バックナンバーについて

TIPS-MLは、毎週金曜日に更新され、新しい記事が掲載されます。

Tipsꗗy[W 

Pick Up Q&A

Q
ログファイルの中の空のデータ行を削除したい
 このエントリーをはてなブックマークに追加 
A
ログのデータ個数(列数)が固定で、空のログが"<><><>"だと既知であれば if ($line === "<><><>") { continue; } で読み飛ばしてもいいのでは? ...

>>続きを読む

まずは配列や文字列の扱いから、じっくり勉強して行きましょう。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)