がるの健忘録

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

やっぱり「型に厳格なのは大事だなぁ」という雑感

大本のネタは
https://twitter.com/ndxbn/status/808159644874993664

「in_array の第3引数にtrue必須」っていうコーディング規約をCIで回したい人生だった。

https://twitter.com/gallu/status/808161595578662912

@ndxbn in_array()、色々と気になるから使わない一派所属。線形検索とか、イクナイ!、って思うの。


ってあたりからほんのり調べ物をして見つけた、某所でみたコード。
コード自体は一通り引用、別にさらしたりするのが目的ではないので、引用元は一端オミット。

<?php
header('Content-Type: text/plain; charset=utf-8');
$secret_password = 'This is very secret password';
$input_password  = isset($_POST['password'])    ? $_POST['password']    : '';
$shell_input     = isset($_POST['shell_input']) ? $_POST['shell_input'] : '';
if (!strcmp($password, $input_password)) {
    - 中略:認証が通った時にさせたい処理 -
} else {
    - 中略:認証NGの時にさせたい処理 -
}


論調としては「配列が帰ってくる事があるから上述そのままだと(パスワードがわからなくても「認証が通った時」のロジックが通るから)危ない」って話なんだけど…微妙な違和感が2か所ほど。


シンプルなところは「$_POSTの戻り値、なんでstringでキャストしないん?」ってあたり。まぁこの辺は賛否あってもいい所ではあるのでそんなに強く言わないのだけど、おいちゃん的には気になる違和感。


if文の「$passwordって、多分、$secret_passwordだよねぇtypoじゃない?」って細かい話はおいといて。


もうちょっと気になるのが、if文の中の条件式。

if (!strcmp($password, $input_password)) {

って書いてあるんだけど、おいちゃんなら間違いなく

if (0 !== strcmp($password, $input_password)) {

って書く。記法がヨーダなのは「おいちゃんの癖」なので気にするなw


で…簡単なテストコードを書くと、===で「厳格なチェック」すると、配列がわたってきても「とりあえず認証が(誤って)通る事はない」事が、ほんのりわかる(Warningがうざいので、エラー出力一端消し)。

ini_set('display_errors', 1);
ini_set('display_errors', 0);
error_reporting(-1);

$password = 'hoge';
$input_password = array();

var_dump( !strcmp($password, $input_password) );
var_dump( 0 === strcmp($password, $input_password) );
var_dump( strcmp($password, $input_password) );

bool(true)
bool(false)
NULL

…へぇ「引数が配列だと戻り値NULLになる」のか。
マニュアルには書いてない挙動だw


まぁ、いずれにしても。
おいちゃん的に、なんとなし「!(なんかの値)」は、この手の自動変換もあるので、割合と好まないのだよねぇ。
なので、この辺の「!(なんかの値)」で判定しちゃってるところが、おいちゃんの違和感で、気になるところ。


おまけで、strcmpの挙動を少しみてみた。

ini_set('display_errors', 1);
ini_set('display_errors', 0);
error_reporting(-1);

function hoge($p1, $p2) {
  var_dump($p2);
  var_dump(strcmp($p1, $p2));
  echo "\n";
}

hoge('hoge', 'hoge');
hoge('0', 0);
hoge('2a', 2);
hoge('0', 0.0);
hoge('1', 1.0);
hoge('2a', 2.0);
hoge('hoge', true);
hoge('hoge', array());
hoge('hoge', new stdClass());
hoge('hoge', fopen(__FILE__, "r"));
hoge('hoge', NULL);

string(4) "hoge"
int(0)

int(0)
int(0)

int(2)
int(1)

float(0)
int(0)

float(1)
int(0)

float(2)
int(1)

bool(true)
int(55)

array(0) {
}
NULL

object(stdClass)#1 (0) {
}
NULL

resource(5) of type (stream)
NULL

NULL
int(4)

まぁWebアプリから入ってくる経路だと「文字列または配列」だからよいのだけど、むしろ怖いのは数値だわintにしてもfloatにしても。
booleanの時の値が謎なんだけどとりあえず「不一致」にはなるし。NULLも謎くさいけど、同じく「不一致」になるので気にしない*1
あと、配列、インスタンス、リソース型を渡した時にNULLになる、ってのは覚えておくと色々と便利な気がする。


しばらくこの手の「調査系/技術系」のネタを書いてなかったので、ちょろり。

*1:NULLは多分「もう片方の比較する文字列の長さ」が帰ってくるぽ