【PHP】【JavaScript】PHP内の値を安全確実にJavaScriptへ渡して使う方法

 PHPとJavaScriptは、Web開発においてよく一緒に使われるプログラミング言語です。PHPはサーバーサイドでデータ処理を行い、その結果をJavaScriptに渡してクライアントサイドで利用することが多々あります。しかし、データの受け渡しには注意が必要です。受け渡し方によっては予期しないエラーや脆弱性につながる場合があります。この記事ではPHPで生成された値をJavaScriptで安全かつ確実に受け渡す方法を紹介します。

 受け渡し方法の大まかな流れは次です。プリミティブな値や配列、データのみのオブジェクトは結構楽にやれます。リソース型や何がしかのインスタンスは頑張って JavaScript 上で過不足なく使える JSON を生成する所からスタートです。

  1. PHPでデータを生成し、JSON形式にエンコードする。
  2. HTMLのデータ属性(`data-*`)を使って、JSONデータを埋め込む。この時 htmlspecialchars でエラーや脆弱性を防ぐ
  3. 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でデータ属性からデータを取得し、デコードしてオブジェクトに変換することで、簡単かつ安全にデータの受け渡しができます。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG