開発環境(Local)でスクレイピングやAIによるデータ加工を行い、完成したデータを本番環境(VPS)へ反映させる際、数万件規模になると通常のインポート/エクスポートでは手間がかかり、タイムアウトのリスクも伴います。
今回は、PHPのcURLを用いた「チャンク(分割)送信」により、巨大なデータを安全に同期する仕組みを構築しました。
1. 構成の概要
ローカル側に「送信スクリプト」、VPS側に「データ受信用API」を設置します。 一度に全データを送るとサーバーのPOST制限に抵触するため、1,000件ずつの塊(チャンク)にして連続送信するのがポイントです。

2. VPS側:データ受信API (api_sync_db.php)
VPS側のディレクトリ(例: /var/www/html/project/api_sync_db.php)に配置します。
-
役割: 送られてきた分割データを受け取り、DBに書き込む。
-
ポイント: 各テーブルの最初のデータ(
is_first)が届いた時だけTRUNCATE(テーブル初期化)を行い、残りはINSERTしていきます。
<?php set_time_limit(0); // 処理時間を無制限に ini_set('memory_limit', '512M'); // DB接続設定 define('DB_HOST', 'localhost'); define('DB_USER', 'your_user'); define('DB_PASS', 'your_password'); define('DB_NAME', 'your_db_name'); define('SYNC_TOKEN', 'your_secure_token'); // 認証用の合言葉 try { $pdo = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8mb4", DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
} catch (PDOException $e) {
http_response_code(500);
exit('DB Connection Error');
}
// トークンチェック
if (($_POST['token'] ?? '') !== SYNC_TOKEN) {
http_response_code(403);
exit('Forbidden');
}
$table = $_POST['table'] ?? '';
$is_first_chunk = ($_POST['is_first'] === '1');
$rows = json_decode($_POST['data'], true);
try {
$pdo->exec("SET FOREIGN_KEY_CHECKS = 0"); // 外部キー制約を一時解除
if ($is_first_chunk) {
$pdo->exec("TRUNCATE TABLE `$table` "); // 初回のみテーブルを空に
}
if (!empty($rows)) {
$columns = array_keys($rows[0]);
$colNames = "`" . implode("`, `", $columns) . "`";
$placeholders = implode(", ", array_fill(0, count($columns), "?"));
$stmt = $pdo->prepare("INSERT INTO `$table` ($colNames) VALUES ($placeholders)");
foreach ($rows as $row) {
$stmt->execute(array_values($row));
}
}
$pdo->exec("SET FOREIGN_KEY_CHECKS = 1");
echo "Success: Chunk processed for $table";
} catch (Exception $e) {
http_response_code(500);
echo "Sync Error: " . $e->getMessage();
}
3. ローカル側:分割送信スクリプト (db_push_to_vps.php)
XAMPPのプロジェクトルートに配置し、ブラウザまたはCLIから実行します。
-
役割: ローカルDBから全データを取得し、1,000件単位でVPSへPOST。
-
メリット: 万が一途中で失敗しても、どのチャンクで止まったか把握しやすい。
<?php set_time_limit(0); ini_set('memory_limit', '1024M'); // ローカルDB設定 define('L_DB_HOST', 'localhost'); define('L_DB_USER', 'root'); define('L_DB_PASS', '0000'); define('L_DB_NAME', 'your_db_name'); // 送信先URLと設定 $vps_url = "http://your-vps-ip/project/api_sync_db.php"; $token = "your_secure_token"; $chunk_size = 1000; try { $pdo = new PDO("mysql:host=".L_DB_HOST.";dbname=".L_DB_NAME.";charset=utf8mb4", L_DB_USER, L_DB_PASS, [ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
} catch (PDOException $e) {
exit('Local DB Error');
}
// 同期対象テーブル
$tables = ['products', 'actresses', 'genres', 'rewritten_titles', 'product_screenshots'];
foreach ($tables as $table) {
echo "Synchronizing $table...\n";
$stmt = $pdo->query("SELECT * FROM `$table` ");
$all_rows = $stmt->fetchAll();
$chunks = array_chunk($all_rows, $chunk_size);
foreach ($chunks as $index => $chunk) {
$post_data = [
'token' => $token,
'table' => $table,
'is_first' => ($index === 0) ? '1' : '0',
'data' => json_encode($chunk)
];
// cURLで送信
$ch = curl_init($vps_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo "."; // 進捗ドット
}
echo " Done!\n";
}
4. まとめ:なぜこの方法が優れているか
-
タイムアウト回避: 1回のリクエストを小さくすることで、サーバー側の負荷を分散できます。
-
容量制限を突破:
post_max_sizeが8MB程度の標準設定でも、数万件(数十MB分)のデータを確実に送れます。 -
完全同期:
TRUNCATE方式を採用しているため、ローカルで削除したレコードもVPS側に反映されます。
数万件のデータ移動に悩んでいる方は、ぜひこのAPIベースの同期を試してみてください。


コメント