From fe6221fe4950c97992e0444608d366e972ccd023 Mon Sep 17 00:00:00 2001 From: oleibman Date: Thu, 1 Oct 2020 03:38:36 -0700 Subject: [PATCH 1/7] Reader/Gnumeric Failure with PHP8 (#1662) * Reader/Gnumeric Failure with PHP8 An explicit cast from SimpleXML to int is now needed with PHP8, where it was performed implicitly with PHP7. Unit tests run correctly for both PHP7 and PHP8 on corrected code. --- src/PhpSpreadsheet/Reader/Gnumeric.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Reader/Gnumeric.php b/src/PhpSpreadsheet/Reader/Gnumeric.php index f4a44895..dc921c1e 100644 --- a/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -543,7 +543,8 @@ class Gnumeric extends BaseReader $endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : (int) $styleAttributes['endCol']; $endColumn = Coordinate::stringFromColumnIndex($endColumn + 1); - $endRow = 1 + (($styleAttributes['endRow'] > $maxRow) ? $maxRow : $styleAttributes['endRow']); + + $endRow = 1 + (($styleAttributes['endRow'] > $maxRow) ? $maxRow : (int) $styleAttributes['endRow']); $cellRange = $startColumn . $startRow . ':' . $endColumn . $endRow; $styleAttributes = $styleRegion->Style->attributes(); From 416e27b6323b10e5f2072736553bf7fd6fc229e5 Mon Sep 17 00:00:00 2001 From: oleibman Date: Fri, 2 Oct 2020 01:52:28 -0700 Subject: [PATCH 2/7] ReverseSort bug, exposed but not caused by PHP8 (#1660) Some tests of ReferenceHelper functions columnReverseSort and cellReverseSort which passed with PHP7 fail with PHP8. Both functions use the following construction: return 1 - strcasecmp(whatever); The "1" seems very mysterious. I believe that the correct code should be: return -strcasecmp(whatever); It appears in particular that PHP7 strcasecmp was never returning a value of 1 for the tests in question, but PHP8 strcasecmp does so. With the corrected code, the tests pass in both PHP7 and PHP8. --- src/PhpSpreadsheet/ReferenceHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpSpreadsheet/ReferenceHelper.php b/src/PhpSpreadsheet/ReferenceHelper.php index 9205b76e..13f7cf71 100644 --- a/src/PhpSpreadsheet/ReferenceHelper.php +++ b/src/PhpSpreadsheet/ReferenceHelper.php @@ -69,7 +69,7 @@ class ReferenceHelper */ public static function columnReverseSort($a, $b) { - return 1 - strcasecmp(strlen($a) . $a, strlen($b) . $b); + return -strcasecmp(strlen($a) . $a, strlen($b) . $b); } /** @@ -108,7 +108,7 @@ class ReferenceHelper [$bc, $br] = sscanf($b, '%[A-Z]%d'); if ($ar === $br) { - return 1 - strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc); + return -strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc); } return ($ar < $br) ? 1 : -1; From 3d9867ce95c1134a2ddc44a115d8bbef1aef8e99 Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Fri, 2 Oct 2020 10:55:50 +0200 Subject: [PATCH 3/7] Drop $this->spreadSheet null check from Xlsx Writer (#1646) $this->spreadSheet cannot be null --- src/PhpSpreadsheet/Writer/Xlsx.php | 458 ++++++++++++++--------------- 1 file changed, 225 insertions(+), 233 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/Xlsx.php b/src/PhpSpreadsheet/Writer/Xlsx.php index 4cb10287..d71541c8 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx.php +++ b/src/PhpSpreadsheet/Writer/Xlsx.php @@ -178,238 +178,234 @@ class Xlsx extends BaseWriter */ public function save($pFilename): void { - if ($this->spreadSheet !== null) { - // garbage collect - $this->pathNames = []; - $this->spreadSheet->garbageCollect(); + // garbage collect + $this->pathNames = []; + $this->spreadSheet->garbageCollect(); - $this->openFileHandle($pFilename); + $this->openFileHandle($pFilename); - $saveDebugLog = Calculation::getInstance($this->spreadSheet)->getDebugLog()->getWriteDebugLog(); - Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog(false); - $saveDateReturnType = Functions::getReturnDateType(); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); + $saveDebugLog = Calculation::getInstance($this->spreadSheet)->getDebugLog()->getWriteDebugLog(); + Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog(false); + $saveDateReturnType = Functions::getReturnDateType(); + Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - // Create string lookup table - $this->stringTable = []; - for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { - $this->stringTable = $this->getWriterPart('StringTable')->createStringTable($this->spreadSheet->getSheet($i), $this->stringTable); - } - - // Create styles dictionaries - $this->styleHashTable->addFromSource($this->getWriterPart('Style')->allStyles($this->spreadSheet)); - $this->stylesConditionalHashTable->addFromSource($this->getWriterPart('Style')->allConditionalStyles($this->spreadSheet)); - $this->fillHashTable->addFromSource($this->getWriterPart('Style')->allFills($this->spreadSheet)); - $this->fontHashTable->addFromSource($this->getWriterPart('Style')->allFonts($this->spreadSheet)); - $this->bordersHashTable->addFromSource($this->getWriterPart('Style')->allBorders($this->spreadSheet)); - $this->numFmtHashTable->addFromSource($this->getWriterPart('Style')->allNumberFormats($this->spreadSheet)); - - // Create drawing dictionary - $this->drawingHashTable->addFromSource($this->getWriterPart('Drawing')->allDrawings($this->spreadSheet)); - - $options = new Archive(); - $options->setEnableZip64(false); - $options->setOutputStream($this->fileHandle); - - $this->zip = new ZipStream(null, $options); - - // Add [Content_Types].xml to ZIP file - $this->addZipFile('[Content_Types].xml', $this->getWriterPart('ContentTypes')->writeContentTypes($this->spreadSheet, $this->includeCharts)); - - //if hasMacros, add the vbaProject.bin file, Certificate file(if exists) - if ($this->spreadSheet->hasMacros()) { - $macrosCode = $this->spreadSheet->getMacrosCode(); - if ($macrosCode !== null) { - // we have the code ? - $this->addZipFile('xl/vbaProject.bin', $macrosCode); //allways in 'xl', allways named vbaProject.bin - if ($this->spreadSheet->hasMacrosCertificate()) { - //signed macros ? - // Yes : add the certificate file and the related rels file - $this->addZipFile('xl/vbaProjectSignature.bin', $this->spreadSheet->getMacrosCertificate()); - $this->addZipFile('xl/_rels/vbaProject.bin.rels', $this->getWriterPart('RelsVBA')->writeVBARelationships($this->spreadSheet)); - } - } - } - //a custom UI in this workbook ? add it ("base" xml and additional objects (pictures) and rels) - if ($this->spreadSheet->hasRibbon()) { - $tmpRibbonTarget = $this->spreadSheet->getRibbonXMLData('target'); - $this->addZipFile($tmpRibbonTarget, $this->spreadSheet->getRibbonXMLData('data')); - if ($this->spreadSheet->hasRibbonBinObjects()) { - $tmpRootPath = dirname($tmpRibbonTarget) . '/'; - $ribbonBinObjects = $this->spreadSheet->getRibbonBinObjects('data'); //the files to write - foreach ($ribbonBinObjects as $aPath => $aContent) { - $this->addZipFile($tmpRootPath . $aPath, $aContent); - } - //the rels for files - $this->addZipFile($tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels', $this->getWriterPart('RelsRibbonObjects')->writeRibbonRelationships($this->spreadSheet)); - } - } - - // Add relationships to ZIP file - $this->addZipFile('_rels/.rels', $this->getWriterPart('Rels')->writeRelationships($this->spreadSheet)); - $this->addZipFile('xl/_rels/workbook.xml.rels', $this->getWriterPart('Rels')->writeWorkbookRelationships($this->spreadSheet)); - - // Add document properties to ZIP file - $this->addZipFile('docProps/app.xml', $this->getWriterPart('DocProps')->writeDocPropsApp($this->spreadSheet)); - $this->addZipFile('docProps/core.xml', $this->getWriterPart('DocProps')->writeDocPropsCore($this->spreadSheet)); - $customPropertiesPart = $this->getWriterPart('DocProps')->writeDocPropsCustom($this->spreadSheet); - if ($customPropertiesPart !== null) { - $this->addZipFile('docProps/custom.xml', $customPropertiesPart); - } - - // Add theme to ZIP file - $this->addZipFile('xl/theme/theme1.xml', $this->getWriterPart('Theme')->writeTheme($this->spreadSheet)); - - // Add string table to ZIP file - $this->addZipFile('xl/sharedStrings.xml', $this->getWriterPart('StringTable')->writeStringTable($this->stringTable)); - - // Add styles to ZIP file - $this->addZipFile('xl/styles.xml', $this->getWriterPart('Style')->writeStyles($this->spreadSheet)); - - // Add workbook to ZIP file - $this->addZipFile('xl/workbook.xml', $this->getWriterPart('Workbook')->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas)); - - $chartCount = 0; - // Add worksheets - for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { - $this->addZipFile('xl/worksheets/sheet' . ($i + 1) . '.xml', $this->getWriterPart('Worksheet')->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts)); - if ($this->includeCharts) { - $charts = $this->spreadSheet->getSheet($i)->getChartCollection(); - if (count($charts) > 0) { - foreach ($charts as $chart) { - $this->addZipFile('xl/charts/chart' . ($chartCount + 1) . '.xml', $this->getWriterPart('Chart')->writeChart($chart, $this->preCalculateFormulas)); - ++$chartCount; - } - } - } - } - - $chartRef1 = 0; - // Add worksheet relationships (drawings, ...) - for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { - // Add relationships - $this->addZipFile('xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts)); - - // Add unparsedLoadedData - $sheetCodeName = $this->spreadSheet->getSheet($i)->getCodeName(); - $unparsedLoadedData = $this->spreadSheet->getUnparsedLoadedData(); - if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'])) { - foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'] as $ctrlProp) { - $this->addZipFile($ctrlProp['filePath'], $ctrlProp['content']); - } - } - if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'])) { - foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'] as $ctrlProp) { - $this->addZipFile($ctrlProp['filePath'], $ctrlProp['content']); - } - } - - $drawings = $this->spreadSheet->getSheet($i)->getDrawingCollection(); - $drawingCount = count($drawings); - if ($this->includeCharts) { - $chartCount = $this->spreadSheet->getSheet($i)->getChartCount(); - } - - // Add drawing and image relationship parts - if (($drawingCount > 0) || ($chartCount > 0)) { - // Drawing relationships - $this->addZipFile('xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts)); - - // Drawings - $this->addZipFile('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts)); - } elseif (isset($unparsedLoadedData['sheets'][$sheetCodeName]['drawingAlternateContents'])) { - // Drawings - $this->addZipFile('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, '.'); - $this->addZipFile('xl' . $drawingFile, $drawingXml); - } - } - } - - // Add comment relationship parts - if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) { - // VML Comments - $this->addZipFile('xl/drawings/vmlDrawing' . ($i + 1) . '.vml', $this->getWriterPart('Comments')->writeVMLComments($this->spreadSheet->getSheet($i))); - - // Comments - $this->addZipFile('xl/comments' . ($i + 1) . '.xml', $this->getWriterPart('Comments')->writeComments($this->spreadSheet->getSheet($i))); - } - - // Add unparsed relationship parts - if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) { - foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) { - $this->addZipFile($vmlDrawing['filePath'], $vmlDrawing['content']); - } - } - - // Add header/footer relationship parts - if (count($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) { - // VML Drawings - $this->addZipFile('xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml', $this->getWriterPart('Drawing')->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i))); - - // VML Drawing relationships - $this->addZipFile('xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels', $this->getWriterPart('Rels')->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i))); - - // Media - foreach ($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages() as $image) { - $this->addZipFile('xl/media/' . $image->getIndexedFilename(), file_get_contents($image->getPath())); - } - } - } - - // Add media - for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) { - if ($this->getDrawingHashTable()->getByIndex($i) instanceof WorksheetDrawing) { - $imageContents = null; - $imagePath = $this->getDrawingHashTable()->getByIndex($i)->getPath(); - if (strpos($imagePath, 'zip://') !== false) { - $imagePath = substr($imagePath, 6); - $imagePathSplitted = explode('#', $imagePath); - - $imageZip = new ZipArchive(); - $imageZip->open($imagePathSplitted[0]); - $imageContents = $imageZip->getFromName($imagePathSplitted[1]); - $imageZip->close(); - unset($imageZip); - } else { - $imageContents = file_get_contents($imagePath); - } - - $this->addZipFile('xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); - } elseif ($this->getDrawingHashTable()->getByIndex($i) instanceof MemoryDrawing) { - ob_start(); - call_user_func( - $this->getDrawingHashTable()->getByIndex($i)->getRenderingFunction(), - $this->getDrawingHashTable()->getByIndex($i)->getImageResource() - ); - $imageContents = ob_get_contents(); - ob_end_clean(); - - $this->addZipFile('xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); - } - } - - Functions::setReturnDateType($saveDateReturnType); - Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog($saveDebugLog); - - // Close file - try { - $this->zip->finish(); - } catch (OverflowException $e) { - throw new WriterException('Could not close resource.'); - } - - $this->maybeCloseFileHandle(); - } else { - throw new WriterException('PhpSpreadsheet object unassigned.'); + // Create string lookup table + $this->stringTable = []; + for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { + $this->stringTable = $this->getWriterPart('StringTable')->createStringTable($this->spreadSheet->getSheet($i), $this->stringTable); } + + // Create styles dictionaries + $this->styleHashTable->addFromSource($this->getWriterPart('Style')->allStyles($this->spreadSheet)); + $this->stylesConditionalHashTable->addFromSource($this->getWriterPart('Style')->allConditionalStyles($this->spreadSheet)); + $this->fillHashTable->addFromSource($this->getWriterPart('Style')->allFills($this->spreadSheet)); + $this->fontHashTable->addFromSource($this->getWriterPart('Style')->allFonts($this->spreadSheet)); + $this->bordersHashTable->addFromSource($this->getWriterPart('Style')->allBorders($this->spreadSheet)); + $this->numFmtHashTable->addFromSource($this->getWriterPart('Style')->allNumberFormats($this->spreadSheet)); + + // Create drawing dictionary + $this->drawingHashTable->addFromSource($this->getWriterPart('Drawing')->allDrawings($this->spreadSheet)); + + $options = new Archive(); + $options->setEnableZip64(false); + $options->setOutputStream($this->fileHandle); + + $this->zip = new ZipStream(null, $options); + + // Add [Content_Types].xml to ZIP file + $this->addZipFile('[Content_Types].xml', $this->getWriterPart('ContentTypes')->writeContentTypes($this->spreadSheet, $this->includeCharts)); + + //if hasMacros, add the vbaProject.bin file, Certificate file(if exists) + if ($this->spreadSheet->hasMacros()) { + $macrosCode = $this->spreadSheet->getMacrosCode(); + if ($macrosCode !== null) { + // we have the code ? + $this->addZipFile('xl/vbaProject.bin', $macrosCode); //allways in 'xl', allways named vbaProject.bin + if ($this->spreadSheet->hasMacrosCertificate()) { + //signed macros ? + // Yes : add the certificate file and the related rels file + $this->addZipFile('xl/vbaProjectSignature.bin', $this->spreadSheet->getMacrosCertificate()); + $this->addZipFile('xl/_rels/vbaProject.bin.rels', $this->getWriterPart('RelsVBA')->writeVBARelationships($this->spreadSheet)); + } + } + } + //a custom UI in this workbook ? add it ("base" xml and additional objects (pictures) and rels) + if ($this->spreadSheet->hasRibbon()) { + $tmpRibbonTarget = $this->spreadSheet->getRibbonXMLData('target'); + $this->addZipFile($tmpRibbonTarget, $this->spreadSheet->getRibbonXMLData('data')); + if ($this->spreadSheet->hasRibbonBinObjects()) { + $tmpRootPath = dirname($tmpRibbonTarget) . '/'; + $ribbonBinObjects = $this->spreadSheet->getRibbonBinObjects('data'); //the files to write + foreach ($ribbonBinObjects as $aPath => $aContent) { + $this->addZipFile($tmpRootPath . $aPath, $aContent); + } + //the rels for files + $this->addZipFile($tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels', $this->getWriterPart('RelsRibbonObjects')->writeRibbonRelationships($this->spreadSheet)); + } + } + + // Add relationships to ZIP file + $this->addZipFile('_rels/.rels', $this->getWriterPart('Rels')->writeRelationships($this->spreadSheet)); + $this->addZipFile('xl/_rels/workbook.xml.rels', $this->getWriterPart('Rels')->writeWorkbookRelationships($this->spreadSheet)); + + // Add document properties to ZIP file + $this->addZipFile('docProps/app.xml', $this->getWriterPart('DocProps')->writeDocPropsApp($this->spreadSheet)); + $this->addZipFile('docProps/core.xml', $this->getWriterPart('DocProps')->writeDocPropsCore($this->spreadSheet)); + $customPropertiesPart = $this->getWriterPart('DocProps')->writeDocPropsCustom($this->spreadSheet); + if ($customPropertiesPart !== null) { + $this->addZipFile('docProps/custom.xml', $customPropertiesPart); + } + + // Add theme to ZIP file + $this->addZipFile('xl/theme/theme1.xml', $this->getWriterPart('Theme')->writeTheme($this->spreadSheet)); + + // Add string table to ZIP file + $this->addZipFile('xl/sharedStrings.xml', $this->getWriterPart('StringTable')->writeStringTable($this->stringTable)); + + // Add styles to ZIP file + $this->addZipFile('xl/styles.xml', $this->getWriterPart('Style')->writeStyles($this->spreadSheet)); + + // Add workbook to ZIP file + $this->addZipFile('xl/workbook.xml', $this->getWriterPart('Workbook')->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas)); + + $chartCount = 0; + // Add worksheets + for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { + $this->addZipFile('xl/worksheets/sheet' . ($i + 1) . '.xml', $this->getWriterPart('Worksheet')->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts)); + if ($this->includeCharts) { + $charts = $this->spreadSheet->getSheet($i)->getChartCollection(); + if (count($charts) > 0) { + foreach ($charts as $chart) { + $this->addZipFile('xl/charts/chart' . ($chartCount + 1) . '.xml', $this->getWriterPart('Chart')->writeChart($chart, $this->preCalculateFormulas)); + ++$chartCount; + } + } + } + } + + $chartRef1 = 0; + // Add worksheet relationships (drawings, ...) + for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { + // Add relationships + $this->addZipFile('xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts)); + + // Add unparsedLoadedData + $sheetCodeName = $this->spreadSheet->getSheet($i)->getCodeName(); + $unparsedLoadedData = $this->spreadSheet->getUnparsedLoadedData(); + if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'])) { + foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'] as $ctrlProp) { + $this->addZipFile($ctrlProp['filePath'], $ctrlProp['content']); + } + } + if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'])) { + foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'] as $ctrlProp) { + $this->addZipFile($ctrlProp['filePath'], $ctrlProp['content']); + } + } + + $drawings = $this->spreadSheet->getSheet($i)->getDrawingCollection(); + $drawingCount = count($drawings); + if ($this->includeCharts) { + $chartCount = $this->spreadSheet->getSheet($i)->getChartCount(); + } + + // Add drawing and image relationship parts + if (($drawingCount > 0) || ($chartCount > 0)) { + // Drawing relationships + $this->addZipFile('xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts)); + + // Drawings + $this->addZipFile('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts)); + } elseif (isset($unparsedLoadedData['sheets'][$sheetCodeName]['drawingAlternateContents'])) { + // Drawings + $this->addZipFile('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, '.'); + $this->addZipFile('xl' . $drawingFile, $drawingXml); + } + } + } + + // Add comment relationship parts + if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) { + // VML Comments + $this->addZipFile('xl/drawings/vmlDrawing' . ($i + 1) . '.vml', $this->getWriterPart('Comments')->writeVMLComments($this->spreadSheet->getSheet($i))); + + // Comments + $this->addZipFile('xl/comments' . ($i + 1) . '.xml', $this->getWriterPart('Comments')->writeComments($this->spreadSheet->getSheet($i))); + } + + // Add unparsed relationship parts + if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) { + foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) { + $this->addZipFile($vmlDrawing['filePath'], $vmlDrawing['content']); + } + } + + // Add header/footer relationship parts + if (count($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) { + // VML Drawings + $this->addZipFile('xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml', $this->getWriterPart('Drawing')->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i))); + + // VML Drawing relationships + $this->addZipFile('xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels', $this->getWriterPart('Rels')->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i))); + + // Media + foreach ($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages() as $image) { + $this->addZipFile('xl/media/' . $image->getIndexedFilename(), file_get_contents($image->getPath())); + } + } + } + + // Add media + for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) { + if ($this->getDrawingHashTable()->getByIndex($i) instanceof WorksheetDrawing) { + $imageContents = null; + $imagePath = $this->getDrawingHashTable()->getByIndex($i)->getPath(); + if (strpos($imagePath, 'zip://') !== false) { + $imagePath = substr($imagePath, 6); + $imagePathSplitted = explode('#', $imagePath); + + $imageZip = new ZipArchive(); + $imageZip->open($imagePathSplitted[0]); + $imageContents = $imageZip->getFromName($imagePathSplitted[1]); + $imageZip->close(); + unset($imageZip); + } else { + $imageContents = file_get_contents($imagePath); + } + + $this->addZipFile('xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); + } elseif ($this->getDrawingHashTable()->getByIndex($i) instanceof MemoryDrawing) { + ob_start(); + call_user_func( + $this->getDrawingHashTable()->getByIndex($i)->getRenderingFunction(), + $this->getDrawingHashTable()->getByIndex($i)->getImageResource() + ); + $imageContents = ob_get_contents(); + ob_end_clean(); + + $this->addZipFile('xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); + } + } + + Functions::setReturnDateType($saveDateReturnType); + Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog($saveDebugLog); + + // Close file + try { + $this->zip->finish(); + } catch (OverflowException $e) { + throw new WriterException('Could not close resource.'); + } + + $this->maybeCloseFileHandle(); } /** @@ -419,11 +415,7 @@ class Xlsx extends BaseWriter */ public function getSpreadsheet() { - if ($this->spreadSheet !== null) { - return $this->spreadSheet; - } - - throw new WriterException('No Spreadsheet object assigned.'); + return $this->spreadSheet; } /** From b9ca8a1a7ba1967d5acdc4e1e5c4de589ab4d5c6 Mon Sep 17 00:00:00 2001 From: Arman Hosseini Date: Fri, 2 Oct 2020 12:35:29 +0330 Subject: [PATCH 4/7] Update index.md (#1620) --- docs/index.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index c1a06459..b1207d53 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,9 +2,8 @@ ![Logo](./assets/logo.svg) -PhpSpreadsheet is a library written in pure PHP and providing a set of -classes that allow you to read from and to write to different -spreadsheet file formats, like Excel and LibreOffice Calc. +PhpSpreadsheet is a library written in pure PHP and offers a set of classes that +allow you to read and write various spreadsheet file formats such as Excel and LibreOffice Calc. ## File formats supported From ef997a0c8e54c4f8d7604fe2c69d1e97ce68a537 Mon Sep 17 00:00:00 2001 From: oleibman Date: Sun, 4 Oct 2020 18:21:40 -0700 Subject: [PATCH 5/7] Bug setting Superscript/Subscript to false (#1567) If font style Superscript is set to true, Subscript is set to false. Likewise, setting Subscript to true sets Superscript to false. Both of these are working as they should. However, setting Superscript to false causes Subscript to be set to true, and setting Subscript to false causes Superscript to be set to true. I believe that is an error in both cases. This change fixes it. There seem to be no existing tests for Font styles. I added the tests necessary to validate this change. I will put adding more on my to-do list. --- src/PhpSpreadsheet/Style/Font.php | 22 ++++------ tests/PhpSpreadsheetTests/Style/FontTest.php | 42 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Style/FontTest.php diff --git a/src/PhpSpreadsheet/Style/Font.php b/src/PhpSpreadsheet/Style/Font.php index eee7df04..a062a38f 100644 --- a/src/PhpSpreadsheet/Style/Font.php +++ b/src/PhpSpreadsheet/Style/Font.php @@ -357,21 +357,18 @@ class Font extends Supervisor /** * Set Superscript. * - * @param bool $pValue - * * @return $this */ - public function setSuperscript($pValue) + public function setSuperscript(bool $pValue) { - if ($pValue == '') { - $pValue = false; - } if ($this->isSupervisor) { $styleArray = $this->getStyleArray(['superscript' => $pValue]); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); } else { $this->superscript = $pValue; - $this->subscript = !$pValue; + if ($this->superscript) { + $this->subscript = false; + } } return $this; @@ -394,21 +391,18 @@ class Font extends Supervisor /** * Set Subscript. * - * @param bool $pValue - * * @return $this */ - public function setSubscript($pValue) + public function setSubscript(bool $pValue) { - if ($pValue == '') { - $pValue = false; - } if ($this->isSupervisor) { $styleArray = $this->getStyleArray(['subscript' => $pValue]); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); } else { $this->subscript = $pValue; - $this->superscript = !$pValue; + if ($this->subscript) { + $this->superscript = false; + } } return $this; diff --git a/tests/PhpSpreadsheetTests/Style/FontTest.php b/tests/PhpSpreadsheetTests/Style/FontTest.php new file mode 100644 index 00000000..c014a4b6 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Style/FontTest.php @@ -0,0 +1,42 @@ +getActiveSheet(); + $cell = $sheet->getCell('A1'); + $cell->setValue('Cell A1'); + $font = $cell->getStyle()->getFont(); + $font->setSuperscript(true); + $font->setSubscript(true); + self::assertFalse($font->getSuperscript(), 'Earlier set true loses'); + self::assertTrue($font->getSubscript(), 'Last set true wins'); + $font->setSubscript(true); + $font->setSuperscript(true); + self::assertTrue($font->getSuperscript(), 'Last set true wins'); + self::assertFalse($font->getSubscript(), 'Earlier set true loses'); + $font->setSuperscript(false); + $font->setSubscript(false); + self::assertFalse($font->getSuperscript(), 'False remains unchanged'); + self::assertFalse($font->getSubscript(), 'False remains unchanged'); + $font->setSubscript(false); + $font->setSuperscript(false); + self::assertFalse($font->getSuperscript(), 'False remains unchanged'); + self::assertFalse($font->getSubscript(), 'False remains unchanged'); + $font->setSubscript(true); + $font->setSuperscript(false); + self::assertFalse($font->getSuperscript(), 'False remains unchanged'); + self::assertTrue($font->getSubscript(), 'True remains unchanged'); + $font->setSubscript(false); + $font->setSuperscript(true); + self::assertTrue($font->getSuperscript()); + self::assertFalse($font->getSubscript(), 'False remains unchanged'); + } +} From 9f6da8a7c26c423947cf468c18f68f9fe8a18eb8 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Mon, 5 Oct 2020 10:27:19 +0900 Subject: [PATCH 6/7] Update CHANGELOG --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5e4e5b9..f4d98d94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Improve Coverage for ODS Reader [#1545](https://github.com/phpoffice/phpspreadsheet/pull/1545) - Named formula implementation, and improved handling of Defined Names generally [#1535](https://github.com/PHPOffice/PhpSpreadsheet/pull/1535) - - fix resolution of relative named range values in the calculation engine; previously all named range values had been treated as absolute. +- fix resolution of relative named range values in the calculation engine; previously all named range values had been treated as absolute. +- Drop $this->spreadSheet null check from Xlsx Writer [#1646](https://github.com/phpoffice/phpspreadsheet/pull/1646) ### Deprecated @@ -49,6 +50,10 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed - PrintArea causes exception [#1544](https://github.com/phpoffice/phpspreadsheet/pull/1544) +- Calculation/DateTime Failure With PHP8 [#1661](https://github.com/phpoffice/phpspreadsheet/pull/1661) +- Reader/Gnumeric Failure with PHP8 [#1662](https://github.com/phpoffice/phpspreadsheet/pull/1662) +- ReverseSort bug, exposed but not caused by PHP8 [#1660](https://github.com/phpoffice/phpspreadsheet/pull/1660) +- Bug setting Superscript/Subscript to false [#1567](https://github.com/phpoffice/phpspreadsheet/pull/1567) ## 1.14.1 - 2020-07-19 From 12bdcaa78377848c48fdc7ebf137a550160b2b2f Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Mon, 5 Oct 2020 10:27:27 +0900 Subject: [PATCH 7/7] Sync README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 893b3784..0fed4301 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ [![License](https://poser.pugx.org/phpoffice/phpspreadsheet/license.png)](https://packagist.org/packages/phpoffice/phpspreadsheet) [![Join the chat at https://gitter.im/PHPOffice/PhpSpreadsheet](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PhpSpreadsheet) -PhpSpreadsheet is a library written in pure PHP and providing a set of classes that allow you to read from and to write to different spreadsheet file formats, like Excel and LibreOffice Calc. +PhpSpreadsheet is a library written in pure PHP and offers a set of classes that +allow you to read and write various spreadsheet file formats such as Excel and LibreOffice Calc. ## Documentation