By Greg Nowak. Last updated 2026-07-06.
CSV imports still sit behind product feeds, finance uploads, CRM migrations, marketplace listings, and supplier handoffs. When they fail, the real cost is usually not the parser. It is duplicated products, bad prices, missing customer data, and operations staff editing spreadsheets by hand before a deadline.
For a business-facing PHP import, the useful question is not “which CSV library is best?” It is “how predictable is the file, and what happens when it is wrong?” If you control the file format, PHP core may be enough. If uploads come from suppliers, customers, or exported spreadsheets, invest in header handling, encoding rules, validation, and useful error messages.
Start with the import contract
Before choosing a parser, define the contract: delimiter, encoding, required headers, optional columns, blank-line behavior, date formats, decimal formats, duplicate handling, and failure policy. A parser can read rows. It cannot decide whether an empty SKU should block the import, whether an unknown customer should be created, or whether a supplier file should be rejected before anything is written.
| Import situation | Parser to consider | Design around |
|---|---|---|
| Controlled nightly feed with a stable schema | fgetcsv() |
Explicit delimiter, enclosure, escape, and row validation |
| Large recurring internal job | SplFileObject |
Streaming, empty rows, logging, and resumable processing |
| Client-facing upload or supplier workflow | league/csv |
Headers, encoding, BOMs, missing fields, and clear feedback |
| Messy one-off intake or data triage | ParseCsv | Convenience features, delimiter detection, and PHP-version testing |
Use PHP core when the file is stable
For a scheduled import where you control the export, fgetcsv() is still a good default. It streams row by row, avoids a dependency, and keeps memory use predictable. The important current detail is the escape parameter. As of PHP 8.4, relying on its default value is deprecated, and PHP recommends setting it explicitly. For portable CSV behavior, set it to an empty string and use doubled quotes for quotes inside quoted fields.
<?php
$handle = fopen('/path/to/import.csv', 'r');
while (($row = fgetcsv($handle, 0, ',', '"', '')) !== false) {
if ($row === [null]) {
continue;
}
// Map fields, validate business rules, then persist.
}
fclose($handle);This is strongest when the import is internal, the file shape is known, and failures can be handled by developers or operations staff who understand the feed.
Use SplFileObject for recurring backend jobs
SplFileObject gives you a cleaner iterator-based structure for long-running jobs. It is a good fit for imports that need progress logging, batching, or a service class around the file reader. Set CSV controls explicitly, and do not leave blank-line behavior to chance.
<?php
$file = new SplFileObject('/path/to/import.csv', 'r');
$file->setCsvControl(',', '"', '');
$file->setFlags(
SplFileObject::READ_CSV
| SplFileObject::READ_AHEAD
| SplFileObject::SKIP_EMPTY
| SplFileObject::DROP_NEW_LINE
);
foreach ($file as $row) {
if ($row === false || $row === [null]) {
continue;
}
// Validate, normalize, and import in small batches.
}Use League CSV when the workflow is messy
For a client admin panel, agency handover, or supplier upload flow, league/csv is usually the first package I would evaluate. Its current documentation covers reader objects, header offsets, normalized records, empty-record handling, stream filters, and BOM behavior. That matters because real imports often fail on UTF-16 files, duplicate headers, missing columns, or extra values that looked harmless in a spreadsheet.
composer require league/csv:^9.28.0<?php
use League\Csv\Reader;
$csv = Reader::from('/path/to/file.csv', 'r');
$csv->setHeaderOffset(0);
foreach ($csv->getRecords() as $offset => $record) {
// Associative array keyed by the header row.
}League CSV is not just a nicer loop. It gives the importer a better place to express business expectations: required headers, duplicate-header failures, column normalization, and encoding conversion when spreadsheets are involved.
Use ParseCsv as a convenience tool, not the whole strategy
ParseCsv still has a useful place when you are exploring inconsistent supplier files. Its README highlights automatic delimiter detection, encoding conversion, offset and limit options, and simple data manipulation. That can save time during intake and triage.
composer require parsecsv/php-parsecsvI would be more cautious about making it the foundation of a new long-lived platform. Treat it as a practical utility, and test it explicitly against your target PHP version before putting it in a core billing, reporting, or product-data path.
Make bad files easy to fix
The best import systems are strict in code and helpful in the interface. Show which row failed, which field is wrong, what format was expected, and whether any data was written. Keep the original uploaded file, log the parser settings used, and make imports idempotent where possible so a corrected file can be safely retried.
If your team needs a CSV import flow that business users can trust, Greg can help design the parser choice, validation rules, admin workflow, and failure handling. Talk to Greg about a dependable import workflow.
Related on GrN.dk
- AI automations need a spend dashboard before the first runaway bill
- ChatGPT apps need a permissions map before they touch company data
- Debugging PHP: Practical Steps for Faster Fixes
Need help with this kind of work?
Get help with a reliable CSV import workflow Get in touch with Greg.