1. continueとbreak、使いこなしてますか?
switch文やループの操作をする際に使用される制御構造に、continueとbreakがあります。
大概の入門書で登場し、動作自体は非常に単純なものなので、意外とこれらのマニュアルを省みない人も多いのではないでしょうか。
しかしマニュアルをよく見ると、ちょっと便利な動作をしてくれることがわかります。
ご存知のとおり、continueはループ内の残り処理をスキップして条件式判定まで戻りbreakはループ処理を終了します。
動作の違いはありますが、いずれも現在のループを抜ける制御構造です。
しかし、これらは単に現在のループを抜けるだけでなく、以下のように指定することで現在のループとその上のレベルのループの、2重ループを抜けることが可能です。
$count = 0;
echo "start\n";
while (true) {
$count++;
echo "one : $count\n";
while (true) {
echo "two\n";
if ($count < 3) {
continue 2;
} else {
break 2;
}
}
}
echo "end\n";
結果:=======================
start
one : 1
two
one : 2
two
one : 3
two
end
ここでは例として2重ループのcontinue/breakを行いましたが、2重ループに限らず、それぞれの引数として処理をスキップ/中断するループのレベルを指定することができます。(例えば、break 3; とすれば3重ループをbreakします。)これを使いこなすとループ操作が非常に楽になり、便利です。
さて、これだけだと「PHPのマニュアルは有益だからよく読みましょう」だけで終わってしまいますので、このネタの続きをもう少し。
PHPの各種言語構造や関数は、他の言語に比べて柔軟な動作をします。(人によっては、柔軟とは呼ばないかもしれませんが・・・。)
よく言われるところでは、switch...case構文でcaseの値に関数や条件式を指定できる点などがあります。
今回のテーマであるcontinue/breakのループレベル指定も、その例に漏れずなかなか柔軟です。
まず、この引数(ループレベル指定)に0や-1といった、そもそもループのレベルとして存在し得ない整数値を与えた場合には、何も指定しなかった時と同様に現在のループのみを抜ける動作になります。(なお、Noticeは出ません。)
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
echo "$i : $j \n";
continue -2;
}
}
結果:==========================
0 : 0
0 : 1
0 : 2
1 : 0
1 : 1
1 : 2
2 : 0
2 : 1
2 : 2
また、引数に対してint型以外の値や変数、もしくは演算式や関数などを与えると、きちんとint型に型変換して評価してくれます。
演算式や関数の場合は、その返り値に対して同様の評価が行われます。このため、単純な例ですが、以下のような事も可能です。
$count = 0;
while (true) {
echo "start\n";
while (true) {
echo "one\n";
while (true) {
echo "two\n";
while (true) {
echo "three\n";
while (true) {
echo "four : $count\n";
break $count++;
}
}
}
}
}
echo"end : count = $count \n";
結果:=======================
start
one
two
three
four : 0
three
four : 1
three
four : 2
two
three
four : 3
one
two
three
four : 4
start
one
two
three
four : 5
end : count = 6
実際に例のような深いネスト構造がスクリプト中に現れるのは、あまり良い事ではありません。
ですが、breakの引数にユーザー定義関数を配置することも可能であることを考えば、使い方次第で色々できる気がしてきませんか?
このような柔軟性を、PHPの良いところと見るか悪いところと見るかは、使う人次第でしょう。
しかし、こういう処理が可能なことを知っておくのも、何かの足しになるかもしれませんね。
- PHPマニュアル:continue http://www.phppro.jp/phpmanual/php/control-structures.continue.html
- PHPマニュアル:break http://www.phppro.jp/phpmanual/php/control-structures.break.html
2. PHPのイースターエッグを見つけ出そう
PHPを長年使っている方には結構有名なことですが、PHPを使用しているページに特殊なクエリを渡すと、面白い画像やPHPのクレジットを見ることができます。
- PHP Logo http://php.net/?=PHPE9568F34-D428-11d2-A769-00AA001ACF42
- Zend Logo http://php.net/?=PHPE9568F35-D428-11d2-A769-00AA001ACF42
- PHP Credits http://php.net/?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000
- PHP Logo http://php.net/?=PHPE9568F36-D428-11d2-A769-00AA001ACF42
画像は上記以外にも何種類か存在しており、またバージョンによって表示されるものが違うようです。それらの画像を探してみるのも楽しいかもしれません。
ちなみに、この機能はphp.iniの設定で
expose_php = Off
とすれば、表示されないようになります。
以下マニュアルより
「expose_php(例えば、Web サーバヘッダに PHP のサインを追加することにより、) PHP がサーバにインストールされていることを表示するかどうかを指定します。これは全くセキュリティ上の脅威ではなく、サーバ上 で PHP を使用しているかどうかを調べられるようにするものです。 」
このようにマニュアルには書いてありますが、expose_phpをONにしている場合、HTTPレスポンスヘッダでPHPのバージョンも表示されてしまう為、そのバージョン特有の脆弱性を狙われる可能性がでてきます。また、システム開発や運用の際に、案件によっては問題になる場合もありますので、設定はOFFにすることをお奨めします。
3. HTMLエスケープ方法を見直そう htmlspecialcharsとhtmlentities
HTMLをエスケープする関数にhtmlspecialcharsとhtmlentitiesがあります。この2つの関数の違いをご存知でしょうか。また、意図通りにエスケープ処理を実行する為には第2、第3引数を指定する必要があります。
これらの関数の違いは変換する文字数です。htmlspecialcharsはデフォルトで4つの文字(<、>、&、")をHTML の表現形式に変換します。対して、htmlentitiesはデフォルトで先の4つを含む100個の文字を変換します。より厳密にエスケープしたいなら、 htmlentitiesを使う必要があります。
これらの文字変換テーブルはget_html_translation_table関数で確認して下さい。
しかし、オプションで用意されている引数を指定せずに、これらの関数を使うことは危険です。シングルクォーテーション(')をエスケープしないからです。脆弱性の例として、HTMLタグの属性値をシングルクォーテーションで囲っている場合が考えられます。
<input type='text' name='sample'
value='<?php echo htmlentities($_POST['sample'])?>' />
このような場合、XSS脆弱性が存在し
$_POST['sample'] = "100' onMouseover='alert(\"XSS\")";
とすることでjavascriptが実行されたり、不正なタグが表示されてしまいます。 これを防ぐにはシングルクォーテーションを変換することが必要ですが、第2引 数にENT_QUOTESを指定することで可能になります。また、第3引数で変換に使用 される文字セットを指定して下さい。つまり、意図通りに出力したいなら
htmlentities($str, ENT_QUOTES, mb_internal_encoding())
とする必要があります。ただし、サポートされている文字セットは http://www.phppro.jp/phpmanual/php/function.htmlentities.html の表2に載っているものだけであり、eucJP-win等の場合はEUC-JPで指定する必要があります。
皆さんのコードをもう一度確認してみて下さい。もしかしたら思わぬ所に脆弱性が見つかるかもしれません。
バックナンバーについて
TIPS-MLは、毎週金曜日に更新され、新しい記事が掲載されます。




