がるの健忘録 このページをアンテナに追加 RSSフィード

2006-11-08

[][][]素晴らしき自動的な世界〜或いは「型のない」世界〜

昼の激闘が嘘のような。あるいはその激闘を癒し包むかのような真夜中の静寂。

初冬ともいえるこの時期の冷たい風が、激務に火照った体をゆっくりと静めてくれる。ほんの一瞬の、至福な時。

その永遠の如き静けさを引き裂くかのように。

そのメールは不意にやってきた。

PHP驚愕の事実

if ('2a' == 2) {

 ここ通る

}

………まてやこら。


あんまりの驚きに「ドラマ風」なスタートを切ってみましたがるです皆様いかがお過ごしでしょうか(まだテンションがおかしい)。

なんていうか…驚きですワンダーです冒険ですドラマですそんなネタまみれなプログラム言語イヤだい。


おいといて。


ちょっと実験をしてみました。

if ('2a' == 2) { // true
if ("2a" == 2) { // true
if ('a2' == 2) { // false
if ('a2' == 0) { // true
if ('22a' == 22) { // true
if ('022a' == 22) { // true
if ('-22a' == -22) { // true
if (' 2a' == 2) { // 先頭に空白 true
if (' 2a' == 2) { // 先頭にtab true
if ('\n2a' == 2) { // false
if ("\n2a" == 2) { // true
if ("0x10" == 16) { // true
if ("0x1a" == 26) { // true
if ("0123" == 83) { // false
if ("0123" == 123) { // true

………すんごいですねぇ。

ちなみに変数に代入した場合。

$a = 2;
$b = "2a";
if ($b == $a) { // true

で、

$a = 2;
$a = $a . "";
$b = "2a";
if ($b == $a) { // false

になります。

皆様はこの規則性見えますでしょうか?


答えはこちら。

http://www.php.net/manual/ja/language.operators.comparison.php

整数値を文字列と比較する際、文字列が 数値に変換されます。 数値形式の文字列を比較する場合、それは整数として比較されます。これらの ルールは、 switch 文にも適用されます。

……………………あのなぁ。

ちなみに「文字列が数値に置換される」ルールは

http://www.php.net/manual/ja/language.types.string.php#language.types.string.conversion

をご覧くださいませ。

文字列の変換

数値として文字列が評価された時、結果の値と型は次のように定義されます。

文字列は、'.'、'e'、'E' のどれかが含まれている場合は float、それ以外は整数として評価されます。

文字列の最初の部分により値が決まります。文字列が、 有効な数値データから始まる場合、この値が使用されます。その他の場合、 値は 0 (ゼロ) となります。有効な数値データは符号(オプション)の後に、 1 つ以上の数字 (オプションとして小数点を 1 つ含む)、 オプションとして指数部が続きます。指数部は 'e' または 'E' の後に 1 つ以上の数字が続く形式です。

つまり。

'2a'は2になり、'a2'は0になるわけです。ちなみに、タブ、空白、改行などは都合よく無視してくれることが、"\t2a"、" 2a"、"\n2a"などのテストにより明らかになっております。

ちなみに0xつけて16進数は理解するようですが、先頭0で8進数はサポートされておりませんのでご注意ください。


えと。世間様でよく「PHPは型のない言語」だとかなんとかいう風評が流されておりますが。とんでもハップンでございます。

PHPは、素晴らしく「型の厳密な」言語でございますっていうか「型を厳密にプログラマが意識しておかないといかん言語」でございます。

そうでなければ何故に gettype などという関数が用意されているとおっしゃるのでしょうか? is_int()が、is_string()が、用意されているとお思いでしょうか?


とりあえず。「文字列の比較」に==演算子使っちゃいけませぬ。

ド最低限===(=が三つ)か、冷静には、正規表現なり(重いけどね)strcmpなり(多分こっちが無難)を使いましょう。


…案外いい言語かも。「お勉強のため」には。

PHPプログラミングされている諸氏(特にお仕事でプロとしてなさっている諸氏)。くれぐれも「型」をお忘れなき用に。

ちなみに「どっかのタイミングで適当に自動で変換(functionの引数とか一撃ですな)」してくださりやがりますので、そのあたりにもご注意を。

wiz-zilwiz-zil 2006/11/08 14:00 えー。
ぶっちゃけ。
超改悪版かつ超サブセットなC++のスクリプト版

という認識でよろしいのかしら?
C++に失礼かしら・・・・(滝汗

かずくんかずくん 2006/11/08 18:53 > ド最低限===(=が三つ)か、
やばいなぁ。ついつい、
$hoge == ’’
とかやっちゃうなぁ。

これって、確か
0 == ’’
がtrueになるんですよねぇ。

まじヤバ。見直しとかねば....

gallugallu 2006/11/08 19:28 はいまさに
0 == ’’
はtrueになるですねぇ怖いですねぇオカルトですねぇ。
………夏ならよかったのに。

今回のネタ、多分、かなりしゃれになってないでふ。まぢで。

かずくんかずくん 2006/11/17 10:05 strtotimeの引数にnull渡すと-1を返さず、コアはきやがりまふ(PHP4系)。

strtotimeの使用前にはnullおよび空文字チェックが必須と。

gallugallu 2006/11/17 11:21 むむぅどのバージョンでしょう?
手元にある、
4.3.10、4.3.11、4.4.2、4.4.3、4.4.4では、いずれもNULL渡してもとりあえず死ななかったです。
コードは
$ret = strtotime(NULL);
print_r($ret);
こんな感じ。
ただ…ほかの関数含め「引数チェックやってない」の壮絶に多いっす。
そこでハーディングパッチなんですがね。ウチはいいけど、よそ様は大抵「globalが使えないんなら使えない」になるのが困りモノです(苦笑

gallugallu 2006/11/17 11:23 追伸。5.1.6だとsyntax errorになるです。
…挙動一致しねぇなぁ流石に(笑

teraccteracc 2006/11/19 16:08 はじめまして。大きくうなづくところがありましたんで、コメントさせてもらいます。

文字列の比較では、strcmpを使うべきというのは知っています。でも、
if ($action == ’confirm’) {
みたいな書き方をすることは、よくあります(僕だけか?)。

この例だと無害ですが、これに慣れちゃうと、本当にstrcmpを使わなきゃならないときにも、無意識のうちに == を使ってしまうようになります(これも僕だけ?)。

恥ずかしながら、以前書いたログイン機能で、
if ($pass == $pass_in_db) {
みたいなコードを書いてしまったことがあります。
ユーザがログイン画面で入力したパスワードと、DBのパスワードを比較する処理です。

$pass_in_dbが ”10e3” だったら、$passが ”0010000”、”10000.000”、”100E2” などを入力してもログイン出来ちゃいました。はっはっはー・・・... ぁぁ

emptyの挙動などをみて、PHPの怖さは感じていましたが、それを身をもって体験した瞬間でした。

gallugallu 2006/11/20 11:22 がるです。
んと…マンモス本やらセキュリティ系の書籍やら含め。ほと〜んどのPHP書籍で普通に==使ってます(苦笑
なんていうか………まぁCの時はそうだったのですが。「数値以外で使っちゃいかんなぁ」って感じですねぇ。

それにしても。”10e3”もまた、かなり笑えないけど笑えますねぇ。
今回の問題、身内では「2a問題」って呼称してますけど。その追加で「e3問題」とか呼んでみようかしらん(苦笑

正直。PHPは地雷だらけなので。せめてその地雷を「迂回する方法」を出来るだけ提示していきたいものです。
っていうか、ほかにもネタあったら是非教えてください〜 ^^

かずくんかずくん 2006/12/04 14:46 古いネタなので、もうみてないかも、だけど...

あり、なしの2つのラジオボタンがあり、
それぞれPOSTリクエストとして1, 0を送信します。

昨今、何かと物騒なので、一応念のため、入力チェックを行うため、こんなコードを書きました。

if (! in_array(POSTの値, array(0, 1)) {
 入力エラーだってば!!!
}

さて、ちょいといたずらして、
1<script>javascript:alert(’え?でちゃうの?’)</script>
が、POSTされるようにしました。(方法はあえて書きません)

さてこれは、エラーチェックに引っかかるでしょうか?

Thinking Tiiiiiiime!!!!

こたえ
PHP的には、エラーじゃないんだって。
if (! in_array(1, array(0, 1)) {
 入力エラーだってば!!!
}
って解釈するから。

エエエェェェ。うそーん。

ちなみに、
if (! iarray_key_exists(1, array(0 => ’なし’, 1 => ’あり’)) {
 入力エラーだってば!!!
}
と、すれば、エラーとして扱ってくれる。

Dr_RadialistDr_Radialist 2011/05/22 06:48 ありがとうございます。大変参考になりました。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証