-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Fix For #1509 User expected no CSV enclosures after $writer->setEnclosure(''), which had been changed to be consistent with $reader->setEnclosure(''). Writer will now omit enclosures after code above; no change to Reader. Tests have been added for this condition. * Add Option to Write CSV Enclosure Only When Required Allowing the user to specify no enclosure when writing a CSV can lead to a situation where PhpSpreadsheet (likewise Excel) will not read the resulting file as intended, e.g. if any cell contains a delimiter character. This is demonstrated in new test TestBadReread. No existing setting will rectify this situation. A better choice would be to add an option to write the enclosure only when it is needed, which is what Excel does. The RFC4180 spec at https://tools.ietf.org/html/rfc4180 states when it is needed - when the cell contains the delimiter, or the enclosure, or a newline. New test TestGoodReread demonstrates that the file is read as intended. The documentation has been updated to describe the new function, and to change the write example where the enclosure is set to null. * Scrutinizer Suggestions 3 minor changes, all in tests.
- Loading branch information
Showing
4 changed files
with
265 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
216 changes: 216 additions & 0 deletions
216
tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
<?php | ||
|
||
namespace PhpOffice\PhpSpreadsheetTests\Writer\Csv; | ||
|
||
use PhpOffice\PhpSpreadsheet\Reader\Csv as CsvReader; | ||
use PhpOffice\PhpSpreadsheet\Shared\File; | ||
use PhpOffice\PhpSpreadsheet\Spreadsheet; | ||
use PhpOffice\PhpSpreadsheet\Writer\Csv as CsvWriter; | ||
use PhpOffice\PhpSpreadsheetTests\Functional; | ||
|
||
class CsvEnclosureTest extends Functional\AbstractFunctional | ||
{ | ||
private static $cellValues = [ | ||
'A1' => '2020-06-03', | ||
'B1' => '000123', | ||
'C1' => '06.53', | ||
'D1' => '14.22', | ||
'A2' => '2020-06-04', | ||
'B2' => '000234', | ||
'C2' => '07.12', | ||
'D2' => '15.44', | ||
]; | ||
|
||
public function testNormalEnclosure(): void | ||
{ | ||
$delimiter = ';'; | ||
$enclosure = '"'; | ||
$spreadsheet = new Spreadsheet(); | ||
$sheet = $spreadsheet->getActiveSheet(); | ||
foreach (self::$cellValues as $key => $value) { | ||
$sheet->setCellValue($key, $value); | ||
} | ||
$writer = new CsvWriter($spreadsheet); | ||
$writer->setDelimiter($delimiter); | ||
$writer->setEnclosure($enclosure); | ||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); | ||
$writer->save($filename); | ||
$filedata = file_get_contents($filename); | ||
$filedata = preg_replace('/\\r?\\n/', $delimiter, $filedata); | ||
$reader = new CsvReader(); | ||
$reader->setDelimiter($delimiter); | ||
$reader->setEnclosure($enclosure); | ||
$newspreadsheet = $reader->load($filename); | ||
unlink($filename); | ||
$sheet = $newspreadsheet->getActiveSheet(); | ||
$expected = ''; | ||
foreach (self::$cellValues as $key => $value) { | ||
self::assertEquals($value, $sheet->getCell($key)->getValue()); | ||
$expected .= "$enclosure$value$enclosure$delimiter"; | ||
} | ||
self::assertEquals($expected, $filedata); | ||
} | ||
|
||
public function testNoEnclosure(): void | ||
{ | ||
$delimiter = ';'; | ||
$enclosure = ''; | ||
$spreadsheet = new Spreadsheet(); | ||
$sheet = $spreadsheet->getActiveSheet(); | ||
foreach (self::$cellValues as $key => $value) { | ||
$sheet->setCellValue($key, $value); | ||
} | ||
$writer = new CsvWriter($spreadsheet); | ||
$writer->setDelimiter($delimiter); | ||
$writer->setEnclosure($enclosure); | ||
self::assertEquals('', $writer->getEnclosure()); | ||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); | ||
$writer->save($filename); | ||
$filedata = file_get_contents($filename); | ||
$filedata = preg_replace('/\\r?\\n/', $delimiter, $filedata); | ||
$reader = new CsvReader(); | ||
$reader->setDelimiter($delimiter); | ||
$reader->setEnclosure($enclosure); | ||
self::assertEquals('"', $reader->getEnclosure()); | ||
$newspreadsheet = $reader->load($filename); | ||
unlink($filename); | ||
$sheet = $newspreadsheet->getActiveSheet(); | ||
$expected = ''; | ||
foreach (self::$cellValues as $key => $value) { | ||
self::assertEquals($value, $sheet->getCell($key)->getValue()); | ||
$expected .= "$enclosure$value$enclosure$delimiter"; | ||
} | ||
self::assertEquals($expected, $filedata); | ||
} | ||
|
||
public function testNotRequiredEnclosure1(): void | ||
{ | ||
$delimiter = ';'; | ||
$enclosure = '"'; | ||
$spreadsheet = new Spreadsheet(); | ||
$sheet = $spreadsheet->getActiveSheet(); | ||
foreach (self::$cellValues as $key => $value) { | ||
$sheet->setCellValue($key, $value); | ||
} | ||
$writer = new CsvWriter($spreadsheet); | ||
self::assertTrue($writer->getEnclosureRequired()); | ||
$writer->setEnclosureRequired(false)->setDelimiter($delimiter)->setEnclosure($enclosure); | ||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); | ||
$writer->save($filename); | ||
$filedata = file_get_contents($filename); | ||
$filedata = preg_replace('/\\r?\\n/', $delimiter, $filedata); | ||
$reader = new CsvReader(); | ||
$reader->setDelimiter($delimiter); | ||
$reader->setEnclosure($enclosure); | ||
$newspreadsheet = $reader->load($filename); | ||
unlink($filename); | ||
$sheet = $newspreadsheet->getActiveSheet(); | ||
$expected = ''; | ||
foreach (self::$cellValues as $key => $value) { | ||
self::assertEquals($value, $sheet->getCell($key)->getValue()); | ||
$expected .= "$value$delimiter"; | ||
} | ||
self::assertEquals($expected, $filedata); | ||
} | ||
|
||
public function testNotRequiredEnclosure2(): void | ||
{ | ||
$cellValues2 = [ | ||
'A1' => '2020-06-03', | ||
'B1' => 'has,separator', | ||
'C1' => 'has;non-separator', | ||
'D1' => 'has"enclosure', | ||
'A2' => 'has space', | ||
'B2' => "has\nnewline", | ||
'C2' => '', | ||
'D2' => '15.44', | ||
'A3' => ' leadingspace', | ||
'B3' => 'trailingspace ', | ||
'C3' => '=D2*2', | ||
'D3' => ',leadingcomma', | ||
'A4' => 'trailingquote"', | ||
'B4' => 'unused', | ||
'C4' => 'unused', | ||
'D4' => 'unused', | ||
]; | ||
$calcc3 = '30.88'; | ||
$expected1 = '2020-06-03,"has,separator",has;non-separator,"has""enclosure"'; | ||
$expected2 = 'has space,"has' . "\n" . 'newline",,15.44'; | ||
$expected3 = ' leadingspace,trailingspace ,' . $calcc3 . ',",leadingcomma"'; | ||
$expected4 = '"trailingquote""",unused,unused,unused'; | ||
$expectedfile = "$expected1\n$expected2\n$expected3\n$expected4\n"; | ||
$delimiter = ','; | ||
$enclosure = '"'; | ||
$spreadsheet = new Spreadsheet(); | ||
$sheet = $spreadsheet->getActiveSheet(); | ||
foreach ($cellValues2 as $key => $value) { | ||
$sheet->setCellValue($key, $value); | ||
} | ||
$writer = new CsvWriter($spreadsheet); | ||
self::assertTrue($writer->getEnclosureRequired()); | ||
$writer->setEnclosureRequired(false)->setDelimiter($delimiter)->setEnclosure($enclosure); | ||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); | ||
$writer->save($filename); | ||
$filedata = file_get_contents($filename); | ||
$filedata = preg_replace('/\\r/', '', $filedata); | ||
$reader = new CsvReader(); | ||
$reader->setDelimiter($delimiter); | ||
$reader->setEnclosure($enclosure); | ||
$newspreadsheet = $reader->load($filename); | ||
unlink($filename); | ||
$sheet = $newspreadsheet->getActiveSheet(); | ||
foreach ($cellValues2 as $key => $value) { | ||
self::assertEquals(($key === 'C3') ? $calcc3 : $value, $sheet->getCell($key)->getValue()); | ||
} | ||
self::assertEquals($expectedfile, $filedata); | ||
} | ||
|
||
public function testGoodReread(): void | ||
{ | ||
$delimiter = ','; | ||
$enclosure = '"'; | ||
$spreadsheet = new Spreadsheet(); | ||
$sheet = $spreadsheet->getActiveSheet(); | ||
$sheet->setCellValue('A1', '1'); | ||
$sheet->setCellValue('B1', '2,3'); | ||
$sheet->setCellValue('C1', '4'); | ||
$writer = new CsvWriter($spreadsheet); | ||
$writer->setEnclosureRequired(false)->setDelimiter($delimiter)->setEnclosure($enclosure); | ||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); | ||
$writer->save($filename); | ||
$reader = new CsvReader(); | ||
$reader->setDelimiter($delimiter); | ||
$reader->setEnclosure($enclosure); | ||
$newspreadsheet = $reader->load($filename); | ||
unlink($filename); | ||
$sheet = $newspreadsheet->getActiveSheet(); | ||
self::assertEquals('1', $sheet->getCell('A1')->getValue()); | ||
self::assertEquals('2,3', $sheet->getCell('B1')->getValue()); | ||
self::assertEquals('4', $sheet->getCell('C1')->getValue()); | ||
} | ||
|
||
public function testBadReread(): void | ||
{ | ||
$delimiter = ','; | ||
$enclosure = ''; | ||
$spreadsheet = new Spreadsheet(); | ||
$sheet = $spreadsheet->getActiveSheet(); | ||
$sheet->setCellValue('A1', '1'); | ||
$sheet->setCellValue('B1', '2,3'); | ||
$sheet->setCellValue('C1', '4'); | ||
$writer = new CsvWriter($spreadsheet); | ||
$writer->setDelimiter($delimiter)->setEnclosure($enclosure); | ||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); | ||
$writer->save($filename); | ||
$reader = new CsvReader(); | ||
$reader->setDelimiter($delimiter); | ||
$reader->setEnclosure($enclosure); | ||
$newspreadsheet = $reader->load($filename); | ||
unlink($filename); | ||
$sheet = $newspreadsheet->getActiveSheet(); | ||
self::assertEquals('1', $sheet->getCell('A1')->getValue()); | ||
self::assertEquals('2', $sheet->getCell('B1')->getValue()); | ||
self::assertEquals('3', $sheet->getCell('C1')->getValue()); | ||
self::assertEquals('4', $sheet->getCell('D1')->getValue()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters