開発情報・ナレッジ

投稿者: ShiningStar株式会社 2025年9月4日 (木)

CSVファイルをページ上から一括更新するサンプルプログラム

ブラウザ上でCSVファイルを解析し、SPIRALのデータベースに一括更新するサンプルプログラムを紹介します。

注意点

付属のJavaScript CSVパーサーは簡易的なものです。複雑なCSV(改行を含む値など)には対応できない場合があります。
更新先のDB(サンプルでは`csvUpload`)と、CSVの列構成を事前に一致させておく必要があります。
CSVのヘッダー行にはフィールドの差し替えキーワードを入れる必要があります。
$keyName
には更新キーとなるフィールドの識別名及びヘッダーのカラム名と合致した物を入力してください。

実装の概要

このサンプルは、単一のPHPファイル内でクライアント処理とサーバー処理を完結させています。

1. ユーザーがファイル選択フォームでCSVファイルを選ぶ。
2. JavaScriptがファイルを読み込み、ヘッダー行とデータ行に分解してJSON文字列に変換する。
3. 変換したJSONを、フォーム内のhiddenフィールドにセットする。
4. ユーザーが「アップロード」ボタンを押すと、フォームが同じページにPOST送信される。
5. サーバーサイドのPHPがPOSTされたJSONデータを受け取る。
6.
$SPIRAL->doBulkUpdate()
を使用して、データをDBに一括更新する。
7. 処理結果のメッセージを画面に表示する。

サンプルコード

以下がサンプルコードです。この内容でページを作成してください。

<?php //<!-- SMP_DYNAMIC_PAGE DISPLAY_ERRORS=ON NAME=XXX -->?>

<?php
$message = null;
$keyName = "csvId"; //更新キーの識別名を入力してください。

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['columns_json'], $_POST['data_json'])) {
 
    $columns = $_POST['columns_json'];
    $data    = $_POST['data_json'];
    if (is_string($columns)) $columns = json_decode($columns, true);
    if (is_string($data))    $data    = json_decode($data, true);

    try {
        if (!is_array($columns) || !is_array($data)) {
            throw new Exception('columns_json / data_json が配列になっていません');
        }

        $columns = array_values(array_map('strval', $columns));
        $keyPos  = array_search($keyName, $columns, true);
        if ($keyPos === false) throw new Exception("キー列 {$keyName} がヘッダーに存在しません");

        // ヘッダー並べ替え(キー列を先頭)
        if ($keyPos !== 0) {
            [$columns[0], $columns[$keyPos]] = [$columns[$keyPos], $columns[0]];
        }
        $colCount = count($columns);

        // 各行もキー列を先頭へ & 列数をそろえる & 数値添字化
        foreach ($data as &$row) {
            if (!is_array($row)) $row = (array)$row;
            $row = array_values($row);

            // 足りない列は null で埋める/多い場合は切り詰め
            if (count($row) < $colCount) {
                $row = array_pad($row, $colCount, null);
            } elseif (count($row) > $colCount) {
                $row = array_slice($row, 0, $colCount);
            }

            // 並べ替え(元の keyPos と 0 をスワップ)
            if ($keyPos !== 0) {
                [$row[0], $row[$keyPos]] = [$row[$keyPos], $row[0]];
            }

            foreach ($row as $i => $v) {
                if (is_array($v) || is_object($v)) $row[$i] = json_encode($v, JSON_UNESCAPED_UNICODE);
            }
        }
        unset($row);

        $db = $SPIRAL->getDataBase("csvUpload");
        
        foreach (array_chunk($data, 1000) as $chunk) {
        $result = $db->doBulkUpdate($keyName, $columns, $chunk, "skip");
        }
  
        $message = "一括更新完了";
    } catch (Exception $e) {
        $message = "エラー:" . $e->getMessage();
    }
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8"><title>CSV一括更新</title>
</head>
<body>
<?php if ($message): ?>
  <p><?php echo htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); ?></p>
<?php else: ?>
  <form id="csvForm" method="POST">
    <input type="file" id="csvFile" accept=".csv" required>
    <input type="hidden" name="columns_json" id="columnsJson">
    <input type="hidden" name="data_json" id="dataJson">
    <button type="submit">CSVで一括更新</button>
  </form>

  <script>
  (function(){
    'use strict';
    document.addEventListener('DOMContentLoaded', () => {
      const input = document.getElementById('csvFile');
      const columnsEl = document.getElementById('columnsJson');
      const dataEl = document.getElementById('dataJson');
      if (!input || !columnsEl || !dataEl) return;

      input.addEventListener('change', async (ev) => {
        const file = ev.target.files && ev.target.files[0];
        if (!file) return;
        const text = await file.text();
        const parsed = parseCSV(stripBOM(text));
        if (!Array.isArray(parsed) || parsed.length < 2) {
          alert('ヘッダー+1行以上が必要です'); return;
        }
        const columns = parsed[0];
        const data = parsed.slice(1).filter(r => r.some(v => String(v ?? '') !== ''));

        columnsEl.value = JSON.stringify(columns);
        dataEl.value = JSON.stringify(data);
      });
    });

    function stripBOM(s){ return s.charCodeAt(0) === 0xFEFF ? s.slice(1) : s; }

    // ダブルクオート/CRLF対応の簡易CSVパーサ
    function parseCSV(text){
      const rows = []; let row=[], val='', inQ=false;
      for (let i=0;i<text.length;i++){
        const c=text[i], n=text[i+1];
        if (inQ){
          if (c === '"' && n === '"'){ val+='"'; i++; }
          else if (c === '"'){ inQ=false; }
          else { val+=c; }
        } else {
          if (c === '"'){ inQ=true; }
          else if (c === ','){ row.push(val); val=''; }
          else if (c === '\n' || c === '\r'){
            if (c === '\r' && n === '\n') i++;
            row.push(val); val=''; rows.push(row); row=[];
          } else { val+=c; }
        }
      }
      if (val !== '' || row.length) { row.push(val); rows.push(row); }
      return rows;
    }
  })();
  </script>
<?php endif; ?>
</body>
</html>

            

実行結果

ページにアクセスすると、ファイル選択ボタンが表示されます。
CSVファイルを選択して「アップロード」ボタンをクリックするとページがリロードされ、
PHP処理の結果(成功またはエラーメッセージ)が表示されます。

まとめ

本記事では、JavaScriptでCSVを解析し、PHPでSPIRALのDBに更新する一連の流れを解説しました。
実際に活用される際はCSVファイルの中身に応じて適切なパースロジックを実装する必要があります。
解決しない場合はこちら コンテンツに関しての
要望はこちら