/** * Save PHPExcel to file * * @param string $pFilename * @throws \PHPExcel\Writer\Exception */ public function save($pFilename = null) { if ($this->spreadSheet !== null) { // garbage collect $this->spreadSheet->garbageCollect(); // If $pFilename is php://output or php://stdout, make it a temporary file... $originalFilename = $pFilename; if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { $pFilename = @tempnam(\PHPExcel\Shared\File::sysGetTempDir(), 'phpxltmp'); if ($pFilename == '') { $pFilename = $originalFilename; } } $saveDebugLog = \PHPExcel\Calculation::getInstance($this->spreadSheet)->getDebugLog()->getWriteDebugLog(); \PHPExcel\Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog(false); $saveDateReturnType = \PHPExcel\Calculation\Functions::getReturnDateType(); \PHPExcel\Calculation\Functions::setReturnDateType(\PHPExcel\Calculation\Functions::RETURNDATE_EXCEL); // Create string lookup table $this->stringTable = array(); for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { $this->stringTable = $this->getWriterPart('StringTable')->createStringTable($this->spreadSheet->getSheet($i), $this->stringTable); } // Create styles dictionaries $this->styleHashTable->addFromSource($this->getWriterPart('Style')->allStyles($this->spreadSheet)); $this->stylesConditionalHashTable->addFromSource($this->getWriterPart('Style')->allConditionalStyles($this->spreadSheet)); $this->fillHashTable->addFromSource($this->getWriterPart('Style')->allFills($this->spreadSheet)); $this->fontHashTable->addFromSource($this->getWriterPart('Style')->allFonts($this->spreadSheet)); $this->bordersHashTable->addFromSource($this->getWriterPart('Style')->allBorders($this->spreadSheet)); $this->numFmtHashTable->addFromSource($this->getWriterPart('Style')->allNumberFormats($this->spreadSheet)); // Create drawing dictionary $this->drawingHashTable->addFromSource($this->getWriterPart('Drawing')->allDrawings($this->spreadSheet)); // Create new ZIP file and open it for writing $zipClass = \PHPExcel\Settings::getZipClass(); /** @var \ZipArchive $objZip */ $objZip = new $zipClass(); // Retrieve OVERWRITE and CREATE constants from the instantiated zip class // This method of accessing constant values from a dynamic class should work with all appropriate versions of PHP $ro = new \ReflectionObject($objZip); $zipOverWrite = $ro->getConstant('OVERWRITE'); $zipCreate = $ro->getConstant('CREATE'); if (file_exists($pFilename)) { unlink($pFilename); } // Try opening the ZIP file if ($objZip->open($pFilename, $zipOverWrite) !== true) { if ($objZip->open($pFilename, $zipCreate) !== true) { throw new \PHPExcel\Writer\Exception("Could not open " . $pFilename . " for writing."); } } // Add [Content_Types].xml to ZIP file $objZip->addFromString('[Content_Types].xml', $this->getWriterPart('ContentTypes')->writeContentTypes($this->spreadSheet, $this->includeCharts)); //if hasMacros, add the vbaProject.bin file, Certificate file(if exists) if ($this->spreadSheet->hasMacros()) { $macrosCode = $this->spreadSheet->getMacrosCode(); if (!is_null($macrosCode)) { // we have the code ? $objZip->addFromString('xl/vbaProject.bin', $macrosCode); //allways in 'xl', allways named vbaProject.bin if ($this->spreadSheet->hasMacrosCertificate()) { //signed macros ? // Yes : add the certificate file and the related rels file $objZip->addFromString('xl/vbaProjectSignature.bin', $this->spreadSheet->getMacrosCertificate()); $objZip->addFromString('xl/_rels/vbaProject.bin.rels', $this->getWriterPart('RelsVBA')->writeVBARelationships($this->spreadSheet)); } } } //a custom UI in this workbook ? add it ("base" xml and additional objects (pictures) and rels) if ($this->spreadSheet->hasRibbon()) { $tmpRibbonTarget = $this->spreadSheet->getRibbonXMLData('target'); $objZip->addFromString($tmpRibbonTarget, $this->spreadSheet->getRibbonXMLData('data')); if ($this->spreadSheet->hasRibbonBinObjects()) { $tmpRootPath = dirname($tmpRibbonTarget) . '/'; $ribbonBinObjects = $this->spreadSheet->getRibbonBinObjects('data'); //the files to write foreach ($ribbonBinObjects as $aPath => $aContent) { $objZip->addFromString($tmpRootPath . $aPath, $aContent); } //the rels for files $objZip->addFromString($tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels', $this->getWriterPart('RelsRibbonObjects')->writeRibbonRelationships($this->spreadSheet)); } } // Add relationships to ZIP file $objZip->addFromString('_rels/.rels', $this->getWriterPart('Rels')->writeRelationships($this->spreadSheet)); $objZip->addFromString('xl/_rels/workbook.xml.rels', $this->getWriterPart('Rels')->writeWorkbookRelationships($this->spreadSheet)); // Add document properties to ZIP file $objZip->addFromString('docProps/app.xml', $this->getWriterPart('DocProps')->writeDocPropsApp($this->spreadSheet)); $objZip->addFromString('docProps/core.xml', $this->getWriterPart('DocProps')->writeDocPropsCore($this->spreadSheet)); $customPropertiesPart = $this->getWriterPart('DocProps')->writeDocPropsCustom($this->spreadSheet); if ($customPropertiesPart !== null) { $objZip->addFromString('docProps/custom.xml', $customPropertiesPart); } // Add theme to ZIP file $objZip->addFromString('xl/theme/theme1.xml', $this->getWriterPart('Theme')->writeTheme($this->spreadSheet)); // Add string table to ZIP file $objZip->addFromString('xl/sharedStrings.xml', $this->getWriterPart('StringTable')->writeStringTable($this->stringTable)); // Add styles to ZIP file $objZip->addFromString('xl/styles.xml', $this->getWriterPart('Style')->writeStyles($this->spreadSheet)); // Add workbook to ZIP file $objZip->addFromString('xl/workbook.xml', $this->getWriterPart('Workbook')->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas)); $chartCount = 0; // Add worksheets for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { $objZip->addFromString('xl/worksheets/sheet' . ($i + 1) . '.xml', $this->getWriterPart('Worksheet')->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts)); if ($this->includeCharts) { $charts = $this->spreadSheet->getSheet($i)->getChartCollection(); if (count($charts) > 0) { foreach ($charts as $chart) { $objZip->addFromString('xl/charts/chart' . ($chartCount + 1) . '.xml', $this->getWriterPart('Chart')->writeChart($chart, $this->preCalculateFormulas)); $chartCount++; } } } } $chartRef1 = $chartRef2 = 0; // Add worksheet relationships (drawings, ...) for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { // Add relationships $objZip->addFromString('xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeWorksheetRelationships($this->spreadSheet->getSheet($i), $i + 1, $this->includeCharts)); $drawings = $this->spreadSheet->getSheet($i)->getDrawingCollection(); $drawingCount = count($drawings); if ($this->includeCharts) { $chartCount = $this->spreadSheet->getSheet($i)->getChartCount(); } // Add drawing and image relationship parts if ($drawingCount > 0 || $chartCount > 0) { // Drawing relationships $objZip->addFromString('xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts)); // Drawings $objZip->addFromString('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $chartRef2, $this->includeCharts)); } // Add comment relationship parts if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) { // VML Comments $objZip->addFromString('xl/drawings/vmlDrawing' . ($i + 1) . '.vml', $this->getWriterPart('Comments')->writeVMLComments($this->spreadSheet->getSheet($i))); // Comments $objZip->addFromString('xl/comments' . ($i + 1) . '.xml', $this->getWriterPart('Comments')->writeComments($this->spreadSheet->getSheet($i))); } // Add header/footer relationship parts if (count($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) { // VML Drawings $objZip->addFromString('xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml', $this->getWriterPart('Drawing')->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i))); // VML Drawing relationships $objZip->addFromString('xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels', $this->getWriterPart('Rels')->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i))); // Media foreach ($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages() as $image) { $objZip->addFromString('xl/media/' . $image->getIndexedFilename(), file_get_contents($image->getPath())); } } } // Add media for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) { if ($this->getDrawingHashTable()->getByIndex($i) instanceof \PHPExcel\Worksheet\Drawing) { $imageContents = null; $imagePath = $this->getDrawingHashTable()->getByIndex($i)->getPath(); if (strpos($imagePath, 'zip://') !== false) { $imagePath = substr($imagePath, 6); $imagePathSplitted = explode('#', $imagePath); $imageZip = new ZipArchive(); $imageZip->open($imagePathSplitted[0]); $imageContents = $imageZip->getFromName($imagePathSplitted[1]); $imageZip->close(); unset($imageZip); } else { $imageContents = file_get_contents($imagePath); } $objZip->addFromString('xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); } elseif ($this->getDrawingHashTable()->getByIndex($i) instanceof \PHPExcel\Worksheet\MemoryDrawing) { ob_start(); call_user_func($this->getDrawingHashTable()->getByIndex($i)->getRenderingFunction(), $this->getDrawingHashTable()->getByIndex($i)->getImageResource()); $imageContents = ob_get_contents(); ob_end_clean(); $objZip->addFromString('xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); } } \PHPExcel\Calculation\Functions::setReturnDateType($saveDateReturnType); \PHPExcel\Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog($saveDebugLog); // Close file if ($objZip->close() === false) { throw new \PHPExcel\Writer\Exception("Could not close zip file {$pFilename}."); } // If a temporary file was used, copy it to the correct file stream if ($originalFilename != $pFilename) { if (copy($pFilename, $originalFilename) === false) { throw new \PHPExcel\Writer\Exception("Could not copy temporary zip file {$pFilename} to {$originalFilename}."); } @unlink($pFilename); } } else { throw new \PHPExcel\Writer\Exception("PHPExcel object unassigned."); } }
/** * Are there more Worksheet instances available? * * @return boolean */ public function valid() { return $this->position < $this->subject->getSheetCount(); }
/** * Class constructor * * @param \PHPExcel\Spreadsheet $phpExcel The Workbook * @param int &$str_total Total number of strings * @param int &$str_unique Total number of unique strings * @param array &$str_table String Table * @param array &$colors Colour Table * @param mixed $parser The formula parser created for the Workbook */ public function __construct(\PHPExcel\Spreadsheet $phpExcel, &$str_total, &$str_unique, &$str_table, &$colors, $parser) { // It needs to call its parent's constructor explicitly parent::__construct(); $this->parser = $parser; $this->biffSize = 0; $this->palette = array(); $this->countryCode = -1; $this->stringTotal =& $str_total; $this->stringUnique =& $str_unique; $this->stringTable =& $str_table; $this->colors =& $colors; $this->setPaletteXl97(); $this->phpExcel = $phpExcel; // set BIFFwriter limit for CONTINUE records // $this->_limit = 8224; $this->codepage = 0x4b0; // Add empty sheets and Build color cache $countSheets = $phpExcel->getSheetCount(); for ($i = 0; $i < $countSheets; ++$i) { $phpSheet = $phpExcel->getSheet($i); $this->parser->setExtSheet($phpSheet->getTitle(), $i); // Register worksheet name with parser $supbook_index = 0x0; $ref = pack('vvv', $supbook_index, $i, $i); $this->parser->references[] = $ref; // Register reference with parser // Sheet tab colors? if ($phpSheet->isTabColorSet()) { $this->addColor($phpSheet->getTabColor()->getRGB()); } } }
/** * Write content types to XML format * * @param \PHPExcel\Spreadsheet $pPHPExcel * @param boolean $includeCharts Flag indicating if we should include drawing details for charts * @return string XML Output * @throws \PHPExcel\Writer\Exception */ public function writeContentTypes(\PHPExcel\Spreadsheet $pPHPExcel = null, $includeCharts = false) { // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new \PHPExcel\Shared\XMLWriter(\PHPExcel\Shared\XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { $objWriter = new \PHPExcel\Shared\XMLWriter(\PHPExcel\Shared\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 ($pPHPExcel->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 $this->writeDefaultContentType($objWriter, 'bin', 'application/vnd.ms-office.vbaProject'); if ($pPHPExcel->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 = $pPHPExcel->getProperties()->getCustomProperties(); if (!empty($customPropertyList)) { $this->writeOverrideContentType($objWriter, '/docProps/custom.xml', 'application/vnd.openxmlformats-officedocument.custom-properties+xml'); } // Worksheets $sheetCount = $pPHPExcel->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 $chart = 1; for ($i = 0; $i < $sheetCount; ++$i) { $drawings = $pPHPExcel->getSheet($i)->getDrawingCollection(); $drawingCount = count($drawings); $chartCount = $includeCharts ? $pPHPExcel->getSheet($i)->getChartCount() : 0; // We need a drawing relationship for the worksheet if we have either drawings or charts if ($drawingCount > 0 || $chartCount > 0) { $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($pPHPExcel->getSheet($i)->getComments()) > 0) { $this->writeOverrideContentType($objWriter, '/xl/comments' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml'); } } // Add media content-types $aMediaContentTypes = array(); $mediaCount = $this->getParentWriter()->getDrawingHashTable()->count(); for ($i = 0; $i < $mediaCount; ++$i) { $extension = ''; $mimeType = ''; if ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof \PHPExcel\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 \PHPExcel\Worksheet\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 ($pPHPExcel->hasRibbonBinObjects()) { // Some additional objects in the ribbon ? // we need to write "Extension" but not already write for media content $tabRibbonTypes = array_diff($pPHPExcel->getRibbonBinObjects('types'), array_keys($aMediaContentTypes)); foreach ($tabRibbonTypes as $aRibbonType) { $mimeType = 'image/.' . $aRibbonType; //we wrote $mimeType like customUI Editor $this->writeDefaultContentType($objWriter, $aRibbonType, $mimeType); } } $sheetCount = $pPHPExcel->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { if (count($pPHPExcel->getSheet()->getHeaderFooter()->getImages()) > 0) { foreach ($pPHPExcel->getSheet()->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())]); } } } } $objWriter->endElement(); // Return return $objWriter->getData(); }
/** * Loads PHPExcel from file into PHPExcel instance * * @param string $pFilename * @param \PHPExcel\Spreadsheet $objPHPExcel * @return \PHPExcel\Spreadsheet * @throws Exception */ public function loadIntoExisting($pFilename, \PHPExcel\Spreadsheet $objPHPExcel) { // Open file $this->openFile($pFilename); if (!$this->isValidFormat()) { fclose($this->fileHandle); throw new Exception($pFilename . " is an Invalid Spreadsheet file."); } $fileHandle = $this->fileHandle; rewind($fileHandle); // Create new Worksheets while ($objPHPExcel->getSheetCount() <= $this->sheetIndex) { $objPHPExcel->createSheet(); } $objPHPExcel->setActiveSheetIndex($this->sheetIndex); $fromFormats = array('\\-', '\\ '); $toFormats = array('-', ' '); // Loop through file $rowData = array(); $column = $row = ''; // loop through one row (line) at a time in the file while (($rowData = fgets($fileHandle)) !== false) { // convert SYLK encoded $rowData to UTF-8 $rowData = \PHPExcel\Shared\StringHelper::SYLKtoUTF8($rowData); // explode each row at semicolons while taking into account that literal semicolon (;) // is escaped like this (;;) $rowData = explode("\t", str_replace('¤', ';', str_replace(';', "\t", str_replace(';;', '¤', rtrim($rowData))))); $dataType = array_shift($rowData); // Read shared styles if ($dataType == 'P') { $formatArray = array(); foreach ($rowData as $rowDatum) { switch ($rowDatum[0]) { case 'P': $formatArray['numberformat']['code'] = str_replace($fromFormats, $toFormats, substr($rowDatum, 1)); break; case 'E': case 'F': $formatArray['font']['name'] = substr($rowDatum, 1); break; case 'L': $formatArray['font']['size'] = substr($rowDatum, 1); break; case 'S': $styleSettings = substr($rowDatum, 1); for ($i = 0; $i < strlen($styleSettings); ++$i) { switch ($styleSettings[$i]) { case 'I': $formatArray['font']['italic'] = true; break; case 'D': $formatArray['font']['bold'] = true; break; case 'T': $formatArray['borders']['top']['style'] = \PHPExcel\Style\Border::BORDER_THIN; break; case 'B': $formatArray['borders']['bottom']['style'] = \PHPExcel\Style\Border::BORDER_THIN; break; case 'L': $formatArray['borders']['left']['style'] = \PHPExcel\Style\Border::BORDER_THIN; break; case 'R': $formatArray['borders']['right']['style'] = \PHPExcel\Style\Border::BORDER_THIN; break; } } break; } } $this->formats['P' . $this->format++] = $formatArray; // Read cell value data } elseif ($dataType == 'C') { $hasCalculatedValue = false; $cellData = $cellDataFormula = ''; foreach ($rowData as $rowDatum) { switch ($rowDatum[0]) { case 'C': case 'X': $column = substr($rowDatum, 1); break; case 'R': case 'Y': $row = substr($rowDatum, 1); break; case 'K': $cellData = substr($rowDatum, 1); break; case 'E': $cellDataFormula = '=' . substr($rowDatum, 1); // Convert R1C1 style references to A1 style references (but only when not quoted) $temp = explode('"', $cellDataFormula); $key = false; foreach ($temp as &$value) { // Only count/replace in alternate array entries if ($key = !$key) { preg_match_all('/(R(\\[?-?\\d*\\]?))(C(\\[?-?\\d*\\]?))/', $value, $cellReferences, PREG_SET_ORDER + PREG_OFFSET_CAPTURE); // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way // through the formula from left to right. Reversing means that we work right to left.through // the formula $cellReferences = array_reverse($cellReferences); // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent, // then modify the formula to use that new reference foreach ($cellReferences as $cellReference) { $rowReference = $cellReference[2][0]; // Empty R reference is the current row if ($rowReference == '') { $rowReference = $row; } // Bracketed R references are relative to the current row if ($rowReference[0] == '[') { $rowReference = $row + trim($rowReference, '[]'); } $columnReference = $cellReference[4][0]; // Empty C reference is the current column if ($columnReference == '') { $columnReference = $column; } // Bracketed C references are relative to the current column if ($columnReference[0] == '[') { $columnReference = $column + trim($columnReference, '[]'); } $A1CellReference = \PHPExcel\Cell::stringFromColumnIndex($columnReference - 1) . $rowReference; $value = substr_replace($value, $A1CellReference, $cellReference[0][1], strlen($cellReference[0][0])); } } } unset($value); // Then rebuild the formula string $cellDataFormula = implode('"', $temp); $hasCalculatedValue = true; break; } } $columnLetter = \PHPExcel\Cell::stringFromColumnIndex($column - 1); $cellData = \PHPExcel\Calculation::unwrapResult($cellData); // Set cell value $objPHPExcel->getActiveSheet()->getCell($columnLetter . $row)->setValue($hasCalculatedValue ? $cellDataFormula : $cellData); if ($hasCalculatedValue) { $cellData = \PHPExcel\Calculation::unwrapResult($cellData); $objPHPExcel->getActiveSheet()->getCell($columnLetter . $row)->setCalculatedValue($cellData); } // Read cell formatting } elseif ($dataType == 'F') { $formatStyle = $columnWidth = $styleSettings = ''; $styleData = array(); foreach ($rowData as $rowDatum) { switch ($rowDatum[0]) { case 'C': case 'X': $column = substr($rowDatum, 1); break; case 'R': case 'Y': $row = substr($rowDatum, 1); break; case 'P': $formatStyle = $rowDatum; break; case 'W': list($startCol, $endCol, $columnWidth) = explode(' ', substr($rowDatum, 1)); break; case 'S': $styleSettings = substr($rowDatum, 1); for ($i = 0; $i < strlen($styleSettings); ++$i) { switch ($styleSettings[$i]) { case 'I': $styleData['font']['italic'] = true; break; case 'D': $styleData['font']['bold'] = true; break; case 'T': $styleData['borders']['top']['style'] = \PHPExcel\Style\Border::BORDER_THIN; break; case 'B': $styleData['borders']['bottom']['style'] = \PHPExcel\Style\Border::BORDER_THIN; break; case 'L': $styleData['borders']['left']['style'] = \PHPExcel\Style\Border::BORDER_THIN; break; case 'R': $styleData['borders']['right']['style'] = \PHPExcel\Style\Border::BORDER_THIN; break; } } break; } } if ($formatStyle > '' && $column > '' && $row > '') { $columnLetter = \PHPExcel\Cell::stringFromColumnIndex($column - 1); if (isset($this->formats[$formatStyle])) { $objPHPExcel->getActiveSheet()->getStyle($columnLetter . $row)->applyFromArray($this->formats[$formatStyle]); } } if (!empty($styleData) && $column > '' && $row > '') { $columnLetter = \PHPExcel\Cell::stringFromColumnIndex($column - 1); $objPHPExcel->getActiveSheet()->getStyle($columnLetter . $row)->applyFromArray($styleData); } if ($columnWidth > '') { if ($startCol == $endCol) { $startCol = \PHPExcel\Cell::stringFromColumnIndex($startCol - 1); $objPHPExcel->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth); } else { $startCol = \PHPExcel\Cell::stringFromColumnIndex($startCol - 1); $endCol = \PHPExcel\Cell::stringFromColumnIndex($endCol - 1); $objPHPExcel->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth); do { $objPHPExcel->getActiveSheet()->getColumnDimension(++$startCol)->setWidth($columnWidth); } while ($startCol != $endCol); } } } else { foreach ($rowData as $rowDatum) { switch ($rowDatum[0]) { case 'C': case 'X': $column = substr($rowDatum, 1); break; case 'R': case 'Y': $row = substr($rowDatum, 1); break; } } } } // Close file fclose($fileHandle); // Return return $objPHPExcel; }
/** * Calculate information about HTML colspan and rowspan which is not always the same as Excel's */ private function calculateSpans() { // Identify all cells that should be omitted in HTML due to cell merge. // In HTML only the upper-left cell should be written and it should have // appropriate rowspan / colspan attribute $sheetIndexes = $this->sheetIndex !== null ? array($this->sheetIndex) : range(0, $this->phpExcel->getSheetCount() - 1); foreach ($sheetIndexes as $sheetIndex) { $sheet = $this->phpExcel->getSheet($sheetIndex); $candidateSpannedRow = array(); // loop through all Excel merged cells foreach ($sheet->getMergeCells() as $cells) { list($cells, ) = \PHPExcel\Cell::splitRange($cells); $first = $cells[0]; $last = $cells[1]; list($fc, $fr) = \PHPExcel\Cell::coordinateFromString($first); $fc = \PHPExcel\Cell::columnIndexFromString($fc) - 1; list($lc, $lr) = \PHPExcel\Cell::coordinateFromString($last); $lc = \PHPExcel\Cell::columnIndexFromString($lc) - 1; // loop through the individual cells in the individual merge $r = $fr - 1; while ($r++ < $lr) { // also, flag this row as a HTML row that is candidate to be omitted $candidateSpannedRow[$r] = $r; $c = $fc - 1; while ($c++ < $lc) { if (!($c == $fc && $r == $fr)) { // not the upper-left cell (should not be written in HTML) $this->isSpannedCell[$sheetIndex][$r][$c] = array('baseCell' => array($fr, $fc)); } else { // upper-left is the base cell that should hold the colspan/rowspan attribute $this->isBaseCell[$sheetIndex][$r][$c] = array('xlrowspan' => $lr - $fr + 1, 'rowspan' => $lr - $fr + 1, 'xlcolspan' => $lc - $fc + 1, 'colspan' => $lc - $fc + 1); } } } } // Identify which rows should be omitted in HTML. These are the rows where all the cells // participate in a merge and the where base cells are somewhere above. $countColumns = \PHPExcel\Cell::columnIndexFromString($sheet->getHighestColumn()); foreach ($candidateSpannedRow as $rowIndex) { if (isset($this->isSpannedCell[$sheetIndex][$rowIndex])) { if (count($this->isSpannedCell[$sheetIndex][$rowIndex]) == $countColumns) { $this->isSpannedRow[$sheetIndex][$rowIndex] = $rowIndex; } } } // For each of the omitted rows we found above, the affected rowspans should be subtracted by 1 if (isset($this->isSpannedRow[$sheetIndex])) { foreach ($this->isSpannedRow[$sheetIndex] as $rowIndex) { $adjustedBaseCells = array(); $c = -1; $e = $countColumns - 1; while ($c++ < $e) { $baseCell = $this->isSpannedCell[$sheetIndex][$rowIndex][$c]['baseCell']; if (!in_array($baseCell, $adjustedBaseCells)) { // subtract rowspan by 1 --$this->isBaseCell[$sheetIndex][$baseCell[0]][$baseCell[1]]['rowspan']; $adjustedBaseCells[] = $baseCell; } } } } // TODO: Same for columns } // We have calculated the spans $this->spansAreCalculated = true; }