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

Php Parsecsv Laravel Package

parsecsv/php-parsecsv

ParseCsv is a lightweight PHP library for reading, parsing, and writing CSV files with a simple API. It supports custom delimiters, enclosures, encodings, header mapping, filtering, sorting, and large-file handling, making CSV import/export straightforward in PHP and Laravel projects.

Deep Wiki
Context7

Getting Started

Install with Composer; there is no Laravel service provider or facade to register:

composer require parsecsv/php-parsecsv

The package is framework-agnostic. The class you will use nearly every time is ParseCsv\Csv. Start by reading src/Csv.php and focusing on:

  • parse(), parseString(), and auto()
  • $csv->data, $csv->titles, and $csv->rowcount
  • public tuning properties such as $delimiter, $enclosure, $heading, $offset, $limit, $conditions, $sort_by, and $sort_reverse

The quickest useful pattern is importing an uploaded CSV into an array:

use ParseCsv\Csv;

$csv = new Csv();
$csv->auto(Storage::path('imports/users.csv'));

$headers = $csv->titles; // first row when heading = true
$rows    = $csv->data;   // associative rows keyed by header

For an uploaded file, avoid writing to disk when possible:

$csv = new Csv();
$csv->parseString($request->file('csv')->get());

foreach ($csv->data as $row) {
    // $row['email'], $row['name'], etc.
}

Use auto() when you do not control the file source. It attempts to detect encoding and delimiter. Use parse() or parseString() when you know the format and want deterministic behavior. A good first production use case is a small admin import: read a CSV, validate each row with Laravel’s validator, transform it into a DTO/array, and dispatch inserts in a transaction or queue.

Implementation Patterns

Wrap the parser in an application-level importer. The library is stateful and exposes public properties, so keep it behind a small class rather than scattering property assignments through controllers:

final class CsvUserImporter
{
    public function handle(string $path): array
    {
        $csv = new Csv();
        $csv->auto($path);

        $valid = [];
        $errors = [];

        foreach ($csv->data as $index => $row) {
            $line = $index + 2; // account for header row
            $validator = Validator::make($row, [
                'name'  => 'required|string|max:255',
                'email' => 'required|email',
            ]);

            if ($validator->fails()) {
                $errors[$line] = $validator->errors()->all();
                continue;
            }

            $valid[] = $validator->validated();
        }

        return compact('valid', 'errors');
    }
}

Normalize headers before trusting them. Real CSVs have headers like E-mail Address, email, or duplicate names. When heading = true, the parser keys $csv->data by the header row. If you need canonical keys, either map rows manually or parse without headers and handle the first row yourself:

$csv = new Csv();
$csv->heading = false;
$csv->parseString($contents);

$rawHeaders = array_shift($csv->data);
$headers = array_map(fn ($h) => Str::slug(trim($h), '_'), $rawHeaders);

$rows = array_map(fn ($row) => array_combine($headers, $row), $csv->data);

Use built-in filtering and sorting for simple reports. Conditions and sorting are applied during parsing, which is convenient for small files:

$csv = new Csv();
$csv->conditions = [
    ['field' => 'status', 'value' => 'active'],
    ['field' => 'created_at', 'value' => '2024-01-01', 'operator' => '>='],
];
$csv->sort_by = 'last_name';
$csv->sort_reverse = false;
$csv->parse($path);

Batch large imports with offset and limit. The parser loads the whole file into $csv->data, so memory is the limiting factor. For moderately large files, process windows:

$offset = 0;
$batchSize = 500;

do {
    $csv = new Csv();
    $csv->offset = $offset;
    $csv->limit = $batchSize;
    $csv->parse($path);

    foreach ($csv->data as $row) {
        // process one batch
    }

    $offset += $batchSize;
} while (count($csv->data) === $batchSize);

This still re-reads the file for each batch in most cases. If files are very large, use fgetcsv() or league/csv with generators instead.

Export by setting titles and data, then call save(). This is useful for generated reports:

$csv = new Csv();
$csv->titles = ['Name', 'Email', 'Created'];
$csv->data = $users->map(fn ($user) => [
    'name'    => $user->name,
    'email'   => $user->email,
    'created' => $user->created_at->toDateTimeString(),
])->all();

$csv->save(storage_path('app/exports/users.csv'));

For an HTTP download in Laravel, prefer streamDownload() over the package’s output helper so Laravel controls headers:

return response()->streamDownload(function () use ($csv) {
    $csv->save('php://output');
}, 'users.csv', ['Content-Type' => 'text/csv']);

Use it as a parsing step, not as your domain layer. A good workflow is: parse CSV → normalize headers → validate rows → map to DTOs → persist. Keep the Csv object local to the parsing method so its mutable state cannot leak between requests or queued jobs.

In queues, pass the file path, not the parsed data. Serializing $csv->data for large files bloats jobs. Store the file in storage/app/imports, pass an ID/path to the job, and let the job parse it.

Gotchas and Tips

  • The package is low-activity. The last release was 2021. Treat it as a stable utility, pin the version in composer.json, and isolate it behind an adapter if the import/export flow is important. For complex CSV requirements, compare against league/csv or Laravel Excel before committing.
  • The object is stateful. $csv->conditions, $offset, $limit, $sort_by, and related properties persist on the instance. Reusing one instance for multiple files can produce surprising results. Create a new Csv per parse.
  • auto() is a heuristic. It guesses delimiter and encoding from the file. Semicolon-separated exports, tab-delimited files, or malformed first rows can confuse it. If you control the format, set $csv->delimiter = ';' explicitly and call parse().
  • Excel exports often include a UTF-8 BOM. auto() generally copes better than raw parsing, but if the first header looks like \xEF\xBB\xBFemail, strip the BOM or normalize the first title. For Windows-1252 files, convert to UTF-8 before or during parsing using the encoding-related properties or mb_convert_encoding().
  • Header keys are not normalized. $csv->titles and the keys in $csv->data are exactly what the file contains. Duplicate, empty, or whitespace-padded headers cause missing or overwritten columns. Validate headers up front and fail fast with a clear error.
  • Ragged rows are possible. Rows with fewer columns than the header produce missing keys; rows with extra columns may be ignored or produce unexpected keys. Validate count($row) or map positionally when consistency matters.
  • Large files are memory-bound. $csv->data is a full in-memory array. A 100 MB CSV can easily become hundreds of MB as PHP arrays. Use batching only for modest files; switch to a streaming parser for large uploads.
  • CSV injection is a real export risk. If users control exported values, cells beginning with =, +, -, or @ can execute in spreadsheet software. Sanitize before saving:
$value = preg_match('/^[=+\-@]/', (string) $value) ? "'" . $value : $value;
  • Quoted newlines need testing. The parser handles enclosed fields, but multiline cell values and mixed line endings are common failure points. Add fixture tests for \r\n, \n, quoted commas, and embedded newlines.
  • save() and output buffering can conflict in Laravel. Avoid calling a method that emits headers after Laravel has started the response. Use response()->streamDownload() and write to php://output, or generate the file and return a Storage::download() response.
  • Numbers and dates remain strings. The parser does not infer types. Cast IDs, decimals, booleans, and dates explicitly after parsing; be careful with leading-zero values such as ZIP codes and phone numbers.
  • Watch PHP-version deprecations. CSV functions around escape parameters have changed across PHP 8.x releases. If you see deprecation notices from str_getcsv() or fgetcsv() internals, suppress or patch carefully, and run your test suite on the PHP version used in production.
  • The extension surface is limited. There are few interfaces or events. If you need custom behavior, subclass ParseCsv\Csv or, more maintainably, wrap it in your own CsvReader/CsvWriter adapter so a future replacement does not ripple through the codebase.
  • Test with parseString(). It avoids filesystem fixtures and makes importer tests fast and deterministic:
$csv = new Csv();
$csv->parseString("name,email\nJane,[email protected]\n");
$this->assertSame('Jane', $csv->data[0]['name']);
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.
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
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core