Skip to content

Commit 66d6d59

Browse files
committed
Allow Csv Reader to Treat String as Contents of File
See PHPOffice#1285, which went stale and was closed, but recently received some positive feeback. It seems easy to implement, and the only other plaintext file format, Html, allows loading from a string. Those two reasons combined suggest that we should do it.
1 parent bbebc0e commit 66d6d59

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

docs/topics/reading-and-writing-to-file.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,14 @@ You can read a .csv file using the following code:
436436

437437
```php
438438
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
439-
$spreadsheet = $reader->load("sample.csv");
439+
$spreadsheet = $reader->load('sample.csv');
440+
```
441+
442+
You can also treat a string as if it were the contents of a CSV file as follows:
443+
444+
```php
445+
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
446+
$spreadsheet = $reader->loadSpreadsheetFromString($data);
440447
```
441448

442449
#### Setting CSV options

src/PhpSpreadsheet/Reader/Csv.php

+42-3
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,18 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
265265
return $this->loadIntoExisting($filename, $spreadsheet);
266266
}
267267

268+
/**
269+
* Loads Spreadsheet from string.
270+
*/
271+
public function loadSpreadsheetFromString(string $contents): Spreadsheet
272+
{
273+
// Create new Spreadsheet
274+
$spreadsheet = new Spreadsheet();
275+
276+
// Load into this instance
277+
return $this->loadStringOrFile('data://text/plain,' . urlencode($contents), $spreadsheet, true);
278+
}
279+
268280
private function openFileOrMemory(string $filename): void
269281
{
270282
// Open file
@@ -314,16 +326,43 @@ public function castFormattedNumberToNumeric(
314326
$this->preserveNumericFormatting = $preserveNumericFormatting;
315327
}
316328

329+
/**
330+
* Open data uri for reading.
331+
*/
332+
private function openDataUri(string $filename): void
333+
{
334+
$fileHandle = fopen($filename, 'rb');
335+
if ($fileHandle === false) {
336+
// @codeCoverageIgnoreStart
337+
throw new ReaderException('Could not open file ' . $filename . ' for reading.');
338+
// @codeCoverageIgnoreEnd
339+
}
340+
341+
$this->fileHandle = $fileHandle;
342+
}
343+
317344
/**
318345
* Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
319346
*/
320347
public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Spreadsheet
348+
{
349+
return $this->loadStringOrFile($filename, $spreadsheet, false);
350+
}
351+
352+
/**
353+
* Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
354+
*/
355+
private function loadStringOrFile(string $filename, Spreadsheet $spreadsheet, bool $dataUri): Spreadsheet
321356
{
322357
// Deprecated in Php8.1
323358
$iniset = $this->setAutoDetect('1');
324359

325360
// Open file
326-
$this->openFileOrMemory($filename);
361+
if ($dataUri) {
362+
$this->openDataUri($filename);
363+
} else {
364+
$this->openFileOrMemory($filename);
365+
}
327366
$fileHandle = $this->fileHandle;
328367

329368
// Skip BOM, if any
@@ -395,8 +434,8 @@ private function convertBoolean(&$rowDatum, bool $preserveBooleanString): void
395434
} elseif (strcasecmp(Calculation::getFALSE(), $rowDatum) === 0 || strcasecmp('false', $rowDatum) === 0) {
396435
$rowDatum = false;
397436
}
398-
} elseif ($rowDatum === null) {
399-
$rowDatum = '';
437+
} else {
438+
$rowDatum = $rowDatum ?? '';
400439
}
401440
}
402441

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
4+
5+
use PhpOffice\PhpSpreadsheet\Reader\Csv;
6+
use PHPUnit\Framework\TestCase;
7+
8+
class CsvLoadFromStringTest extends TestCase
9+
{
10+
public function testLoadFromString(): void
11+
{
12+
$data = <<<EOF
13+
1,2,3
14+
4,2+3,6
15+
"7 , 8", 9, 10
16+
11,"12
17+
13",14
18+
EOF;
19+
$reader = new Csv();
20+
$spreadsheet = $reader->loadSpreadsheetFromString($data);
21+
$sheet = $spreadsheet->getActiveSheet();
22+
self::AssertSame('2+3', $sheet->getCell('B2')->getValue());
23+
self::AssertSame('7 , 8', $sheet->getCell('A3')->getValue());
24+
self::AssertSame("12\n13", $sheet->getCell('B4')->getValue());
25+
}
26+
}

0 commit comments

Comments
 (0)