連想配列のキーも値もまとめてhtmlspecialchars()でサニタイズする関数の作成解説
2017/06/16
連想配列のキーも値もまとめてhtmlspecialchars()でサニタイズ
PHPの配列・連想配列のキーと値を一括してサニタイズする関数
PHPの配列の値に対して一括で htmlspecialchars()関数を実行し、値のサニタイズ(無害化、無毒化)を行う方法を解説します。
また、配列の値だけではなく、連想配列のキーに対してもサニタイズ(無害化、無毒化)を行っています。
PHPの配列・連想配列のキーと値を一括してサニタイズする関数のサンプルソースコード
// 連想配列をサニタイズする関数
function mysanitize ( $input ) {
$_input = array ();
foreach ( $input as $key => $val ) {
if ( is_array ( $val ) ){
$key = htmlspecialchars ( $key );
$_input[$key] = mysanitize ( $val );
} else {
$key = htmlspecialchars ( $key );
$_input[$key] = htmlspecialchars ( $val );
}
}
return $_input;
}
// 入力される連想配列
$array = array ( "aaa" => "aaa", "bbb" => "<a href=bbb>bbb</a>", '<a href="#ccc">ccc</a>' => '<a href="#ccc">ccc</a>' );
$array_h = mysanitize ( $array );
// サニタイズした結果を表示
print_r ( $array_h );
PHPの配列・連想配列のキーと値を一括してサニタイズする関数の解説
配列(連想配列)を引数に関数を実行すると、配列のキーと、値に対して一括して htmlspecialchars()関数を実行し、サニタイズ(無害化、無毒化)を行った結果を返す関数です。
クロスサイトスクリプティング(XSS)の対策のために htmlspecialchars()関数でサニタイズ(無害化、無毒化)を行いますが、この関数では、配列(連想配列)に対しても一括して処理を実行することができます。
見てもらえばわかると思いますが、foreach文でグルグル回しながら、入力値が配列であれば、改めて「mysanitize()」関数を呼び出し、さらに foreach文を実行して階層を深堀していく、という処理になっています。
配列でなければ「htmlspecialchars()」関数でサニタイズを実行します。
また、連想配列のキーもサニタイズを実行しています。
連想配列のキーも値もまとめてサニタイズする処理を作った経緯
この記事を書くきっかけになったのは、下記のツールを作成したことでした。
JSONの値のデコードツール
XMLを配列に変換するツール
そして、そのツールの解説記事として下記の記事を書きました。
JSON形式の値を配列形式に変換・PHPでは json_decode()、json_encode()
XML形式の値を配列形式に変換・PHPでは simplexml_load_string()
SMTP Mailerでスパム判定回避。WP Mail SMTPで発生する送信エラーも対応
作成したツールは、入力された JSON形式のデータ、XML形式のデータを配列に変換するという単純なツールなのですが、単純なツールだからと言ってもセキュリティホールを放置するわけにはいかないわけですので、サニタイズの対応を行うことにしました。
ですが、簡易的なツールですので、「json_decode()」関数、「simplexml_load_string()」関数で生成した配列を、そのまま「print_r()」で出力しているだけのツールでした。
そのため、「json_decode()」関数、「simplexml_load_string()」関数で生成した配列を何とかまとめてサニタイズを行う方法を実装しないと、JSON形式、XML形式の変換ツールなのにサニタイズの処理の方が大きくなってしまう、と思ったわけです。
そして出来上がったのが、このサニタイズの関数です。
まぁ、結果的にはサニタイズ処理の方が大きな処理ですし、実装にははるかに悩みましたが...
array_map()を利用してサニタイズする方法
最初は、下記のようなサニタイズの処理を書いていました。
ですが、これだと配列の値のサニタイズは問題なくできるのですが、連想配列の場合は、キーに対しては全く無防備だということが確認できました。
function mysanitize ( $string ) {
if ( is_array ( $string ) ) {
return array_map ( "mysanitize", $string );
} else {
return htmlspecialchars ( $string, ENT_QUOTES );
}
}
$array = array ( "aaa" => "aaa", "bbb" => "<a href=bbb>bbb</a>", '<a href="#ccc">ccc</a>' => '<a href="#ccc">ccc</a>' );
$array_h = array_map ( 'mysanitize', $array );
print_r ( $array_h );
そのため、下記の様に修正をしてみました。
function mysanitize ( $key, $value ) {
if ( is_array ( $value ) ) {
return array_map ( "mysanitize", array_keys ( $value ), array_values ( $value ) );
} else {
$output[htmlspecialchars ( $key, ENT_QUOTES )] = htmlspecialchars ( $value, ENT_QUOTES );
return $output;
}
}
$array = array ( "aaa" => "aaa", "bbb" => "<a href=bbb>bbb</a>", '<a href="#ccc">ccc</a>' => '<a href="#ccc">ccc</a>' );
$array_h = array_map ( 'mysanitize', array_keys($array), array_values($array) );
print_r ( $array_h );
この方法でも一応、連想配列のキーもサニタイズできてはいますが、結果が想定しているものとは違う状態になりまして、実用には耐えうることができないと判断するに至りました。
「array_map()」関数は「指定した配列の要素にコールバック関数を適用する」関数ですので、連想配列のキーに対する処理は想定していないからであろう、と思います。
もう少しどうにかすれば...という感じもしましたが、下記のサイトに『「array_map()」関数を使うより、foreach文を使おう!』と書いてありましたので、上記の処理はあきらめて、記事の最初に載せた foreach文で実行する方法を採用することにしました。
http://qiita.com/tadsan/items/bfd1acb7c35a9a6fe452
他にこんな簡単な方法があるよ!というのがあると教えていただけると幸いです。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-
-
PHPのデバッグで使う print_r、var_dump、var_exportの動作の違い
PHPのデバッグ等で変数や配列の中身を確認するために使用する関数print_r、var_dump、var_exportの動作の違い、仕様の違いについて確認した。var_exportがオススメ。
-
-
ECCUBE mtb_constants initパラメータ設定の項目を追加する方法
ECCUBEのパラメータ設定で設定できる項目を追加する方法を説明します。
-
-
数値文字参照コード変換ツール(HTML特殊文字コード変換ツール)
テキストを数値文字参照コード(特殊文字コード)に変換するツール。テキストを数値文字参照コードに簡単変換。数値文字参照、文字実体参照、特殊文字などの違いも解説。
-
-
PHP range関数を使って階乗と重複組み合わせを計算
PHPの range関数を使って階乗と重複組み合わせを計算し、それを元に乱数発生器を作成しました。
-
-
ECCUBEのポイント設定、ポイント付与率を一括で変更する方法解説
ECCUBEの商品個別に設定してあるポイントを一括で変更する方法を解説。ECCUBEには商品個別のポイントを一括して変更する機能がありません。SQLを作成して一括置換!
-
-
PHP画面が真っ白 header(“Location: $url”);
PHPの開発で header(“Location: $url”);を使うと画面が真っ白になる不具合が出る場合もあります。
-
-
ECCUBEの新規追加ページがInternal Server Error・Not Foundに
ECCUBEで新規追加したページがInternal Server Errorに!原因はファイルのパーミッションの場合が多くその対処方法とプログラムの修正ポイントを解説。Not Foundも解説。
-
-
路線・駅検索をPHPで実装する方法解説。GoogleMapsの緯度経度から計算し検索
路線・駅検索の仕組みの構築は大変。登録する側も最寄り駅が多い場合は大変。なので簡易に実装するため緯度経度に基づき直線距離を計算する処理を考案して実装して、その処理を解説。
-
-
ECCUBEでアップロードできない。upload_max_filesizeを設定する場所
テンプレートをアップロードする際に発生するエラー「テンプレートファイルがアップロードされていません」の対処方法。これはファイル容量の制限に引っかかっています。
-
-
指定した数で文字列を丸める(n文字目で…にする)関数substr、mb_substr、mb_strimwidthの違い
文字列を指定された数で抜き出すPHPの関数、substr、mb_substr、mb_strimwidthについての解説。似た関数だが引数の指定方法が違ったり、文字数がバイト数か文字数かも違ったり、注意が必要だ。