PHP Logoleague/csv

League/CSV is a robust, flexible, and performant PHP library designed for parsing and writing CSV data. It provides a clean, object-oriented API for handling various aspects of CSV files, including reading from files or strings, writing to files or streams, filtering rows, mapping data, and validating entries.

Key features of league/csv include:

1. Immutability: Reader and Writer instances are immutable, meaning methods that modify their state (like setting a delimiter or BOM) return new instances, promoting predictable behavior and making it safe for concurrent operations.
2. Performance: It's built with performance in mind, leveraging PHP streams and generators to handle large CSV files efficiently without loading the entire file into memory.
3. Flexibility: Supports various delimiters, enclosures, escape characters, and byte order marks (BOMs). It can read from any `SplFileObject` or `Psr\Http\Message\StreamInterface` compatible resource, and write to any `SplFileObject` or `Psr\Http\\Message\StreamInterface` compatible resource.
4. Data Filtering and Mapping: Allows easy filtering of rows based on custom conditions and mapping data to different formats (e.g., associative arrays using a header row).
5. Validation: Provides mechanisms to validate CSV records, ensuring data integrity.
6. Composer Integration: Easily installed and managed via Composer.

At its core, `league/csv` provides two main classes: `Reader` for reading CSV data and `Writer` for writing CSV data. Both work with underlying `SplFileObject` instances or stream interfaces, allowing seamless interaction with various data sources and destinations.

Example Code

<?php

require 'vendor/autoload.php'; // Include Composer's autoloader

use League\Csv\Reader;
use League\Csv\Writer;
use League\Csv\Statement;

// --- PART 1: Reading from a CSV file ---

echo "\n--- Reading CSV ---\n";

// 1. Create a sample CSV file for reading
$sampleCsvContent = "id,name,email\n1,Alice,alice@example.com\n2,Bob,bob@example.com\n3,Charlie,charlie@example.com\n4,David,david@example.com";
file_put_contents('sample.csv', $sampleCsvContent);

try {
    // Create a League\Csv\Reader instance from a file
    $reader = Reader::createFromPath('sample.csv', 'r');

    // Set the header offset to 0, so the first row is used as headers
    $reader->setHeaderOffset(0);

    // Get the header names
    $headers = $reader->getHeader();
    echo "Headers: " . implode(', ', $headers) . "\n";

    // Get all records as associative arrays
    $records = $reader->getRecords();

    echo "All Records:\n";
    foreach ($records as $record) {
        print_r($record);
    }

    // --- Filtering and Limiting Records ---

    echo "\nFiltered Records (Skip first, limit to 2):\n";
    $statement = Statement::create()
        ->offset(1)  // Skip the first data row (after header)
        ->limit(2); // Get only 2 records

    $filteredRecords = $statement->process($reader);

    foreach ($filteredRecords as $record) {
        print_r($record);
    }

} catch (Exception $e) {
    echo "Error reading CSV: " . $e->getMessage() . "\n";
}


// --- PART 2: Writing to a CSV file ---

echo "\n--- Writing CSV ---\n";

// Define data to write
$dataToWrite = [
    ['product_id', 'product_name', 'price'],
    ['P001', 'Laptop', 1200.00],
    ['P002', 'Mouse', 25.50],
    ['P003', 'Keyboard', 75.00]
];

$outputFilePath = 'output.csv';

try {
    // Create a League\Csv\Writer instance from a file
    // 'w+' mode creates the file if it doesn't exist, and truncates it if it does.
    $writer = Writer::createFromPath($outputFilePath, 'w+');

    // Set the delimiter (optional, default is ',')
    $writer->setDelimiter(',');

    // Insert all records at once
    $writer->insertAll($dataToWrite);

    echo "CSV written successfully to '{$outputFilePath}'\n";
    echo "\nContent of '{$outputFilePath}':\n";
    echo file_get_contents($outputFilePath) . "\n";

    // --- Appending to an existing CSV ---

    echo "\n--- Appending to CSV ---\n";

    $additionalData = [
        ['P004', 'Monitor', 300.00],
        ['P005', 'Webcam', 50.00]
    ];

    // Open the file in 'a+' mode for appending
    $appender = Writer::createFromPath($outputFilePath, 'a+');
    $appender->insertAll($additionalData);

    echo "Additional data appended to '{$outputFilePath}'\n";
    echo "\nContent of '{$outputFilePath}' after appending:\n";
    echo file_get_contents($outputFilePath) . "\n";

} catch (Exception $e) {
    echo "Error writing CSV: " . $e->getMessage() . "\n";
}

// --- Clean up sample files (optional) ---
@unlink('sample.csv');
@unlink('output.csv');

?>