* 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) {
|
||||
$unparsedDrawings = [];
|
||||
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"
|
||||
$relsDrawing = simplexml_load_string(
|
||||
$this->securityScanner->scan(
|
||||
|
@ -1631,10 +1633,11 @@ class Xlsx extends BaseReader
|
|||
$this->securityScanner->scan($this->getFromZipArchive($zip, $fileDrawing)),
|
||||
'SimpleXMLElement',
|
||||
Settings::getLibXmlLoaderOptions()
|
||||
)->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
|
||||
);
|
||||
$xmlDrawingChildren = $xmlDrawing->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
|
||||
|
||||
if ($xmlDrawing->oneCellAnchor) {
|
||||
foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
|
||||
if ($xmlDrawingChildren->oneCellAnchor) {
|
||||
foreach ($xmlDrawingChildren->oneCellAnchor as $oneCellAnchor) {
|
||||
if ($oneCellAnchor->pic->blipFill) {
|
||||
/** @var SimpleXMLElement $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) {
|
||||
foreach ($xmlDrawing->twoCellAnchor as $twoCellAnchor) {
|
||||
if ($xmlDrawingChildren->twoCellAnchor) {
|
||||
foreach ($xmlDrawingChildren->twoCellAnchor as $twoCellAnchor) {
|
||||
if ($twoCellAnchor->pic->blipFill) {
|
||||
$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;
|
||||
|
@ -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
|
||||
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'] = [];
|
||||
foreach ($relsWorksheet->Relationship as $ele) {
|
||||
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));
|
||||
}
|
||||
|
||||
// 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
|
||||
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
|
||||
// VML Comments
|
||||
|
@ -338,8 +349,8 @@ class Xlsx extends BaseWriter
|
|||
}
|
||||
|
||||
// Add unparsed relationship parts
|
||||
if (isset($unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['vmlDrawings'])) {
|
||||
foreach ($unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['vmlDrawings'] as $vmlDrawing) {
|
||||
if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) {
|
||||
foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) {
|
||||
$zip->addFromString($vmlDrawing['filePath'], $vmlDrawing['content']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace PhpOffice\PhpSpreadsheetTests\Reader;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class XlsxTest extends TestCase
|
||||
|
@ -32,4 +33,21 @@ class XlsxTest extends TestCase
|
|||
$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