PHPとJavaScriptは、Web開発においてよく一緒に使われるプログラミング言語です。PHPはサーバーサイドでデータ処理を行い、その結果をJavaScriptに渡してクライアントサイドで利用することが多々あります。しかし、データの受け渡しには注意が必要です。受け渡し方によっては予期しないエラーや脆弱性につながる場合があります。この記事ではPHPで生成された値をJavaScriptで安全かつ確実に受け渡す方法を紹介します。
受け渡し方法の大まかな流れは次です。プリミティブな値や配列、データのみのオブジェクトは結構楽にやれます。リソース型や何がしかのインスタンスは頑張って JavaScript 上で過不足なく使える JSON を生成する所からスタートです。
- PHPでデータを生成し、JSON形式にエンコードする。
- HTMLのデータ属性(`data-*`)を使って、JSONデータを埋め込む。この時 htmlspecialchars でエラーや脆弱性を防ぐ
- JavaScriptでデータ属性からJSONデータを取得し、デコードしてオブジェクトに変換して利用する。
実装手順です。
まず、PHPでデータを生成し、JSON形式にエンコードします。
<?php $raw = [ 'key1' => '`1', 'key2' => '\\2', 'key3' => '\\\\3', 'key4' => '"4', 'key5' => '\'5', 'key6' => '<6', 'key7' => '>7', ]; $json = json_encode($raw); ?>
次にHTMLの属性を使ってJSON形式にエンコードしたを埋め込みます。ここではデータ属性(data-*)を使用しています。データ属性の他には meta タグの content 属性が HTML のセマンティクスを守りつつ使えておすすめです。
データ属性の使用 – ウェブ開発を学ぶ | MDN
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>PHP data in JavaScript</title> </head> <body> <!-- PHPで生成した値をデータ属性に埋め込む --> <!-- htmlspecialcharsを使うことで不等号、クォーテーション混じりの文字列によるエラーやXSSを防ぐ --> <div id="php-data" data-json='<?php echo htmlspecialchars($json, ENT_QUOTES, "UTF-8"); ?>' style="display:none;"></div> <!-- Laravel組み込みのテンプレートエンジンであるBladeを使うなら次の様になる --> <!-- <div id="php-data" data-json='{{ $json }}' style="display:none;"></div> --> <!-- JavaScriptファイルを読み込む --> <script src="script.js"></script> </body> </html>
最後に、JavaScriptでデータ属性からJSONデータを取得し、デコードしてオブジェクトに変換して利用します。
// script.js document.addEventListener('DOMContentLoaded', function() { // データ属性からJSONデータを取得 var jsonDataElement = document.getElementById('php-data'); var jsonData = jsonDataElement.getAttribute('data-json'); // JSONデータをデコードしてオブジェクトに変換 var data = JSON.parse(jsonData); // 値を利用する console.log(data); // Object { key1: "`1", key2: "\\2", key3: "\\\\3", key4: '"4', key5: "'5", key6: "<6", key7: ">7" } });
この様にして適切なエスケープを行い、PHPからJavaScriptにデータを渡せます。
以下に、JSONデータを正しくエスケープせずに`<script>`タグ内に直接埋め込むアンチパターンを紹介します。これはほとんどのデータで正常に動くのですがエスケープが必要なデータでは期待通りに動きません。適切なエスケープができていればいいのですが、この渡し方に即した htmlspecialchars の様なエスケープ用の関数が PHP に存在しないためエスケープは煩雑になりミスが生まれやすいです。もし適切なエスケープがなされなかった場合、'
"
`
といった文字列リテラルで処理を区切ることによってJavaScriptの構文エラーが起こる可能性があり、区切り方と隙間にいれるコードに次第でXSSもされます。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>PHP data in JavaScript</title> </head> <body> <!-- PHPで生成した値をHTML中に埋め込む(アンチパターン) --> <script> // そのまま JSON データを echo すると ' が含まれるデータでやりたい放題、壊れたい放題になります var jsonData = '<?php echo $json; ?>'; // 文字列リテラルの区切り文字のみエスケープした場合、$raw = "\\';alert('1');'"; のようなデータで壊れます var jsonData = '<?php echo str_replace("'", "\\'", $json); ?>'; // htmlspecialcharsを使った場合、& がそのまま読まれてしまい JSON として不適切なデータと扱われてしまいます var jsonData = '<?php echo htmlspecialchars($json, ENT_QUOTES, "UTF-8"); ?>'; </script> <!-- JavaScriptファイルを読み込む --> <script src="script.js"></script> </body> </html>
この記事では、PHPで生成された値を安全かつ確実にJavaScriptに渡す方法を紹介しました。データ属性を利用してJSONデータを埋め込み、JavaScriptでデータ属性からデータを取得し、デコードしてオブジェクトに変換することで、簡単かつ安全にデータの受け渡しができます。