Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Colibri Csv Laravel Package

csanquer/colibri-csv

Colibri CSV is a lightweight, fast PHP library for reading and writing CSV files. It offers a fluent object-oriented API, streamed iteration for large files, and configurable delimiters, enclosures, and encodings, working standalone or in any PHP project.

Deep Wiki
Context7

Getting Started

Install with Composer. The package is csanquer/colibri-csv and exposes a small Colibri\ namespace (CsvReader, CsvWriter, and a shared AbstractCsv base class):

composer require csanquer/colibri-csv

Where to look first:

  1. README.md — the examples cover 90% of real usage.
  2. src/Colibri/CsvReader.php — iterator behavior and the setter surface.
  3. src/Colibri/AbstractCsv.php — stream, delimiter, enclosure, and encoding handling shared by both reader and writer.

First use case — read a delimited export row by row:

use Colibri\CsvReader;

$reader = new CsvReader(storage_path('app/imports/customers.csv'));
$reader->setDelimiter(';')
       ->setEnclosure('"')
       ->setEncoding('ISO-8859-1'); // source encoding; converted internally
// $reader->setSkipHeader(true);

foreach ($reader as $row) {
    // $row is a plain array of fields
    [$id, $name, $email] = $row;
}

The reader is an iterator, not an array-returning loader, so it streams the file and gives you constant-ish memory for large imports. Write your first transform (read → map → write) and you will have exercised the whole package.

Implementation Patterns

Streaming import into a Laravel command. Wrap the reader in an artisan command and flush in chunks. Because iteration is lazy, a 500k-row file does not have to fit in memory:

foreach ($reader as $i => $row) {
    if ($i === 0) { continue; } // or use the header-skip setter
    Customer::updateOrCreate(['id' => $row[0]], ['name' => $row[1]]);
    if ($i % 1000 === 0) { /* gc / progress output */ }
}

Header-aware processing. The package returns indexed arrays, so map headers manually. Read the first row as the header, then iterate the rest:

$iterator = $reader->getIterator();
$headers  = $iterator->current(); // or rewind + current
$iterator->next();

foreach ($iterator as $row) {
    $record = array_combine($headers, $row);
    // $record['email'], ...
}

This also lets you validate required columns before processing any data.

Chunked / paginated reads. Use the offset and limit setters (exposed on the reader) to process a slice at a time — useful for resumable queue jobs where each job handles N rows:

$reader->setOffset($job->offset())->setLimit(5000);

Persist the new offset after the job commits so a retry is idempotent.

Writer for exports. The mirror pattern: build a CsvWriter, configure delimiter/enclosure to match the consumer (Excel in some locales wants ;), and write rows:

use Colibri\CsvWriter;

$writer = new CsvWriter(storage_path('app/exports/report.csv'));
$writer->setDelimiter(';')->setEnclosure('"');
$writer->writeLine(['id', 'name', 'email']);
foreach ($rows as $row) {
    $writer->writeLine([$row->id, $row->name, $row->email]);
}

For direct downloads, point the writer at php://output (via stream) inside a response callback instead of writing to disk — that avoids the temp file entirely.

Streams over paths. Both reader and writer accept resources. That makes php://temp, php://memory, and remote streams (S3 via a wrapped stream) usable for tests:

$fh = fopen('php://temp', 'r+');
fwrite($fh, "a,b\n1,2\n"); rewind($fh);
$reader = (new CsvReader())->setStream($fh);

This is the cleanest way to unit-test CSV logic without fixtures on disk.

Laravel integration tips. Keep the parsing in a dedicated service/importer class and inject the path or stream; that isolates the dependency and makes swapping to league/csv trivial if you ever need to. Run large imports through a queued job and emit progress events per chunk. Use Storage::path() / Storage::readStream() to feed the reader so it works across local and S3 disks.

Gotchas and Tips

  • GPL-3.0 is the headline risk. This is copyleft. Linking it into a proprietary Laravel application is generally not acceptable to legal teams; if your product is closed-source, prefer league/csv (MIT). Evaluate the license before writing code around it.
  • It is an old, low-activity package. PHP 5.4-era code, ~16 stars. Audit it for PHP 8 compatibility. In particular, PHP 8.4 deprecates relying on the default $escape argument of fgetcsv/fputcsv/str_getcsv; if the package passes those implicitly you will see deprecation notices. Consider E_DEPRECATED filtering or contributing a patch.
  • UTF-8 BOM. A BOM at the start of the file ends up in the first field of the first row. Strip \xEF\xBB\xBF from the first value before validating headers.
  • Encoding conversion needs iconv/mbstring. The source-encoding setter relies on them; malformed bytes can silently corrupt fields or throw. Verify the extension is installed and validate a sample before batch processing.
  • Delimiter defaults are comma. Tab-separated files need an explicit setDelimiter("\t"); semicolon exports need ;. Wrong delimiter produces single-column rows silently — assert the column count on the first row.
  • Trailing empty columns. fgetcsv (what the reader wraps) returns null for trailing empty fields, so count($row) can vary row to row. Normalize with array_pad or validate before array_combine.
  • Blank lines. Depending on configuration, blank lines come back as [null] or empty arrays. Skip them explicitly or enable the package's blank-line option, but confirm its behavior with a fixture — don't assume.
  • No type casting or header mapping built in. Everything is strings. Cast integers/booleans/decimals yourself, and coerce "null"/empty strings deliberately.
  • Writer quoting is fputcsv-style. It quotes when necessary, which can surprise downstream consumers expecting everything quoted. If your target requires forced quoting, the writer's fixed behavior will fight you — post-process or build a custom wrapper.
  • File locking. The writer does not coordinate concurrent writers. If multiple queue workers can target the same export path, add unique temp names and rename atomically.
  • Track row numbers for errors. The iterator gives you values, not line numbers. Maintain your own counter and include it in exception messages — CSV import failures without a row number are miserable to debug.
  • Extension points are thin. The classes are small and largely final-behavior; you generally extend by decorating (CsvReader inside your own importer, transforming rows in your layer) rather than subclassing internals. Keep parsing logic in one adapter class so the swap to another library is a one-file change.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource