league/csv: reading, filtering and writing CSV in PHP without loading the file into memory
CSV data manipulation made easy in PHP
At a glance
- What is it?
- league/csv is a framework-agnostic PHP library for parsing, querying and writing CSV documents through stream-backed readers and writers. It suits PHP 8.2+ projects that need row-level filtering and typed mapping, and it stops being the right choice when the data is not really CSV.
- Who is it for?
- Adopt league/csv if you are on PHP 8.2 or newer and need to read, filter or write CSV row by row without holding the whole document in memory. Do not adopt it if your actual input is a spreadsheet with formulas, multiple sheets or encoding quirks, or if you only ever parse a handful of tiny files where fgetcsv is enough.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 11 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What league/csv actually takes off your plate
The library describes itself as a way to ease parsing, writing and filtering CSV in PHP, with the stated goal of being powerful while remaining lightweight by using PHP native features where possible. That last part matters more than it sounds. PHP already ships fgetcsv and fputcsv; what it does not ship is a consistent object model around them, header handling, row-level querying, and conversion into JSON, XML or HTML. league/csv fills that gap rather than replacing the C-level parser.
The audience is PHP developers working with tabular exports and imports: order feeds, analytics dumps, migration files, anything that arrives as comma-separated text and needs to be inspected or reshaped before it reaches a database. Because the README calls it framework-agnostic, it is equally usable inside Laravel, Symfony or a plain script. If your project already depends on a framework's own CSV helper, the value here is the query and conversion layer rather than the reading itself.
Streams, readers and writers: the data flow
The README's highlight list is the clearest statement of the architecture: read from and write to CSV documents in a memory efficient and scalable way, with support for PHP stream filtering capabilities. That points to a design built on PHP streams rather than on string concatenation. A reader wraps a stream, yields rows one at a time, and lets you attach filters; a writer takes rows and serialises them back out. Memory use scales with the row you are processing, not with the file size.
The second layer is querying and mapping. The README lists flexible and powerful query features and array to object mapping, which is what turns a stream of string arrays into something you can filter by column and hydrate into objects. The third layer is output: transform CSV documents into JSON, XML or HTML. So the flow is stream in, filter and map in the middle, stream or serialise out. That is a sensible shape, and it is why the library can claim scalability without a custom parser.
One structural detail worth noting from the repository layout: there is a polyfill/ directory alongside src/. That suggests the package carries compatibility shims for older PHP behaviour rather than relying purely on the host runtime. The README does not document what those shims cover, so treat it as a packaging detail rather than a feature.
Installing league/csv and reading a file on the first run
Installation is a single Composer command. The README gives it exactly as follows, and the package name is league/csv:
composer require league/csv:^9.0The constraint ^9.0 is what the README shows. Before you run it, check the version table in the README against your PHP build, because support is version-specific: 9.29.0 requires PHP 8.2.0 as the minimum and supports PHP 8.x, while 9.16.0 still allowed PHP 8.1.2. The README also states you need the ext-filter extension to use Csv, and recommends the latest stable version of PHP.
After installing, the README's guidance on configuration is the part most people skip. Two warnings apply. Starting with PHP 8.4, deprecation notices are triggered if you do not explicitly set the escape parameter. Starting with PHP 8.6, deprecation notices are triggered if you use the package with SplFileObject or SplTempFileObject instances. Both are about the CSV escaping rules changing in PHP itself, and both are documented in the README rather than buried in the changelog.
There is also a legacy-Macintosh tip. If your CSV document was created or read on a legacy Macintosh computer, the README says to add this before using the library, so PHP can detect the line ending:
if (!ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', '1');
}For a first real use, the README does not print a full read example, so the safest path is to follow the documentation site at csv.thephpleague.com, which the README points to as the full documentation. What you should expect from the API surface, based on the README's own wording, is a reader object over a stream that yields rows, filters you attach to narrow those rows, and writers that emit rows back to a stream. If you are migrating from raw fgetcsv calls, the behaviour you are gaining is the filter and mapping layer, not a different parsing algorithm.
Where league/csv is the wrong tool
The most common mismatch is treating a spreadsheet as CSV. league/csv parses delimited text. It does not evaluate formulas, walk multiple sheets, preserve cell formatting, or resolve the encoding ambiguity that Excel introduces when it saves a file. If your input arrives as .xlsx, converting it to CSV first is a separate problem the library does not address.
The second limitation is environmental. The README requires ext-filter, and it flags two forward-looking deprecations tied to PHP's own CSV escaping changes in 8.4 and 8.6. If you cannot set the escape parameter explicitly, or if your codebase is built around SplFileObject, you are on a path toward deprecation notices that the library cannot suppress for you. That is a real upgrade cost, not a theoretical one.
Third, if your CSV files are small and your needs are simple, the library is overhead. A one-off script that reads a 200-line file with fgetcsv and no filtering gains nothing from an object model, a Composer dependency and a version compatibility table. The library earns its place when files are large, when filtering is non-trivial, or when the same parsing code has to serve several call sites.
league/csv against raw fgetcsv and framework CSV helpers
The honest comparison is with PHP's own fgetcsv, which the related searches show people are already looking at. fgetcsv is a function: you open a handle, call it in a loop, and get an array of fields. It has no concept of headers, no filters, no mapping to objects, and no output conversion. league/csv keeps the same underlying parsing behaviour but wraps it in readers, writers and query objects, and adds JSON, XML and HTML output on top. The difference is not speed of parsing; it is how much code you write around it and how much of that code you have to test yourself.
The second alternative is a framework-specific helper, for example the CSV facilities bundled with a full-stack PHP framework. Those tend to be convenient inside that framework and awkward outside it. The README explicitly positions league/csv as framework-agnostic, which is the substantive difference: the same reader and writer code moves with you between projects. If you are already committed to one framework and never leave it, the framework helper may be less friction. If you maintain libraries or code that has to run in more than one context, the framework-agnostic packaging is the reason to pick this one.
Maintenance, version support and the MIT licence
The repository is not archived, and the last push was on 2026-09-19, which is four days before this article's reference point. Recent releases run 9.27.0, 9.27.1 and 9.28.0, the most recent dated 2025-12-27. Note the gap between the latest tagged release and the last push: development activity on the branch does not map one-to-one onto releases, so pinning a version is safer than tracking master.
The upgrade cost is concentrated in the PHP version table. Each library version declares a minimum and maximum supported PHP version, and the ceiling moves. Someone on PHP 8.1.2 can run 9.16.0 but not 9.29.0, which requires 8.2.0. That means a PHP upgrade can force a library upgrade, and the library upgrade can force you to handle the escape-parameter change before PHP 8.4 deprecation notices appear. Budget for that when planning a PHP version bump, not after.
Licensing is MIT, per the README and the LICENSE file. MIT is permissive: it allows use, modification and redistribution provided the copyright notice and permission notice are included. That is a statement about the licence text, not legal advice, and if you redistribute the library inside a product you should read the LICENSE file in the repository rather than rely on a summary.
Editorial conclusion
Adopt league/csv if you are on PHP 8.2 or newer and need to read, filter or write CSV row by row without holding the whole document in memory. Do not adopt it if your actual input is a spreadsheet with formulas, multiple sheets or encoding quirks, or if you only ever parse a handful of tiny files where fgetcsv is enough. Verify first that ext-filter is enabled, that you explicitly set the escape parameter before PHP 8.4 starts raising deprecation notices, and that your code does not pass SplFileObject or SplTempFileObject instances if you plan to run on PHP 8.6. Check the version table in the README against your PHP build before pinning league/csv:^9.0, because 9.29.0 requires PHP 8.2.0 while 9.16.0 still allows 8.1.2.
Frequently asked questions
How can I view a CSV file?
The README does not describe a viewer. It presents league/csv as a library for parsing, writing and filtering CSV in PHP, and points to csv.thephpleague.com for full documentation.
How can I read a CSV file in PHP?
The README lists reading from CSV documents in a memory efficient and scalable way as a highlight, using PHP streams, with filtering and array to object mapping available on top. The README does not print a complete read example itself and directs you to csv.thephpleague.com.
What is a CSV file and its uses?
The README treats CSV as a document format it can parse, write, filter and convert into JSON, XML or HTML. It does not define the format itself.
How can I create a CSV file using PHP?
The README lists writing to CSV documents in a memory efficient and scalable way as a highlight, and the package installs through Composer as league/csv. You need the ext-filter extension to use Csv.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/thephpleague-csv)