CSVインポート機能でエラーが頻発していませんか?メモリ不足、文字化け、処理タイムアウトなど、実案件で遭遇した問題と解決法を詳しく解説します。
CSVインポートでこんな問題に悩んでいませんか?
「商品データのCSVインポートで毎回エラーが発生する」「大容量ファイルで処理が止まってしまう」「文字化けでデータが正しく登録されない」
Laravelで管理システムを構築する際、CSVインポート機能は必須の機能ですが、実際に運用を始めると様々な問題に直面します。横浜のWeb制作会社として20年以上の実績を持つ私たちも、多くのクライアントからこのような相談を受けてきました。
今回は、実案件で遭遇したCSVインポートの失敗事例と、確実に動作する解決法をご紹介します。
実案件で遭遇した典型的な失敗パターン
パターン1:メモリ不足でシステムが止まる
あるECサイトのクライアントでは、5万件の商品データをインポートする際、毎回「Fatal error: Allowed memory size」エラーが発生していました。
原因: 一度に全データを配列に読み込んでいた
// ❌ NGパターン:メモリを大量消費
$csvData = array_map('str_getcsv', file('large_file.csv'));
foreach ($csvData as $row) {
Product::create($row);
}
解決策: チャンク処理とキューを組み合わせる
// ✅ OKパターン:少しずつ処理
use League\Csv\Reader;
use Illuminate\Support\LazyCollection;
public function importCsv($filePath)
{
$csv = Reader::createFromPath($filePath, 'r');
$csv->setHeaderOffset(0);
LazyCollection::make(function () use ($csv) {
foreach ($csv as $record) {
yield $record;
}
})
->chunk(100) // 100件ずつ処理
->each(function ($chunk) {
ProcessCsvChunk::dispatch($chunk->toArray());
});
}
この改善により、10万件のデータも安定してインポートできるようになり、「システムが止まる心配がなくなった」とお客様から喜ばれています。
パターン2:文字化けでデータが破損
製造業のクライアントでは、日本語の製品名が「???」に化けて登録される問題が発生していました。
原因: 文字エンコーディングの自動判定に失敗
解決策: エンコーディングを明示的に指定
// ✅ 文字化け対策
public function detectEncoding($filePath)
{
$content = file_get_contents($filePath);
$encoding = mb_detect_encoding($content, ['UTF-8', 'SJIS', 'EUC-JP'], true);
if ($encoding === 'SJIS') {
$content = mb_convert_encoding($content, 'UTF-8', 'SJIS');
file_put_contents($filePath, $content);
}
return $encoding;
}
パターン3:処理時間がかかりすぎてタイムアウト
解決策: キューワーカーとプログレスバーの実装
// Job側の実装
class ImportCsvJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
$totalRows = count($this->data);
foreach ($this->data as $index => $row) {
// データ処理
Product::create($this->formatData($row));
// 進捗更新
$progress = round(($index + 1) / $totalRows * 100);
Cache::put('import_progress_' . $this->importId, $progress, 3600);
}
}
}
バリデーションでデータ品質を保証する
実際の運用では、不正なデータが含まれるケースが多発します。事前のバリデーションは必須です。
// ✅ 堅牢なバリデーション
public function validateCsvData($data)
{
$rules = [
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
'email' => 'nullable|email',
];
$errors = [];
foreach ($data as $rowIndex => $row) {
$validator = Validator::make($row, $rules);
if ($validator->fails()) {
$errors[] = [
'row' => $rowIndex + 2, // ヘッダー行を考慮
'errors' => $validator->errors()->all()
];
}
}
if (!empty($errors)) {
throw new ValidationException('CSV validation failed', $errors);
}
}
よくある失敗と注意点
失敗例1:エラーハンドリングの不備
「インポート中にエラーが発生したが、どの行で失敗したかわからない」という相談をよく受けます。
// ✅ 詳細なエラーログ
try {
$this->processRow($row);
} catch (Exception $e) {
Log::error('CSV Import Error', [
'row' => $rowNumber,
'data' => $row,
'error' => $e->getMessage(),
'file' => $fileName
]);
// エラー行をスキップして続行するかどうかの制御
if ($this->stopOnError) {
throw $e;
}
}
失敗例2:重複データの考慮不足
// ✅ 重複チェックとupsert処理
Product::upsert(
$dataArray,
['sku'], // ユニークキー
['name', 'price', 'updated_at'] // 更新対象カラム
);
システム改善後の成果
これらの対策を実装したクライアントでは以下のような成果が得られています:
- 処理時間の短縮: 10万件のインポートが2時間から30分に短縮
- エラー率の改善: インポート失敗率が30%から1%以下に改善
- 運用負荷の軽減: エラー調査に費やす時間が大幅に削減
- データ品質の向上: バリデーションにより不正データの混入を防止
まず取り組むべきこと
CSVインポート機能を安定化させるために、まず以下の点を確認してください:
- 現在のメモリ使用量を確認 -
memory_get_peak_usage()で実測 - 処理対象データのサイズを把握 - 1回でどの程度の件数を扱うか
- エラーログの整備 - 問題発生時の調査ができる体制作り
- テストデータでの検証 - 本番前の十分なテスト実施
横浜を拠点とする私たちFivenine Designでは、Laravel管理システムの構築・改善を多数手がけてきました。CSVインポート機能でお困りの際は、実績豊富な技術チームがサポートいたします。安定した業務システムの構築をご検討の方は、お気軽にご相談ください。