mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-13 03:26:26 +00:00
b82756de76
Fix #4537. PhpSpreadsheet currently changes apostrophes in text values to `'`. This is perfectly valid Xml. Issue was opened because R does not handle this correctly; this is unquestionably a bug on R's part. So I was not inclined to do anything about it. However ... User suggested a change to how `htmlspecialchars` was called. Investigating the use of that routine in PhpSpreadsheet, I found that there was some double escaping going on for cells whose type was set to `TYPE_INLINE` - `htmlspecialchars` escaped the string correctly, but it was later written as Xml using a method which escaped the data a second time. So, a real bug in PhpSpreadsheet after all. There was one call to `htmlspecialchars` in `Shared\XmlWriter`. I replaced `writeRaw(htmlspecialchars(...))` with `text(...)`. And one call in `Writer\Xlsx\Worksheet`, the source of the double escaping bug above; the call to `htmlspecialchars` can just be eliminated there. Making those changes, the only remaining calls to `htmlspecialchars` are in `Writer\Html`, where they belong. As a bonus, apostrophes now wind up unescaped, so R will be satisfied (even though they should fix their bug).
77 lines
2.9 KiB
PHP
77 lines
2.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
|
|
|
|
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
|
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
|
|
use PhpOffice\PhpSpreadsheet\RichText\RichText;
|
|
use PhpOffice\PhpSpreadsheet\RichText\TextElement;
|
|
use PhpOffice\PhpSpreadsheet\Shared\File;
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class Issue4537Test extends TestCase
|
|
{
|
|
private string $outputFilename = '';
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
if ($this->outputFilename !== '') {
|
|
unlink($this->outputFilename);
|
|
$this->outputFilename = '';
|
|
}
|
|
}
|
|
|
|
public function testBackgroundImage(): void
|
|
{
|
|
$this->outputFilename = File::temporaryFilename();
|
|
$testString = "\"He\": '<?>'";
|
|
$spreadsheet = new Spreadsheet();
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
$sheet->getCell('A1')->setValueExplicit($testString, DataType::TYPE_INLINE);
|
|
$sheet->getCell('A2')->setValue($testString);
|
|
$richText = new RichText();
|
|
$richText->addText(new TextElement($testString));
|
|
$sheet->getCell('A3')->setValue($richText);
|
|
$writer = new XlsxWriter($spreadsheet);
|
|
$writer->save($this->outputFilename);
|
|
$spreadsheet->disconnectWorksheets();
|
|
|
|
$reader = new XlsxReader();
|
|
$reloadedSpreadsheet = $reader->load($this->outputFilename);
|
|
$rsheet = $reloadedSpreadsheet->getActiveSheet();
|
|
self::assertSame($testString, $rsheet->getCell('A1')->getValueString());
|
|
self::assertSame($testString, $rsheet->getCell('A2')->getValueString());
|
|
self::assertSame($testString, $rsheet->getCell('A3')->getValueString());
|
|
$reloadedSpreadsheet->disconnectWorksheets();
|
|
|
|
$file = 'zip://';
|
|
$file .= $this->outputFilename;
|
|
$file .= '#xl/worksheets/sheet1.xml';
|
|
$data = file_get_contents($file);
|
|
// expected, and expected1/2 below, do not escape apostrophes
|
|
$expected = 't="inlineStr"><is><t>"He": \'<?>\'</t></is>';
|
|
if ($data === false) {
|
|
self::fail('Unable to read worksheets file');
|
|
} else {
|
|
self::assertStringContainsString($expected, $data, 'inline string');
|
|
}
|
|
|
|
$file = 'zip://';
|
|
$file .= $this->outputFilename;
|
|
$file .= '#xl/sharedStrings.xml';
|
|
$data = file_get_contents($file);
|
|
$expected1 = '<t>"He": \'<?>\'</t>';
|
|
$expected2 = '<t xml:space="preserve">"He": \'<?>\'</t>';
|
|
if ($data === false) {
|
|
self::fail('Unable to read sharedStrings file');
|
|
} else {
|
|
self::assertStringContainsString($expected1, $data, 'string');
|
|
self::assertStringContainsString($expected2, $data, 'rich text');
|
|
}
|
|
}
|
|
}
|