* Fix #853 when loading and saving XLSX file with empty drawing cause corrupted output file. Store empty drawing as unparsed entity and save it as is when saving the file. * Fix code style
This commit is contained in:
parent
e096391f54
commit
ebc0b56959
|
@ -1598,8 +1598,10 @@ class Xlsx extends BaseReader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($xmlSheet->drawing && !$this->readDataOnly) {
|
if ($xmlSheet->drawing && !$this->readDataOnly) {
|
||||||
|
$unparsedDrawings = [];
|
||||||
foreach ($xmlSheet->drawing as $drawing) {
|
foreach ($xmlSheet->drawing as $drawing) {
|
||||||
$fileDrawing = $drawings[(string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
|
$drawingRelId = (string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id');
|
||||||
|
$fileDrawing = $drawings[$drawingRelId];
|
||||||
//~ http://schemas.openxmlformats.org/package/2006/relationships"
|
//~ http://schemas.openxmlformats.org/package/2006/relationships"
|
||||||
$relsDrawing = simplexml_load_string(
|
$relsDrawing = simplexml_load_string(
|
||||||
$this->securityScanner->scan(
|
$this->securityScanner->scan(
|
||||||
|
@ -1631,10 +1633,11 @@ class Xlsx extends BaseReader
|
||||||
$this->securityScanner->scan($this->getFromZipArchive($zip, $fileDrawing)),
|
$this->securityScanner->scan($this->getFromZipArchive($zip, $fileDrawing)),
|
||||||
'SimpleXMLElement',
|
'SimpleXMLElement',
|
||||||
Settings::getLibXmlLoaderOptions()
|
Settings::getLibXmlLoaderOptions()
|
||||||
)->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
|
);
|
||||||
|
$xmlDrawingChildren = $xmlDrawing->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
|
||||||
|
|
||||||
if ($xmlDrawing->oneCellAnchor) {
|
if ($xmlDrawingChildren->oneCellAnchor) {
|
||||||
foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
|
foreach ($xmlDrawingChildren->oneCellAnchor as $oneCellAnchor) {
|
||||||
if ($oneCellAnchor->pic->blipFill) {
|
if ($oneCellAnchor->pic->blipFill) {
|
||||||
/** @var SimpleXMLElement $blip */
|
/** @var SimpleXMLElement $blip */
|
||||||
$blip = $oneCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
|
$blip = $oneCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
|
||||||
|
@ -1690,8 +1693,8 @@ class Xlsx extends BaseReader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($xmlDrawing->twoCellAnchor) {
|
if ($xmlDrawingChildren->twoCellAnchor) {
|
||||||
foreach ($xmlDrawing->twoCellAnchor as $twoCellAnchor) {
|
foreach ($xmlDrawingChildren->twoCellAnchor as $twoCellAnchor) {
|
||||||
if ($twoCellAnchor->pic->blipFill) {
|
if ($twoCellAnchor->pic->blipFill) {
|
||||||
$blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
|
$blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
|
||||||
$xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
|
$xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
|
||||||
|
@ -1757,13 +1760,21 @@ class Xlsx extends BaseReader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($relsDrawing === false && $xmlDrawing->count() == 0) {
|
||||||
|
// Save Drawing without rels and children as unparsed
|
||||||
|
$unparsedDrawings[$drawingRelId] = $xmlDrawing->asXML();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// store original rId of drawing files
|
// store original rId of drawing files
|
||||||
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'] = [];
|
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'] = [];
|
||||||
foreach ($relsWorksheet->Relationship as $ele) {
|
foreach ($relsWorksheet->Relationship as $ele) {
|
||||||
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing') {
|
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing') {
|
||||||
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'][(string) $ele['Target']] = (string) $ele['Id'];
|
$drawingRelId = (string) $ele['Id'];
|
||||||
|
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'][(string) $ele['Target']] = $drawingRelId;
|
||||||
|
if (isset($unparsedDrawings[$drawingRelId])) {
|
||||||
|
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['Drawings'][$drawingRelId] = $unparsedDrawings[$drawingRelId];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -328,6 +328,17 @@ class Xlsx extends BaseWriter
|
||||||
$zip->addFromString('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts));
|
$zip->addFromString('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add unparsed drawings
|
||||||
|
if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['Drawings'])) {
|
||||||
|
foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['Drawings'] as $relId => $drawingXml) {
|
||||||
|
$drawingFile = array_search($relId, $unparsedLoadedData['sheets'][$sheetCodeName]['drawingOriginalIds']);
|
||||||
|
if ($drawingFile !== false) {
|
||||||
|
$drawingFile = ltrim($drawingFile, '.');
|
||||||
|
$zip->addFromString('xl' . $drawingFile, $drawingXml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add comment relationship parts
|
// Add comment relationship parts
|
||||||
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
|
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
|
||||||
// VML Comments
|
// VML Comments
|
||||||
|
@ -338,8 +349,8 @@ class Xlsx extends BaseWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add unparsed relationship parts
|
// Add unparsed relationship parts
|
||||||
if (isset($unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['vmlDrawings'])) {
|
if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) {
|
||||||
foreach ($unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['vmlDrawings'] as $vmlDrawing) {
|
foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) {
|
||||||
$zip->addFromString($vmlDrawing['filePath'], $vmlDrawing['content']);
|
$zip->addFromString($vmlDrawing['filePath'], $vmlDrawing['content']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace PhpOffice\PhpSpreadsheetTests\Reader;
|
namespace PhpOffice\PhpSpreadsheetTests\Reader;
|
||||||
|
|
||||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class XlsxTest extends TestCase
|
class XlsxTest extends TestCase
|
||||||
|
@ -32,4 +33,21 @@ class XlsxTest extends TestCase
|
||||||
$this->assertEquals($ref, \array_slice($data[$i], 0, 10, true));
|
$this->assertEquals($ref, \array_slice($data[$i], 0, 10, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test correct save and load xlsx files with empty drawings.
|
||||||
|
* Such files can be generated by Google Sheets.
|
||||||
|
*/
|
||||||
|
public function testLoadSaveWithEmptyDrawings()
|
||||||
|
{
|
||||||
|
$filename = __DIR__ . '/../../data/Reader/XLSX/empty_drawing.xlsx';
|
||||||
|
$reader = new Xlsx();
|
||||||
|
$excel = $reader->load($filename);
|
||||||
|
$resultFilename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test');
|
||||||
|
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($excel);
|
||||||
|
$writer->save($resultFilename);
|
||||||
|
$excel = $reader->load($resultFilename);
|
||||||
|
// Fake assert. The only thing we need is to ensure the file is loaded without exception
|
||||||
|
$this->assertNotNull($excel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue