{"id":48225558,"url":"https://github.com/lekoala/baresheet","last_synced_at":"2026-04-04T19:18:48.534Z","repository":{"id":342040435,"uuid":"1172495907","full_name":"lekoala/baresheet","owner":"lekoala","description":"Fast, zero-dependency CSV, XLSX and ODS reader/writer for PHP","archived":false,"fork":false,"pushed_at":"2026-03-27T17:00:30.000Z","size":291,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-27T22:40:26.541Z","etag":null,"topics":["csv","lightweight","minimal","ods","php","spreadsheet","xlsx"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lekoala.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"lekoala"}},"created_at":"2026-03-04T11:25:48.000Z","updated_at":"2026-03-27T10:51:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lekoala/baresheet","commit_stats":null,"previous_names":["lekoala/baresheet"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/lekoala/baresheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lekoala%2Fbaresheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lekoala%2Fbaresheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lekoala%2Fbaresheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lekoala%2Fbaresheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lekoala","download_url":"https://codeload.github.com/lekoala/baresheet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lekoala%2Fbaresheet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31409988,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csv","lightweight","minimal","ods","php","spreadsheet","xlsx"],"created_at":"2026-04-04T19:18:47.840Z","updated_at":"2026-04-04T19:18:48.520Z","avatar_url":"https://github.com/lekoala.png","language":"PHP","readme":"# Baresheet\n\nFast, zero-dependency CSV, XLSX, and ODS reader/writer for PHP.\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n## Requirements\n\n- PHP 8.1+\n- ext-mbstring (Required for all formats; Symfony polyfill is a valid alternative)\n\n### Format Specific (Required for XLSX/ODS)\n\n- ext-zip\n- ext-xmlreader, ext-simplexml, ext-libxml (standard XML extensions, usually bundled together)\n\n### Optional\n\n- ext-iconv (Required only for CSV BOM transcoding)\n- maennchen/zipstream-php (Required only for streaming XLSX/ODS output)\n\n## Installation\n\n```bash\ncomposer require lekoala/baresheet\n```\n\n## Quick Start\n\n```php\nuse LeKoala\\Baresheet\\Baresheet;\nuse LeKoala\\Baresheet\\Options;\n\n// Auto-detect format from extension\n$rows = Baresheet::read('data.xlsx', new Options(assoc: true));\nforeach ($rows as $row) {\n    echo $row['email'];\n}\n\n// Write — format from extension\nBaresheet::write($data, 'output.csv', new Options(bom: false));\nBaresheet::write($data, 'output.xlsx', new Options(meta: ['creator' =\u003e 'My App']));\nBaresheet::write($data, 'output.ods');\n\n// Write to string\n$csv = Baresheet::writeString($data, 'csv');\n$xlsx = Baresheet::writeString($data, 'xlsx');\n$ods = Baresheet::writeString($data, 'ods');\n\n// Write to PHP resource (for PSR-7 or Laravel Responses)\n$stream = Baresheet::writeStream($data, 'xlsx');\n\n// Stream as download (sends HTTP headers)\nBaresheet::output($data, 'report.xlsx');\n```\n\n## Direct Reader/Writer Usage\n\nConcrete classes allow setting properties directly or passing an `Options` object to the constructor:\n\n```php\nuse LeKoala\\Baresheet\\Options;\nuse LeKoala\\Baresheet\\CsvReader;\nuse LeKoala\\Baresheet\\CsvWriter;\nuse LeKoala\\Baresheet\\XlsxReader;\nuse LeKoala\\Baresheet\\XlsxWriter;\n\n// CSV - Manual pattern\n$reader = new CsvReader();\n$reader-\u003eassoc = true;\n$rows = $reader-\u003ereadFile('data.csv');\n\n// CSV - Options pattern\n$writer = new CsvWriter(new Options(\n    escapeFormulas: true,\n));\n$writer-\u003ewriteFile($data, 'safe-export.csv');\n\n// XLSX - Manual pattern\n$reader = new XlsxReader();\n$reader-\u003esheet = 'Data';\n$rows = $reader-\u003ereadFile('report.xlsx');\n\n// XLSX - Options pattern\n$writer = new XlsxWriter(new Options(\n    meta: ['creator' =\u003e 'My App'],\n));\n$writer-\u003ewriteFile($data, 'report.xlsx');\n```\n\n## Features\n\n### CSV\n\n- **Auto delimiter detection** — analyzes a sample to pick the best separator (default: `auto`)\n- **BOM handling** — detects and natively transcodes UTF-8/16/32 BOM sequences on the fly via stream filters\n- **Formula injection protection** — `escapeFormulas: true` (opt-in security flag, see Security section)\n- **RFC 4180 compliant** — handles enclosures, double-quote escaping, and **CRLF (`\\r\\n`)** line endings by default for maximum interoperability.\n- **Stream reading** — `readStream()` for reading from any PHP resource\n\n### XLSX\n\n- **Blazing fast reading** — optimized `XMLReader` with direct `zip://` streaming (2x faster than SimpleXLSX)\n- **Data offset** \u0026 **Empty line skipping** — safely skip arbitrary leading rows or completely empty lines\n- **Extreme memory efficiency** — unified 0.63MB footprint regardless of file size\n- **Shared string table** — opt-in de-duplication for smaller files (default: `false` for speed)\n- **Auto column widths** — opt-in automatic column sizing (default: `false` for speed)\n- **DateTime support** — pass `DateTimeInterface` objects directly, seamlessly handles 1900/1904 calendar systems\n- **Freeze Pane \u0026 Autofilter** — simple options for improved sheet usability\n- **Document properties** — set creator, title, subject, keywords, etc. via `meta`\n\n### ODS\n\n- **Streaming reader** — handles large files with minimal 0.63MB memory usage\n- **Data offset** \u0026 **Empty line skipping** — safely skip arbitrary leading rows or completely empty lines\n- **Zero-dependency** — uses native `ZipArchive` + `XMLReader`\n- **DateTime support** — dates stored accurately in ISO 8601\n- **Document properties** — set creator and title via `meta`\n- **Sheet selection** — read specific sheets by name or index\n\n## Options\n\nThere are two ways to pass options:\n\n**1. Directly on instances:**\n\n```php\n$reader = new CsvReader();\n$reader-\u003eassoc = true;\n$reader-\u003eseparator = \";\";\n\n// Or directly in the constructor\n$reader = new CsvReader(new Options(assoc: true, separator: \";\"));\n```\n\n**2. Options object** (works on any method, including the `Baresheet` facade). The constructor provides **full IDE autocomplete**:\n\n```php\nuse LeKoala\\Baresheet\\Options;\n\n$opts = new Options(\n    assoc: true, \n    separator: 'auto',\n    meta: ['creator' =\u003e 'My App']\n);\n$rows = Baresheet::read('data.csv', $opts);\n```\n\n| Option           | Type              | Default  | Applies to                |\n|------------------|-------------------|----------|---------------------------|\n| `assoc`          | bool              | `false`  | Read (All)                |\n| `strict`         | bool              | `false`  | Read (CSV, XLSX, ODS)     |\n| `stream`         | bool              | `true`   | Output (Any)              |\n| `limit`          | ?int              | `null`   | Read (All)                |\n| `offset`         | int               | `0`      | Read (All)                |\n| `skipEmptyLines` | bool              | `true`   | Read (All)                |\n| `headers`        | string[]          | `[]`     | Write (All), Read (CSV)   |\n| `separator`      | string            | `\"auto\"` | Read (CSV)                |\n| `enclosure`      | string            | `\"`      | Read (CSV)                |\n| `escape`         | string            | `\"\"`     | Read (CSV)                |\n| `eol`            | string            | `\\r\\n`   | Write (CSV)               |\n| `inputEncoding`  | ?string           | `null`   | Read (CSV)                |\n| `outputEncoding` | ?string           | `null`   | Read (CSV)                |\n| `bom`            | bool\\|string\\|Bom | `true`   | Write (CSV)               |\n| `escapeFormulas` | bool              | `false`  | Write (CSV)               |\n| `meta`           | array/Meta        | `null`   | Write (XLSX, ODS)         |\n| `autofilter`     | ?string           | `null`   | Write (XLSX)              |\n| `freezePane`     | ?string           | `null`   | Write (XLSX)              |\n| `sheet`          | string/int        | `null`   | Read/Write (XLSX, ODS)    |\n| `boldHeaders`    | bool              | `false`  | Write (XLSX, ODS)         |\n| `tempPath`       | ?string           | `null`   | Any (Temp files location) |\n| `sharedStrings`  | bool              | `false`  | Write (XLSX)              |\n| `autoWidth`      | bool              | `false`  | Write (XLSX)              |\n\n## Streaming Output\n\nFor large files, streaming avoids writing a temporary file to disk. **Baresheet streams `output()` by default.**\n\nHowever, keep in mind that **streaming changes how data is sent to the browser**. Because the total file size is unknown before the transfer starts, the server cannot send a `Content-Length` header. This means the browser download will not display a progress bar or an estimated time of completion.\n\nTo bypass streaming and force buffering, use `stream: false` with `output()`. Baresheet will buffer the file (either in memory for CSV, or via a temporary zip file for XLSX/ODS) to precisely calculate and send the `Content-Length` header along with it.\n\n\u003e **Note on XLSX/ODS:** Streaming requires an optional dependency. Install it with:\n\n```bash\ncomposer require maennchen/zipstream-php\n```\n\nIf the `zipstream-php` dependency is missing, Baresheet will seamlessly and automatically fall back to buffered output.\n\n```php\n$writer = new XlsxWriter();\n$writer-\u003estream = false;\n$writer-\u003eoutput($data, 'report.xlsx');\n\n// or via Options\nBaresheet::output($data, 'report.xlsx', new Options(stream: false));\n```\n\n## PSR-7 / Response Objects (Symfony, Laravel)\n\nTo avoid breaking the flow of your application or sending explicit `header()` calls directly, you should create a Response object when applicable in your framework.\n\nUse the `writeStream()` method to generate the spreadsheet as a memory-capped `php://temp` stream resource, and feed it into your Response class:\n\n### Symfony / Laravel (StreamedResponse)\n\n```php\nuse LeKoala\\Baresheet\\XlsxWriter;\nuse Symfony\\Component\\HttpFoundation\\StreamedResponse;\n\n$writer = new XlsxWriter();\n$stream = $writer-\u003ewriteStream($data);\n\nreturn new StreamedResponse(function () use ($stream) {\n    fpassthru($stream);\n    fclose($stream);\n}, 200, [\n    'Content-Type' =\u003e 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n    'Content-Disposition' =\u003e 'attachment; filename=\"report.xlsx\"',\n]);\n```\n\n### PSR-7 (Guzzle, Nyholm, etc.)\n\n```php\n$stream = Baresheet::writeStream($data, 'xlsx');\n$body = new \\GuzzleHttp\\Psr7\\Stream($stream); // wrap the native resource\n\nreturn $response\n    -\u003ewithHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')\n    -\u003ewithHeader('Content-Disposition', 'attachment; filename=\"report.xlsx\"')\n    -\u003ewithBody($body);\n```\n\n## Performance\n\nBaresheet is explicitly engineered to minimize server resource footprint.\n\nThe XLSX and ODS readers use an optimized `XMLReader` approach that opens `zip://` streams directly. This avoids any temporary file extraction, cutting I/O overhead by 50% compared to standard zip extraction methods.\n\nHere are the results extracting/writing 50,000 rows (4 columns) locally against other common industry standard libraries:\n\n### Reading (Parsing) 50,000 Rows\n\n#### Reading CSV\n\n| Library         | Avg Time (s) | Peak Memory (MB) |\n|-----------------|--------------|------------------|\n| Baresheet (CSV) | 0.0056       | 0.63             |\n| League (CSV)    | 0.0088       | 0.63             |\n| OpenSpout (CSV) | 0.0200       | 0.63             |\n\n#### Reading XLSX\n\n| Library           | Avg Time (s) | Peak Memory (MB) |\n|-------------------|--------------|------------------|\n| Baresheet (XLSX)  | 0.0406       | 0.63             |\n| SimpleXLSX (XLSX) | 0.0797       | 5.78             |\n| OpenSpout (XLSX)  | 0.2151       | 0.63             |\n\n#### Reading ODS\n\n| Library         | Avg Time (s) | Peak Memory (MB) |\n|-----------------|--------------|------------------|\n| Baresheet (ODS) | 0.0630       | 0.63             |\n| OpenSpout (ODS) | 0.1685       | 0.63             |\n\n### Writing 50,000 Rows\n\n#### Writing CSV\n\n| Library         | Avg Time (s) | Peak Memory (MB) |\n|-----------------|--------------|------------------|\n| Baresheet (CSV) | 0.1070       | 0.48             |\n| League (CSV)    | 0.1384       | 0.55             |\n| OpenSpout (CSV) | 0.2855       | 0.47             |\n\n#### Writing XLSX\n\n| Library                           | Avg Time (s) | Peak Memory (MB) |\n|-----------------------------------|--------------|------------------|\n| Baresheet (XLSX - Auto Width)     | 0.4823       | 0.77             |\n| Baresheet (XLSX)                  | 0.5022       | 0.77             |\n| SimpleXLSXGen (XLSX)              | 0.6742       | 109.77           |\n| OpenSpout (XLSX)                  | 0.9063       | 1.01             |\n| Baresheet (XLSX - Shared Strings) | 0.9387       | 57.14            |\n\n\u003e Note: By default, Baresheet uses the fastest mode (shared strings and auto column width disabled). You can re-enable them via Options.\n\n#### Writing ODS\n\n| Library         | Avg Time (s) | Peak Memory (MB) |\n|-----------------|--------------|------------------|\n| Baresheet (ODS) | 0.8540       | 0.91             |\n| OpenSpout (ODS) | 1.2791       | 0.88             |\n\n## Security Considerations\n\n### CSV Formula Injection\n\nWhen writing CSV files, any cell beginning with `=`, `+`, `-`, or `@` could be interpreted as a formula if the file is opened in spreadsheet software like Microsoft Excel. A maliciously crafted input could lead to execution of arbitrary functions or system commands on the user's local machine.\n\nBy default, Baresheet prioritizes **data round-trip integrity**. Attempting to automatically prefix formulas with a single quote (`'`) to disable formula execution corrupts otherwise valid user inputs.\n\nIf you are exporting data to be consumed by clients opening the file in Excel, you **must opt-in** to the protection logic:\n\n```php\n$writer = new CsvWriter();\n$writer-\u003eescapeFormulas = true; // Protects against formula injection by prefixing a single-quote\n```\n\n## License\n\nMIT\n","funding_links":["https://github.com/sponsors/lekoala"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flekoala%2Fbaresheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flekoala%2Fbaresheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flekoala%2Fbaresheet/lists"}