Last updated: August 28, 2026.
A scalable CSV import keeps only one row in memory. Validate the header once, reject malformed records with line numbers, and write database changes in controlled batches.
Stream with SplFileObject
<?php
$file = new SplFileObject(__DIR__ . '/customers.csv', 'r');
$file->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY);
$file->setCsvControl(',', '"', '');
$header = $file->fgetcsv();
if ($header !== ['email', 'name', 'country']) throw new RuntimeException('Unexpected header.');
foreach ($file as $row) {
if ($row === [null] || count($row) !== 3) continue;
if (!filter_var($row[0], FILTER_VALIDATE_EMAIL)) continue;
// Persist with a prepared statement.
}Make imports predictable
- Require an explicit delimiter and encoding.
- Log row numbers and rejection reasons.
- Use prepared statements and transaction batches.
- Move long imports to a background job.
Reference: PHP SplFileObject CSV reference.