投稿日:2023年1月31日

分かりづらいタイトルかと思います。
申し込みフォームとアンケートフォームを作成。
誰がどのような回答をしたかを紐付けたいとの要望がありました。

アンケート回答時に名前を入力すれば良いのでしょうが、打ち間違い、スペースの有無、CSVを結合したりと手作業の工程で手間がかかります。
このような工程を自動化できないか検証してみました。

▲フォームから送信すると。

▲アンケートのURLを記載したHTML確認メールが届きます。
クリックでアンケートフォームに遷移します。
下図のようにURLパラメータでIDと名前を出力するようにしています。

▲Contact form 7の返信メールの内容です。
aタグにはURLパラメータでIDと名前を出力するようにしています。

▲パラメータに仕込んだID値と名前を取得し、入力欄に自動入力する仕様にしています。
パラメータに表示ということがセキュリティ的な不安感を与えてしまうかも知れません。
セッションストレージに一時保存とかも検証してみたいと思います。
また、ユーザーが打ち替えられないように入力欄を非表示にしたり、編集不可にした方が良さそうですね。

▲申し込みフォーム(IDと名前)とアンケートフォーム(感想)のデータをそれぞれのデータベースから取得し、結合表示させたところです。
CSVダウンロードボタンをクリックすると結合したCSVをダウンロードします。

ソースコードです。

<?php
session_start();
?>
<!DOCTYPE html>
<html lang="ja">

<head>
  <!-- 省略 -->
</head>

<body>
  <?php
  $db_user = "xxxxxxxxxx"; //ユーザー名
  $db_pass = "xxxxxxxxxx"; //パスワード
  $db_host = "xxxxxxxxxx"; //ホスト名
  $db_name01 = "xxxxxxxxxx_test"; //申し込みフォームデータベース名
  $db_name02 = "xxxxxxxxxx_enq"; //アンケートフォームデータベース名
  $db_type = "mysql"; //データベースの種類
  $dns01 = "$db_type:host=$db_host;dbname=$db_name01;charset=utf8"; //申し込みフォームデータベース接続準備
  $dns02 = "$db_type:host=$db_host;dbname=$db_name02;charset=utf8"; //アンケートフォームデータベース接続準備

  try {
    // 申し込みフォームデータベースに接続
    $pdo01 = new PDO($dns01, $db_user, $db_pass);
    $pdo01->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo01->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    // アンケートフォームデータベースに接続
    $pdo02 = new PDO($dns02, $db_user, $db_pass);
    $pdo02->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo02->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
  } catch (PDOException $Exception) {
    die('接続エラー:' . $Exception->getMessage());
  }

  //フィールドform_idを取得
  $idStmt = $pdo01->prepare("SELECT form_id FROM wp_db7_forms");
  $idStmt->bindValue(':form_id', 'form_id', PDO::PARAM_INT);
  $idRes = $idStmt->execute();

  //フィールドform_valueを取得(ここに申し込みフォームの情報が格納されている)
  $val01Stmt = $pdo01->prepare("SELECT form_value FROM wp_db7_forms");
  $val01Stmt->bindValue(':form_value', 'form_value', PDO::PARAM_INT);
  $val01Res = $val01Stmt->execute();

  //フィールドform_valueを取得(ここにアンケートフォームの情報が格納されている)
  $val02Stmt = $pdo02->prepare("SELECT form_value FROM wp_db7_forms");
  $val02Stmt->bindValue(':form_value', 'form_value', PDO::PARAM_INT);
  $val02Res = $val02Stmt->execute();

  //フィールドform_post_idを取得 ※固定ページのID
  $postIdStmt = $pdo01->prepare("SELECT form_post_id FROM wp_db7_forms");
  $postIdStmt->bindValue(':form_post_id', 'form_post_id', PDO::PARAM_INT);
  $postIdRes = $postIdStmt->execute();

  //タイムスタンプform_dateを取得
  $timeStampStmt = $pdo01->prepare("SELECT form_date FROM wp_db7_forms");
  $timeStampStmt->bindValue(':form_date', 'form_date', PDO::PARAM_INT);
  $timeStampRes = $timeStampStmt->execute();

  //flagを取得(チェックボックスのflag)
  $flagStmt = $pdo01->prepare("SELECT flag FROM wp_db7_forms");
  $flagStmt->bindValue(':flag', 'flag', PDO::PARAM_INT);
  $flagRes = $flagStmt->execute();

  // lagが1の数(チェックボックスのflag)
  $flagTrueStmt = $pdo01->prepare("SELECT flag FROM wp_db7_forms  WHERE `flag` = '1'");
  // $flagTrueStmt->bindValue(':flag', 'flag', PDO::PARAM_INT);
  $flagTrueRes = $flagTrueStmt->execute();

  if ($idRes && $val01Res && $postIdRes && $timeStampRes && $flagRes && $val02Res) {
    $postIdData = $postIdStmt->fetchAll(PDO::FETCH_COLUMN); //fetchAllじゃないと取得できない
    $val01Data = $val01Stmt->fetchAll(PDO::FETCH_COLUMN); //testのデータベース
    $val02Data = $val02Stmt->fetchAll(PDO::FETCH_COLUMN); // enqのデータベース
    $idData = $idStmt->fetchAll(PDO::FETCH_COLUMN);
    $timeStampData = $timeStampStmt->fetchAll(PDO::FETCH_COLUMN);
    $flagData = $flagStmt->fetchAll(PDO::FETCH_COLUMN);
    $flagTrueData = $flagTrueStmt->fetchAll(PDO::FETCH_COLUMN);

    // ------------------------------------------------------------------------------------------
    // ▼▼▼ 申し込みフォームから出力
    echo ("<table cellspacing='0' id='csvTarget'><tbody id='trWrap'>"); //tableタグ出力
    foreach ($val01Data as $i => $val01Val) { //ループで書き出し
      $id = $idData[$i]; //ID
      $postId = $postIdData[$i]; // 固定ページのID
      $unserializeArr01 = unserialize($val01Val); //アンシリアル化(復元)
      $nameVal01 = $unserializeArr01["your-name"]; //氏名
      $timeStampVal = $timeStampData[$i]; //タイムスタンプ
      $flagVal = $flagData[$i]; //flag
      $flagTrueCnt = count($flagTrueData); //flagが1の数
      // テーブルコンテンツ作成
      echo ('<tr id="id_' . $id . '"><td>' . $id . '</td><td>' . $nameVal01 . '</td><td class="radioBtn"></td><td class="flag" hidden>' . $flagVal . '</td><td><form name="checkForm"><input type="checkbox" name="checkbox"></form></td></tr>'); //table内trを出力
    }
    echo ("</tbody></table>"); //閉じタグ
    // ------------------------------------------------------------------------------------------

    // ------------------------------------------------------------------------------------------
    // ▼▼▼ アンケートフォームから出力
    echo ("<table cellspacing='0' id='csvTarget02' hidden><tbody id='trWrap02'>"); //tableタグ出力(hiddenで非表示)
    foreach ($val02Data as $j => $val02Val) { //ループで書き出し
      $unserializeArr02 = unserialize($val02Val); //アンシリアル化(復元)
      $nameVal02 = $unserializeArr02["your-name_enq"]; //アンケートの氏名
      $receptionId = $unserializeArr02["text-261"]; //受付時のID
      $radioBtn = $unserializeArr02["radio-554"]; // アンケートのラジオボタン
      // テーブルコンテンツ作成
      echo ('<tr class=id__' . $receptionId . '"><td class="idNum">' . $receptionId . '</td><td class="radioBtnResult">' . $radioBtn[0] . '</td></tr>');
    }
    echo ("</tbody></table>"); //閉じタグ
    // ------------------------------------------------------------------------------------------
  }
  ?>

  <!-- ------------------------------------------------------------------------------------------ -->
  <!-- ▼▼▼ HTML -->
  <div id="inputDisplay">
    <div>
      <input name="inputTxt" id="inputTxt" cols="30" rows="10">
    </div>
  </div>

  <form action="">
    <a id="csvBtn">CSVダウンロード</a>
  </form>
  <!-- ------------------------------------------------------------------------------------------ -->


  <script defer src="form.js"></script>

  <script defer>
    let receptionLength = $('#csvTarget02 tr').length;
    $('#receptionLength').text(receptionLength); // アンケート回答数に値を表示
    for (let l = 0; l < receptionLength; l++) {
      let idNum = $('.idNum').eq(l).text();
      let radioBtnResult = $('.radioBtnResult').eq(l).text();
      $('#csvTarget tr .radioBtn').eq(idNum - 1).text(radioBtnResult);
    }
  </script>
</body>

</html>

▲16〜33行目で2つのデータベースの設定、接続を行っています。
22行目のからの try 文でデータベースから取得する内容を設定しています。
タイムスタンプは今回使用しません。
70行目の if 文からそれぞれのデータベースからのタグ出力を行います。ループで登録数分出力します。
97行目、アンケートフォームからの出力は table hidden で非表示にしています。この非表示の table から内容だけを取得し、128行目の script で申し込みフォームの table ID値を照合させ出力する仕様にしています。

form.js 中のCSV書き出しのソースです。

// ▼▼▼ tableからデータを取得
$('#csvBtn').click(function () { // クリックで表示されてるtableの行を絞り込む
  let table = $('#csvTarget tr').map(function (i) {
    return $(this).find('th,td').map(function () {
      return $(this).text()
    });
  });

  // CSVデータ整形
  let csv = table.map(function (i, row) {
    return row.toArray().join(','); // カンマ区切り
  }).toArray().join('\r'); //改行(Mac)

  //▼ゼロパッディング関数
  const zeroPad = (zeroNum) => {
    zeroNum = ('00' + zeroNum).slice(-2);
    return zeroNum
  }
  // タイムスタンプ取得
  let nowDate = new Date();
  let year = nowDate.getFullYear(), //年を取得
    month = nowDate.getMonth() + 1, //月を取得
    date = nowDate.getDate(), //日を取得
    hours = nowDate.getHours(), //時を取得
    minutes = nowDate.getMinutes(), //分を取得
    seconds = nowDate.getSeconds(); //秒を取得
  let timeStamp = '_' + year.toString() + '_' + zeroPad(month.toString()) + zeroPad(date.toString()) + '_' + zeroPad(hours.toString()) + zeroPad(minutes.toString()) + '_' + zeroPad(seconds.toString());

  // Excelの文字化け対策
  let bom = new Uint8Array([0xEF, 0xBB, 0xBF])
  // ダウンロードボタン設置
  let blob = new Blob([bom, csv], {
    type: 'text/csv'
  })
  let url = (window.URL || window.webkitURL).createObjectURL(blob);
  let a = document.getElementById('csvBtn'); // ←jQueryだと動かない。。。
  a.download = timeStamp + '.csv'; // ファイル名はタイムスタンプ
  a.href = url;
});

▲詳細はコメントに書いてある通りです。
タイムスタンプをファイル名として指定の場所に保存します。

まとめ

実際の仕事では項目数はかなり多いです。
多数の項目を書き出したCSVをキレイにまとめらるかが要になってきます。
フォーム作成には、例えば「その他」を選択したら「その他 入力欄」を必須にするとかのロジックも求められます。
これらのロジックも踏襲、トライアル・アンド・エラーを繰り返し、より良いものを作れるよう精進したいと思います。
かつ、少しでも周りの人を幸せにできればと思います。

なお、ソースコードはご自由に使っていただいても構いませんが、不備など起こっても責任は負いませんのでご了承ください。

最後まで読んでいただき、ありがとうございました。

関連記事
Pocket