PHPで文字列を比較し、バリデーションに使ったりすることも多いですね。
ただ、PHPは型を変換し、10
と"10a"
は同じだよ!と判定することもあり、なんでよ?とハマることもよくあります。
厳密に比較する方法と、strcmp()
で比較する方法をご紹介します。
比較演算子「==」で文字列比較
登録ユーザー名「5secondsofsummer」さんがログインしようとして、間違えて「5」と入力した場合を仮定しました。
1 2 3 4 5 6 7 8 |
$name = 5; $user = '5secondsofsummer'; if ($name == $user) { echo 'ようこそ'.$user.'さん!'; } else { echo 'ユーザー名が違います!'; } |
ようこそ5secondsofsummerさん!
比較演算子==
で比較すると、「5」としか入力していないにも関わらず、バリデーションを通過してしまっています。
「バリデーションとは?」
フォームを検証し、入力ミスや入力漏れ等をチェックすることです。
これでは、セキュリティ上問題がありますね。
以下リンクでもご紹介しましたが、文字列型と数値型を比較する場合、PHPは型を揃えるために数値型に自動変換し、"5secondsofsummer"
が数値型に変換されたためにこのような結果となります。
整数値を文字列と比較したり、比較に数値形式の文字が含まれる場合は、文字列が 数値に変換され、 数値としての比較を行います。
出典:PHPマニュアル・比較演算子
1 |
var_dump((int)'5secondsofsummer'); |
int(5)
上記のように数値型にキャストすると「5secondsofsummer」が「5」に変換されているのが分かるかと思います。
数値型へ変換する際、頭の数値以外の文字列は消えてしまうようです。
厳密な比較演算子「===」で型まで比較
型まで比較するには===
を使います。
1 2 3 4 5 6 7 8 |
$name = 5; $user = '5secondsofsummer'; if ($name === $user) { echo 'ようこそ'.$user.'さん!'; } else { echo 'ユーザー名が違います!'; } |
ユーザー名が違います!
上記のように厳密に比較することで「違います!」と出てくれました。
厳密に比較すると弊害が起こることも
しかし、厳密にし過ぎると困ることもあります。
同じ「175」を数値型と文字列型で比較してみます。
1 2 3 4 5 |
if (175 === '175') { echo '同じ値です'; } else { echo '違います!'; } |
違います!
同じ文字でも型が違うため、違う値と判定されてしまいます。
思わぬバグの元となるため、注意しましょう。
strcmp関数で型が違う文字を比較
前項のような同じ文字でも型が違う場合、strcmp()
なら同じ文字として判定してくれます。
1 2 3 4 5 |
if (strcmp(175, '175') == 0) { echo '同じです'; } else { echo '違います!'; } |
同じです
strcmp関数の構文
strcmp(比較する値1,比較する値2)
比較する値1が大きい→ 「>0」を返す
比較する値2が大きい→ 「<0」を返す
比較する値が同じ→ 「0」を返す
先ほどのサンプルコードだと、strcmp
の後に== 0
で条件分岐していますが、これはstrcmp()
が同じ値は「0」を返すことを利用したものです。
PHPは型を意識しなくてもコーディングできることも多いため、型の意識が抜けることもあるかと思います。
ただ、思わぬバグを誘発することもあるため、関数や演算子の動作を理解した上で、型を意識してコーディングする必要があるでしょう。