Allow Csv Reader to Treat String as Contents of File (#2792)

See #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.
This commit is contained in:
oleibman 2022-05-07 08:24:53 -07:00 committed by GitHub
parent a32861a0a0
commit 35530502d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 4 deletions

View File

@ -436,7 +436,14 @@ You can read a .csv file using the following code:
```php ```php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv(); $reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
$spreadsheet = $reader->load("sample.csv"); $spreadsheet = $reader->load('sample.csv');
```
You can also treat a string as if it were the contents of a CSV file as follows:
```php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
$spreadsheet = $reader->loadSpreadsheetFromString($data);
``` ```
#### Setting CSV options #### Setting CSV options

View File

@ -265,6 +265,18 @@ class Csv extends BaseReader
return $this->loadIntoExisting($filename, $spreadsheet); return $this->loadIntoExisting($filename, $spreadsheet);
} }
/**
* Loads Spreadsheet from string.
*/
public function loadSpreadsheetFromString(string $contents): Spreadsheet
{
// Create new Spreadsheet
$spreadsheet = new Spreadsheet();
// Load into this instance
return $this->loadStringOrFile('data://text/plain,' . urlencode($contents), $spreadsheet, true);
}
private function openFileOrMemory(string $filename): void private function openFileOrMemory(string $filename): void
{ {
// Open file // Open file
@ -314,16 +326,43 @@ class Csv extends BaseReader
$this->preserveNumericFormatting = $preserveNumericFormatting; $this->preserveNumericFormatting = $preserveNumericFormatting;
} }
/**
* Open data uri for reading.
*/
private function openDataUri(string $filename): void
{
$fileHandle = fopen($filename, 'rb');
if ($fileHandle === false) {
// @codeCoverageIgnoreStart
throw new ReaderException('Could not open file ' . $filename . ' for reading.');
// @codeCoverageIgnoreEnd
}
$this->fileHandle = $fileHandle;
}
/** /**
* Loads PhpSpreadsheet from file into PhpSpreadsheet instance. * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
*/ */
public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Spreadsheet public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Spreadsheet
{
return $this->loadStringOrFile($filename, $spreadsheet, false);
}
/**
* Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
*/
private function loadStringOrFile(string $filename, Spreadsheet $spreadsheet, bool $dataUri): Spreadsheet
{ {
// Deprecated in Php8.1 // Deprecated in Php8.1
$iniset = $this->setAutoDetect('1'); $iniset = $this->setAutoDetect('1');
// Open file // Open file
if ($dataUri) {
$this->openDataUri($filename);
} else {
$this->openFileOrMemory($filename); $this->openFileOrMemory($filename);
}
$fileHandle = $this->fileHandle; $fileHandle = $this->fileHandle;
// Skip BOM, if any // Skip BOM, if any
@ -395,8 +434,8 @@ class Csv extends BaseReader
} elseif (strcasecmp(Calculation::getFALSE(), $rowDatum) === 0 || strcasecmp('false', $rowDatum) === 0) { } elseif (strcasecmp(Calculation::getFALSE(), $rowDatum) === 0 || strcasecmp('false', $rowDatum) === 0) {
$rowDatum = false; $rowDatum = false;
} }
} elseif ($rowDatum === null) { } else {
$rowDatum = ''; $rowDatum = $rowDatum ?? '';
} }
} }

View File

@ -0,0 +1,26 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PHPUnit\Framework\TestCase;
class CsvLoadFromStringTest extends TestCase
{
public function testLoadFromString(): void
{
$data = <<<EOF
1,2,3
4,2+3,6
"7 , 8", 9, 10
11,"12
13",14
EOF;
$reader = new Csv();
$spreadsheet = $reader->loadSpreadsheetFromString($data);
$sheet = $spreadsheet->getActiveSheet();
self::AssertSame('2+3', $sheet->getCell('B2')->getValue());
self::AssertSame('7 , 8', $sheet->getCell('A3')->getValue());
self::AssertSame("12\n13", $sheet->getCell('B4')->getValue());
}
}