diff --git a/samples/Reader/22_Reader_formscomments.php b/samples/Reader/22_Reader_formscomments.php
new file mode 100644
index 0000000000..3f1dd3c5cb
--- /dev/null
+++ b/samples/Reader/22_Reader_formscomments.php
@@ -0,0 +1,22 @@
+log('Start');
+
+$inputFileType = 'Xlsx';
+$inputFileName = __DIR__ . '/sampleData/formscomments.xlsx';
+
+$helper->log('Loading file ' . $inputFileName . ' using IOFactory with a defined reader type of ' . $inputFileType);
+$reader = IOFactory::createReader($inputFileType);
+$helper->log('Loading all WorkSheets');
+$reader->setLoadAllSheets();
+$spreadsheet = $reader->load($inputFileName);
+
+// Save
+$helper->write($spreadsheet, __FILE__, ['Xlsx']);
+$spreadsheet->disconnectWorksheets();
+
+$helper->log('end');
diff --git a/samples/Reader/22_Reader_issue1767.php b/samples/Reader/22_Reader_issue1767.php
index 2c1ce93143..10caef1216 100644
--- a/samples/Reader/22_Reader_issue1767.php
+++ b/samples/Reader/22_Reader_issue1767.php
@@ -17,5 +17,6 @@
// Save
$helper->write($spreadsheet, __FILE__);
+$spreadsheet->disconnectWorksheets();
$helper->log('end');
diff --git a/samples/Reader/sampleData/formscomments.xlsx b/samples/Reader/sampleData/formscomments.xlsx
new file mode 100644
index 0000000000..b63b00c1ca
Binary files /dev/null and b/samples/Reader/sampleData/formscomments.xlsx differ
diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php
index 8ae685037b..599a558142 100644
--- a/src/PhpSpreadsheet/Reader/Xlsx.php
+++ b/src/PhpSpreadsheet/Reader/Xlsx.php
@@ -122,9 +122,12 @@ public static function falseToArray($value): array
return is_array($value) ? $value : [];
}
- private function loadZip(string $filename, string $ns = ''): SimpleXMLElement
+ private function loadZip(string $filename, string $ns = '', bool $replaceUnclosedBr = false): SimpleXMLElement
{
$contents = $this->getFromZipArchive($this->zip, $filename);
+ if ($replaceUnclosedBr) {
+ $contents = str_replace('
', '
', $contents);
+ }
$rels = simplexml_load_string(
$this->securityScanner->scan($contents),
'SimpleXMLElement',
@@ -1024,6 +1027,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
// later we will remove from it real vmlComments
$unparsedVmlDrawings = $vmlComments;
+ $vmlDrawingContents = [];
// Loop through VML comments
foreach ($vmlComments as $relName => $relPath) {
@@ -1032,7 +1036,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
try {
// no namespace okay - processed with Xpath
- $vmlCommentsFile = $this->loadZip($relPath, '');
+ $vmlCommentsFile = $this->loadZip($relPath, '', true);
$vmlCommentsFile->registerXPathNamespace('v', Namespaces::URN_VML);
} catch (Throwable $ex) {
//Ignore unparsable vmlDrawings. Later they will be moved from $unparsedVmlDrawings to $unparsedLoadedData
@@ -1042,6 +1046,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
// Locate VML drawings image relations
$drowingImages = [];
$VMLDrawingsRelations = dirname($relPath) . '/_rels/' . basename($relPath) . '.rels';
+ $vmlDrawingContents[$relName] = $this->securityScanner->scan($this->getFromZipArchive($zip, $relPath));
if ($zip->locateName($VMLDrawingsRelations)) {
$relsVMLDrawing = $this->loadZip($VMLDrawingsRelations, Namespaces::RELATIONSHIPS);
foreach ($relsVMLDrawing->Relationship as $elex) {
@@ -1495,6 +1500,14 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
}
}
}
+ if ($xmlSheet->legacyDrawing && !$this->readDataOnly) {
+ foreach ($xmlSheet->legacyDrawing as $drawing) {
+ $drawingRelId = (string) self::getArrayItem(self::getAttributes($drawing, $xmlNamespaceBase), 'id');
+ if (isset($vmlDrawingContents[$drawingRelId])) {
+ $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['legacyDrawing'] = $vmlDrawingContents[$drawingRelId];
+ }
+ }
+ }
// unparsed drawing AlternateContent
$xmlAltDrawing = $this->loadZip((string) $fileDrawing, Namespaces::COMPATIBILITY);
diff --git a/src/PhpSpreadsheet/Writer/Xlsx.php b/src/PhpSpreadsheet/Writer/Xlsx.php
index c9446e7077..5e7d688ae4 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx.php
@@ -455,14 +455,17 @@ public function save($filename, int $flags = 0): void
}
// Add comment relationship parts
- if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
+ $legacy = $unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['legacyDrawing'] ?? null;
+ if (count($this->spreadSheet->getSheet($i)->getComments()) > 0 || $legacy !== null) {
// VML Comments relationships
$zipContent['xl/drawings/_rels/vmlDrawing' . ($i + 1) . '.vml.rels'] = $this->getWriterPartRels()->writeVMLDrawingRelationships($this->spreadSheet->getSheet($i));
// VML Comments
- $zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i));
+ $zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $legacy ?? $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i));
+ }
- // Comments
+ // Comments
+ if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
$zipContent['xl/comments' . ($i + 1) . '.xml'] = $this->getWriterPartComments()->writeComments($this->spreadSheet->getSheet($i));
// Media
@@ -477,7 +480,9 @@ public function save($filename, int $flags = 0): void
// Add unparsed relationship parts
if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) {
foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) {
- $zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content'];
+ if (!isset($zipContent[$vmlDrawing['filePath']])) {
+ $zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content'];
+ }
}
}
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Rels.php b/src/PhpSpreadsheet/Writer/Xlsx/Rels.php
index e621dc3ea3..e1006ea934 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/Rels.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/Rels.php
@@ -239,14 +239,16 @@ public function writeWorksheetRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\
// Write comments relationship?
$i = 1;
- if (count($worksheet->getComments()) > 0) {
+ if (count($worksheet->getComments()) > 0 || isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'])) {
$this->writeRelationship(
$objWriter,
'_comments_vml' . $i,
Namespaces::VML,
'../drawings/vmlDrawing' . $worksheetId . '.vml'
);
+ }
+ if (count($worksheet->getComments()) > 0) {
$this->writeRelationship(
$objWriter,
'_comments' . $i,
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
index 58259a6394..b5bebc7a84 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
@@ -1322,7 +1322,8 @@ private function writeDrawings(XMLWriter $objWriter, PhpspreadsheetWorksheet $wo
private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
{
// If sheet contains comments, add the relationships
- if (count($worksheet->getComments()) > 0) {
+ $unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
+ if (count($worksheet->getComments()) > 0 || isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'])) {
$objWriter->startElement('legacyDrawing');
$objWriter->writeAttribute('r:id', 'rId_comments_vml1');
$objWriter->endElement();