8889841cPKO**ContentTypes.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Types $objWriter->startElement('Types'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); // Theme $this->writeOverrideContentType($objWriter, '/xl/theme/theme1.xml', 'application/vnd.openxmlformats-officedocument.theme+xml'); // Styles $this->writeOverrideContentType($objWriter, '/xl/styles.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml'); // Rels $this->writeDefaultContentType($objWriter, 'rels', 'application/vnd.openxmlformats-package.relationships+xml'); // XML $this->writeDefaultContentType($objWriter, 'xml', 'application/xml'); // VML $this->writeDefaultContentType($objWriter, 'vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'); // Workbook if ($spreadsheet->hasMacros()) { //Macros in workbook ? // Yes : not standard content but "macroEnabled" $this->writeOverrideContentType($objWriter, '/xl/workbook.xml', 'application/vnd.ms-excel.sheet.macroEnabled.main+xml'); //... and define a new type for the VBA project // Better use Override, because we can use 'bin' also for xl\printerSettings\printerSettings1.bin $this->writeOverrideContentType($objWriter, '/xl/vbaProject.bin', 'application/vnd.ms-office.vbaProject'); if ($spreadsheet->hasMacrosCertificate()) { // signed macros ? // Yes : add needed information $this->writeOverrideContentType($objWriter, '/xl/vbaProjectSignature.bin', 'application/vnd.ms-office.vbaProjectSignature'); } } else { // no macros in workbook, so standard type $this->writeOverrideContentType($objWriter, '/xl/workbook.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml'); } // DocProps $this->writeOverrideContentType($objWriter, '/docProps/app.xml', 'application/vnd.openxmlformats-officedocument.extended-properties+xml'); $this->writeOverrideContentType($objWriter, '/docProps/core.xml', 'application/vnd.openxmlformats-package.core-properties+xml'); $customPropertyList = $spreadsheet->getProperties()->getCustomProperties(); if (!empty($customPropertyList)) { $this->writeOverrideContentType($objWriter, '/docProps/custom.xml', 'application/vnd.openxmlformats-officedocument.custom-properties+xml'); } // Worksheets $sheetCount = $spreadsheet->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { $this->writeOverrideContentType($objWriter, '/xl/worksheets/sheet' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml'); } // Shared strings $this->writeOverrideContentType($objWriter, '/xl/sharedStrings.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml'); // Add worksheet relationship content types $unparsedLoadedData = $spreadsheet->getUnparsedLoadedData(); $chart = 1; for ($i = 0; $i < $sheetCount; ++$i) { $drawings = $spreadsheet->getSheet($i)->getDrawingCollection(); $drawingCount = count($drawings); $chartCount = ($includeCharts) ? $spreadsheet->getSheet($i)->getChartCount() : 0; $hasUnparsedDrawing = isset($unparsedLoadedData['sheets'][$spreadsheet->getSheet($i)->getCodeName()]['drawingOriginalIds']); // We need a drawing relationship for the worksheet if we have either drawings or charts if (($drawingCount > 0) || ($chartCount > 0) || $hasUnparsedDrawing) { $this->writeOverrideContentType($objWriter, '/xl/drawings/drawing' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.drawing+xml'); } // If we have charts, then we need a chart relationship for every individual chart if ($chartCount > 0) { for ($c = 0; $c < $chartCount; ++$c) { $this->writeOverrideContentType($objWriter, '/xl/charts/chart' . $chart++ . '.xml', 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml'); } } } // Comments for ($i = 0; $i < $sheetCount; ++$i) { if (count($spreadsheet->getSheet($i)->getComments()) > 0) { $this->writeOverrideContentType($objWriter, '/xl/comments' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml'); } } // Add media content-types $aMediaContentTypes = []; $mediaCount = $this->getParentWriter()->getDrawingHashTable()->count(); for ($i = 0; $i < $mediaCount; ++$i) { $extension = ''; $mimeType = ''; if ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing) { $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getExtension()); $mimeType = $this->getImageMimeType($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getPath()); } elseif ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof MemoryDrawing) { $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getMimeType()); $extension = explode('/', $extension); $extension = $extension[1]; $mimeType = $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getMimeType(); } if (!isset($aMediaContentTypes[$extension])) { $aMediaContentTypes[$extension] = $mimeType; $this->writeDefaultContentType($objWriter, $extension, $mimeType); } } if ($spreadsheet->hasRibbonBinObjects()) { // Some additional objects in the ribbon ? // we need to write "Extension" but not already write for media content $tabRibbonTypes = array_diff($spreadsheet->getRibbonBinObjects('types') ?? [], array_keys($aMediaContentTypes)); foreach ($tabRibbonTypes as $aRibbonType) { $mimeType = 'image/.' . $aRibbonType; //we wrote $mimeType like customUI Editor $this->writeDefaultContentType($objWriter, $aRibbonType, $mimeType); } } $sheetCount = $spreadsheet->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { if (count($spreadsheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) { foreach ($spreadsheet->getSheet($i)->getHeaderFooter()->getImages() as $image) { if (!isset($aMediaContentTypes[strtolower($image->getExtension())])) { $aMediaContentTypes[strtolower($image->getExtension())] = $this->getImageMimeType($image->getPath()); $this->writeDefaultContentType($objWriter, strtolower($image->getExtension()), $aMediaContentTypes[strtolower($image->getExtension())]); } } } } // unparsed defaults if (isset($unparsedLoadedData['default_content_types'])) { foreach ($unparsedLoadedData['default_content_types'] as $extName => $contentType) { $this->writeDefaultContentType($objWriter, $extName, $contentType); } } // unparsed overrides if (isset($unparsedLoadedData['override_content_types'])) { foreach ($unparsedLoadedData['override_content_types'] as $partName => $overrideType) { $this->writeOverrideContentType($objWriter, $partName, $overrideType); } } $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Get image mime type. * * @param string $filename Filename * * @return string Mime Type */ private function getImageMimeType($filename) { if (File::fileExists($filename)) { $image = getimagesize($filename); return image_type_to_mime_type((is_array($image) && count($image) >= 3) ? $image[2] : 0); } throw new WriterException("File $filename does not exist"); } /** * Write Default content type. * * @param string $partName Part name * @param string $contentType Content type */ private function writeDefaultContentType(XMLWriter $objWriter, $partName, $contentType): void { if ($partName != '' && $contentType != '') { // Write content type $objWriter->startElement('Default'); $objWriter->writeAttribute('Extension', $partName); $objWriter->writeAttribute('ContentType', $contentType); $objWriter->endElement(); } else { throw new WriterException('Invalid parameters passed.'); } } /** * Write Override content type. * * @param string $partName Part name * @param string $contentType Content type */ private function writeOverrideContentType(XMLWriter $objWriter, $partName, $contentType): void { if ($partName != '' && $contentType != '') { // Write content type $objWriter->startElement('Override'); $objWriter->writeAttribute('PartName', $partName); $objWriter->writeAttribute('ContentType', $contentType); $objWriter->endElement(); } else { throw new WriterException('Invalid parameters passed.'); } } } PK[`|rr Worksheet.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Worksheet $objWriter->startElement('worksheet'); $objWriter->writeAttribute('xml:space', 'preserve'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'); $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing'); $objWriter->writeAttribute('xmlns:x14', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main'); $objWriter->writeAttribute('xmlns:xm', 'http://schemas.microsoft.com/office/excel/2006/main'); $objWriter->writeAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); $objWriter->writeAttribute('mc:Ignorable', 'x14ac'); $objWriter->writeAttribute('xmlns:x14ac', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac'); // sheetPr $this->writeSheetPr($objWriter, $worksheet); // Dimension $this->writeDimension($objWriter, $worksheet); // sheetViews $this->writeSheetViews($objWriter, $worksheet); // sheetFormatPr $this->writeSheetFormatPr($objWriter, $worksheet); // cols $this->writeCols($objWriter, $worksheet); // sheetData $this->writeSheetData($objWriter, $worksheet, $stringTable); // sheetProtection $this->writeSheetProtection($objWriter, $worksheet); // protectedRanges $this->writeProtectedRanges($objWriter, $worksheet); // autoFilter $this->writeAutoFilter($objWriter, $worksheet); // mergeCells $this->writeMergeCells($objWriter, $worksheet); // conditionalFormatting $this->writeConditionalFormatting($objWriter, $worksheet); // dataValidations $this->writeDataValidations($objWriter, $worksheet); // hyperlinks $this->writeHyperlinks($objWriter, $worksheet); // Print options $this->writePrintOptions($objWriter, $worksheet); // Page margins $this->writePageMargins($objWriter, $worksheet); // Page setup $this->writePageSetup($objWriter, $worksheet); // Header / footer $this->writeHeaderFooter($objWriter, $worksheet); // Breaks $this->writeBreaks($objWriter, $worksheet); // Drawings and/or Charts $this->writeDrawings($objWriter, $worksheet, $includeCharts); // LegacyDrawing $this->writeLegacyDrawing($objWriter, $worksheet); // LegacyDrawingHF $this->writeLegacyDrawingHF($objWriter, $worksheet); // AlternateContent $this->writeAlternateContent($objWriter, $worksheet); // ConditionalFormattingRuleExtensionList // (Must be inserted last. Not insert last, an Excel parse error will occur) $this->writeExtLst($objWriter, $worksheet); $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write SheetPr. */ private function writeSheetPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // sheetPr $objWriter->startElement('sheetPr'); if ($worksheet->getParent()->hasMacros()) { //if the workbook have macros, we need to have codeName for the sheet if (!$worksheet->hasCodeName()) { $worksheet->setCodeName($worksheet->getTitle()); } self::writeAttributeNotNull($objWriter, 'codeName', $worksheet->getCodeName()); } $autoFilterRange = $worksheet->getAutoFilter()->getRange(); if (!empty($autoFilterRange)) { $objWriter->writeAttribute('filterMode', 1); $worksheet->getAutoFilter()->showHideRows(); } // tabColor if ($worksheet->isTabColorSet()) { $objWriter->startElement('tabColor'); $objWriter->writeAttribute('rgb', $worksheet->getTabColor()->getARGB()); $objWriter->endElement(); } // outlinePr $objWriter->startElement('outlinePr'); $objWriter->writeAttribute('summaryBelow', ($worksheet->getShowSummaryBelow() ? '1' : '0')); $objWriter->writeAttribute('summaryRight', ($worksheet->getShowSummaryRight() ? '1' : '0')); $objWriter->endElement(); // pageSetUpPr if ($worksheet->getPageSetup()->getFitToPage()) { $objWriter->startElement('pageSetUpPr'); $objWriter->writeAttribute('fitToPage', '1'); $objWriter->endElement(); } $objWriter->endElement(); } /** * Write Dimension. */ private function writeDimension(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // dimension $objWriter->startElement('dimension'); $objWriter->writeAttribute('ref', $worksheet->calculateWorksheetDimension()); $objWriter->endElement(); } /** * Write SheetViews. */ private function writeSheetViews(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // sheetViews $objWriter->startElement('sheetViews'); // Sheet selected? $sheetSelected = false; if ($this->getParentWriter()->getSpreadsheet()->getIndex($worksheet) == $this->getParentWriter()->getSpreadsheet()->getActiveSheetIndex()) { $sheetSelected = true; } // sheetView $objWriter->startElement('sheetView'); $objWriter->writeAttribute('tabSelected', $sheetSelected ? '1' : '0'); $objWriter->writeAttribute('workbookViewId', '0'); // Zoom scales if ($worksheet->getSheetView()->getZoomScale() != 100) { $objWriter->writeAttribute('zoomScale', $worksheet->getSheetView()->getZoomScale()); } if ($worksheet->getSheetView()->getZoomScaleNormal() != 100) { $objWriter->writeAttribute('zoomScaleNormal', $worksheet->getSheetView()->getZoomScaleNormal()); } // Show zeros (Excel also writes this attribute only if set to false) if ($worksheet->getSheetView()->getShowZeros() === false) { $objWriter->writeAttribute('showZeros', 0); } // View Layout Type if ($worksheet->getSheetView()->getView() !== SheetView::SHEETVIEW_NORMAL) { $objWriter->writeAttribute('view', $worksheet->getSheetView()->getView()); } // Gridlines if ($worksheet->getShowGridlines()) { $objWriter->writeAttribute('showGridLines', 'true'); } else { $objWriter->writeAttribute('showGridLines', 'false'); } // Row and column headers if ($worksheet->getShowRowColHeaders()) { $objWriter->writeAttribute('showRowColHeaders', '1'); } else { $objWriter->writeAttribute('showRowColHeaders', '0'); } // Right-to-left if ($worksheet->getRightToLeft()) { $objWriter->writeAttribute('rightToLeft', 'true'); } $topLeftCell = $worksheet->getTopLeftCell(); $activeCell = $worksheet->getActiveCell(); $sqref = $worksheet->getSelectedCells(); // Pane $pane = ''; if ($worksheet->getFreezePane()) { [$xSplit, $ySplit] = Coordinate::coordinateFromString($worksheet->getFreezePane() ?? ''); $xSplit = Coordinate::columnIndexFromString($xSplit); --$xSplit; --$ySplit; // pane $pane = 'topRight'; $objWriter->startElement('pane'); if ($xSplit > 0) { $objWriter->writeAttribute('xSplit', $xSplit); } if ($ySplit > 0) { $objWriter->writeAttribute('ySplit', $ySplit); $pane = ($xSplit > 0) ? 'bottomRight' : 'bottomLeft'; } self::writeAttributeNotNull($objWriter, 'topLeftCell', $topLeftCell); $objWriter->writeAttribute('activePane', $pane); $objWriter->writeAttribute('state', 'frozen'); $objWriter->endElement(); if (($xSplit > 0) && ($ySplit > 0)) { // Write additional selections if more than two panes (ie both an X and a Y split) $objWriter->startElement('selection'); $objWriter->writeAttribute('pane', 'topRight'); $objWriter->endElement(); $objWriter->startElement('selection'); $objWriter->writeAttribute('pane', 'bottomLeft'); $objWriter->endElement(); } } else { self::writeAttributeNotNull($objWriter, 'topLeftCell', $topLeftCell); } // Selection // Only need to write selection element if we have a split pane // We cheat a little by over-riding the active cell selection, setting it to the split cell $objWriter->startElement('selection'); if ($pane != '') { $objWriter->writeAttribute('pane', $pane); } $objWriter->writeAttribute('activeCell', $activeCell); $objWriter->writeAttribute('sqref', $sqref); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); } /** * Write SheetFormatPr. */ private function writeSheetFormatPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // sheetFormatPr $objWriter->startElement('sheetFormatPr'); // Default row height if ($worksheet->getDefaultRowDimension()->getRowHeight() >= 0) { $objWriter->writeAttribute('customHeight', 'true'); $objWriter->writeAttribute('defaultRowHeight', StringHelper::formatNumber($worksheet->getDefaultRowDimension()->getRowHeight())); } else { $objWriter->writeAttribute('defaultRowHeight', '14.4'); } // Set Zero Height row if ( (string) $worksheet->getDefaultRowDimension()->getZeroHeight() === '1' || strtolower((string) $worksheet->getDefaultRowDimension()->getZeroHeight()) == 'true' ) { $objWriter->writeAttribute('zeroHeight', '1'); } // Default column width if ($worksheet->getDefaultColumnDimension()->getWidth() >= 0) { $objWriter->writeAttribute('defaultColWidth', StringHelper::formatNumber($worksheet->getDefaultColumnDimension()->getWidth())); } // Outline level - row $outlineLevelRow = 0; foreach ($worksheet->getRowDimensions() as $dimension) { if ($dimension->getOutlineLevel() > $outlineLevelRow) { $outlineLevelRow = $dimension->getOutlineLevel(); } } $objWriter->writeAttribute('outlineLevelRow', (int) $outlineLevelRow); // Outline level - column $outlineLevelCol = 0; foreach ($worksheet->getColumnDimensions() as $dimension) { if ($dimension->getOutlineLevel() > $outlineLevelCol) { $outlineLevelCol = $dimension->getOutlineLevel(); } } $objWriter->writeAttribute('outlineLevelCol', (int) $outlineLevelCol); $objWriter->endElement(); } /** * Write Cols. */ private function writeCols(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // cols if (count($worksheet->getColumnDimensions()) > 0) { $objWriter->startElement('cols'); $worksheet->calculateColumnWidths(); // Loop through column dimensions foreach ($worksheet->getColumnDimensions() as $colDimension) { // col $objWriter->startElement('col'); $objWriter->writeAttribute('min', Coordinate::columnIndexFromString($colDimension->getColumnIndex())); $objWriter->writeAttribute('max', Coordinate::columnIndexFromString($colDimension->getColumnIndex())); if ($colDimension->getWidth() < 0) { // No width set, apply default of 10 $objWriter->writeAttribute('width', '9.10'); } else { // Width set $objWriter->writeAttribute('width', StringHelper::formatNumber($colDimension->getWidth())); } // Column visibility if ($colDimension->getVisible() === false) { $objWriter->writeAttribute('hidden', 'true'); } // Auto size? if ($colDimension->getAutoSize()) { $objWriter->writeAttribute('bestFit', 'true'); } // Custom width? if ($colDimension->getWidth() != $worksheet->getDefaultColumnDimension()->getWidth()) { $objWriter->writeAttribute('customWidth', 'true'); } // Collapsed if ($colDimension->getCollapsed() === true) { $objWriter->writeAttribute('collapsed', 'true'); } // Outline level if ($colDimension->getOutlineLevel() > 0) { $objWriter->writeAttribute('outlineLevel', $colDimension->getOutlineLevel()); } // Style $objWriter->writeAttribute('style', $colDimension->getXfIndex()); $objWriter->endElement(); } $objWriter->endElement(); } } /** * Write SheetProtection. */ private function writeSheetProtection(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // sheetProtection $objWriter->startElement('sheetProtection'); $protection = $worksheet->getProtection(); if ($protection->getAlgorithm()) { $objWriter->writeAttribute('algorithmName', $protection->getAlgorithm()); $objWriter->writeAttribute('hashValue', $protection->getPassword()); $objWriter->writeAttribute('saltValue', $protection->getSalt()); $objWriter->writeAttribute('spinCount', $protection->getSpinCount()); } elseif ($protection->getPassword() !== '') { $objWriter->writeAttribute('password', $protection->getPassword()); } $objWriter->writeAttribute('sheet', ($protection->getSheet() ? 'true' : 'false')); $objWriter->writeAttribute('objects', ($protection->getObjects() ? 'true' : 'false')); $objWriter->writeAttribute('scenarios', ($protection->getScenarios() ? 'true' : 'false')); $objWriter->writeAttribute('formatCells', ($protection->getFormatCells() ? 'true' : 'false')); $objWriter->writeAttribute('formatColumns', ($protection->getFormatColumns() ? 'true' : 'false')); $objWriter->writeAttribute('formatRows', ($protection->getFormatRows() ? 'true' : 'false')); $objWriter->writeAttribute('insertColumns', ($protection->getInsertColumns() ? 'true' : 'false')); $objWriter->writeAttribute('insertRows', ($protection->getInsertRows() ? 'true' : 'false')); $objWriter->writeAttribute('insertHyperlinks', ($protection->getInsertHyperlinks() ? 'true' : 'false')); $objWriter->writeAttribute('deleteColumns', ($protection->getDeleteColumns() ? 'true' : 'false')); $objWriter->writeAttribute('deleteRows', ($protection->getDeleteRows() ? 'true' : 'false')); $objWriter->writeAttribute('selectLockedCells', ($protection->getSelectLockedCells() ? 'true' : 'false')); $objWriter->writeAttribute('sort', ($protection->getSort() ? 'true' : 'false')); $objWriter->writeAttribute('autoFilter', ($protection->getAutoFilter() ? 'true' : 'false')); $objWriter->writeAttribute('pivotTables', ($protection->getPivotTables() ? 'true' : 'false')); $objWriter->writeAttribute('selectUnlockedCells', ($protection->getSelectUnlockedCells() ? 'true' : 'false')); $objWriter->endElement(); } private static function writeAttributeIf(XMLWriter $objWriter, $condition, string $attr, string $val): void { if ($condition) { $objWriter->writeAttribute($attr, $val); } } private static function writeAttributeNotNull(XMLWriter $objWriter, string $attr, ?string $val): void { if ($val !== null) { $objWriter->writeAttribute($attr, $val); } } private static function writeElementIf(XMLWriter $objWriter, $condition, string $attr, string $val): void { if ($condition) { $objWriter->writeElement($attr, $val); } } private static function writeOtherCondElements(XMLWriter $objWriter, Conditional $conditional, string $cellCoordinate): void { if ( $conditional->getConditionType() == Conditional::CONDITION_CELLIS || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT || $conditional->getConditionType() == Conditional::CONDITION_EXPRESSION ) { foreach ($conditional->getConditions() as $formula) { // Formula $objWriter->writeElement('formula', Xlfn::addXlfn($formula)); } } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSBLANKS) { // formula copied from ms xlsx xml source file $objWriter->writeElement('formula', 'LEN(TRIM(' . $cellCoordinate . '))=0'); } elseif ($conditional->getConditionType() == Conditional::CONDITION_NOTCONTAINSBLANKS) { // formula copied from ms xlsx xml source file $objWriter->writeElement('formula', 'LEN(TRIM(' . $cellCoordinate . '))>0'); } } private static function writeTextCondElements(XMLWriter $objWriter, Conditional $conditional, string $cellCoordinate): void { $txt = $conditional->getText(); if ($txt !== null) { $objWriter->writeAttribute('text', $txt); if ($conditional->getOperatorType() == Conditional::OPERATOR_CONTAINSTEXT) { $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $txt . '",' . $cellCoordinate . ')))'); } elseif ($conditional->getOperatorType() == Conditional::OPERATOR_BEGINSWITH) { $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($txt) . ')="' . $txt . '"'); } elseif ($conditional->getOperatorType() == Conditional::OPERATOR_ENDSWITH) { $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($txt) . ')="' . $txt . '"'); } elseif ($conditional->getOperatorType() == Conditional::OPERATOR_NOTCONTAINS) { $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $txt . '",' . $cellCoordinate . '))'); } } } private static function writeExtConditionalFormattingElements(XMLWriter $objWriter, ConditionalFormattingRuleExtension $ruleExtension): void { $prefix = 'x14'; $objWriter->startElementNs($prefix, 'conditionalFormatting', null); $objWriter->startElementNs($prefix, 'cfRule', null); $objWriter->writeAttribute('type', $ruleExtension->getCfRule()); $objWriter->writeAttribute('id', $ruleExtension->getId()); $objWriter->startElementNs($prefix, 'dataBar', null); $dataBar = $ruleExtension->getDataBarExt(); foreach ($dataBar->getXmlAttributes() as $attrKey => $val) { $objWriter->writeAttribute($attrKey, $val); } $minCfvo = $dataBar->getMinimumConditionalFormatValueObject(); if ($minCfvo) { $objWriter->startElementNs($prefix, 'cfvo', null); $objWriter->writeAttribute('type', $minCfvo->getType()); if ($minCfvo->getCellFormula()) { $objWriter->writeElement('xm:f', $minCfvo->getCellFormula()); } $objWriter->endElement(); //end cfvo } $maxCfvo = $dataBar->getMaximumConditionalFormatValueObject(); if ($maxCfvo) { $objWriter->startElementNs($prefix, 'cfvo', null); $objWriter->writeAttribute('type', $maxCfvo->getType()); if ($maxCfvo->getCellFormula()) { $objWriter->writeElement('xm:f', $maxCfvo->getCellFormula()); } $objWriter->endElement(); //end cfvo } foreach ($dataBar->getXmlElements() as $elmKey => $elmAttr) { $objWriter->startElementNs($prefix, $elmKey, null); foreach ($elmAttr as $attrKey => $attrVal) { $objWriter->writeAttribute($attrKey, $attrVal); } $objWriter->endElement(); //end elmKey } $objWriter->endElement(); //end dataBar $objWriter->endElement(); //end cfRule $objWriter->writeElement('xm:sqref', $ruleExtension->getSqref()); $objWriter->endElement(); //end conditionalFormatting } private static function writeDataBarElements(XMLWriter $objWriter, $dataBar): void { /** @var ConditionalDataBar $dataBar */ if ($dataBar) { $objWriter->startElement('dataBar'); self::writeAttributeIf($objWriter, null !== $dataBar->getShowValue(), 'showValue', $dataBar->getShowValue() ? '1' : '0'); $minCfvo = $dataBar->getMinimumConditionalFormatValueObject(); if ($minCfvo) { $objWriter->startElement('cfvo'); self::writeAttributeIf($objWriter, $minCfvo->getType(), 'type', (string) $minCfvo->getType()); self::writeAttributeIf($objWriter, $minCfvo->getValue(), 'val', (string) $minCfvo->getValue()); $objWriter->endElement(); } $maxCfvo = $dataBar->getMaximumConditionalFormatValueObject(); if ($maxCfvo) { $objWriter->startElement('cfvo'); self::writeAttributeIf($objWriter, $maxCfvo->getType(), 'type', (string) $maxCfvo->getType()); self::writeAttributeIf($objWriter, $maxCfvo->getValue(), 'val', (string) $maxCfvo->getValue()); $objWriter->endElement(); } if ($dataBar->getColor()) { $objWriter->startElement('color'); $objWriter->writeAttribute('rgb', $dataBar->getColor()); $objWriter->endElement(); } $objWriter->endElement(); // end dataBar if ($dataBar->getConditionalFormattingRuleExt()) { $objWriter->startElement('extLst'); $extension = $dataBar->getConditionalFormattingRuleExt(); $objWriter->startElement('ext'); $objWriter->writeAttribute('uri', '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}'); $objWriter->startElementNs('x14', 'id', null); $objWriter->text($extension->getId()); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); //end extLst } } } /** * Write ConditionalFormatting. */ private function writeConditionalFormatting(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // Conditional id $id = 1; // Loop through styles in the current worksheet foreach ($worksheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) { foreach ($conditionalStyles as $conditional) { // WHY was this again? // if ($this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) == '') { // continue; // } if ($conditional->getConditionType() != Conditional::CONDITION_NONE) { // conditionalFormatting $objWriter->startElement('conditionalFormatting'); $objWriter->writeAttribute('sqref', $cellCoordinate); // cfRule $objWriter->startElement('cfRule'); $objWriter->writeAttribute('type', $conditional->getConditionType()); self::writeAttributeIf( $objWriter, ($conditional->getConditionType() != Conditional::CONDITION_DATABAR), 'dxfId', (string) $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) ); $objWriter->writeAttribute('priority', $id++); self::writeAttributeif( $objWriter, ( $conditional->getConditionType() === Conditional::CONDITION_CELLIS || $conditional->getConditionType() === Conditional::CONDITION_CONTAINSTEXT || $conditional->getConditionType() === Conditional::CONDITION_NOTCONTAINSTEXT ) && $conditional->getOperatorType() !== Conditional::OPERATOR_NONE, 'operator', $conditional->getOperatorType() ); self::writeAttributeIf($objWriter, $conditional->getStopIfTrue(), 'stopIfTrue', '1'); if ( $conditional->getConditionType() === Conditional::CONDITION_CONTAINSTEXT || $conditional->getConditionType() === Conditional::CONDITION_NOTCONTAINSTEXT ) { self::writeTextCondElements($objWriter, $conditional, $cellCoordinate); } else { self::writeOtherCondElements($objWriter, $conditional, $cellCoordinate); } // self::writeDataBarElements($objWriter, $conditional->getDataBar()); $objWriter->endElement(); //end cfRule $objWriter->endElement(); } } } } /** * Write DataValidations. */ private function writeDataValidations(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // Datavalidation collection $dataValidationCollection = $worksheet->getDataValidationCollection(); // Write data validations? if (!empty($dataValidationCollection)) { $dataValidationCollection = Coordinate::mergeRangesInCollection($dataValidationCollection); $objWriter->startElement('dataValidations'); $objWriter->writeAttribute('count', count($dataValidationCollection)); foreach ($dataValidationCollection as $coordinate => $dv) { $objWriter->startElement('dataValidation'); if ($dv->getType() != '') { $objWriter->writeAttribute('type', $dv->getType()); } if ($dv->getErrorStyle() != '') { $objWriter->writeAttribute('errorStyle', $dv->getErrorStyle()); } if ($dv->getOperator() != '') { $objWriter->writeAttribute('operator', $dv->getOperator()); } $objWriter->writeAttribute('allowBlank', ($dv->getAllowBlank() ? '1' : '0')); $objWriter->writeAttribute('showDropDown', (!$dv->getShowDropDown() ? '1' : '0')); $objWriter->writeAttribute('showInputMessage', ($dv->getShowInputMessage() ? '1' : '0')); $objWriter->writeAttribute('showErrorMessage', ($dv->getShowErrorMessage() ? '1' : '0')); if ($dv->getErrorTitle() !== '') { $objWriter->writeAttribute('errorTitle', $dv->getErrorTitle()); } if ($dv->getError() !== '') { $objWriter->writeAttribute('error', $dv->getError()); } if ($dv->getPromptTitle() !== '') { $objWriter->writeAttribute('promptTitle', $dv->getPromptTitle()); } if ($dv->getPrompt() !== '') { $objWriter->writeAttribute('prompt', $dv->getPrompt()); } $objWriter->writeAttribute('sqref', $dv->getSqref() ?? $coordinate); if ($dv->getFormula1() !== '') { $objWriter->writeElement('formula1', $dv->getFormula1()); } if ($dv->getFormula2() !== '') { $objWriter->writeElement('formula2', $dv->getFormula2()); } $objWriter->endElement(); } $objWriter->endElement(); } } /** * Write Hyperlinks. */ private function writeHyperlinks(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // Hyperlink collection $hyperlinkCollection = $worksheet->getHyperlinkCollection(); // Relation ID $relationId = 1; // Write hyperlinks? if (!empty($hyperlinkCollection)) { $objWriter->startElement('hyperlinks'); foreach ($hyperlinkCollection as $coordinate => $hyperlink) { $objWriter->startElement('hyperlink'); $objWriter->writeAttribute('ref', $coordinate); if (!$hyperlink->isInternal()) { $objWriter->writeAttribute('r:id', 'rId_hyperlink_' . $relationId); ++$relationId; } else { $objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl())); } if ($hyperlink->getTooltip() !== '') { $objWriter->writeAttribute('tooltip', $hyperlink->getTooltip()); $objWriter->writeAttribute('display', $hyperlink->getTooltip()); } $objWriter->endElement(); } $objWriter->endElement(); } } /** * Write ProtectedRanges. */ private function writeProtectedRanges(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { if (count($worksheet->getProtectedCells()) > 0) { // protectedRanges $objWriter->startElement('protectedRanges'); // Loop protectedRanges foreach ($worksheet->getProtectedCells() as $protectedCell => $passwordHash) { // protectedRange $objWriter->startElement('protectedRange'); $objWriter->writeAttribute('name', 'p' . md5($protectedCell)); $objWriter->writeAttribute('sqref', $protectedCell); if (!empty($passwordHash)) { $objWriter->writeAttribute('password', $passwordHash); } $objWriter->endElement(); } $objWriter->endElement(); } } /** * Write MergeCells. */ private function writeMergeCells(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { if (count($worksheet->getMergeCells()) > 0) { // mergeCells $objWriter->startElement('mergeCells'); // Loop mergeCells foreach ($worksheet->getMergeCells() as $mergeCell) { // mergeCell $objWriter->startElement('mergeCell'); $objWriter->writeAttribute('ref', $mergeCell); $objWriter->endElement(); } $objWriter->endElement(); } } /** * Write PrintOptions. */ private function writePrintOptions(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // printOptions $objWriter->startElement('printOptions'); $objWriter->writeAttribute('gridLines', ($worksheet->getPrintGridlines() ? 'true' : 'false')); $objWriter->writeAttribute('gridLinesSet', 'true'); if ($worksheet->getPageSetup()->getHorizontalCentered()) { $objWriter->writeAttribute('horizontalCentered', 'true'); } if ($worksheet->getPageSetup()->getVerticalCentered()) { $objWriter->writeAttribute('verticalCentered', 'true'); } $objWriter->endElement(); } /** * Write PageMargins. */ private function writePageMargins(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // pageMargins $objWriter->startElement('pageMargins'); $objWriter->writeAttribute('left', StringHelper::formatNumber($worksheet->getPageMargins()->getLeft())); $objWriter->writeAttribute('right', StringHelper::formatNumber($worksheet->getPageMargins()->getRight())); $objWriter->writeAttribute('top', StringHelper::formatNumber($worksheet->getPageMargins()->getTop())); $objWriter->writeAttribute('bottom', StringHelper::formatNumber($worksheet->getPageMargins()->getBottom())); $objWriter->writeAttribute('header', StringHelper::formatNumber($worksheet->getPageMargins()->getHeader())); $objWriter->writeAttribute('footer', StringHelper::formatNumber($worksheet->getPageMargins()->getFooter())); $objWriter->endElement(); } /** * Write AutoFilter. */ private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { $autoFilterRange = $worksheet->getAutoFilter()->getRange(); if (!empty($autoFilterRange)) { // autoFilter $objWriter->startElement('autoFilter'); // Strip any worksheet reference from the filter coordinates $range = Coordinate::splitRange($autoFilterRange); $range = $range[0]; // Strip any worksheet ref [$ws, $range[0]] = PhpspreadsheetWorksheet::extractSheetTitle($range[0], true); $range = implode(':', $range); $objWriter->writeAttribute('ref', str_replace('$', '', $range)); $columns = $worksheet->getAutoFilter()->getColumns(); if (count($columns) > 0) { foreach ($columns as $columnID => $column) { $rules = $column->getRules(); if (count($rules) > 0) { $objWriter->startElement('filterColumn'); $objWriter->writeAttribute('colId', $worksheet->getAutoFilter()->getColumnOffset($columnID)); $objWriter->startElement($column->getFilterType()); if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) { $objWriter->writeAttribute('and', 1); } foreach ($rules as $rule) { if ( ($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) && ($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) && ($rule->getValue() === '') ) { // Filter rule for Blanks $objWriter->writeAttribute('blank', 1); } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) { // Dynamic Filter Rule $objWriter->writeAttribute('type', $rule->getGrouping()); $val = $column->getAttribute('val'); if ($val !== null) { $objWriter->writeAttribute('val', "$val"); } $maxVal = $column->getAttribute('maxVal'); if ($maxVal !== null) { $objWriter->writeAttribute('maxVal', "$maxVal"); } } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) { // Top 10 Filter Rule $ruleValue = $rule->getValue(); if (!is_array($ruleValue)) { $objWriter->writeAttribute('val', "$ruleValue"); } $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0')); $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0')); } else { // Filter, DateGroupItem or CustomFilter $objWriter->startElement($rule->getRuleType()); if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) { $objWriter->writeAttribute('operator', $rule->getOperator()); } if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) { // Date Group filters $ruleValue = $rule->getValue(); if (is_array($ruleValue)) { foreach ($ruleValue as $key => $value) { $objWriter->writeAttribute($key, "$value"); } } $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping()); } else { $ruleValue = $rule->getValue(); if (!is_array($ruleValue)) { $objWriter->writeAttribute('val', "$ruleValue"); } } $objWriter->endElement(); } } $objWriter->endElement(); $objWriter->endElement(); } } } $objWriter->endElement(); } } /** * Write PageSetup. */ private function writePageSetup(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // pageSetup $objWriter->startElement('pageSetup'); $objWriter->writeAttribute('paperSize', $worksheet->getPageSetup()->getPaperSize()); $objWriter->writeAttribute('orientation', $worksheet->getPageSetup()->getOrientation()); if ($worksheet->getPageSetup()->getScale() !== null) { $objWriter->writeAttribute('scale', $worksheet->getPageSetup()->getScale()); } if ($worksheet->getPageSetup()->getFitToHeight() !== null) { $objWriter->writeAttribute('fitToHeight', $worksheet->getPageSetup()->getFitToHeight()); } else { $objWriter->writeAttribute('fitToHeight', '0'); } if ($worksheet->getPageSetup()->getFitToWidth() !== null) { $objWriter->writeAttribute('fitToWidth', $worksheet->getPageSetup()->getFitToWidth()); } else { $objWriter->writeAttribute('fitToWidth', '0'); } if ($worksheet->getPageSetup()->getFirstPageNumber() !== null) { $objWriter->writeAttribute('firstPageNumber', $worksheet->getPageSetup()->getFirstPageNumber()); $objWriter->writeAttribute('useFirstPageNumber', '1'); } $objWriter->writeAttribute('pageOrder', $worksheet->getPageSetup()->getPageOrder()); $getUnparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData(); if (isset($getUnparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId'])) { $objWriter->writeAttribute('r:id', $getUnparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId']); } $objWriter->endElement(); } /** * Write Header / Footer. */ private function writeHeaderFooter(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // headerFooter $objWriter->startElement('headerFooter'); $objWriter->writeAttribute('differentOddEven', ($worksheet->getHeaderFooter()->getDifferentOddEven() ? 'true' : 'false')); $objWriter->writeAttribute('differentFirst', ($worksheet->getHeaderFooter()->getDifferentFirst() ? 'true' : 'false')); $objWriter->writeAttribute('scaleWithDoc', ($worksheet->getHeaderFooter()->getScaleWithDocument() ? 'true' : 'false')); $objWriter->writeAttribute('alignWithMargins', ($worksheet->getHeaderFooter()->getAlignWithMargins() ? 'true' : 'false')); $objWriter->writeElement('oddHeader', $worksheet->getHeaderFooter()->getOddHeader()); $objWriter->writeElement('oddFooter', $worksheet->getHeaderFooter()->getOddFooter()); $objWriter->writeElement('evenHeader', $worksheet->getHeaderFooter()->getEvenHeader()); $objWriter->writeElement('evenFooter', $worksheet->getHeaderFooter()->getEvenFooter()); $objWriter->writeElement('firstHeader', $worksheet->getHeaderFooter()->getFirstHeader()); $objWriter->writeElement('firstFooter', $worksheet->getHeaderFooter()->getFirstFooter()); $objWriter->endElement(); } /** * Write Breaks. */ private function writeBreaks(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // Get row and column breaks $aRowBreaks = []; $aColumnBreaks = []; foreach ($worksheet->getBreaks() as $cell => $breakType) { if ($breakType == PhpspreadsheetWorksheet::BREAK_ROW) { $aRowBreaks[] = $cell; } elseif ($breakType == PhpspreadsheetWorksheet::BREAK_COLUMN) { $aColumnBreaks[] = $cell; } } // rowBreaks if (!empty($aRowBreaks)) { $objWriter->startElement('rowBreaks'); $objWriter->writeAttribute('count', count($aRowBreaks)); $objWriter->writeAttribute('manualBreakCount', count($aRowBreaks)); foreach ($aRowBreaks as $cell) { $coords = Coordinate::coordinateFromString($cell); $objWriter->startElement('brk'); $objWriter->writeAttribute('id', $coords[1]); $objWriter->writeAttribute('man', '1'); $objWriter->endElement(); } $objWriter->endElement(); } // Second, write column breaks if (!empty($aColumnBreaks)) { $objWriter->startElement('colBreaks'); $objWriter->writeAttribute('count', count($aColumnBreaks)); $objWriter->writeAttribute('manualBreakCount', count($aColumnBreaks)); foreach ($aColumnBreaks as $cell) { $coords = Coordinate::coordinateFromString($cell); $objWriter->startElement('brk'); $objWriter->writeAttribute('id', Coordinate::columnIndexFromString($coords[0]) - 1); $objWriter->writeAttribute('man', '1'); $objWriter->endElement(); } $objWriter->endElement(); } } /** * Write SheetData. * * @param string[] $stringTable String table */ private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet, array $stringTable): void { // Flipped stringtable, for faster index searching $aFlippedStringTable = $this->getParentWriter()->getWriterPartstringtable()->flipStringTable($stringTable); // sheetData $objWriter->startElement('sheetData'); // Get column count $colCount = Coordinate::columnIndexFromString($worksheet->getHighestColumn()); // Highest row number $highestRow = $worksheet->getHighestRow(); // Loop through cells $cellsByRow = []; foreach ($worksheet->getCoordinates() as $coordinate) { $cellAddress = Coordinate::coordinateFromString($coordinate); $cellsByRow[$cellAddress[1]][] = $coordinate; } $currentRow = 0; while ($currentRow++ < $highestRow) { // Get row dimension $rowDimension = $worksheet->getRowDimension($currentRow); // Write current row? $writeCurrentRow = isset($cellsByRow[$currentRow]) || $rowDimension->getRowHeight() >= 0 || $rowDimension->getVisible() == false || $rowDimension->getCollapsed() == true || $rowDimension->getOutlineLevel() > 0 || $rowDimension->getXfIndex() !== null; if ($writeCurrentRow) { // Start a new row $objWriter->startElement('row'); $objWriter->writeAttribute('r', $currentRow); $objWriter->writeAttribute('spans', '1:' . $colCount); // Row dimensions if ($rowDimension->getRowHeight() >= 0) { $objWriter->writeAttribute('customHeight', '1'); $objWriter->writeAttribute('ht', StringHelper::formatNumber($rowDimension->getRowHeight())); } // Row visibility if (!$rowDimension->getVisible() === true) { $objWriter->writeAttribute('hidden', 'true'); } // Collapsed if ($rowDimension->getCollapsed() === true) { $objWriter->writeAttribute('collapsed', 'true'); } // Outline level if ($rowDimension->getOutlineLevel() > 0) { $objWriter->writeAttribute('outlineLevel', $rowDimension->getOutlineLevel()); } // Style if ($rowDimension->getXfIndex() !== null) { $objWriter->writeAttribute('s', $rowDimension->getXfIndex()); $objWriter->writeAttribute('customFormat', '1'); } // Write cells if (isset($cellsByRow[$currentRow])) { foreach ($cellsByRow[$currentRow] as $cellAddress) { // Write cell $this->writeCell($objWriter, $worksheet, $cellAddress, $aFlippedStringTable); } } // End row $objWriter->endElement(); } } $objWriter->endElement(); } /** * @param RichText|string $cellValue */ private function writeCellInlineStr(XMLWriter $objWriter, string $mappedType, $cellValue): void { $objWriter->writeAttribute('t', $mappedType); if (!$cellValue instanceof RichText) { $objWriter->writeElement( 't', StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue, Settings::htmlEntityFlags())) ); } elseif ($cellValue instanceof RichText) { $objWriter->startElement('is'); $this->getParentWriter()->getWriterPartstringtable()->writeRichText($objWriter, $cellValue); $objWriter->endElement(); } } /** * @param RichText|string $cellValue * @param string[] $flippedStringTable */ private function writeCellString(XMLWriter $objWriter, string $mappedType, $cellValue, array $flippedStringTable): void { $objWriter->writeAttribute('t', $mappedType); if (!$cellValue instanceof RichText) { self::writeElementIf($objWriter, isset($flippedStringTable[$cellValue]), 'v', $flippedStringTable[$cellValue] ?? ''); } else { $objWriter->writeElement('v', $flippedStringTable[$cellValue->getHashCode()]); } } /** * @param float|int $cellValue */ private function writeCellNumeric(XMLWriter $objWriter, $cellValue): void { //force a decimal to be written if the type is float if (is_float($cellValue)) { // force point as decimal separator in case current locale uses comma $cellValue = str_replace(',', '.', (string) $cellValue); if (strpos($cellValue, '.') === false) { $cellValue = $cellValue . '.0'; } } $objWriter->writeElement('v', $cellValue); } private function writeCellBoolean(XMLWriter $objWriter, string $mappedType, bool $cellValue): void { $objWriter->writeAttribute('t', $mappedType); $objWriter->writeElement('v', $cellValue ? '1' : '0'); } private function writeCellError(XMLWriter $objWriter, string $mappedType, string $cellValue, string $formulaerr = '#NULL!'): void { $objWriter->writeAttribute('t', $mappedType); $cellIsFormula = substr($cellValue, 0, 1) === '='; self::writeElementIf($objWriter, $cellIsFormula, 'f', Xlfn::addXlfnStripEquals($cellValue)); $objWriter->writeElement('v', $cellIsFormula ? $formulaerr : $cellValue); } private function writeCellFormula(XMLWriter $objWriter, string $cellValue, Cell $cell): void { $calculatedValue = $this->getParentWriter()->getPreCalculateFormulas() ? $cell->getCalculatedValue() : $cellValue; if (is_string($calculatedValue)) { if (\PhpOffice\PhpSpreadsheet\Calculation\Functions::isError($calculatedValue)) { $this->writeCellError($objWriter, 'e', $cellValue, $calculatedValue); return; } $objWriter->writeAttribute('t', 'str'); $calculatedValue = StringHelper::controlCharacterPHP2OOXML($calculatedValue); } elseif (is_bool($calculatedValue)) { $objWriter->writeAttribute('t', 'b'); $calculatedValue = (int) $calculatedValue; } $attributes = $cell->getFormulaAttributes(); if (($attributes['t'] ?? null) === 'array') { $objWriter->startElement('f'); $objWriter->writeAttribute('t', 'array'); $objWriter->writeAttribute('ref', $cell->getCoordinate()); $objWriter->writeAttribute('aca', '1'); $objWriter->writeAttribute('ca', '1'); $objWriter->text(substr($cellValue, 1)); $objWriter->endElement(); } else { $objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue)); self::writeElementIf( $objWriter, $this->getParentWriter()->getOffice2003Compatibility() === false, 'v', ($this->getParentWriter()->getPreCalculateFormulas() && !is_array($calculatedValue) && substr($calculatedValue, 0, 1) !== '#') ? StringHelper::formatNumber($calculatedValue) : '0' ); } } /** * Write Cell. * * @param string $cellAddress Cell Address * @param string[] $flippedStringTable String table (flipped), for faster index searching */ private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet, string $cellAddress, array $flippedStringTable): void { // Cell $pCell = $worksheet->getCell($cellAddress); $objWriter->startElement('c'); $objWriter->writeAttribute('r', $cellAddress); // Sheet styles $xfi = $pCell->getXfIndex(); self::writeAttributeIf($objWriter, $xfi, 's', $xfi); // If cell value is supplied, write cell value $cellValue = $pCell->getValue(); if (is_object($cellValue) || $cellValue !== '') { // Map type $mappedType = $pCell->getDataType(); // Write data depending on its type switch (strtolower($mappedType)) { case 'inlinestr': // Inline string $this->writeCellInlineStr($objWriter, $mappedType, $cellValue); break; case 's': // String $this->writeCellString($objWriter, $mappedType, $cellValue, $flippedStringTable); break; case 'f': // Formula $this->writeCellFormula($objWriter, $cellValue, $pCell); break; case 'n': // Numeric $this->writeCellNumeric($objWriter, $cellValue); break; case 'b': // Boolean $this->writeCellBoolean($objWriter, $mappedType, $cellValue); break; case 'e': // Error $this->writeCellError($objWriter, $mappedType, $cellValue); } } $objWriter->endElement(); } /** * Write Drawings. * * @param bool $includeCharts Flag indicating if we should include drawing details for charts */ private function writeDrawings(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet, $includeCharts = false): void { $unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData(); $hasUnparsedDrawing = isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds']); $chartCount = ($includeCharts) ? $worksheet->getChartCollection()->count() : 0; if ($chartCount == 0 && $worksheet->getDrawingCollection()->count() == 0 && !$hasUnparsedDrawing) { return; } // If sheet contains drawings, add the relationships $objWriter->startElement('drawing'); $rId = 'rId1'; if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'])) { $drawingOriginalIds = $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds']; // take first. In future can be overriten // (! synchronize with \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Rels::writeWorksheetRelationships) $rId = reset($drawingOriginalIds); } $objWriter->writeAttribute('r:id', $rId); $objWriter->endElement(); } /** * Write LegacyDrawing. */ private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // If sheet contains comments, add the relationships if (count($worksheet->getComments()) > 0) { $objWriter->startElement('legacyDrawing'); $objWriter->writeAttribute('r:id', 'rId_comments_vml1'); $objWriter->endElement(); } } /** * Write LegacyDrawingHF. */ private function writeLegacyDrawingHF(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { // If sheet contains images, add the relationships if (count($worksheet->getHeaderFooter()->getImages()) > 0) { $objWriter->startElement('legacyDrawingHF'); $objWriter->writeAttribute('r:id', 'rId_headerfooter_vml1'); $objWriter->endElement(); } } private function writeAlternateContent(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { if (empty($worksheet->getParent()->getUnparsedLoadedData()['sheets'][$worksheet->getCodeName()]['AlternateContents'])) { return; } foreach ($worksheet->getParent()->getUnparsedLoadedData()['sheets'][$worksheet->getCodeName()]['AlternateContents'] as $alternateContent) { $objWriter->writeRaw($alternateContent); } } /** * write * only implementation conditionalFormattings. * * @url https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/07d607af-5618-4ca2-b683-6a78dc0d9627 */ private function writeExtLst(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void { $conditionalFormattingRuleExtList = []; foreach ($worksheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) { /** @var Conditional $conditional */ foreach ($conditionalStyles as $conditional) { $dataBar = $conditional->getDataBar(); // @phpstan-ignore-next-line if ($dataBar && $dataBar->getConditionalFormattingRuleExt()) { $conditionalFormattingRuleExtList[] = $dataBar->getConditionalFormattingRuleExt(); } } } if (count($conditionalFormattingRuleExtList) > 0) { $conditionalFormattingRuleExtNsPrefix = 'x14'; $objWriter->startElement('extLst'); $objWriter->startElement('ext'); $objWriter->writeAttribute('uri', '{78C0D931-6437-407d-A8EE-F0AAD7539E65}'); $objWriter->startElementNs($conditionalFormattingRuleExtNsPrefix, 'conditionalFormattings', null); foreach ($conditionalFormattingRuleExtList as $extension) { self::writeExtConditionalFormattingElements($objWriter, $extension); } $objWriter->endElement(); //end conditionalFormattings $objWriter->endElement(); //end ext $objWriter->endElement(); //end extLst } } } PKjo Theme.phpnu[themeName = $themeName; $this->colourSchemeName = $colourSchemeName; $this->colourMap = $colourMap; } /** * Get Theme Name. * * @return string */ public function getThemeName() { return $this->themeName; } /** * Get colour Scheme Name. * * @return string */ public function getColourSchemeName() { return $this->colourSchemeName; } /** * Get colour Map Value by Position. * * @param int $index * * @return null|string */ public function getColourByIndex($index) { if (isset($this->colourMap[$index])) { return $this->colourMap[$index]; } return null; } /** * Implement PHP __clone to create a deep clone, not just a shallow copy. */ public function __clone() { $vars = get_object_vars($this); foreach ($vars as $key => $value) { if ((is_object($value)) && ($key != '_parent')) { $this->$key = clone $value; } else { $this->$key = $value; } } } } PK[+^0Xlfn.phpnu[i>Rels.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Relationships $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); $customPropertyList = $spreadsheet->getProperties()->getCustomProperties(); if (!empty($customPropertyList)) { // Relationship docProps/app.xml $this->writeRelationship( $objWriter, 4, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties', 'docProps/custom.xml' ); } // Relationship docProps/app.xml $this->writeRelationship( $objWriter, 3, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', 'docProps/app.xml' ); // Relationship docProps/core.xml $this->writeRelationship( $objWriter, 2, 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', 'docProps/core.xml' ); // Relationship xl/workbook.xml $this->writeRelationship( $objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument', 'xl/workbook.xml' ); // a custom UI in workbook ? if ($spreadsheet->hasRibbon()) { $this->writeRelationShip( $objWriter, 5, 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility', $spreadsheet->getRibbonXMLData('target') ); } $objWriter->endElement(); return $objWriter->getData(); } /** * Write workbook relationships to XML format. * * @return string XML Output */ public function writeWorkbookRelationships(Spreadsheet $spreadsheet) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Relationships $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Relationship styles.xml $this->writeRelationship( $objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles', 'styles.xml' ); // Relationship theme/theme1.xml $this->writeRelationship( $objWriter, 2, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', 'theme/theme1.xml' ); // Relationship sharedStrings.xml $this->writeRelationship( $objWriter, 3, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings', 'sharedStrings.xml' ); // Relationships with sheets $sheetCount = $spreadsheet->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { $this->writeRelationship( $objWriter, ($i + 1 + 3), 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet', 'worksheets/sheet' . ($i + 1) . '.xml' ); } // Relationships for vbaProject if needed // id : just after the last sheet if ($spreadsheet->hasMacros()) { $this->writeRelationShip( $objWriter, ($i + 1 + 3), 'http://schemas.microsoft.com/office/2006/relationships/vbaProject', 'vbaProject.bin' ); ++$i; //increment i if needed for an another relation } $objWriter->endElement(); return $objWriter->getData(); } /** * Write worksheet relationships to XML format. * * Numbering is as follows: * rId1 - Drawings * rId_hyperlink_x - Hyperlinks * * @param int $worksheetId * @param bool $includeCharts Flag indicating if we should write charts * * @return string XML Output */ public function writeWorksheetRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, $worksheetId = 1, $includeCharts = false) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Relationships $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Write drawing relationships? $drawingOriginalIds = []; $unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData(); if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'])) { $drawingOriginalIds = $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds']; } if ($includeCharts) { $charts = $worksheet->getChartCollection(); } else { $charts = []; } if (($worksheet->getDrawingCollection()->count() > 0) || (count($charts) > 0) || $drawingOriginalIds) { $rId = 1; // Use original $relPath to get original $rId. // Take first. In future can be overwritten. // (! synchronize with \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Worksheet::writeDrawings) reset($drawingOriginalIds); $relPath = key($drawingOriginalIds); if (isset($drawingOriginalIds[$relPath])) { $rId = (int) (substr($drawingOriginalIds[$relPath], 3)); } // Generate new $relPath to write drawing relationship $relPath = '../drawings/drawing' . $worksheetId . '.xml'; $this->writeRelationship( $objWriter, $rId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing', $relPath ); } // Write hyperlink relationships? $i = 1; foreach ($worksheet->getHyperlinkCollection() as $hyperlink) { if (!$hyperlink->isInternal()) { $this->writeRelationship( $objWriter, '_hyperlink_' . $i, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External' ); ++$i; } } // Write comments relationship? $i = 1; if (count($worksheet->getComments()) > 0) { $this->writeRelationship( $objWriter, '_comments_vml' . $i, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing', '../drawings/vmlDrawing' . $worksheetId . '.vml' ); $this->writeRelationship( $objWriter, '_comments' . $i, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', '../comments' . $worksheetId . '.xml' ); } // Write header/footer relationship? $i = 1; if (count($worksheet->getHeaderFooter()->getImages()) > 0) { $this->writeRelationship( $objWriter, '_headerfooter_vml' . $i, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing', '../drawings/vmlDrawingHF' . $worksheetId . '.vml' ); } $this->writeUnparsedRelationship($worksheet, $objWriter, 'ctrlProps', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp'); $this->writeUnparsedRelationship($worksheet, $objWriter, 'vmlDrawings', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing'); $this->writeUnparsedRelationship($worksheet, $objWriter, 'printerSettings', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings'); $objWriter->endElement(); return $objWriter->getData(); } private function writeUnparsedRelationship(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, XMLWriter $objWriter, $relationship, $type): void { $unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData(); if (!isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()][$relationship])) { return; } foreach ($unparsedLoadedData['sheets'][$worksheet->getCodeName()][$relationship] as $rId => $value) { $this->writeRelationship( $objWriter, $rId, $type, $value['relFilePath'] ); } } /** * Write drawing relationships to XML format. * * @param int $chartRef Chart ID * @param bool $includeCharts Flag indicating if we should write charts * * @return string XML Output */ public function writeDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, &$chartRef, $includeCharts = false) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Relationships $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Loop through images and write relationships $i = 1; $iterator = $worksheet->getDrawingCollection()->getIterator(); while ($iterator->valid()) { $drawing = $iterator->current(); if ( $drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing || $drawing instanceof MemoryDrawing ) { // Write relationship for image drawing $this->writeRelationship( $objWriter, $i, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . str_replace(' ', '', $drawing->getIndexedFilename()) ); $i = $this->writeDrawingHyperLink($objWriter, $drawing, $i); } $iterator->next(); ++$i; } if ($includeCharts) { // Loop through charts and write relationships $chartCount = $worksheet->getChartCount(); if ($chartCount > 0) { for ($c = 0; $c < $chartCount; ++$c) { $this->writeRelationship( $objWriter, $i++, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', '../charts/chart' . ++$chartRef . '.xml' ); } } } $objWriter->endElement(); return $objWriter->getData(); } /** * Write header/footer drawing relationships to XML format. * * @return string XML Output */ public function writeHeaderFooterDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Relationships $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Loop through images and write relationships foreach ($worksheet->getHeaderFooter()->getImages() as $key => $value) { // Write relationship for image drawing $this->writeRelationship( $objWriter, $key, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $value->getIndexedFilename() ); } $objWriter->endElement(); return $objWriter->getData(); } /** * Write Override content type. * * @param int $id Relationship ID. rId will be prepended! * @param string $type Relationship type * @param string $target Relationship target * @param string $targetMode Relationship target mode */ private function writeRelationship(XMLWriter $objWriter, $id, $type, $target, $targetMode = ''): void { if ($type != '' && $target != '') { // Write relationship $objWriter->startElement('Relationship'); $objWriter->writeAttribute('Id', 'rId' . $id); $objWriter->writeAttribute('Type', $type); $objWriter->writeAttribute('Target', $target); if ($targetMode != '') { $objWriter->writeAttribute('TargetMode', $targetMode); } $objWriter->endElement(); } else { throw new WriterException('Invalid parameters passed.'); } } private function writeDrawingHyperLink(XMLWriter $objWriter, BaseDrawing $drawing, int $i): int { if ($drawing->getHyperlink() === null) { return $i; } ++$i; $this->writeRelationship( $objWriter, $i, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $drawing->getHyperlink()->getUrl(), $drawing->getHyperlink()->getTypeHyperlink() ); return $i; } } PKZ RelsVBA.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Relationships $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); $objWriter->startElement('Relationship'); $objWriter->writeAttribute('Id', 'rId1'); $objWriter->writeAttribute('Type', 'http://schemas.microsoft.com/office/2006/relationships/vbaProjectSignature'); $objWriter->writeAttribute('Target', 'vbaProjectSignature.bin'); $objWriter->endElement(); $objWriter->endElement(); return $objWriter->getData(); } } PKp"p" DocProps.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Properties $objWriter->startElement('Properties'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'); $objWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); // Application $objWriter->writeElement('Application', 'Microsoft Excel'); // DocSecurity $objWriter->writeElement('DocSecurity', '0'); // ScaleCrop $objWriter->writeElement('ScaleCrop', 'false'); // HeadingPairs $objWriter->startElement('HeadingPairs'); // Vector $objWriter->startElement('vt:vector'); $objWriter->writeAttribute('size', '2'); $objWriter->writeAttribute('baseType', 'variant'); // Variant $objWriter->startElement('vt:variant'); $objWriter->writeElement('vt:lpstr', 'Worksheets'); $objWriter->endElement(); // Variant $objWriter->startElement('vt:variant'); $objWriter->writeElement('vt:i4', $spreadsheet->getSheetCount()); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); // TitlesOfParts $objWriter->startElement('TitlesOfParts'); // Vector $objWriter->startElement('vt:vector'); $objWriter->writeAttribute('size', $spreadsheet->getSheetCount()); $objWriter->writeAttribute('baseType', 'lpstr'); $sheetCount = $spreadsheet->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { $objWriter->writeElement('vt:lpstr', $spreadsheet->getSheet($i)->getTitle()); } $objWriter->endElement(); $objWriter->endElement(); // Company $objWriter->writeElement('Company', $spreadsheet->getProperties()->getCompany()); // Company $objWriter->writeElement('Manager', $spreadsheet->getProperties()->getManager()); // LinksUpToDate $objWriter->writeElement('LinksUpToDate', 'false'); // SharedDoc $objWriter->writeElement('SharedDoc', 'false'); // HyperlinksChanged $objWriter->writeElement('HyperlinksChanged', 'false'); // AppVersion $objWriter->writeElement('AppVersion', '12.0000'); $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write docProps/core.xml to XML format. * * @return string XML Output */ public function writeDocPropsCore(Spreadsheet $spreadsheet) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // cp:coreProperties $objWriter->startElement('cp:coreProperties'); $objWriter->writeAttribute('xmlns:cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties'); $objWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); $objWriter->writeAttribute('xmlns:dcterms', 'http://purl.org/dc/terms/'); $objWriter->writeAttribute('xmlns:dcmitype', 'http://purl.org/dc/dcmitype/'); $objWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); // dc:creator $objWriter->writeElement('dc:creator', $spreadsheet->getProperties()->getCreator()); // cp:lastModifiedBy $objWriter->writeElement('cp:lastModifiedBy', $spreadsheet->getProperties()->getLastModifiedBy()); // dcterms:created $objWriter->startElement('dcterms:created'); $objWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); $created = $spreadsheet->getProperties()->getCreated(); $date = Date::dateTimeFromTimestamp("$created"); $objWriter->writeRawData($date->format(DATE_W3C)); $objWriter->endElement(); // dcterms:modified $objWriter->startElement('dcterms:modified'); $objWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); $created = $spreadsheet->getProperties()->getModified(); $date = Date::dateTimeFromTimestamp("$created"); $objWriter->writeRawData($date->format(DATE_W3C)); $objWriter->endElement(); // dc:title $objWriter->writeElement('dc:title', $spreadsheet->getProperties()->getTitle()); // dc:description $objWriter->writeElement('dc:description', $spreadsheet->getProperties()->getDescription()); // dc:subject $objWriter->writeElement('dc:subject', $spreadsheet->getProperties()->getSubject()); // cp:keywords $objWriter->writeElement('cp:keywords', $spreadsheet->getProperties()->getKeywords()); // cp:category $objWriter->writeElement('cp:category', $spreadsheet->getProperties()->getCategory()); $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write docProps/custom.xml to XML format. * * @return null|string XML Output */ public function writeDocPropsCustom(Spreadsheet $spreadsheet) { $customPropertyList = $spreadsheet->getProperties()->getCustomProperties(); if (empty($customPropertyList)) { return null; } // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // cp:coreProperties $objWriter->startElement('Properties'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/custom-properties'); $objWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); foreach ($customPropertyList as $key => $customProperty) { $propertyValue = $spreadsheet->getProperties()->getCustomPropertyValue($customProperty); $propertyType = $spreadsheet->getProperties()->getCustomPropertyType($customProperty); $objWriter->startElement('property'); $objWriter->writeAttribute('fmtid', '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}'); $objWriter->writeAttribute('pid', $key + 2); $objWriter->writeAttribute('name', $customProperty); switch ($propertyType) { case Properties::PROPERTY_TYPE_INTEGER: $objWriter->writeElement('vt:i4', $propertyValue); break; case Properties::PROPERTY_TYPE_FLOAT: $objWriter->writeElement('vt:r8', $propertyValue); break; case Properties::PROPERTY_TYPE_BOOLEAN: $objWriter->writeElement('vt:bool', ($propertyValue) ? 'true' : 'false'); break; case Properties::PROPERTY_TYPE_DATE: $objWriter->startElement('vt:filetime'); $date = Date::dateTimeFromTimestamp("$propertyValue"); $objWriter->writeRawData($date->format(DATE_W3C)); $objWriter->endElement(); break; default: $objWriter->writeElement('vt:lpwstr', $propertyValue); break; } $objWriter->endElement(); } $objWriter->endElement(); return $objWriter->getData(); } } PK[ Workbook.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // workbook $objWriter->startElement('workbook'); $objWriter->writeAttribute('xml:space', 'preserve'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'); $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); // fileVersion $this->writeFileVersion($objWriter); // workbookPr $this->writeWorkbookPr($objWriter); // workbookProtection $this->writeWorkbookProtection($objWriter, $spreadsheet); // bookViews if ($this->getParentWriter()->getOffice2003Compatibility() === false) { $this->writeBookViews($objWriter, $spreadsheet); } // sheets $this->writeSheets($objWriter, $spreadsheet); // definedNames (new DefinedNamesWriter($objWriter, $spreadsheet))->write(); // calcPr $this->writeCalcPr($objWriter, $recalcRequired); $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write file version. */ private function writeFileVersion(XMLWriter $objWriter): void { $objWriter->startElement('fileVersion'); $objWriter->writeAttribute('appName', 'xl'); $objWriter->writeAttribute('lastEdited', '4'); $objWriter->writeAttribute('lowestEdited', '4'); $objWriter->writeAttribute('rupBuild', '4505'); $objWriter->endElement(); } /** * Write WorkbookPr. */ private function writeWorkbookPr(XMLWriter $objWriter): void { $objWriter->startElement('workbookPr'); if (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904) { $objWriter->writeAttribute('date1904', '1'); } $objWriter->writeAttribute('codeName', 'ThisWorkbook'); $objWriter->endElement(); } /** * Write BookViews. */ private function writeBookViews(XMLWriter $objWriter, Spreadsheet $spreadsheet): void { // bookViews $objWriter->startElement('bookViews'); // workbookView $objWriter->startElement('workbookView'); $objWriter->writeAttribute('activeTab', $spreadsheet->getActiveSheetIndex()); $objWriter->writeAttribute('autoFilterDateGrouping', ($spreadsheet->getAutoFilterDateGrouping() ? 'true' : 'false')); $objWriter->writeAttribute('firstSheet', $spreadsheet->getFirstSheetIndex()); $objWriter->writeAttribute('minimized', ($spreadsheet->getMinimized() ? 'true' : 'false')); $objWriter->writeAttribute('showHorizontalScroll', ($spreadsheet->getShowHorizontalScroll() ? 'true' : 'false')); $objWriter->writeAttribute('showSheetTabs', ($spreadsheet->getShowSheetTabs() ? 'true' : 'false')); $objWriter->writeAttribute('showVerticalScroll', ($spreadsheet->getShowVerticalScroll() ? 'true' : 'false')); $objWriter->writeAttribute('tabRatio', $spreadsheet->getTabRatio()); $objWriter->writeAttribute('visibility', $spreadsheet->getVisibility()); $objWriter->endElement(); $objWriter->endElement(); } /** * Write WorkbookProtection. */ private function writeWorkbookProtection(XMLWriter $objWriter, Spreadsheet $spreadsheet): void { if ($spreadsheet->getSecurity()->isSecurityEnabled()) { $objWriter->startElement('workbookProtection'); $objWriter->writeAttribute('lockRevision', ($spreadsheet->getSecurity()->getLockRevision() ? 'true' : 'false')); $objWriter->writeAttribute('lockStructure', ($spreadsheet->getSecurity()->getLockStructure() ? 'true' : 'false')); $objWriter->writeAttribute('lockWindows', ($spreadsheet->getSecurity()->getLockWindows() ? 'true' : 'false')); if ($spreadsheet->getSecurity()->getRevisionsPassword() != '') { $objWriter->writeAttribute('revisionsPassword', $spreadsheet->getSecurity()->getRevisionsPassword()); } if ($spreadsheet->getSecurity()->getWorkbookPassword() != '') { $objWriter->writeAttribute('workbookPassword', $spreadsheet->getSecurity()->getWorkbookPassword()); } $objWriter->endElement(); } } /** * Write calcPr. * * @param bool $recalcRequired Indicate whether formulas should be recalculated before writing */ private function writeCalcPr(XMLWriter $objWriter, $recalcRequired = true): void { $objWriter->startElement('calcPr'); // Set the calcid to a higher value than Excel itself will use, otherwise Excel will always recalc // If MS Excel does do a recalc, then users opening a file in MS Excel will be prompted to save on exit // because the file has changed $objWriter->writeAttribute('calcId', '999999'); $objWriter->writeAttribute('calcMode', 'auto'); // fullCalcOnLoad isn't needed if we've recalculating for the save $objWriter->writeAttribute('calcCompleted', ($recalcRequired) ? 1 : 0); $objWriter->writeAttribute('fullCalcOnLoad', ($recalcRequired) ? 0 : 1); $objWriter->writeAttribute('forceFullCalc', ($recalcRequired) ? 0 : 1); $objWriter->endElement(); } /** * Write sheets. */ private function writeSheets(XMLWriter $objWriter, Spreadsheet $spreadsheet): void { // Write sheets $objWriter->startElement('sheets'); $sheetCount = $spreadsheet->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { // sheet $this->writeSheet( $objWriter, $spreadsheet->getSheet($i)->getTitle(), ($i + 1), ($i + 1 + 3), $spreadsheet->getSheet($i)->getSheetState() ); } $objWriter->endElement(); } /** * Write sheet. * * @param string $worksheetName Sheet name * @param int $worksheetId Sheet id * @param int $relId Relationship ID * @param string $sheetState Sheet state (visible, hidden, veryHidden) */ private function writeSheet(XMLWriter $objWriter, $worksheetName, $worksheetId = 1, $relId = 1, $sheetState = 'visible'): void { if ($worksheetName != '') { // Write sheet $objWriter->startElement('sheet'); $objWriter->writeAttribute('name', $worksheetName); $objWriter->writeAttribute('sheetId', $worksheetId); if ($sheetState !== 'visible' && $sheetState != '') { $objWriter->writeAttribute('state', $sheetState); } $objWriter->writeAttribute('r:id', 'rId' . $relId); $objWriter->endElement(); } else { throw new WriterException('Invalid parameters passed.'); } } } PK[剾cWriterPart.phpnu[parentWriter; } /** * Set parent Xlsx object. */ public function __construct(Xlsx $writer) { $this->parentWriter = $writer; } } PKE<<RelsRibbon.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Relationships $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); $localRels = $spreadsheet->getRibbonBinObjects('names'); if (is_array($localRels)) { foreach ($localRels as $aId => $aTarget) { $objWriter->startElement('Relationship'); $objWriter->writeAttribute('Id', $aId); $objWriter->writeAttribute('Type', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'); $objWriter->writeAttribute('Target', $aTarget); $objWriter->endElement(); } } $objWriter->endElement(); return $objWriter->getData(); } } PK[ Comments.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Comments cache $comments = $worksheet->getComments(); // Authors cache $authors = []; $authorId = 0; foreach ($comments as $comment) { if (!isset($authors[$comment->getAuthor()])) { $authors[$comment->getAuthor()] = $authorId++; } } // comments $objWriter->startElement('comments'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'); // Loop through authors $objWriter->startElement('authors'); foreach ($authors as $author => $index) { $objWriter->writeElement('author', $author); } $objWriter->endElement(); // Loop through comments $objWriter->startElement('commentList'); foreach ($comments as $key => $value) { $this->writeComment($objWriter, $key, $value, $authors); } $objWriter->endElement(); $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write comment to XML format. * * @param string $cellReference Cell reference * @param Comment $comment Comment * @param array $authors Array of authors */ private function writeComment(XMLWriter $objWriter, $cellReference, Comment $comment, array $authors): void { // comment $objWriter->startElement('comment'); $objWriter->writeAttribute('ref', $cellReference); $objWriter->writeAttribute('authorId', $authors[$comment->getAuthor()]); // text $objWriter->startElement('text'); $this->getParentWriter()->getWriterPartstringtable()->writeRichText($objWriter, $comment->getText()); $objWriter->endElement(); $objWriter->endElement(); } /** * Write VML comments to XML format. * * @return string XML Output */ public function writeVMLComments(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Comments cache $comments = $worksheet->getComments(); // xml $objWriter->startElement('xml'); $objWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); $objWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); $objWriter->writeAttribute('xmlns:x', 'urn:schemas-microsoft-com:office:excel'); // o:shapelayout $objWriter->startElement('o:shapelayout'); $objWriter->writeAttribute('v:ext', 'edit'); // o:idmap $objWriter->startElement('o:idmap'); $objWriter->writeAttribute('v:ext', 'edit'); $objWriter->writeAttribute('data', '1'); $objWriter->endElement(); $objWriter->endElement(); // v:shapetype $objWriter->startElement('v:shapetype'); $objWriter->writeAttribute('id', '_x0000_t202'); $objWriter->writeAttribute('coordsize', '21600,21600'); $objWriter->writeAttribute('o:spt', '202'); $objWriter->writeAttribute('path', 'm,l,21600r21600,l21600,xe'); // v:stroke $objWriter->startElement('v:stroke'); $objWriter->writeAttribute('joinstyle', 'miter'); $objWriter->endElement(); // v:path $objWriter->startElement('v:path'); $objWriter->writeAttribute('gradientshapeok', 't'); $objWriter->writeAttribute('o:connecttype', 'rect'); $objWriter->endElement(); $objWriter->endElement(); // Loop through comments foreach ($comments as $key => $value) { $this->writeVMLComment($objWriter, $key, $value); } $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write VML comment to XML format. * * @param string $cellReference Cell reference, eg: 'A1' * @param Comment $comment Comment */ private function writeVMLComment(XMLWriter $objWriter, $cellReference, Comment $comment): void { // Metadata [$column, $row] = Coordinate::indexesFromString($cellReference); $id = 1024 + $column + $row; $id = substr($id, 0, 4); // v:shape $objWriter->startElement('v:shape'); $objWriter->writeAttribute('id', '_x0000_s' . $id); $objWriter->writeAttribute('type', '#_x0000_t202'); $objWriter->writeAttribute('style', 'position:absolute;margin-left:' . $comment->getMarginLeft() . ';margin-top:' . $comment->getMarginTop() . ';width:' . $comment->getWidth() . ';height:' . $comment->getHeight() . ';z-index:1;visibility:' . ($comment->getVisible() ? 'visible' : 'hidden')); $objWriter->writeAttribute('fillcolor', '#' . $comment->getFillColor()->getRGB()); $objWriter->writeAttribute('o:insetmode', 'auto'); // v:fill $objWriter->startElement('v:fill'); $objWriter->writeAttribute('color2', '#' . $comment->getFillColor()->getRGB()); $objWriter->endElement(); // v:shadow $objWriter->startElement('v:shadow'); $objWriter->writeAttribute('on', 't'); $objWriter->writeAttribute('color', 'black'); $objWriter->writeAttribute('obscured', 't'); $objWriter->endElement(); // v:path $objWriter->startElement('v:path'); $objWriter->writeAttribute('o:connecttype', 'none'); $objWriter->endElement(); // v:textbox $objWriter->startElement('v:textbox'); $objWriter->writeAttribute('style', 'mso-direction-alt:auto'); // div $objWriter->startElement('div'); $objWriter->writeAttribute('style', 'text-align:left'); $objWriter->endElement(); $objWriter->endElement(); // x:ClientData $objWriter->startElement('x:ClientData'); $objWriter->writeAttribute('ObjectType', 'Note'); // x:MoveWithCells $objWriter->writeElement('x:MoveWithCells', ''); // x:SizeWithCells $objWriter->writeElement('x:SizeWithCells', ''); // x:AutoFill $objWriter->writeElement('x:AutoFill', 'False'); // x:Row $objWriter->writeElement('x:Row', ($row - 1)); // x:Column $objWriter->writeElement('x:Column', ($column - 1)); $objWriter->endElement(); $objWriter->endElement(); } } PK[ (f4&4&StringTable.phpnu[flipStringTable($aStringTable); // Loop through cells foreach ($worksheet->getCoordinates() as $coordinate) { $cell = $worksheet->getCell($coordinate); $cellValue = $cell->getValue(); if ( !is_object($cellValue) && ($cellValue !== null) && $cellValue !== '' && ($cell->getDataType() == DataType::TYPE_STRING || $cell->getDataType() == DataType::TYPE_STRING2 || $cell->getDataType() == DataType::TYPE_NULL) && !isset($aFlippedStringTable[$cellValue]) ) { $aStringTable[] = $cellValue; $aFlippedStringTable[$cellValue] = true; } elseif ( $cellValue instanceof RichText && ($cellValue !== null) && !isset($aFlippedStringTable[$cellValue->getHashCode()]) ) { $aStringTable[] = $cellValue; $aFlippedStringTable[$cellValue->getHashCode()] = true; } } return $aStringTable; } /** * Write string table to XML format. * * @param string[] $stringTable * * @return string XML Output */ public function writeStringTable(array $stringTable) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // String table $objWriter->startElement('sst'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'); $objWriter->writeAttribute('uniqueCount', count($stringTable)); // Loop through string table foreach ($stringTable as $textElement) { $objWriter->startElement('si'); if (!$textElement instanceof RichText) { $textToWrite = StringHelper::controlCharacterPHP2OOXML($textElement); $objWriter->startElement('t'); if ($textToWrite !== trim($textToWrite)) { $objWriter->writeAttribute('xml:space', 'preserve'); } $objWriter->writeRawData($textToWrite); $objWriter->endElement(); } elseif ($textElement instanceof RichText) { $this->writeRichText($objWriter, $textElement); } $objWriter->endElement(); } $objWriter->endElement(); return $objWriter->getData(); } /** * Write Rich Text. * * @param string $prefix Optional Namespace prefix */ public function writeRichText(XMLWriter $objWriter, RichText $richText, $prefix = null): void { if ($prefix !== null) { $prefix .= ':'; } // Loop through rich text elements $elements = $richText->getRichTextElements(); foreach ($elements as $element) { // r $objWriter->startElement($prefix . 'r'); // rPr if ($element instanceof Run) { // rPr $objWriter->startElement($prefix . 'rPr'); // rFont $objWriter->startElement($prefix . 'rFont'); $objWriter->writeAttribute('val', $element->getFont()->getName()); $objWriter->endElement(); // Bold $objWriter->startElement($prefix . 'b'); $objWriter->writeAttribute('val', ($element->getFont()->getBold() ? 'true' : 'false')); $objWriter->endElement(); // Italic $objWriter->startElement($prefix . 'i'); $objWriter->writeAttribute('val', ($element->getFont()->getItalic() ? 'true' : 'false')); $objWriter->endElement(); // Superscript / subscript if ($element->getFont()->getSuperscript() || $element->getFont()->getSubscript()) { $objWriter->startElement($prefix . 'vertAlign'); if ($element->getFont()->getSuperscript()) { $objWriter->writeAttribute('val', 'superscript'); } elseif ($element->getFont()->getSubscript()) { $objWriter->writeAttribute('val', 'subscript'); } $objWriter->endElement(); } // Strikethrough $objWriter->startElement($prefix . 'strike'); $objWriter->writeAttribute('val', ($element->getFont()->getStrikethrough() ? 'true' : 'false')); $objWriter->endElement(); // Color $objWriter->startElement($prefix . 'color'); $objWriter->writeAttribute('rgb', $element->getFont()->getColor()->getARGB()); $objWriter->endElement(); // Size $objWriter->startElement($prefix . 'sz'); $objWriter->writeAttribute('val', $element->getFont()->getSize()); $objWriter->endElement(); // Underline $objWriter->startElement($prefix . 'u'); $objWriter->writeAttribute('val', $element->getFont()->getUnderline()); $objWriter->endElement(); $objWriter->endElement(); } // t $objWriter->startElement($prefix . 't'); $objWriter->writeAttribute('xml:space', 'preserve'); $objWriter->writeRawData(StringHelper::controlCharacterPHP2OOXML($element->getText())); $objWriter->endElement(); $objWriter->endElement(); } } /** * Write Rich Text. * * @param RichText|string $richText text string or Rich text * @param string $prefix Optional Namespace prefix */ public function writeRichTextForCharts(XMLWriter $objWriter, $richText = null, $prefix = null): void { if (!$richText instanceof RichText) { $textRun = $richText; $richText = new RichText(); $richText->createTextRun($textRun); } if ($prefix !== null) { $prefix .= ':'; } // Loop through rich text elements $elements = $richText->getRichTextElements(); foreach ($elements as $element) { // r $objWriter->startElement($prefix . 'r'); // rPr $objWriter->startElement($prefix . 'rPr'); // Bold $objWriter->writeAttribute('b', ($element->getFont()->getBold() ? 1 : 0)); // Italic $objWriter->writeAttribute('i', ($element->getFont()->getItalic() ? 1 : 0)); // Underline $underlineType = $element->getFont()->getUnderline(); switch ($underlineType) { case 'single': $underlineType = 'sng'; break; case 'double': $underlineType = 'dbl'; break; } $objWriter->writeAttribute('u', $underlineType); // Strikethrough $objWriter->writeAttribute('strike', ($element->getFont()->getStrikethrough() ? 'sngStrike' : 'noStrike')); // rFont $objWriter->startElement($prefix . 'latin'); $objWriter->writeAttribute('typeface', $element->getFont()->getName()); $objWriter->endElement(); $objWriter->endElement(); // t $objWriter->startElement($prefix . 't'); $objWriter->writeRawData(StringHelper::controlCharacterPHP2OOXML($element->getText())); $objWriter->endElement(); $objWriter->endElement(); } } /** * Flip string table (for index searching). * * @param array $stringTable Stringtable * * @return array */ public function flipStringTable(array $stringTable) { // Return value $returnValue = []; // Loop through stringtable and add flipped items to $returnValue foreach ($stringTable as $key => $value) { if (!$value instanceof RichText) { $returnValue[$value] = $key; } elseif ($value instanceof RichText) { $returnValue[$value->getHashCode()] = $key; } } return $returnValue; } } PK[[HH Drawing.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // xdr:wsDr $objWriter->startElement('xdr:wsDr'); $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing'); $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); // Loop through images and write drawings $i = 1; $iterator = $worksheet->getDrawingCollection()->getIterator(); while ($iterator->valid()) { /** @var BaseDrawing $pDrawing */ $pDrawing = $iterator->current(); $pRelationId = $i; $hlinkClickId = $pDrawing->getHyperlink() === null ? null : ++$i; $this->writeDrawing($objWriter, $pDrawing, $pRelationId, $hlinkClickId); $iterator->next(); ++$i; } if ($includeCharts) { $chartCount = $worksheet->getChartCount(); // Loop through charts and write the chart position if ($chartCount > 0) { for ($c = 0; $c < $chartCount; ++$c) { $this->writeChart($objWriter, $worksheet->getChartByIndex($c), $c + $i); } } } // unparsed AlternateContent $unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData(); if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingAlternateContents'])) { foreach ($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingAlternateContents'] as $drawingAlternateContent) { $objWriter->writeRaw($drawingAlternateContent); } } $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write drawings to XML format. * * @param int $relationId */ public function writeChart(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $relationId = -1): void { $tl = $chart->getTopLeftPosition(); $tlColRow = Coordinate::indexesFromString($tl['cell']); $br = $chart->getBottomRightPosition(); $brColRow = Coordinate::indexesFromString($br['cell']); $objWriter->startElement('xdr:twoCellAnchor'); $objWriter->startElement('xdr:from'); $objWriter->writeElement('xdr:col', $tlColRow[0] - 1); $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($tl['xOffset'])); $objWriter->writeElement('xdr:row', $tlColRow[1] - 1); $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($tl['yOffset'])); $objWriter->endElement(); $objWriter->startElement('xdr:to'); $objWriter->writeElement('xdr:col', $brColRow[0] - 1); $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($br['xOffset'])); $objWriter->writeElement('xdr:row', $brColRow[1] - 1); $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($br['yOffset'])); $objWriter->endElement(); $objWriter->startElement('xdr:graphicFrame'); $objWriter->writeAttribute('macro', ''); $objWriter->startElement('xdr:nvGraphicFramePr'); $objWriter->startElement('xdr:cNvPr'); $objWriter->writeAttribute('name', 'Chart ' . $relationId); $objWriter->writeAttribute('id', 1025 * $relationId); $objWriter->endElement(); $objWriter->startElement('xdr:cNvGraphicFramePr'); $objWriter->startElement('a:graphicFrameLocks'); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); $objWriter->startElement('xdr:xfrm'); $objWriter->startElement('a:off'); $objWriter->writeAttribute('x', '0'); $objWriter->writeAttribute('y', '0'); $objWriter->endElement(); $objWriter->startElement('a:ext'); $objWriter->writeAttribute('cx', '0'); $objWriter->writeAttribute('cy', '0'); $objWriter->endElement(); $objWriter->endElement(); $objWriter->startElement('a:graphic'); $objWriter->startElement('a:graphicData'); $objWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart'); $objWriter->startElement('c:chart'); $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart'); $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $objWriter->writeAttribute('r:id', 'rId' . $relationId); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); $objWriter->startElement('xdr:clientData'); $objWriter->endElement(); $objWriter->endElement(); } /** * Write drawings to XML format. * * @param int $relationId * @param null|int $hlinkClickId */ public function writeDrawing(XMLWriter $objWriter, BaseDrawing $drawing, $relationId = -1, $hlinkClickId = null): void { if ($relationId >= 0) { // xdr:oneCellAnchor $objWriter->startElement('xdr:oneCellAnchor'); // Image location $aCoordinates = Coordinate::indexesFromString($drawing->getCoordinates()); // xdr:from $objWriter->startElement('xdr:from'); $objWriter->writeElement('xdr:col', $aCoordinates[0] - 1); $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetX())); $objWriter->writeElement('xdr:row', $aCoordinates[1] - 1); $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetY())); $objWriter->endElement(); // xdr:ext $objWriter->startElement('xdr:ext'); $objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getWidth())); $objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getHeight())); $objWriter->endElement(); // xdr:pic $objWriter->startElement('xdr:pic'); // xdr:nvPicPr $objWriter->startElement('xdr:nvPicPr'); // xdr:cNvPr $objWriter->startElement('xdr:cNvPr'); $objWriter->writeAttribute('id', $relationId); $objWriter->writeAttribute('name', $drawing->getName()); $objWriter->writeAttribute('descr', $drawing->getDescription()); //a:hlinkClick $this->writeHyperLinkDrawing($objWriter, $hlinkClickId); $objWriter->endElement(); // xdr:cNvPicPr $objWriter->startElement('xdr:cNvPicPr'); // a:picLocks $objWriter->startElement('a:picLocks'); $objWriter->writeAttribute('noChangeAspect', '1'); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); // xdr:blipFill $objWriter->startElement('xdr:blipFill'); // a:blip $objWriter->startElement('a:blip'); $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $objWriter->writeAttribute('r:embed', 'rId' . $relationId); $objWriter->endElement(); // a:stretch $objWriter->startElement('a:stretch'); $objWriter->writeElement('a:fillRect', null); $objWriter->endElement(); $objWriter->endElement(); // xdr:spPr $objWriter->startElement('xdr:spPr'); // a:xfrm $objWriter->startElement('a:xfrm'); $objWriter->writeAttribute('rot', \PhpOffice\PhpSpreadsheet\Shared\Drawing::degreesToAngle($drawing->getRotation())); $objWriter->endElement(); // a:prstGeom $objWriter->startElement('a:prstGeom'); $objWriter->writeAttribute('prst', 'rect'); // a:avLst $objWriter->writeElement('a:avLst', null); $objWriter->endElement(); if ($drawing->getShadow()->getVisible()) { // a:effectLst $objWriter->startElement('a:effectLst'); // a:outerShdw $objWriter->startElement('a:outerShdw'); $objWriter->writeAttribute('blurRad', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getShadow()->getBlurRadius())); $objWriter->writeAttribute('dist', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getShadow()->getDistance())); $objWriter->writeAttribute('dir', \PhpOffice\PhpSpreadsheet\Shared\Drawing::degreesToAngle($drawing->getShadow()->getDirection())); $objWriter->writeAttribute('algn', $drawing->getShadow()->getAlignment()); $objWriter->writeAttribute('rotWithShape', '0'); // a:srgbClr $objWriter->startElement('a:srgbClr'); $objWriter->writeAttribute('val', $drawing->getShadow()->getColor()->getRGB()); // a:alpha $objWriter->startElement('a:alpha'); $objWriter->writeAttribute('val', $drawing->getShadow()->getAlpha() * 1000); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); } $objWriter->endElement(); $objWriter->endElement(); // xdr:clientData $objWriter->writeElement('xdr:clientData', null); $objWriter->endElement(); } else { throw new WriterException('Invalid parameters passed.'); } } /** * Write VML header/footer images to XML format. * * @return string XML Output */ public function writeVMLHeaderFooterImages(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // Header/footer images $images = $worksheet->getHeaderFooter()->getImages(); // xml $objWriter->startElement('xml'); $objWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); $objWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); $objWriter->writeAttribute('xmlns:x', 'urn:schemas-microsoft-com:office:excel'); // o:shapelayout $objWriter->startElement('o:shapelayout'); $objWriter->writeAttribute('v:ext', 'edit'); // o:idmap $objWriter->startElement('o:idmap'); $objWriter->writeAttribute('v:ext', 'edit'); $objWriter->writeAttribute('data', '1'); $objWriter->endElement(); $objWriter->endElement(); // v:shapetype $objWriter->startElement('v:shapetype'); $objWriter->writeAttribute('id', '_x0000_t75'); $objWriter->writeAttribute('coordsize', '21600,21600'); $objWriter->writeAttribute('o:spt', '75'); $objWriter->writeAttribute('o:preferrelative', 't'); $objWriter->writeAttribute('path', 'm@4@5l@4@11@9@11@9@5xe'); $objWriter->writeAttribute('filled', 'f'); $objWriter->writeAttribute('stroked', 'f'); // v:stroke $objWriter->startElement('v:stroke'); $objWriter->writeAttribute('joinstyle', 'miter'); $objWriter->endElement(); // v:formulas $objWriter->startElement('v:formulas'); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'if lineDrawn pixelLineWidth 0'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'sum @0 1 0'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'sum 0 0 @1'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'prod @2 1 2'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelWidth'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelHeight'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'sum @0 0 1'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'prod @6 1 2'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelWidth'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'sum @8 21600 0'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelHeight'); $objWriter->endElement(); // v:f $objWriter->startElement('v:f'); $objWriter->writeAttribute('eqn', 'sum @10 21600 0'); $objWriter->endElement(); $objWriter->endElement(); // v:path $objWriter->startElement('v:path'); $objWriter->writeAttribute('o:extrusionok', 'f'); $objWriter->writeAttribute('gradientshapeok', 't'); $objWriter->writeAttribute('o:connecttype', 'rect'); $objWriter->endElement(); // o:lock $objWriter->startElement('o:lock'); $objWriter->writeAttribute('v:ext', 'edit'); $objWriter->writeAttribute('aspectratio', 't'); $objWriter->endElement(); $objWriter->endElement(); // Loop through images foreach ($images as $key => $value) { $this->writeVMLHeaderFooterImage($objWriter, $key, $value); } $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write VML comment to XML format. * * @param string $reference Reference */ private function writeVMLHeaderFooterImage(XMLWriter $objWriter, $reference, HeaderFooterDrawing $image): void { // Calculate object id preg_match('{(\d+)}', md5($reference), $m); $id = 1500 + ((int) substr($m[1], 0, 2) * 1); // Calculate offset $width = $image->getWidth(); $height = $image->getHeight(); $marginLeft = $image->getOffsetX(); $marginTop = $image->getOffsetY(); // v:shape $objWriter->startElement('v:shape'); $objWriter->writeAttribute('id', $reference); $objWriter->writeAttribute('o:spid', '_x0000_s' . $id); $objWriter->writeAttribute('type', '#_x0000_t75'); $objWriter->writeAttribute('style', "position:absolute;margin-left:{$marginLeft}px;margin-top:{$marginTop}px;width:{$width}px;height:{$height}px;z-index:1"); // v:imagedata $objWriter->startElement('v:imagedata'); $objWriter->writeAttribute('o:relid', 'rId' . $reference); $objWriter->writeAttribute('o:title', $image->getName()); $objWriter->endElement(); // o:lock $objWriter->startElement('o:lock'); $objWriter->writeAttribute('v:ext', 'edit'); $objWriter->writeAttribute('textRotation', 't'); $objWriter->endElement(); $objWriter->endElement(); } /** * Get an array of all drawings. * * @return BaseDrawing[] All drawings in PhpSpreadsheet */ public function allDrawings(Spreadsheet $spreadsheet) { // Get an array of all drawings $aDrawings = []; // Loop through PhpSpreadsheet $sheetCount = $spreadsheet->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { // Loop through images and add to array $iterator = $spreadsheet->getSheet($i)->getDrawingCollection()->getIterator(); while ($iterator->valid()) { $aDrawings[] = $iterator->current(); $iterator->next(); } } return $aDrawings; } /** * @param null|int $hlinkClickId */ private function writeHyperLinkDrawing(XMLWriter $objWriter, $hlinkClickId): void { if ($hlinkClickId === null) { return; } $objWriter->startElement('a:hlinkClick'); $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $objWriter->writeAttribute('r:id', 'rId' . $hlinkClickId); $objWriter->endElement(); } } PKnR!!DefinedNames.phpnu[objWriter = $objWriter; $this->spreadsheet = $spreadsheet; } public function write(): void { // Write defined names $this->objWriter->startElement('definedNames'); // Named ranges if (count($this->spreadsheet->getDefinedNames()) > 0) { // Named ranges $this->writeNamedRangesAndFormulae(); } // Other defined names $sheetCount = $this->spreadsheet->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { // NamedRange for autoFilter $this->writeNamedRangeForAutofilter($this->spreadsheet->getSheet($i), $i); // NamedRange for Print_Titles $this->writeNamedRangeForPrintTitles($this->spreadsheet->getSheet($i), $i); // NamedRange for Print_Area $this->writeNamedRangeForPrintArea($this->spreadsheet->getSheet($i), $i); } $this->objWriter->endElement(); } /** * Write defined names. */ private function writeNamedRangesAndFormulae(): void { // Loop named ranges $definedNames = $this->spreadsheet->getDefinedNames(); foreach ($definedNames as $definedName) { $this->writeDefinedName($definedName); } } /** * Write Defined Name for named range. */ private function writeDefinedName(DefinedName $definedName): void { // definedName for named range $local = -1; if ($definedName->getLocalOnly() && $definedName->getScope() !== null) { try { $local = $definedName->getScope()->getParent()->getIndex($definedName->getScope()); } catch (Exception $e) { // See issue 2266 - deleting sheet which contains // defined names will cause Exception above. return; } } $this->objWriter->startElement('definedName'); $this->objWriter->writeAttribute('name', $definedName->getName()); if ($local >= 0) { $this->objWriter->writeAttribute( 'localSheetId', "$local" ); } $definedRange = $this->getDefinedRange($definedName); $this->objWriter->writeRawData($definedRange); $this->objWriter->endElement(); } /** * Write Defined Name for autoFilter. */ private function writeNamedRangeForAutofilter(Worksheet $worksheet, int $worksheetId = 0): void { // NamedRange for autoFilter $autoFilterRange = $worksheet->getAutoFilter()->getRange(); if (!empty($autoFilterRange)) { $this->objWriter->startElement('definedName'); $this->objWriter->writeAttribute('name', '_xlnm._FilterDatabase'); $this->objWriter->writeAttribute('localSheetId', "$worksheetId"); $this->objWriter->writeAttribute('hidden', '1'); // Create absolute coordinate and write as raw text $range = Coordinate::splitRange($autoFilterRange); $range = $range[0]; // Strip any worksheet ref so we can make the cell ref absolute [, $range[0]] = Worksheet::extractSheetTitle($range[0], true); $range[0] = Coordinate::absoluteCoordinate($range[0]); $range[1] = Coordinate::absoluteCoordinate($range[1]); $range = implode(':', $range); $this->objWriter->writeRawData('\'' . str_replace("'", "''", $worksheet->getTitle() ?? '') . '\'!' . $range); $this->objWriter->endElement(); } } /** * Write Defined Name for PrintTitles. */ private function writeNamedRangeForPrintTitles(Worksheet $worksheet, int $worksheetId = 0): void { // NamedRange for PrintTitles if ($worksheet->getPageSetup()->isColumnsToRepeatAtLeftSet() || $worksheet->getPageSetup()->isRowsToRepeatAtTopSet()) { $this->objWriter->startElement('definedName'); $this->objWriter->writeAttribute('name', '_xlnm.Print_Titles'); $this->objWriter->writeAttribute('localSheetId', "$worksheetId"); // Setting string $settingString = ''; // Columns to repeat if ($worksheet->getPageSetup()->isColumnsToRepeatAtLeftSet()) { $repeat = $worksheet->getPageSetup()->getColumnsToRepeatAtLeft(); $settingString .= '\'' . str_replace("'", "''", $worksheet->getTitle()) . '\'!$' . $repeat[0] . ':$' . $repeat[1]; } // Rows to repeat if ($worksheet->getPageSetup()->isRowsToRepeatAtTopSet()) { if ($worksheet->getPageSetup()->isColumnsToRepeatAtLeftSet()) { $settingString .= ','; } $repeat = $worksheet->getPageSetup()->getRowsToRepeatAtTop(); $settingString .= '\'' . str_replace("'", "''", $worksheet->getTitle()) . '\'!$' . $repeat[0] . ':$' . $repeat[1]; } $this->objWriter->writeRawData($settingString); $this->objWriter->endElement(); } } /** * Write Defined Name for PrintTitles. */ private function writeNamedRangeForPrintArea(Worksheet $worksheet, int $worksheetId = 0): void { // NamedRange for PrintArea if ($worksheet->getPageSetup()->isPrintAreaSet()) { $this->objWriter->startElement('definedName'); $this->objWriter->writeAttribute('name', '_xlnm.Print_Area'); $this->objWriter->writeAttribute('localSheetId', "$worksheetId"); // Print area $printArea = Coordinate::splitRange($worksheet->getPageSetup()->getPrintArea()); $chunks = []; foreach ($printArea as $printAreaRect) { $printAreaRect[0] = Coordinate::absoluteReference($printAreaRect[0]); $printAreaRect[1] = Coordinate::absoluteReference($printAreaRect[1]); $chunks[] = '\'' . str_replace("'", "''", $worksheet->getTitle()) . '\'!' . implode(':', $printAreaRect); } $this->objWriter->writeRawData(implode(',', $chunks)); $this->objWriter->endElement(); } } private function getDefinedRange(DefinedName $definedName): string { $definedRange = $definedName->getValue(); $splitCount = preg_match_all( '/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/mui', $definedRange, $splitRanges, PREG_OFFSET_CAPTURE ); $lengths = array_map('strlen', array_column($splitRanges[0], 0)); $offsets = array_column($splitRanges[0], 1); $worksheets = $splitRanges[2]; $columns = $splitRanges[6]; $rows = $splitRanges[7]; while ($splitCount > 0) { --$splitCount; $length = $lengths[$splitCount]; $offset = $offsets[$splitCount]; $worksheet = $worksheets[$splitCount][0]; $column = $columns[$splitCount][0]; $row = $rows[$splitCount][0]; $newRange = ''; if (empty($worksheet)) { if (($offset === 0) || ($definedRange[$offset - 1] !== ':')) { // We should have a worksheet $ws = $definedName->getWorksheet(); $worksheet = ($ws === null) ? null : $ws->getTitle(); } } else { $worksheet = str_replace("''", "'", trim($worksheet, "'")); } if (!empty($worksheet)) { $newRange = "'" . str_replace("'", "''", $worksheet) . "'!"; } $newRange = "{$newRange}{$column}{$row}"; $definedRange = substr($definedRange, 0, $offset) . $newRange . substr($definedRange, $offset + $length); } if (substr($definedRange, 0, 1) === '=') { $definedRange = substr($definedRange, 1); } return $definedRange; } } PK8]] Style.phpnu[getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); // styleSheet $objWriter->startElement('styleSheet'); $objWriter->writeAttribute('xml:space', 'preserve'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'); // numFmts $objWriter->startElement('numFmts'); $objWriter->writeAttribute('count', $this->getParentWriter()->getNumFmtHashTable()->count()); // numFmt for ($i = 0; $i < $this->getParentWriter()->getNumFmtHashTable()->count(); ++$i) { $this->writeNumFmt($objWriter, $this->getParentWriter()->getNumFmtHashTable()->getByIndex($i), $i); } $objWriter->endElement(); // fonts $objWriter->startElement('fonts'); $objWriter->writeAttribute('count', $this->getParentWriter()->getFontHashTable()->count()); // font for ($i = 0; $i < $this->getParentWriter()->getFontHashTable()->count(); ++$i) { $this->writeFont($objWriter, $this->getParentWriter()->getFontHashTable()->getByIndex($i)); } $objWriter->endElement(); // fills $objWriter->startElement('fills'); $objWriter->writeAttribute('count', $this->getParentWriter()->getFillHashTable()->count()); // fill for ($i = 0; $i < $this->getParentWriter()->getFillHashTable()->count(); ++$i) { $this->writeFill($objWriter, $this->getParentWriter()->getFillHashTable()->getByIndex($i)); } $objWriter->endElement(); // borders $objWriter->startElement('borders'); $objWriter->writeAttribute('count', $this->getParentWriter()->getBordersHashTable()->count()); // border for ($i = 0; $i < $this->getParentWriter()->getBordersHashTable()->count(); ++$i) { $this->writeBorder($objWriter, $this->getParentWriter()->getBordersHashTable()->getByIndex($i)); } $objWriter->endElement(); // cellStyleXfs $objWriter->startElement('cellStyleXfs'); $objWriter->writeAttribute('count', 1); // xf $objWriter->startElement('xf'); $objWriter->writeAttribute('numFmtId', 0); $objWriter->writeAttribute('fontId', 0); $objWriter->writeAttribute('fillId', 0); $objWriter->writeAttribute('borderId', 0); $objWriter->endElement(); $objWriter->endElement(); // cellXfs $objWriter->startElement('cellXfs'); $objWriter->writeAttribute('count', count($spreadsheet->getCellXfCollection())); // xf foreach ($spreadsheet->getCellXfCollection() as $cellXf) { $this->writeCellStyleXf($objWriter, $cellXf, $spreadsheet); } $objWriter->endElement(); // cellStyles $objWriter->startElement('cellStyles'); $objWriter->writeAttribute('count', 1); // cellStyle $objWriter->startElement('cellStyle'); $objWriter->writeAttribute('name', 'Normal'); $objWriter->writeAttribute('xfId', 0); $objWriter->writeAttribute('builtinId', 0); $objWriter->endElement(); $objWriter->endElement(); // dxfs $objWriter->startElement('dxfs'); $objWriter->writeAttribute('count', $this->getParentWriter()->getStylesConditionalHashTable()->count()); // dxf for ($i = 0; $i < $this->getParentWriter()->getStylesConditionalHashTable()->count(); ++$i) { $this->writeCellStyleDxf($objWriter, $this->getParentWriter()->getStylesConditionalHashTable()->getByIndex($i)->getStyle()); } $objWriter->endElement(); // tableStyles $objWriter->startElement('tableStyles'); $objWriter->writeAttribute('defaultTableStyle', 'TableStyleMedium9'); $objWriter->writeAttribute('defaultPivotStyle', 'PivotTableStyle1'); $objWriter->endElement(); $objWriter->endElement(); // Return return $objWriter->getData(); } /** * Write Fill. */ private function writeFill(XMLWriter $objWriter, Fill $fill): void { // Check if this is a pattern type or gradient type if ( $fill->getFillType() === Fill::FILL_GRADIENT_LINEAR || $fill->getFillType() === Fill::FILL_GRADIENT_PATH ) { // Gradient fill $this->writeGradientFill($objWriter, $fill); } elseif ($fill->getFillType() !== null) { // Pattern fill $this->writePatternFill($objWriter, $fill); } } /** * Write Gradient Fill. */ private function writeGradientFill(XMLWriter $objWriter, Fill $fill): void { // fill $objWriter->startElement('fill'); // gradientFill $objWriter->startElement('gradientFill'); $objWriter->writeAttribute('type', $fill->getFillType()); $objWriter->writeAttribute('degree', $fill->getRotation()); // stop $objWriter->startElement('stop'); $objWriter->writeAttribute('position', '0'); // color $objWriter->startElement('color'); $objWriter->writeAttribute('rgb', $fill->getStartColor()->getARGB()); $objWriter->endElement(); $objWriter->endElement(); // stop $objWriter->startElement('stop'); $objWriter->writeAttribute('position', '1'); // color $objWriter->startElement('color'); $objWriter->writeAttribute('rgb', $fill->getEndColor()->getARGB()); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); $objWriter->endElement(); } /** * Write Pattern Fill. */ private function writePatternFill(XMLWriter $objWriter, Fill $fill): void { // fill $objWriter->startElement('fill'); // patternFill $objWriter->startElement('patternFill'); $objWriter->writeAttribute('patternType', $fill->getFillType()); if ($fill->getFillType() !== Fill::FILL_NONE) { // fgColor if ($fill->getStartColor()->getARGB()) { $objWriter->startElement('fgColor'); $objWriter->writeAttribute('rgb', $fill->getStartColor()->getARGB()); $objWriter->endElement(); } } if ($fill->getFillType() !== Fill::FILL_NONE) { // bgColor if ($fill->getEndColor()->getARGB()) { $objWriter->startElement('bgColor'); $objWriter->writeAttribute('rgb', $fill->getEndColor()->getARGB()); $objWriter->endElement(); } } $objWriter->endElement(); $objWriter->endElement(); } /** * Write Font. */ private function writeFont(XMLWriter $objWriter, Font $font): void { // font $objWriter->startElement('font'); // Weird! The order of these elements actually makes a difference when opening Xlsx // files in Excel2003 with the compatibility pack. It's not documented behaviour, // and makes for a real WTF! // Bold. We explicitly write this element also when false (like MS Office Excel 2007 does // for conditional formatting). Otherwise it will apparently not be picked up in conditional // formatting style dialog if ($font->getBold() !== null) { $objWriter->startElement('b'); $objWriter->writeAttribute('val', $font->getBold() ? '1' : '0'); $objWriter->endElement(); } // Italic if ($font->getItalic() !== null) { $objWriter->startElement('i'); $objWriter->writeAttribute('val', $font->getItalic() ? '1' : '0'); $objWriter->endElement(); } // Strikethrough if ($font->getStrikethrough() !== null) { $objWriter->startElement('strike'); $objWriter->writeAttribute('val', $font->getStrikethrough() ? '1' : '0'); $objWriter->endElement(); } // Underline if ($font->getUnderline() !== null) { $objWriter->startElement('u'); $objWriter->writeAttribute('val', $font->getUnderline()); $objWriter->endElement(); } // Superscript / subscript if ($font->getSuperscript() === true || $font->getSubscript() === true) { $objWriter->startElement('vertAlign'); if ($font->getSuperscript() === true) { $objWriter->writeAttribute('val', 'superscript'); } elseif ($font->getSubscript() === true) { $objWriter->writeAttribute('val', 'subscript'); } $objWriter->endElement(); } // Size if ($font->getSize() !== null) { $objWriter->startElement('sz'); $objWriter->writeAttribute('val', StringHelper::formatNumber($font->getSize())); $objWriter->endElement(); } // Foreground color if ($font->getColor()->getARGB() !== null) { $objWriter->startElement('color'); $objWriter->writeAttribute('rgb', $font->getColor()->getARGB()); $objWriter->endElement(); } // Name if ($font->getName() !== null) { $objWriter->startElement('name'); $objWriter->writeAttribute('val', $font->getName()); $objWriter->endElement(); } $objWriter->endElement(); } /** * Write Border. */ private function writeBorder(XMLWriter $objWriter, Borders $borders): void { // Write border $objWriter->startElement('border'); // Diagonal? switch ($borders->getDiagonalDirection()) { case Borders::DIAGONAL_UP: $objWriter->writeAttribute('diagonalUp', 'true'); $objWriter->writeAttribute('diagonalDown', 'false'); break; case Borders::DIAGONAL_DOWN: $objWriter->writeAttribute('diagonalUp', 'false'); $objWriter->writeAttribute('diagonalDown', 'true'); break; case Borders::DIAGONAL_BOTH: $objWriter->writeAttribute('diagonalUp', 'true'); $objWriter->writeAttribute('diagonalDown', 'true'); break; } // BorderPr $this->writeBorderPr($objWriter, 'left', $borders->getLeft()); $this->writeBorderPr($objWriter, 'right', $borders->getRight()); $this->writeBorderPr($objWriter, 'top', $borders->getTop()); $this->writeBorderPr($objWriter, 'bottom', $borders->getBottom()); $this->writeBorderPr($objWriter, 'diagonal', $borders->getDiagonal()); $objWriter->endElement(); } /** * Write Cell Style Xf. */ private function writeCellStyleXf(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Style\Style $style, Spreadsheet $spreadsheet): void { // xf $objWriter->startElement('xf'); $objWriter->writeAttribute('xfId', 0); $objWriter->writeAttribute('fontId', (int) $this->getParentWriter()->getFontHashTable()->getIndexForHashCode($style->getFont()->getHashCode())); if ($style->getQuotePrefix()) { $objWriter->writeAttribute('quotePrefix', 1); } if ($style->getNumberFormat()->getBuiltInFormatCode() === false) { $objWriter->writeAttribute('numFmtId', (int) ($this->getParentWriter()->getNumFmtHashTable()->getIndexForHashCode($style->getNumberFormat()->getHashCode()) + 164)); } else { $objWriter->writeAttribute('numFmtId', (int) $style->getNumberFormat()->getBuiltInFormatCode()); } $objWriter->writeAttribute('fillId', (int) $this->getParentWriter()->getFillHashTable()->getIndexForHashCode($style->getFill()->getHashCode())); $objWriter->writeAttribute('borderId', (int) $this->getParentWriter()->getBordersHashTable()->getIndexForHashCode($style->getBorders()->getHashCode())); // Apply styles? $objWriter->writeAttribute('applyFont', ($spreadsheet->getDefaultStyle()->getFont()->getHashCode() != $style->getFont()->getHashCode()) ? '1' : '0'); $objWriter->writeAttribute('applyNumberFormat', ($spreadsheet->getDefaultStyle()->getNumberFormat()->getHashCode() != $style->getNumberFormat()->getHashCode()) ? '1' : '0'); $objWriter->writeAttribute('applyFill', ($spreadsheet->getDefaultStyle()->getFill()->getHashCode() != $style->getFill()->getHashCode()) ? '1' : '0'); $objWriter->writeAttribute('applyBorder', ($spreadsheet->getDefaultStyle()->getBorders()->getHashCode() != $style->getBorders()->getHashCode()) ? '1' : '0'); $objWriter->writeAttribute('applyAlignment', ($spreadsheet->getDefaultStyle()->getAlignment()->getHashCode() != $style->getAlignment()->getHashCode()) ? '1' : '0'); if ($style->getProtection()->getLocked() != Protection::PROTECTION_INHERIT || $style->getProtection()->getHidden() != Protection::PROTECTION_INHERIT) { $objWriter->writeAttribute('applyProtection', 'true'); } // alignment $objWriter->startElement('alignment'); $objWriter->writeAttribute('horizontal', $style->getAlignment()->getHorizontal()); $objWriter->writeAttribute('vertical', $style->getAlignment()->getVertical()); $textRotation = 0; if ($style->getAlignment()->getTextRotation() >= 0) { $textRotation = $style->getAlignment()->getTextRotation(); } elseif ($style->getAlignment()->getTextRotation() < 0) { $textRotation = 90 - $style->getAlignment()->getTextRotation(); } $objWriter->writeAttribute('textRotation', $textRotation); $objWriter->writeAttribute('wrapText', ($style->getAlignment()->getWrapText() ? 'true' : 'false')); $objWriter->writeAttribute('shrinkToFit', ($style->getAlignment()->getShrinkToFit() ? 'true' : 'false')); if ($style->getAlignment()->getIndent() > 0) { $objWriter->writeAttribute('indent', $style->getAlignment()->getIndent()); } if ($style->getAlignment()->getReadOrder() > 0) { $objWriter->writeAttribute('readingOrder', $style->getAlignment()->getReadOrder()); } $objWriter->endElement(); // protection if ($style->getProtection()->getLocked() != Protection::PROTECTION_INHERIT || $style->getProtection()->getHidden() != Protection::PROTECTION_INHERIT) { $objWriter->startElement('protection'); if ($style->getProtection()->getLocked() != Protection::PROTECTION_INHERIT) { $objWriter->writeAttribute('locked', ($style->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED ? 'true' : 'false')); } if ($style->getProtection()->getHidden() != Protection::PROTECTION_INHERIT) { $objWriter->writeAttribute('hidden', ($style->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED ? 'true' : 'false')); } $objWriter->endElement(); } $objWriter->endElement(); } /** * Write Cell Style Dxf. */ private function writeCellStyleDxf(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Style\Style $style): void { // dxf $objWriter->startElement('dxf'); // font $this->writeFont($objWriter, $style->getFont()); // numFmt $this->writeNumFmt($objWriter, $style->getNumberFormat()); // fill $this->writeFill($objWriter, $style->getFill()); // alignment $objWriter->startElement('alignment'); if ($style->getAlignment()->getHorizontal() !== null) { $objWriter->writeAttribute('horizontal', $style->getAlignment()->getHorizontal()); } if ($style->getAlignment()->getVertical() !== null) { $objWriter->writeAttribute('vertical', $style->getAlignment()->getVertical()); } if ($style->getAlignment()->getTextRotation() !== null) { $textRotation = 0; if ($style->getAlignment()->getTextRotation() >= 0) { $textRotation = $style->getAlignment()->getTextRotation(); } elseif ($style->getAlignment()->getTextRotation() < 0) { $textRotation = 90 - $style->getAlignment()->getTextRotation(); } $objWriter->writeAttribute('textRotation', $textRotation); } $objWriter->endElement(); // border $this->writeBorder($objWriter, $style->getBorders()); // protection if (($style->getProtection()->getLocked() !== null) || ($style->getProtection()->getHidden() !== null)) { if ( $style->getProtection()->getLocked() !== Protection::PROTECTION_INHERIT || $style->getProtection()->getHidden() !== Protection::PROTECTION_INHERIT ) { $objWriter->startElement('protection'); if ( ($style->getProtection()->getLocked() !== null) && ($style->getProtection()->getLocked() !== Protection::PROTECTION_INHERIT) ) { $objWriter->writeAttribute('locked', ($style->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED ? 'true' : 'false')); } if ( ($style->getProtection()->getHidden() !== null) && ($style->getProtection()->getHidden() !== Protection::PROTECTION_INHERIT) ) { $objWriter->writeAttribute('hidden', ($style->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED ? 'true' : 'false')); } $objWriter->endElement(); } } $objWriter->endElement(); } /** * Write BorderPr. * * @param string $name Element name */ private function writeBorderPr(XMLWriter $objWriter, $name, Border $border): void { // Write BorderPr if ($border->getBorderStyle() != Border::BORDER_NONE) { $objWriter->startElement($name); $objWriter->writeAttribute('style', $border->getBorderStyle()); // color $objWriter->startElement('color'); $objWriter->writeAttribute('rgb', $border->getColor()->getARGB()); $objWriter->endElement(); $objWriter->endElement(); } } /** * Write NumberFormat. * * @param int $id Number Format identifier */ private function writeNumFmt(XMLWriter $objWriter, NumberFormat $numberFormat, $id = 0): void { // Translate formatcode $formatCode = $numberFormat->getFormatCode(); // numFmt if ($formatCode !== null) { $objWriter->startElement('numFmt'); $objWriter->writeAttribute('numFmtId', ($id + 164)); $objWriter->writeAttribute('formatCode', $formatCode); $objWriter->endElement(); } } /** * Get an array of all styles. * * @return \PhpOffice\PhpSpreadsheet\Style\Style[] All styles in PhpSpreadsheet */ public function allStyles(Spreadsheet $spreadsheet) { return $spreadsheet->getCellXfCollection(); } /** * Get an array of all conditional styles. * * @return Conditional[] All conditional styles in PhpSpreadsheet */ public function allConditionalStyles(Spreadsheet $spreadsheet) { // Get an array of all styles $aStyles = []; $sheetCount = $spreadsheet->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { foreach ($spreadsheet->getSheet($i)->getConditionalStylesCollection() as $conditionalStyles) { foreach ($conditionalStyles as $conditionalStyle) { $aStyles[] = $conditionalStyle; } } } return $aStyles; } /** * Get an array of all fills. * * @return Fill[] All fills in PhpSpreadsheet */ public function allFills(Spreadsheet $spreadsheet) { // Get an array of unique fills $aFills = []; // Two first fills are predefined $fill0 = new Fill(); $fill0->setFillType(Fill::FILL_NONE); $aFills[] = $fill0; $fill1 = new Fill(); $fill1->setFillType(Fill::FILL_PATTERN_GRAY125); $aFills[] = $fill1; // The remaining fills $aStyles = $this->allStyles($spreadsheet); /** @var \PhpOffice\PhpSpreadsheet\Style\Style $style */ foreach ($aStyles as $style) { if (!isset($aFills[$style->getFill()->getHashCode()])) { $aFills[$style->getFill()->getHashCode()] = $style->getFill(); } } return $aFills; } /** * Get an array of all fonts. * * @return Font[] All fonts in PhpSpreadsheet */ public function allFonts(Spreadsheet $spreadsheet) { // Get an array of unique fonts $aFonts = []; $aStyles = $this->allStyles($spreadsheet); /** @var \PhpOffice\PhpSpreadsheet\Style\Style $style */ foreach ($aStyles as $style) { if (!isset($aFonts[$style->getFont()->getHashCode()])) { $aFonts[$style->getFont()->getHashCode()] = $style->getFont(); } } return $aFonts; } /** * Get an array of all borders. * * @return Borders[] All borders in PhpSpreadsheet */ public function allBorders(Spreadsheet $spreadsheet) { // Get an array of unique borders $aBorders = []; $aStyles = $this->allStyles($spreadsheet); /** @var \PhpOffice\PhpSpreadsheet\Style\Style $style */ foreach ($aStyles as $style) { if (!isset($aBorders[$style->getBorders()->getHashCode()])) { $aBorders[$style->getBorders()->getHashCode()] = $style->getBorders(); } } return $aBorders; } /** * Get an array of all number formats. * * @return NumberFormat[] All number formats in PhpSpreadsheet */ public function allNumberFormats(Spreadsheet $spreadsheet) { // Get an array of unique number formats $aNumFmts = []; $aStyles = $this->allStyles($spreadsheet); /** @var \PhpOffice\PhpSpreadsheet\Style\Style $style */ foreach ($aStyles as $style) { if ($style->getNumberFormat()->getBuiltInFormatCode() === false && !isset($aNumFmts[$style->getNumberFormat()->getHashCode()])) { $aNumFmts[$style->getNumberFormat()->getHashCode()] = $style->getNumberFormat(); } } return $aNumFmts; } } PK hnhn Chart.phpnu[attributes(); if (isset($attributes[$name])) { if ($format == 'string') { return (string) $attributes[$name]; } elseif ($format == 'integer') { return (int) $attributes[$name]; } elseif ($format == 'boolean') { $value = (string) $attributes[$name]; return $value === 'true' || $value === '1'; } return (float) $attributes[$name]; } return null; } private static function readColor($color, $background = false) { if (isset($color['rgb'])) { return (string) $color['rgb']; } elseif (isset($color['indexed'])) { return Color::indexedColor($color['indexed'] - 7, $background)->getARGB(); } } /** * @param string $chartName * * @return \PhpOffice\PhpSpreadsheet\Chart\Chart */ public static function readChart(SimpleXMLElement $chartElements, $chartName) { $namespacesChartMeta = $chartElements->getNamespaces(true); $chartElementsC = $chartElements->children($namespacesChartMeta['c']); $XaxisLabel = $YaxisLabel = $legend = $title = null; $dispBlanksAs = $plotVisOnly = null; $plotArea = null; foreach ($chartElementsC as $chartElementKey => $chartElement) { switch ($chartElementKey) { case 'chart': foreach ($chartElement as $chartDetailsKey => $chartDetails) { $chartDetailsC = $chartDetails->children($namespacesChartMeta['c']); switch ($chartDetailsKey) { case 'plotArea': $plotAreaLayout = $XaxisLable = $YaxisLable = null; $plotSeries = $plotAttributes = []; foreach ($chartDetails as $chartDetailKey => $chartDetail) { switch ($chartDetailKey) { case 'layout': $plotAreaLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta); break; case 'catAx': if (isset($chartDetail->title)) { $XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta); } break; case 'dateAx': if (isset($chartDetail->title)) { $XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta); } break; case 'valAx': if (isset($chartDetail->title, $chartDetail->axPos)) { $axisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta); $axPos = self::getAttribute($chartDetail->axPos, 'val', 'string'); switch ($axPos) { case 't': case 'b': $XaxisLabel = $axisLabel; break; case 'r': case 'l': $YaxisLabel = $axisLabel; break; } } break; case 'barChart': case 'bar3DChart': $barDirection = self::getAttribute($chartDetail->barDir, 'val', 'string'); $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotSer->setPlotDirection($barDirection); $plotSeries[] = $plotSer; $plotAttributes = self::readChartAttributes($chartDetail); break; case 'lineChart': case 'line3DChart': $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotAttributes = self::readChartAttributes($chartDetail); break; case 'areaChart': case 'area3DChart': $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotAttributes = self::readChartAttributes($chartDetail); break; case 'doughnutChart': case 'pieChart': case 'pie3DChart': $explosion = isset($chartDetail->ser->explosion); $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotSer->setPlotStyle($explosion); $plotSeries[] = $plotSer; $plotAttributes = self::readChartAttributes($chartDetail); break; case 'scatterChart': $scatterStyle = self::getAttribute($chartDetail->scatterStyle, 'val', 'string'); $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotSer->setPlotStyle($scatterStyle); $plotSeries[] = $plotSer; $plotAttributes = self::readChartAttributes($chartDetail); break; case 'bubbleChart': $bubbleScale = self::getAttribute($chartDetail->bubbleScale, 'val', 'integer'); $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotSer->setPlotStyle($bubbleScale); $plotSeries[] = $plotSer; $plotAttributes = self::readChartAttributes($chartDetail); break; case 'radarChart': $radarStyle = self::getAttribute($chartDetail->radarStyle, 'val', 'string'); $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotSer->setPlotStyle($radarStyle); $plotSeries[] = $plotSer; $plotAttributes = self::readChartAttributes($chartDetail); break; case 'surfaceChart': case 'surface3DChart': $wireFrame = self::getAttribute($chartDetail->wireframe, 'val', 'boolean'); $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotSer->setPlotStyle($wireFrame); $plotSeries[] = $plotSer; $plotAttributes = self::readChartAttributes($chartDetail); break; case 'stockChart': $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey); $plotAttributes = self::readChartAttributes($plotAreaLayout); break; } } if ($plotAreaLayout == null) { $plotAreaLayout = new Layout(); } $plotArea = new PlotArea($plotAreaLayout, $plotSeries); self::setChartAttributes($plotAreaLayout, $plotAttributes); break; case 'plotVisOnly': $plotVisOnly = self::getAttribute($chartDetails, 'val', 'string'); break; case 'dispBlanksAs': $dispBlanksAs = self::getAttribute($chartDetails, 'val', 'string'); break; case 'title': $title = self::chartTitle($chartDetails, $namespacesChartMeta); break; case 'legend': $legendPos = 'r'; $legendLayout = null; $legendOverlay = false; foreach ($chartDetails as $chartDetailKey => $chartDetail) { switch ($chartDetailKey) { case 'legendPos': $legendPos = self::getAttribute($chartDetail, 'val', 'string'); break; case 'overlay': $legendOverlay = self::getAttribute($chartDetail, 'val', 'boolean'); break; case 'layout': $legendLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta); break; } } $legend = new Legend($legendPos, $legendLayout, $legendOverlay); break; } } } } $chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, $dispBlanksAs, $XaxisLabel, $YaxisLabel); return $chart; } private static function chartTitle(SimpleXMLElement $titleDetails, array $namespacesChartMeta) { $caption = []; $titleLayout = null; foreach ($titleDetails as $titleDetailKey => $chartDetail) { switch ($titleDetailKey) { case 'tx': $titleDetails = $chartDetail->rich->children($namespacesChartMeta['a']); foreach ($titleDetails as $titleKey => $titleDetail) { switch ($titleKey) { case 'p': $titleDetailPart = $titleDetail->children($namespacesChartMeta['a']); $caption[] = self::parseRichText($titleDetailPart); } } break; case 'layout': $titleLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta); break; } } return new Title($caption, $titleLayout); } private static function chartLayoutDetails($chartDetail, $namespacesChartMeta) { if (!isset($chartDetail->manualLayout)) { return null; } $details = $chartDetail->manualLayout->children($namespacesChartMeta['c']); if ($details === null) { return null; } $layout = []; foreach ($details as $detailKey => $detail) { $layout[$detailKey] = self::getAttribute($detail, 'val', 'string'); } return new Layout($layout); } private static function chartDataSeries($chartDetail, $namespacesChartMeta, $plotType) { $multiSeriesType = null; $smoothLine = false; $seriesLabel = $seriesCategory = $seriesValues = $plotOrder = []; $seriesDetailSet = $chartDetail->children($namespacesChartMeta['c']); foreach ($seriesDetailSet as $seriesDetailKey => $seriesDetails) { switch ($seriesDetailKey) { case 'grouping': $multiSeriesType = self::getAttribute($chartDetail->grouping, 'val', 'string'); break; case 'ser': $marker = null; $seriesIndex = ''; foreach ($seriesDetails as $seriesKey => $seriesDetail) { switch ($seriesKey) { case 'idx': $seriesIndex = self::getAttribute($seriesDetail, 'val', 'integer'); break; case 'order': $seriesOrder = self::getAttribute($seriesDetail, 'val', 'integer'); $plotOrder[$seriesIndex] = $seriesOrder; break; case 'tx': $seriesLabel[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta); break; case 'marker': $marker = self::getAttribute($seriesDetail->symbol, 'val', 'string'); break; case 'smooth': $smoothLine = self::getAttribute($seriesDetail, 'val', 'boolean'); break; case 'cat': $seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta); break; case 'val': $seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker); break; case 'xVal': $seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker); break; case 'yVal': $seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker); break; } } } } return new DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $smoothLine); } private static function chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker = null) { if (isset($seriesDetail->strRef)) { $seriesSource = (string) $seriesDetail->strRef->f; $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker); if (isset($seriesDetail->strRef->strCache)) { $seriesData = self::chartDataSeriesValues($seriesDetail->strRef->strCache->children($namespacesChartMeta['c']), 's'); $seriesValues ->setFormatCode($seriesData['formatCode']) ->setDataValues($seriesData['dataValues']); } return $seriesValues; } elseif (isset($seriesDetail->numRef)) { $seriesSource = (string) $seriesDetail->numRef->f; $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, null, null, $marker); if (isset($seriesDetail->numRef->numCache)) { $seriesData = self::chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c'])); $seriesValues ->setFormatCode($seriesData['formatCode']) ->setDataValues($seriesData['dataValues']); } return $seriesValues; } elseif (isset($seriesDetail->multiLvlStrRef)) { $seriesSource = (string) $seriesDetail->multiLvlStrRef->f; $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker); if (isset($seriesDetail->multiLvlStrRef->multiLvlStrCache)) { $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($namespacesChartMeta['c']), 's'); $seriesValues ->setFormatCode($seriesData['formatCode']) ->setDataValues($seriesData['dataValues']); } return $seriesValues; } elseif (isset($seriesDetail->multiLvlNumRef)) { $seriesSource = (string) $seriesDetail->multiLvlNumRef->f; $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker); if (isset($seriesDetail->multiLvlNumRef->multiLvlNumCache)) { $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($namespacesChartMeta['c']), 's'); $seriesValues ->setFormatCode($seriesData['formatCode']) ->setDataValues($seriesData['dataValues']); } return $seriesValues; } return null; } private static function chartDataSeriesValues($seriesValueSet, $dataType = 'n') { $seriesVal = []; $formatCode = ''; $pointCount = 0; foreach ($seriesValueSet as $seriesValueIdx => $seriesValue) { switch ($seriesValueIdx) { case 'ptCount': $pointCount = self::getAttribute($seriesValue, 'val', 'integer'); break; case 'formatCode': $formatCode = (string) $seriesValue; break; case 'pt': $pointVal = self::getAttribute($seriesValue, 'idx', 'integer'); if ($dataType == 's') { $seriesVal[$pointVal] = (string) $seriesValue->v; } elseif ($seriesValue->v === Functions::NA()) { $seriesVal[$pointVal] = null; } else { $seriesVal[$pointVal] = (float) $seriesValue->v; } break; } } return [ 'formatCode' => $formatCode, 'pointCount' => $pointCount, 'dataValues' => $seriesVal, ]; } private static function chartDataSeriesValuesMultiLevel($seriesValueSet, $dataType = 'n') { $seriesVal = []; $formatCode = ''; $pointCount = 0; foreach ($seriesValueSet->lvl as $seriesLevelIdx => $seriesLevel) { foreach ($seriesLevel as $seriesValueIdx => $seriesValue) { switch ($seriesValueIdx) { case 'ptCount': $pointCount = self::getAttribute($seriesValue, 'val', 'integer'); break; case 'formatCode': $formatCode = (string) $seriesValue; break; case 'pt': $pointVal = self::getAttribute($seriesValue, 'idx', 'integer'); if ($dataType == 's') { $seriesVal[$pointVal][] = (string) $seriesValue->v; } elseif ($seriesValue->v === Functions::NA()) { $seriesVal[$pointVal] = null; } else { $seriesVal[$pointVal][] = (float) $seriesValue->v; } break; } } } return [ 'formatCode' => $formatCode, 'pointCount' => $pointCount, 'dataValues' => $seriesVal, ]; } private static function parseRichText(SimpleXMLElement $titleDetailPart) { $value = new RichText(); $objText = null; foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) { if (isset($titleDetailElement->t)) { $objText = $value->createTextRun((string) $titleDetailElement->t); } if (isset($titleDetailElement->rPr)) { if (isset($titleDetailElement->rPr->rFont['val'])) { $objText->getFont()->setName((string) $titleDetailElement->rPr->rFont['val']); } $fontSize = (self::getAttribute($titleDetailElement->rPr, 'sz', 'integer')); if (is_int($fontSize)) { $objText->getFont()->setSize(floor($fontSize / 100)); } $fontColor = (self::getAttribute($titleDetailElement->rPr, 'color', 'string')); if ($fontColor !== null) { $objText->getFont()->setColor(new Color(self::readColor($fontColor))); } $bold = self::getAttribute($titleDetailElement->rPr, 'b', 'boolean'); if ($bold !== null) { $objText->getFont()->setBold($bold); } $italic = self::getAttribute($titleDetailElement->rPr, 'i', 'boolean'); if ($italic !== null) { $objText->getFont()->setItalic($italic); } $baseline = self::getAttribute($titleDetailElement->rPr, 'baseline', 'integer'); if ($baseline !== null) { if ($baseline > 0) { $objText->getFont()->setSuperscript(true); } elseif ($baseline < 0) { $objText->getFont()->setSubscript(true); } } $underscore = (self::getAttribute($titleDetailElement->rPr, 'u', 'string')); if ($underscore !== null) { if ($underscore == 'sng') { $objText->getFont()->setUnderline(Font::UNDERLINE_SINGLE); } elseif ($underscore == 'dbl') { $objText->getFont()->setUnderline(Font::UNDERLINE_DOUBLE); } else { $objText->getFont()->setUnderline(Font::UNDERLINE_NONE); } } $strikethrough = (self::getAttribute($titleDetailElement->rPr, 's', 'string')); if ($strikethrough !== null) { if ($strikethrough == 'noStrike') { $objText->getFont()->setStrikethrough(false); } else { $objText->getFont()->setStrikethrough(true); } } } } return $value; } private static function readChartAttributes($chartDetail) { $plotAttributes = []; if (isset($chartDetail->dLbls)) { if (isset($chartDetail->dLbls->showLegendKey)) { $plotAttributes['showLegendKey'] = self::getAttribute($chartDetail->dLbls->showLegendKey, 'val', 'string'); } if (isset($chartDetail->dLbls->showVal)) { $plotAttributes['showVal'] = self::getAttribute($chartDetail->dLbls->showVal, 'val', 'string'); } if (isset($chartDetail->dLbls->showCatName)) { $plotAttributes['showCatName'] = self::getAttribute($chartDetail->dLbls->showCatName, 'val', 'string'); } if (isset($chartDetail->dLbls->showSerName)) { $plotAttributes['showSerName'] = self::getAttribute($chartDetail->dLbls->showSerName, 'val', 'string'); } if (isset($chartDetail->dLbls->showPercent)) { $plotAttributes['showPercent'] = self::getAttribute($chartDetail->dLbls->showPercent, 'val', 'string'); } if (isset($chartDetail->dLbls->showBubbleSize)) { $plotAttributes['showBubbleSize'] = self::getAttribute($chartDetail->dLbls->showBubbleSize, 'val', 'string'); } if (isset($chartDetail->dLbls->showLeaderLines)) { $plotAttributes['showLeaderLines'] = self::getAttribute($chartDetail->dLbls->showLeaderLines, 'val', 'string'); } } return $plotAttributes; } /** * @param mixed $plotAttributes */ private static function setChartAttributes(Layout $plotArea, $plotAttributes): void { foreach ($plotAttributes as $plotAttributeKey => $plotAttributeValue) { switch ($plotAttributeKey) { case 'showLegendKey': $plotArea->setShowLegendKey($plotAttributeValue); break; case 'showVal': $plotArea->setShowVal($plotAttributeValue); break; case 'showCatName': $plotArea->setShowCatName($plotAttributeValue); break; case 'showSerName': $plotArea->setShowSerName($plotAttributeValue); break; case 'showPercent': $plotArea->setShowPercent($plotAttributeValue); break; case 'showBubbleSize': $plotArea->setShowBubbleSize($plotAttributeValue); break; case 'showLeaderLines': $plotArea->setShowLeaderLines($plotAttributeValue); break; } } } } PKD[1}|Hyperlinks.phpnu[worksheet = $workSheet; } public function readHyperlinks(SimpleXMLElement $relsWorksheet): void { foreach ($relsWorksheet->children(Namespaces::RELATIONSHIPS)->Relationship as $elementx) { $element = Xlsx::getAttributes($elementx); if ($element->Type == Namespaces::HYPERLINK) { $this->hyperlinks[(string) $element->Id] = (string) $element->Target; } } } public function setHyperlinks(SimpleXMLElement $worksheetXml): void { foreach ($worksheetXml->children(Namespaces::MAIN)->hyperlink as $hyperlink) { if ($hyperlink !== null) { $this->setHyperlink($hyperlink, $this->worksheet); } } } private function setHyperlink(SimpleXMLElement $hyperlink, Worksheet $worksheet): void { // Link url $linkRel = Xlsx::getAttributes($hyperlink, Namespaces::SCHEMA_OFFICE_DOCUMENT); $attributes = Xlsx::getAttributes($hyperlink); foreach (Coordinate::extractAllCellReferencesInRange($attributes->ref) as $cellReference) { $cell = $worksheet->getCell($cellReference); if (isset($linkRel['id'])) { $hyperlinkUrl = $this->hyperlinks[(string) $linkRel['id']] ?? null; if (isset($attributes['location'])) { $hyperlinkUrl .= '#' . (string) $attributes['location']; } $cell->getHyperlink()->setUrl($hyperlinkUrl); } elseif (isset($attributes['location'])) { $cell->getHyperlink()->setUrl('sheet://' . (string) $attributes['location']); } // Tooltip if (isset($attributes['tooltip'])) { $cell->getHyperlink()->setTooltip((string) $attributes['tooltip']); } } } } PKDs  DataValidations.phpnu[worksheet = $workSheet; $this->worksheetXml = $worksheetXml; } public function load(): void { foreach ($this->worksheetXml->dataValidations->dataValidation as $dataValidation) { // Uppercase coordinate $range = strtoupper($dataValidation['sqref']); $rangeSet = explode(' ', $range); foreach ($rangeSet as $range) { $stRange = $this->worksheet->shrinkRangeToFit($range); // Extract all cell references in $range foreach (Coordinate::extractAllCellReferencesInRange($stRange) as $reference) { // Create validation $docValidation = $this->worksheet->getCell($reference)->getDataValidation(); $docValidation->setType((string) $dataValidation['type']); $docValidation->setErrorStyle((string) $dataValidation['errorStyle']); $docValidation->setOperator((string) $dataValidation['operator']); $docValidation->setAllowBlank(filter_var($dataValidation['allowBlank'], FILTER_VALIDATE_BOOLEAN)); // showDropDown is inverted (works as hideDropDown if true) $docValidation->setShowDropDown(!filter_var($dataValidation['showDropDown'], FILTER_VALIDATE_BOOLEAN)); $docValidation->setShowInputMessage(filter_var($dataValidation['showInputMessage'], FILTER_VALIDATE_BOOLEAN)); $docValidation->setShowErrorMessage(filter_var($dataValidation['showErrorMessage'], FILTER_VALIDATE_BOOLEAN)); $docValidation->setErrorTitle((string) $dataValidation['errorTitle']); $docValidation->setError((string) $dataValidation['error']); $docValidation->setPromptTitle((string) $dataValidation['promptTitle']); $docValidation->setPrompt((string) $dataValidation['prompt']); $docValidation->setFormula1((string) $dataValidation->formula1); $docValidation->setFormula2((string) $dataValidation->formula2); $docValidation->setSqref($range); } } } } } PKD[|JJAutoFilter.phpnu[worksheet = $workSheet; $this->worksheetXml = $worksheetXml; } public function load(): void { // Remove all "$" in the auto filter range $autoFilterRange = preg_replace('/\$/', '', $this->worksheetXml->autoFilter['ref']); if (strpos($autoFilterRange, ':') !== false) { $this->readAutoFilter($autoFilterRange, $this->worksheetXml); } } private function readAutoFilter($autoFilterRange, $xmlSheet): void { $autoFilter = $this->worksheet->getAutoFilter(); $autoFilter->setRange($autoFilterRange); foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) { $column = $autoFilter->getColumnByOffset((int) $filterColumn['colId']); // Check for standard filters if ($filterColumn->filters) { $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); $filters = $filterColumn->filters; if ((isset($filters['blank'])) && ($filters['blank'] == 1)) { // Operator is undefined, but always treated as EQUAL $column->createRule()->setRule(null, '')->setRuleType(Rule::AUTOFILTER_RULETYPE_FILTER); } // Standard filters are always an OR join, so no join rule needs to be set // Entries can be either filter elements foreach ($filters->filter as $filterRule) { // Operator is undefined, but always treated as EQUAL $column->createRule()->setRule(null, (string) $filterRule['val'])->setRuleType(Rule::AUTOFILTER_RULETYPE_FILTER); } // Or Date Group elements $this->readDateRangeAutoFilter($filters, $column); } // Check for custom filters $this->readCustomAutoFilter($filterColumn, $column); // Check for dynamic filters $this->readDynamicAutoFilter($filterColumn, $column); // Check for dynamic filters $this->readTopTenAutoFilter($filterColumn, $column); } } private function readDateRangeAutoFilter(SimpleXMLElement $filters, Column $column): void { foreach ($filters->dateGroupItem as $dateGroupItem) { // Operator is undefined, but always treated as EQUAL $column->createRule()->setRule( null, [ 'year' => (string) $dateGroupItem['year'], 'month' => (string) $dateGroupItem['month'], 'day' => (string) $dateGroupItem['day'], 'hour' => (string) $dateGroupItem['hour'], 'minute' => (string) $dateGroupItem['minute'], 'second' => (string) $dateGroupItem['second'], ], (string) $dateGroupItem['dateTimeGrouping'] )->setRuleType(Rule::AUTOFILTER_RULETYPE_DATEGROUP); } } private function readCustomAutoFilter(SimpleXMLElement $filterColumn, Column $column): void { if ($filterColumn->customFilters) { $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER); $customFilters = $filterColumn->customFilters; // Custom filters can an AND or an OR join; // and there should only ever be one or two entries if ((isset($customFilters['and'])) && ((string) $customFilters['and'] === '1')) { $column->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND); } foreach ($customFilters->customFilter as $filterRule) { $column->createRule()->setRule( (string) $filterRule['operator'], (string) $filterRule['val'] )->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); } } } private function readDynamicAutoFilter(SimpleXMLElement $filterColumn, Column $column): void { if ($filterColumn->dynamicFilter) { $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); // We should only ever have one dynamic filter foreach ($filterColumn->dynamicFilter as $filterRule) { // Operator is undefined, but always treated as EQUAL $column->createRule()->setRule( null, (string) $filterRule['val'], (string) $filterRule['type'] )->setRuleType(Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER); if (isset($filterRule['val'])) { $column->setAttribute('val', (string) $filterRule['val']); } if (isset($filterRule['maxVal'])) { $column->setAttribute('maxVal', (string) $filterRule['maxVal']); } } } } private function readTopTenAutoFilter(SimpleXMLElement $filterColumn, Column $column): void { if ($filterColumn->top10) { $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER); // We should only ever have one top10 filter foreach ($filterColumn->top10 as $filterRule) { $column->createRule()->setRule( ( ((isset($filterRule['percent'])) && ((string) $filterRule['percent'] === '1')) ? Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT : Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE ), (string) $filterRule['val'], ( ((isset($filterRule['top'])) && ((string) $filterRule['top'] === '1')) ? Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP : Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM ) )->setRuleType(Rule::AUTOFILTER_RULETYPE_TOPTENFILTER); } } } } PKD[$ PageSetup.phpnu[worksheet = $workSheet; $this->worksheetXml = $worksheetXml; } public function load(array $unparsedLoadedData) { if (!$this->worksheetXml) { return $unparsedLoadedData; } $this->margins($this->worksheetXml, $this->worksheet); $unparsedLoadedData = $this->pageSetup($this->worksheetXml, $this->worksheet, $unparsedLoadedData); $this->headerFooter($this->worksheetXml, $this->worksheet); $this->pageBreaks($this->worksheetXml, $this->worksheet); return $unparsedLoadedData; } private function margins(SimpleXMLElement $xmlSheet, Worksheet $worksheet): void { if ($xmlSheet->pageMargins) { $docPageMargins = $worksheet->getPageMargins(); $docPageMargins->setLeft((float) ($xmlSheet->pageMargins['left'])); $docPageMargins->setRight((float) ($xmlSheet->pageMargins['right'])); $docPageMargins->setTop((float) ($xmlSheet->pageMargins['top'])); $docPageMargins->setBottom((float) ($xmlSheet->pageMargins['bottom'])); $docPageMargins->setHeader((float) ($xmlSheet->pageMargins['header'])); $docPageMargins->setFooter((float) ($xmlSheet->pageMargins['footer'])); } } private function pageSetup(SimpleXMLElement $xmlSheet, Worksheet $worksheet, array $unparsedLoadedData) { if ($xmlSheet->pageSetup) { $docPageSetup = $worksheet->getPageSetup(); if (isset($xmlSheet->pageSetup['orientation'])) { $docPageSetup->setOrientation((string) $xmlSheet->pageSetup['orientation']); } if (isset($xmlSheet->pageSetup['paperSize'])) { $docPageSetup->setPaperSize((int) ($xmlSheet->pageSetup['paperSize'])); } if (isset($xmlSheet->pageSetup['scale'])) { $docPageSetup->setScale((int) ($xmlSheet->pageSetup['scale']), false); } if (isset($xmlSheet->pageSetup['fitToHeight']) && (int) ($xmlSheet->pageSetup['fitToHeight']) >= 0) { $docPageSetup->setFitToHeight((int) ($xmlSheet->pageSetup['fitToHeight']), false); } if (isset($xmlSheet->pageSetup['fitToWidth']) && (int) ($xmlSheet->pageSetup['fitToWidth']) >= 0) { $docPageSetup->setFitToWidth((int) ($xmlSheet->pageSetup['fitToWidth']), false); } if ( isset($xmlSheet->pageSetup['firstPageNumber'], $xmlSheet->pageSetup['useFirstPageNumber']) && self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber']) ) { $docPageSetup->setFirstPageNumber((int) ($xmlSheet->pageSetup['firstPageNumber'])); } if (isset($xmlSheet->pageSetup['pageOrder'])) { $docPageSetup->setPageOrder((string) $xmlSheet->pageSetup['pageOrder']); } $relAttributes = $xmlSheet->pageSetup->attributes(Namespaces::SCHEMA_OFFICE_DOCUMENT); if (isset($relAttributes['id'])) { $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId'] = (string) $relAttributes['id']; } } return $unparsedLoadedData; } private function headerFooter(SimpleXMLElement $xmlSheet, Worksheet $worksheet): void { if ($xmlSheet->headerFooter) { $docHeaderFooter = $worksheet->getHeaderFooter(); if ( isset($xmlSheet->headerFooter['differentOddEven']) && self::boolean((string) $xmlSheet->headerFooter['differentOddEven']) ) { $docHeaderFooter->setDifferentOddEven(true); } else { $docHeaderFooter->setDifferentOddEven(false); } if ( isset($xmlSheet->headerFooter['differentFirst']) && self::boolean((string) $xmlSheet->headerFooter['differentFirst']) ) { $docHeaderFooter->setDifferentFirst(true); } else { $docHeaderFooter->setDifferentFirst(false); } if ( isset($xmlSheet->headerFooter['scaleWithDoc']) && !self::boolean((string) $xmlSheet->headerFooter['scaleWithDoc']) ) { $docHeaderFooter->setScaleWithDocument(false); } else { $docHeaderFooter->setScaleWithDocument(true); } if ( isset($xmlSheet->headerFooter['alignWithMargins']) && !self::boolean((string) $xmlSheet->headerFooter['alignWithMargins']) ) { $docHeaderFooter->setAlignWithMargins(false); } else { $docHeaderFooter->setAlignWithMargins(true); } $docHeaderFooter->setOddHeader((string) $xmlSheet->headerFooter->oddHeader); $docHeaderFooter->setOddFooter((string) $xmlSheet->headerFooter->oddFooter); $docHeaderFooter->setEvenHeader((string) $xmlSheet->headerFooter->evenHeader); $docHeaderFooter->setEvenFooter((string) $xmlSheet->headerFooter->evenFooter); $docHeaderFooter->setFirstHeader((string) $xmlSheet->headerFooter->firstHeader); $docHeaderFooter->setFirstFooter((string) $xmlSheet->headerFooter->firstFooter); } } private function pageBreaks(SimpleXMLElement $xmlSheet, Worksheet $worksheet): void { if ($xmlSheet->rowBreaks && $xmlSheet->rowBreaks->brk) { $this->rowBreaks($xmlSheet, $worksheet); } if ($xmlSheet->colBreaks && $xmlSheet->colBreaks->brk) { $this->columnBreaks($xmlSheet, $worksheet); } } private function rowBreaks(SimpleXMLElement $xmlSheet, Worksheet $worksheet): void { foreach ($xmlSheet->rowBreaks->brk as $brk) { if ($brk['man']) { $worksheet->setBreak("A{$brk['id']}", Worksheet::BREAK_ROW); } } } private function columnBreaks(SimpleXMLElement $xmlSheet, Worksheet $worksheet): void { foreach ($xmlSheet->colBreaks->brk as $brk) { if ($brk['man']) { $worksheet->setBreak( Coordinate::stringFromColumnIndex(((int) $brk['id']) + 1) . '1', Worksheet::BREAK_COLUMN ); } } } } PKD[|[[BaseParserClass.phpnu[securityScanner = $securityScanner; $this->docProps = $docProps; } /** * @param mixed $obj */ private static function nullOrSimple($obj): ?SimpleXMLElement { return ($obj instanceof SimpleXMLElement) ? $obj : null; } private function extractPropertyData(string $propertyData): ?SimpleXMLElement { // okay to omit namespace because everything will be processed by xpath $obj = simplexml_load_string( $this->securityScanner->scan($propertyData), 'SimpleXMLElement', Settings::getLibXmlLoaderOptions() ); return self::nullOrSimple($obj); } public function readCoreProperties(string $propertyData): void { $xmlCore = $this->extractPropertyData($propertyData); if (is_object($xmlCore)) { $xmlCore->registerXPathNamespace('dc', Namespaces::DC_ELEMENTS); $xmlCore->registerXPathNamespace('dcterms', Namespaces::DC_TERMS); $xmlCore->registerXPathNamespace('cp', Namespaces::CORE_PROPERTIES2); $this->docProps->setCreator((string) self::getArrayItem($xmlCore->xpath('dc:creator'))); $this->docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath('cp:lastModifiedBy'))); $this->docProps->setCreated((string) self::getArrayItem($xmlCore->xpath('dcterms:created'))); //! respect xsi:type $this->docProps->setModified((string) self::getArrayItem($xmlCore->xpath('dcterms:modified'))); //! respect xsi:type $this->docProps->setTitle((string) self::getArrayItem($xmlCore->xpath('dc:title'))); $this->docProps->setDescription((string) self::getArrayItem($xmlCore->xpath('dc:description'))); $this->docProps->setSubject((string) self::getArrayItem($xmlCore->xpath('dc:subject'))); $this->docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath('cp:keywords'))); $this->docProps->setCategory((string) self::getArrayItem($xmlCore->xpath('cp:category'))); } } public function readExtendedProperties(string $propertyData): void { $xmlCore = $this->extractPropertyData($propertyData); if (is_object($xmlCore)) { if (isset($xmlCore->Company)) { $this->docProps->setCompany((string) $xmlCore->Company); } if (isset($xmlCore->Manager)) { $this->docProps->setManager((string) $xmlCore->Manager); } } } public function readCustomProperties(string $propertyData): void { $xmlCore = $this->extractPropertyData($propertyData); if (is_object($xmlCore)) { foreach ($xmlCore as $xmlProperty) { /** @var SimpleXMLElement $xmlProperty */ $cellDataOfficeAttributes = $xmlProperty->attributes(); if (isset($cellDataOfficeAttributes['name'])) { $propertyName = (string) $cellDataOfficeAttributes['name']; $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); $attributeType = $cellDataOfficeChildren->getName(); $attributeValue = (string) $cellDataOfficeChildren->{$attributeType}; $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType); $attributeType = DocumentProperties::convertPropertyType($attributeType); $this->docProps->setCustomProperty($propertyName, $attributeValue, $attributeType); } } } } /** * @param array|false $array * @param mixed $key */ private static function getArrayItem($array, $key = 0): ?SimpleXMLElement { return is_array($array) ? ($array[$key] ?? null) : null; } } PKD[5RRSheetViewOptions.phpnu[worksheet = $workSheet; $this->worksheetXml = $worksheetXml; } /** * @param bool $readDataOnly */ public function load($readDataOnly = false): void { if ($this->worksheetXml === null) { return; } if (isset($this->worksheetXml->sheetPr)) { $this->tabColor($this->worksheetXml->sheetPr); $this->codeName($this->worksheetXml->sheetPr); $this->outlines($this->worksheetXml->sheetPr); $this->pageSetup($this->worksheetXml->sheetPr); } if (isset($this->worksheetXml->sheetFormatPr)) { $this->sheetFormat($this->worksheetXml->sheetFormatPr); } if (!$readDataOnly && isset($this->worksheetXml->printOptions)) { $this->printOptions($this->worksheetXml->printOptions); } } private function tabColor(SimpleXMLElement $sheetPr): void { if (isset($sheetPr->tabColor, $sheetPr->tabColor['rgb'])) { $this->worksheet->getTabColor()->setARGB((string) $sheetPr->tabColor['rgb']); } } private function codeName(SimpleXMLElement $sheetPr): void { if (isset($sheetPr['codeName'])) { $this->worksheet->setCodeName((string) $sheetPr['codeName'], false); } } private function outlines(SimpleXMLElement $sheetPr): void { if (isset($sheetPr->outlinePr)) { if ( isset($sheetPr->outlinePr['summaryRight']) && !self::boolean((string) $sheetPr->outlinePr['summaryRight']) ) { $this->worksheet->setShowSummaryRight(false); } else { $this->worksheet->setShowSummaryRight(true); } if ( isset($sheetPr->outlinePr['summaryBelow']) && !self::boolean((string) $sheetPr->outlinePr['summaryBelow']) ) { $this->worksheet->setShowSummaryBelow(false); } else { $this->worksheet->setShowSummaryBelow(true); } } } private function pageSetup(SimpleXMLElement $sheetPr): void { if (isset($sheetPr->pageSetUpPr)) { if ( isset($sheetPr->pageSetUpPr['fitToPage']) && !self::boolean((string) $sheetPr->pageSetUpPr['fitToPage']) ) { $this->worksheet->getPageSetup()->setFitToPage(false); } else { $this->worksheet->getPageSetup()->setFitToPage(true); } } } private function sheetFormat(SimpleXMLElement $sheetFormatPr): void { if ( isset($sheetFormatPr['customHeight']) && self::boolean((string) $sheetFormatPr['customHeight']) && isset($sheetFormatPr['defaultRowHeight']) ) { $this->worksheet->getDefaultRowDimension() ->setRowHeight((float) $sheetFormatPr['defaultRowHeight']); } if (isset($sheetFormatPr['defaultColWidth'])) { $this->worksheet->getDefaultColumnDimension() ->setWidth((float) $sheetFormatPr['defaultColWidth']); } if ( isset($sheetFormatPr['zeroHeight']) && ((string) $sheetFormatPr['zeroHeight'] === '1') ) { $this->worksheet->getDefaultRowDimension()->setZeroHeight(true); } } private function printOptions(SimpleXMLElement $printOptions): void { if (self::boolean((string) $printOptions['gridLinesSet'])) { $this->worksheet->setShowGridlines(true); } if (self::boolean((string) $printOptions['gridLines'])) { $this->worksheet->setPrintGridlines(true); } if (self::boolean((string) $printOptions['horizontalCentered'])) { $this->worksheet->getPageSetup()->setHorizontalCentered(true); } if (self::boolean((string) $printOptions['verticalCentered'])) { $this->worksheet->getPageSetup()->setVerticalCentered(true); } } } PKDSheetViews.phpnu[sheetViewXml = $sheetViewXml; $this->sheetViewAttributes = Xlsx::testSimpleXml($sheetViewXml->attributes()); $this->worksheet = $workSheet; } public function load(): void { $this->topLeft(); $this->zoomScale(); $this->view(); $this->gridLines(); $this->headers(); $this->direction(); $this->showZeros(); if (isset($this->sheetViewXml->pane)) { $this->pane(); } if (isset($this->sheetViewXml->selection, $this->sheetViewXml->selection->attributes()->sqref)) { $this->selection(); } } private function zoomScale(): void { if (isset($this->sheetViewAttributes->zoomScale)) { $zoomScale = (int) ($this->sheetViewAttributes->zoomScale); if ($zoomScale <= 0) { // setZoomScale will throw an Exception if the scale is less than or equals 0 // that is OK when manually creating documents, but we should be able to read all documents $zoomScale = 100; } $this->worksheet->getSheetView()->setZoomScale($zoomScale); } if (isset($this->sheetViewAttributes->zoomScaleNormal)) { $zoomScaleNormal = (int) ($this->sheetViewAttributes->zoomScaleNormal); if ($zoomScaleNormal <= 0) { // setZoomScaleNormal will throw an Exception if the scale is less than or equals 0 // that is OK when manually creating documents, but we should be able to read all documents $zoomScaleNormal = 100; } $this->worksheet->getSheetView()->setZoomScaleNormal($zoomScaleNormal); } } private function view(): void { if (isset($this->sheetViewAttributes->view)) { $this->worksheet->getSheetView()->setView((string) $this->sheetViewAttributes->view); } } private function topLeft(): void { if (isset($this->sheetViewAttributes->topLeftCell)) { $this->worksheet->setTopLeftCell($this->sheetViewAttributes->topLeftCell); } } private function gridLines(): void { if (isset($this->sheetViewAttributes->showGridLines)) { $this->worksheet->setShowGridLines( self::boolean((string) $this->sheetViewAttributes->showGridLines) ); } } private function headers(): void { if (isset($this->sheetViewAttributes->showRowColHeaders)) { $this->worksheet->setShowRowColHeaders( self::boolean((string) $this->sheetViewAttributes->showRowColHeaders) ); } } private function direction(): void { if (isset($this->sheetViewAttributes->rightToLeft)) { $this->worksheet->setRightToLeft( self::boolean((string) $this->sheetViewAttributes->rightToLeft) ); } } private function showZeros(): void { if (isset($this->sheetViewAttributes->showZeros)) { $this->worksheet->getSheetView()->setShowZeros( self::boolean((string) $this->sheetViewAttributes->showZeros) ); } } private function pane(): void { $xSplit = 0; $ySplit = 0; $topLeftCell = null; $paneAttributes = $this->sheetViewXml->pane->attributes(); if (isset($paneAttributes->xSplit)) { $xSplit = (int) ($paneAttributes->xSplit); } if (isset($paneAttributes->ySplit)) { $ySplit = (int) ($paneAttributes->ySplit); } if (isset($paneAttributes->topLeftCell)) { $topLeftCell = (string) $paneAttributes->topLeftCell; } $this->worksheet->freezePane( Coordinate::stringFromColumnIndex($xSplit + 1) . ($ySplit + 1), $topLeftCell ); } private function selection(): void { $attributes = $this->sheetViewXml->selection->attributes(); if ($attributes !== null) { $sqref = (string) $attributes->sqref; $sqref = explode(' ', $sqref); $sqref = $sqref[0]; $this->worksheet->setSelectedCells($sqref); } } } PKDw vvConditionalStyles.phpnu[worksheet = $workSheet; $this->worksheetXml = $worksheetXml; $this->dxfs = $dxfs; } public function load(): void { $this->setConditionalStyles( $this->worksheet, $this->readConditionalStyles($this->worksheetXml), $this->worksheetXml->extLst ); } private function readConditionalStyles($xmlSheet) { $conditionals = []; foreach ($xmlSheet->conditionalFormatting as $conditional) { foreach ($conditional->cfRule as $cfRule) { if (Conditional::isValidConditionType((string) $cfRule['type']) && isset($this->dxfs[(int) ($cfRule['dxfId'])])) { $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule; } elseif ((string) $cfRule['type'] == Conditional::CONDITION_DATABAR) { $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule; } } } return $conditionals; } private function setConditionalStyles(Worksheet $worksheet, array $conditionals, $xmlExtLst): void { foreach ($conditionals as $ref => $cfRules) { ksort($cfRules); $conditionalStyles = $this->readStyleRules($cfRules, $xmlExtLst); // Extract all cell references in $ref $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref))); foreach ($cellBlocks as $cellBlock) { $worksheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles); } } } private function readStyleRules($cfRules, $extLst) { $conditionalFormattingRuleExtensions = ConditionalFormattingRuleExtension::parseExtLstXml($extLst); $conditionalStyles = []; foreach ($cfRules as $cfRule) { $objConditional = new Conditional(); $objConditional->setConditionType((string) $cfRule['type']); $objConditional->setOperatorType((string) $cfRule['operator']); if ((string) $cfRule['text'] != '') { $objConditional->setText((string) $cfRule['text']); } if (isset($cfRule['stopIfTrue']) && (int) $cfRule['stopIfTrue'] === 1) { $objConditional->setStopIfTrue(true); } if (count($cfRule->formula) > 1) { foreach ($cfRule->formula as $formula) { $objConditional->addCondition((string) $formula); } } else { $objConditional->addCondition((string) $cfRule->formula); } if (isset($cfRule->dataBar)) { $objConditional->setDataBar( $this->readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions) ); } else { $objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]); } $conditionalStyles[] = $objConditional; } return $conditionalStyles; } private function readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions): ConditionalDataBar { $dataBar = new ConditionalDataBar(); //dataBar attribute if (isset($cfRule->dataBar['showValue'])) { $dataBar->setShowValue((bool) $cfRule->dataBar['showValue']); } //dataBar children //conditionalFormatValueObjects $cfvoXml = $cfRule->dataBar->cfvo; $cfvoIndex = 0; foreach ((count($cfvoXml) > 1 ? $cfvoXml : [$cfvoXml]) as $cfvo) { if ($cfvoIndex === 0) { $dataBar->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val'])); } if ($cfvoIndex === 1) { $dataBar->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val'])); } ++$cfvoIndex; } //color if (isset($cfRule->dataBar->color)) { $dataBar->setColor((string) $cfRule->dataBar->color['rgb']); } //extLst $this->readDataBarExtLstOfConditionalRule($dataBar, $cfRule, $conditionalFormattingRuleExtensions); return $dataBar; } private function readDataBarExtLstOfConditionalRule(ConditionalDataBar $dataBar, $cfRule, $conditionalFormattingRuleExtensions): void { if (isset($cfRule->extLst)) { $ns = $cfRule->extLst->getNamespaces(true); foreach ((count($cfRule->extLst) > 0 ? $cfRule->extLst->ext : [$cfRule->extLst->ext]) as $ext) { $extId = (string) $ext->children($ns['x14'])->id; if (isset($conditionalFormattingRuleExtensions[$extId]) && (string) $ext['uri'] === '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}') { $dataBar->setConditionalFormattingRuleExt($conditionalFormattingRuleExtensions[$extId]); } } } } } PKDϦColumnAndRowAttributes.phpnu[worksheet = $workSheet; $this->worksheetXml = $worksheetXml; } /** * Set Worksheet column attributes by attributes array passed. * * @param string $columnAddress A, B, ... DX, ... * @param array $columnAttributes array of attributes (indexes are attribute name, values are value) * 'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'width', ... ? */ private function setColumnAttributes($columnAddress, array $columnAttributes): void { if (isset($columnAttributes['xfIndex'])) { $this->worksheet->getColumnDimension($columnAddress)->setXfIndex($columnAttributes['xfIndex']); } if (isset($columnAttributes['visible'])) { $this->worksheet->getColumnDimension($columnAddress)->setVisible($columnAttributes['visible']); } if (isset($columnAttributes['collapsed'])) { $this->worksheet->getColumnDimension($columnAddress)->setCollapsed($columnAttributes['collapsed']); } if (isset($columnAttributes['outlineLevel'])) { $this->worksheet->getColumnDimension($columnAddress)->setOutlineLevel($columnAttributes['outlineLevel']); } if (isset($columnAttributes['width'])) { $this->worksheet->getColumnDimension($columnAddress)->setWidth($columnAttributes['width']); } } /** * Set Worksheet row attributes by attributes array passed. * * @param int $rowNumber 1, 2, 3, ... 99, ... * @param array $rowAttributes array of attributes (indexes are attribute name, values are value) * 'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'rowHeight', ... ? */ private function setRowAttributes($rowNumber, array $rowAttributes): void { if (isset($rowAttributes['xfIndex'])) { $this->worksheet->getRowDimension($rowNumber)->setXfIndex($rowAttributes['xfIndex']); } if (isset($rowAttributes['visible'])) { $this->worksheet->getRowDimension($rowNumber)->setVisible($rowAttributes['visible']); } if (isset($rowAttributes['collapsed'])) { $this->worksheet->getRowDimension($rowNumber)->setCollapsed($rowAttributes['collapsed']); } if (isset($rowAttributes['outlineLevel'])) { $this->worksheet->getRowDimension($rowNumber)->setOutlineLevel($rowAttributes['outlineLevel']); } if (isset($rowAttributes['rowHeight'])) { $this->worksheet->getRowDimension($rowNumber)->setRowHeight($rowAttributes['rowHeight']); } } public function load(?IReadFilter $readFilter = null, bool $readDataOnly = false): void { if ($this->worksheetXml === null) { return; } $columnsAttributes = []; $rowsAttributes = []; if (isset($this->worksheetXml->cols)) { $columnsAttributes = $this->readColumnAttributes($this->worksheetXml->cols, $readDataOnly); } if ($this->worksheetXml->sheetData && $this->worksheetXml->sheetData->row) { $rowsAttributes = $this->readRowAttributes($this->worksheetXml->sheetData->row, $readDataOnly); } if ($readFilter !== null && get_class($readFilter) === DefaultReadFilter::class) { $readFilter = null; } // set columns/rows attributes $columnsAttributesAreSet = []; foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) { if ( $readFilter === null || !$this->isFilteredColumn($readFilter, $columnCoordinate, $rowsAttributes) ) { if (!isset($columnsAttributesAreSet[$columnCoordinate])) { $this->setColumnAttributes($columnCoordinate, $columnAttributes); $columnsAttributesAreSet[$columnCoordinate] = true; } } } $rowsAttributesAreSet = []; foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) { if ( $readFilter === null || !$this->isFilteredRow($readFilter, $rowCoordinate, $columnsAttributes) ) { if (!isset($rowsAttributesAreSet[$rowCoordinate])) { $this->setRowAttributes($rowCoordinate, $rowAttributes); $rowsAttributesAreSet[$rowCoordinate] = true; } } } } private function isFilteredColumn(IReadFilter $readFilter, $columnCoordinate, array $rowsAttributes) { foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) { if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) { return true; } } return false; } private function readColumnAttributes(SimpleXMLElement $worksheetCols, $readDataOnly) { $columnAttributes = []; foreach ($worksheetCols->col as $column) { $startColumn = Coordinate::stringFromColumnIndex((int) $column['min']); $endColumn = Coordinate::stringFromColumnIndex((int) $column['max']); ++$endColumn; for ($columnAddress = $startColumn; $columnAddress !== $endColumn; ++$columnAddress) { $columnAttributes[$columnAddress] = $this->readColumnRangeAttributes($column, $readDataOnly); if ((int) ($column['max']) == 16384) { break; } } } return $columnAttributes; } private function readColumnRangeAttributes(SimpleXMLElement $column, $readDataOnly) { $columnAttributes = []; if ($column['style'] && !$readDataOnly) { $columnAttributes['xfIndex'] = (int) $column['style']; } if (self::boolean($column['hidden'])) { $columnAttributes['visible'] = false; } if (self::boolean($column['collapsed'])) { $columnAttributes['collapsed'] = true; } if (((int) $column['outlineLevel']) > 0) { $columnAttributes['outlineLevel'] = (int) $column['outlineLevel']; } $columnAttributes['width'] = (float) $column['width']; return $columnAttributes; } private function isFilteredRow(IReadFilter $readFilter, $rowCoordinate, array $columnsAttributes) { foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) { if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) { return true; } } return false; } private function readRowAttributes(SimpleXMLElement $worksheetRow, $readDataOnly) { $rowAttributes = []; foreach ($worksheetRow as $row) { if ($row['ht'] && !$readDataOnly) { $rowAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht']; } if (self::boolean($row['hidden'])) { $rowAttributes[(int) $row['r']]['visible'] = false; } if (self::boolean($row['collapsed'])) { $rowAttributes[(int) $row['r']]['collapsed'] = true; } if ((int) $row['outlineLevel'] > 0) { $rowAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel']; } if ($row['s'] && !$readDataOnly) { $rowAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s']; } } return $rowAttributes; } } PKD[@Q Namespaces.phpnu[styleXml = $styleXml; } public function setStyleBaseData(?Theme $theme = null, $styles = [], $cellStyles = []): void { self::$theme = $theme; $this->styles = $styles; $this->cellStyles = $cellStyles; } public static function readFontStyle(Font $fontStyle, SimpleXMLElement $fontStyleXml): void { if (isset($fontStyleXml->name, $fontStyleXml->name['val'])) { $fontStyle->setName((string) $fontStyleXml->name['val']); } if (isset($fontStyleXml->sz, $fontStyleXml->sz['val'])) { $fontStyle->setSize((float) $fontStyleXml->sz['val']); } if (isset($fontStyleXml->b)) { $fontStyle->setBold(!isset($fontStyleXml->b['val']) || self::boolean((string) $fontStyleXml->b['val'])); } if (isset($fontStyleXml->i)) { $fontStyle->setItalic(!isset($fontStyleXml->i['val']) || self::boolean((string) $fontStyleXml->i['val'])); } if (isset($fontStyleXml->strike)) { $fontStyle->setStrikethrough( !isset($fontStyleXml->strike['val']) || self::boolean((string) $fontStyleXml->strike['val']) ); } $fontStyle->getColor()->setARGB(self::readColor($fontStyleXml->color)); if (isset($fontStyleXml->u) && !isset($fontStyleXml->u['val'])) { $fontStyle->setUnderline(Font::UNDERLINE_SINGLE); } elseif (isset($fontStyleXml->u, $fontStyleXml->u['val'])) { $fontStyle->setUnderline((string) $fontStyleXml->u['val']); } if (isset($fontStyleXml->vertAlign, $fontStyleXml->vertAlign['val'])) { $verticalAlign = strtolower((string) $fontStyleXml->vertAlign['val']); if ($verticalAlign === 'superscript') { $fontStyle->setSuperscript(true); } elseif ($verticalAlign === 'subscript') { $fontStyle->setSubscript(true); } } } private static function readNumberFormat(NumberFormat $numfmtStyle, SimpleXMLElement $numfmtStyleXml): void { if ($numfmtStyleXml->count() === 0) { return; } $numfmt = Xlsx::getAttributes($numfmtStyleXml); if ($numfmt->count() > 0 && isset($numfmt['formatCode'])) { $numfmtStyle->setFormatCode((string) $numfmt['formatCode']); } } public static function readFillStyle(Fill $fillStyle, SimpleXMLElement $fillStyleXml): void { if ($fillStyleXml->gradientFill) { /** @var SimpleXMLElement $gradientFill */ $gradientFill = $fillStyleXml->gradientFill[0]; if (!empty($gradientFill['type'])) { $fillStyle->setFillType((string) $gradientFill['type']); } $fillStyle->setRotation((float) ($gradientFill['degree'])); $gradientFill->registerXPathNamespace('sml', Namespaces::MAIN); $fillStyle->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color)); $fillStyle->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color)); } elseif ($fillStyleXml->patternFill) { $defaultFillStyle = Fill::FILL_NONE; if ($fillStyleXml->patternFill->fgColor) { $fillStyle->getStartColor()->setARGB(self::readColor($fillStyleXml->patternFill->fgColor, true)); $defaultFillStyle = Fill::FILL_SOLID; } if ($fillStyleXml->patternFill->bgColor) { $fillStyle->getEndColor()->setARGB(self::readColor($fillStyleXml->patternFill->bgColor, true)); $defaultFillStyle = Fill::FILL_SOLID; } $patternType = (string) $fillStyleXml->patternFill['patternType'] != '' ? (string) $fillStyleXml->patternFill['patternType'] : $defaultFillStyle; $fillStyle->setFillType($patternType); } } public static function readBorderStyle(Borders $borderStyle, SimpleXMLElement $borderStyleXml): void { $diagonalUp = self::boolean((string) $borderStyleXml['diagonalUp']); $diagonalDown = self::boolean((string) $borderStyleXml['diagonalDown']); if (!$diagonalUp && !$diagonalDown) { $borderStyle->setDiagonalDirection(Borders::DIAGONAL_NONE); } elseif ($diagonalUp && !$diagonalDown) { $borderStyle->setDiagonalDirection(Borders::DIAGONAL_UP); } elseif (!$diagonalUp && $diagonalDown) { $borderStyle->setDiagonalDirection(Borders::DIAGONAL_DOWN); } else { $borderStyle->setDiagonalDirection(Borders::DIAGONAL_BOTH); } self::readBorder($borderStyle->getLeft(), $borderStyleXml->left); self::readBorder($borderStyle->getRight(), $borderStyleXml->right); self::readBorder($borderStyle->getTop(), $borderStyleXml->top); self::readBorder($borderStyle->getBottom(), $borderStyleXml->bottom); self::readBorder($borderStyle->getDiagonal(), $borderStyleXml->diagonal); } private static function readBorder(Border $border, SimpleXMLElement $borderXml): void { if (isset($borderXml['style'])) { $border->setBorderStyle((string) $borderXml['style']); } if (isset($borderXml->color)) { $border->getColor()->setARGB(self::readColor($borderXml->color)); } } public static function readAlignmentStyle(Alignment $alignment, SimpleXMLElement $alignmentXml): void { $alignment->setHorizontal((string) $alignmentXml['horizontal']); $alignment->setVertical((string) $alignmentXml['vertical']); $textRotation = 0; if ((int) $alignmentXml['textRotation'] <= 90) { $textRotation = (int) $alignmentXml['textRotation']; } elseif ((int) $alignmentXml['textRotation'] > 90) { $textRotation = 90 - (int) $alignmentXml['textRotation']; } $alignment->setTextRotation((int) $textRotation); $alignment->setWrapText(self::boolean((string) $alignmentXml['wrapText'])); $alignment->setShrinkToFit(self::boolean((string) $alignmentXml['shrinkToFit'])); $alignment->setIndent( (int) ((string) $alignmentXml['indent']) > 0 ? (int) ((string) $alignmentXml['indent']) : 0 ); $alignment->setReadOrder( (int) ((string) $alignmentXml['readingOrder']) > 0 ? (int) ((string) $alignmentXml['readingOrder']) : 0 ); } private function readStyle(Style $docStyle, $style): void { if ($style->numFmt instanceof SimpleXMLElement) { self::readNumberFormat($docStyle->getNumberFormat(), $style->numFmt); } else { $docStyle->getNumberFormat()->setFormatCode($style->numFmt); } if (isset($style->font)) { self::readFontStyle($docStyle->getFont(), $style->font); } if (isset($style->fill)) { self::readFillStyle($docStyle->getFill(), $style->fill); } if (isset($style->border)) { self::readBorderStyle($docStyle->getBorders(), $style->border); } if (isset($style->alignment->alignment)) { self::readAlignmentStyle($docStyle->getAlignment(), $style->alignment); } // protection if (isset($style->protection)) { self::readProtectionLocked($docStyle, $style); self::readProtectionHidden($docStyle, $style); } // top-level style settings if (isset($style->quotePrefix)) { $docStyle->setQuotePrefix(true); } } public static function readProtectionLocked(Style $docStyle, $style): void { if (isset($style->protection['locked'])) { if (self::boolean((string) $style->protection['locked'])) { $docStyle->getProtection()->setLocked(Protection::PROTECTION_PROTECTED); } else { $docStyle->getProtection()->setLocked(Protection::PROTECTION_UNPROTECTED); } } } public static function readProtectionHidden(Style $docStyle, $style): void { if (isset($style->protection['hidden'])) { if (self::boolean((string) $style->protection['hidden'])) { $docStyle->getProtection()->setHidden(Protection::PROTECTION_PROTECTED); } else { $docStyle->getProtection()->setHidden(Protection::PROTECTION_UNPROTECTED); } } } public static function readColor($color, $background = false) { if (isset($color['rgb'])) { return (string) $color['rgb']; } elseif (isset($color['indexed'])) { return Color::indexedColor($color['indexed'] - 7, $background)->getARGB(); } elseif (isset($color['theme'])) { if (self::$theme !== null) { $returnColour = self::$theme->getColourByIndex((int) $color['theme']); if (isset($color['tint'])) { $tintAdjust = (float) $color['tint']; $returnColour = Color::changeBrightness($returnColour, $tintAdjust); } return 'FF' . $returnColour; } } return ($background) ? 'FFFFFFFF' : 'FF000000'; } public function dxfs($readDataOnly = false) { $dxfs = []; if (!$readDataOnly && $this->styleXml) { // Conditional Styles if ($this->styleXml->dxfs) { foreach ($this->styleXml->dxfs->dxf as $dxf) { $style = new Style(false, true); $this->readStyle($style, $dxf); $dxfs[] = $style; } } // Cell Styles if ($this->styleXml->cellStyles) { foreach ($this->styleXml->cellStyles->cellStyle as $cellStylex) { $cellStyle = Xlsx::getAttributes($cellStylex); if ((int) ($cellStyle['builtinId']) == 0) { if (isset($this->cellStyles[(int) ($cellStyle['xfId'])])) { // Set default style $style = new Style(); $this->readStyle($style, $this->cellStyles[(int) ($cellStyle['xfId'])]); // normal style, currently not using it for anything } } } } } return $dxfs; } public function styles() { return $this->styles; } private static function getArrayItem($array, $key = 0) { return $array[$key] ?? null; } } PKO**ContentTypes.phpnu[PK[`|rr *Worksheet.phpnu[PKjo tTheme.phpnu[PK[+^0Xlfn.phpnu[PK[i>i>)Rels.phpnu[PKZ lhRelsVBA.phpnu[PKp"p" nDocProps.phpnu[PK[ Workbook.phpnu[PK[剾cWriterPart.phpnu[PKE<<VRelsRibbon.phpnu[PK[ иComments.phpnu[PK[ (f4&4&StringTable.phpnu[PK[[HH GDrawing.phpnu[PKnR!!^FDefinedNames.phpnu[PK8]] PhStyle.phpnu[PK hnhn RChart.phpnu[PKD[1}|4Hyperlinks.phpnu[PKDs  =DataValidations.phpnu[PKD[|JJ/HAutoFilter.phpnu[PKD[$ aPageSetup.phpnu[PKD[|[[|BaseParserClass.phpnu[PKD[!-@@1~Properties.phpnu[PKD[5RRSheetViewOptions.phpnu[PKDESheetViews.phpnu[PKDw vv\ConditionalStyles.phpnu[PKDϦColumnAndRowAttributes.phpnu[PKD[@Q -Namespaces.phpnu[PKD"_-_- Styles.phpnu[PK%