『詳細 PHP7+MySQL入門ノート』p.272に、「フォームの入力データのチェック」として、以下のようなコードが載っている。
入力フォームを表示する (nameCheckForm.php)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>フォーム入力</title>
<link href="../../css/style.css" rel="stylesheet">
</head>
<body>
<div>
<form method="POST" action="nameCheck.php">
<ul>
<li><label>名前:<input type="text" name="name"></label></li>
<li><input type="submit" value="送信する"></li>
</ul>
</form>
</div>
</body>
</html>
そして、次に nameCheck.php が載っている。
nameCheck.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf=8">
<title>フォーム入力チェック</title>
<link href="../../css/style.css" rel="stylesheet">
</head>
<body>
<div>
<?php
require_once("../../lib/util.php"); <== <1>
// 文字エンコードの検証
if (!cken($_POST)) { <== <2>
$encoding = mb_internal_encoding();
$err = "Encoding Error! The expected encoding is " . $encoding;
// エラーメッセージを出して、以下のコードをすべてキャンセルする
exit($err);
}
// HTMLエスケープ (XSS対策)
$_POST = es($_POST); <== <3>
?>
<?php
// エラーフラグ
$isError = false;
// 名前を取り出す
if (isset($_POST['name'])) {
$name = trim($_POST['name']);
if ($name === "") {
// 空白のときエラー
$isError = true;
}
} else {
// 未設定のときエラー
$isError = true;
}
?>
<?php if ($isError): ?>
<!-- エラーがあったとき -->
<span class="error">名前を入力してください。</span>
<form method="POST" action="nameCheckForm.php">
<input type="submit" value="戻る">
</form>
<?php else: ?>
<!-- エラーがなかったとき -->
<span>
こんにちは、<?php echo $name; ?>さん。
</span>
<?php endif; ?>
</div>
</body>
</html>
このコードでは、<1>で util.php を読み込み、<2>で cken関数を、
<3>で es関数を呼び出している。
util.php
<?php
// (p.267)
// XSS対策のための HTMLエスケープ
function es($data, $charset = 'UTF-8') {
// $data が配列のとき
if (is_array($data)) { <== <4>
// 再帰呼び出し
return array_map(__METHOD__, $data);
} else {
// HTMLエスケープを行う
return htmlspecialchars($data, ENT_QUOTES, $charset);
}
}
// (p.269)
// 配列の文字エンコードのチェックを行う
function cken(array $data) {
$result = true;
foreach ($data as $key => $value) {
if (is_array($value)) {
// 含まれている値が配列のとき文字列に連結する
$value = implode("", $value);
}
if (!mb_check_encoding($value)) {
// 文字エンコードが一致しないとき
$result = false;
// foreachでの走査をブレイクする
break;
}
}
return $result;
}
// ?>
疑問に思うのは、<2> と <3> のところである。
両方とも $_POST 全部を一度でチェックしている。
だから、es関数も、cken関数も、配列にも対応している。
しかし、このやりかたはおかしい。
文字エンコードのチェックはまだいいとしても、HTMLエスケープをチェックしている <3> のところは危険だと思う。
$_POST をHTMLエスケープをして、しかも、$_POST に上書きしている!!!!
こんなこと、絶対やったらあかんことやろ。
データベースに保存するときどうするねん?
es関数の中で、<4>のところで配列に対してエスケープ処理している。
こういう処理を初めて見た。
$_POST をいっぺんでエスケープ処理したいから、こういうことをしているんやな。
ふつう、エスケープ処理は HTMLに表示する間際におこなうから、文字列に対しておこなうことになる。
配列をそのまま表示することはないからなあ。
この本の著者は、初心者を意識しているだろうから、初心者には難しいことは言わず、とりあえず $_POST をエスケープさせようということだろうか。
しかし、これは初心者に対してエスケープ処理についての間違った考え方を教えることになる。
エスケープ処理はHTMLに表示する間際でおこなうことに注意させるべきだろう。
この本はけっこういい本だと思うんだけど、最初の php.ini の設定のところとか、この部分とか、著者の我流で書かれているところがあるので、気をつけて読まなくてはならないなあ。