114 $this->parser =
new Xls\Parser($spreadsheet);
122 public function save($pFilename): void
125 $this->spreadsheet->garbageCollect();
136 $this->writerWorkbook =
new Xls\Workbook($this->spreadsheet, $this->strTotal, $this->strUnique, $this->strTable, $this->colors, $this->parser);
139 $countSheets = $this->spreadsheet->getSheetCount();
140 for (
$i = 0;
$i < $countSheets; ++
$i) {
141 $this->writerWorksheets[
$i] =
new Xls\Worksheet($this->strTotal, $this->strUnique, $this->strTable, $this->colors, $this->parser, $this->preCalculateFormulas, $this->spreadsheet->getSheet(
$i));
150 $cellXfCollection = $this->spreadsheet->getCellXfCollection();
151 for (
$i = 0;
$i < 15; ++
$i) {
152 $this->writerWorkbook->addXfWriter($cellXfCollection[0],
true);
156 foreach ($this->spreadsheet->getCellXfCollection() as
$style) {
157 $this->writerWorkbook->addXfWriter(
$style,
false);
161 for (
$i = 0;
$i < $countSheets; ++
$i) {
162 foreach ($this->writerWorksheets[
$i]->phpSheet->getCoordinates() as $coordinate) {
163 $cell = $this->writerWorksheets[
$i]->phpSheet->getCell($coordinate);
164 $cVal = $cell->getValue();
166 $elements = $cVal->getRichTextElements();
167 foreach ($elements as $element) {
168 if ($element instanceof
Run) {
169 $font = $element->getFont();
170 $this->writerWorksheets[
$i]->fontHashIndex[$font->getHashCode()] = $this->writerWorkbook->addFont($font);
178 $workbookStreamName =
'Workbook';
183 $worksheetSizes = [];
184 for (
$i = 0;
$i < $countSheets; ++
$i) {
185 $this->writerWorksheets[
$i]->close();
186 $worksheetSizes[] = $this->writerWorksheets[
$i]->_datasize;
190 $OLE->append($this->writerWorkbook->writeWorkbook($worksheetSizes));
193 for (
$i = 0;
$i < $countSheets; ++
$i) {
194 $OLE->append($this->writerWorksheets[
$i]->getData());
199 if (isset($this->documentSummaryInformation) && !empty($this->documentSummaryInformation)) {
200 $OLE_DocumentSummaryInformation =
new File(
OLE::ascToUcs(chr(5) .
'DocumentSummaryInformation'));
201 $OLE_DocumentSummaryInformation->append($this->documentSummaryInformation);
206 if (isset($this->summaryInformation) && !empty($this->summaryInformation)) {
207 $OLE_SummaryInformation =
new File(
OLE::ascToUcs(chr(5) .
'SummaryInformation'));
208 $OLE_SummaryInformation->append($this->summaryInformation);
212 $arrRootData = [$OLE];
214 if (isset($OLE_SummaryInformation)) {
215 $arrRootData[] = $OLE_SummaryInformation;
218 if (isset($OLE_DocumentSummaryInformation)) {
219 $arrRootData[] = $OLE_DocumentSummaryInformation;
222 $time = $this->spreadsheet->getProperties()->getModified();
226 $root->save($this->fileHandle);
240 $lastReducedSpId = 0;
243 foreach ($this->spreadsheet->getAllsheets() as $sheet) {
245 $sheetIndex = $sheet->getParent()->getIndex($sheet);
250 $filterRange = $sheet->getAutoFilter()->getRange();
251 if (count($sheet->getDrawingCollection()) == 0 && empty($filterRange)) {
262 $dgId = $sheet->getParent()->getIndex($sheet) + 1;
263 $dgContainer->setDgId($dgId);
264 $escher->setDgContainer($dgContainer);
268 $dgContainer->setSpgrContainer($spgrContainer);
272 $spContainer->setSpgr(
true);
273 $spContainer->setSpType(0);
274 $spContainer->setSpId(($sheet->getParent()->getIndex($sheet) + 1) << 10);
275 $spgrContainer->addChild($spContainer);
279 $countShapes[$sheetIndex] = 0;
281 foreach ($sheet->getDrawingCollection() as $drawing) {
284 ++$countShapes[$sheetIndex];
290 $spContainer->setSpType(0x004B);
292 $spContainer->setSpFlag(0x02);
295 $reducedSpId = $countShapes[$sheetIndex];
296 $spId = $reducedSpId | ($sheet->getParent()->getIndex($sheet) + 1) << 10;
297 $spContainer->setSpId($spId);
300 $lastReducedSpId = $reducedSpId;
306 $spContainer->setOPT(0x4104, $blipIndex);
309 $coordinates = $drawing->getCoordinates();
310 $offsetX = $drawing->getOffsetX();
311 $offsetY = $drawing->getOffsetY();
312 $width = $drawing->getWidth();
313 $height = $drawing->getHeight();
317 $spContainer->setStartCoordinates($twoAnchor[
'startCoordinates']);
318 $spContainer->setStartOffsetX($twoAnchor[
'startOffsetX']);
319 $spContainer->setStartOffsetY($twoAnchor[
'startOffsetY']);
320 $spContainer->setEndCoordinates($twoAnchor[
'endCoordinates']);
321 $spContainer->setEndOffsetX($twoAnchor[
'endOffsetX']);
322 $spContainer->setEndOffsetY($twoAnchor[
'endOffsetY']);
324 $spgrContainer->addChild($spContainer);
328 if (!empty($filterRange)) {
330 $iNumColStart = $rangeBounds[0][0];
331 $iNumColEnd = $rangeBounds[1][0];
333 $iInc = $iNumColStart;
334 while ($iInc <= $iNumColEnd) {
335 ++$countShapes[$sheetIndex];
341 $oDrawing->setCoordinates($cDrawing);
342 $oDrawing->setWorksheet($sheet);
347 $spContainer->setSpType(0x00C9);
349 $spContainer->setSpFlag(0x01);
352 $reducedSpId = $countShapes[$sheetIndex];
353 $spId = $reducedSpId | ($sheet->getParent()->getIndex($sheet) + 1) << 10;
354 $spContainer->setSpId($spId);
357 $lastReducedSpId = $reducedSpId;
362 $spContainer->setOPT(0x007F, 0x01040104);
363 $spContainer->setOPT(0x00BF, 0x00080008);
364 $spContainer->setOPT(0x01BF, 0x00010000);
365 $spContainer->setOPT(0x01FF, 0x00080000);
366 $spContainer->setOPT(0x03BF, 0x000A0000);
370 $endCoordinates .= $rangeBounds[0][1] + 1;
372 $spContainer->setStartCoordinates($cDrawing);
373 $spContainer->setStartOffsetX(0);
374 $spContainer->setStartOffsetY(0);
375 $spContainer->setEndCoordinates($endCoordinates);
376 $spContainer->setEndOffsetX(0);
377 $spContainer->setEndOffsetY(0);
379 $spgrContainer->addChild($spContainer);
385 $this->IDCLs[$dgId] = $lastReducedSpId;
388 $dgContainer->setLastSpId($lastSpId);
391 $this->writerWorksheets[$sheetIndex]->setEscher($escher);
397 switch ($renderingFunctionx) {
400 $renderingFunction =
'imagejpeg';
405 $renderingFunction =
'imagepng';
412 $blipData = ob_get_contents();
416 $blip->setData($blipData);
419 $BSE->setBlipType($blipType);
420 $BSE->setBlip($blip);
422 $bstoreContainer->
addBSE($BSE);
431 [$imagesx, $imagesy, $imageFormat] = getimagesize(
$filename);
433 switch ($imageFormat) {
438 $blipData = ob_get_contents();
444 $blipData = file_get_contents(
$filename);
449 $blipData = file_get_contents(
$filename);
455 imagepng(SharedDrawing::imagecreatefrombmp(
$filename));
456 $blipData = ob_get_contents();
463 $blip->setData($blipData);
466 $BSE->setBlipType($blipType);
467 $BSE->setBlip($blip);
469 $bstoreContainer->
addBSE($BSE);
475 if ($drawing instanceof
Drawing) {
486 foreach ($this->spreadsheet->getAllSheets() as $sheet) {
487 if (count($sheet->getDrawingCollection()) > 0) {
512 $escher->setDggContainer($dggContainer);
515 $dggContainer->setIDCLs($this->IDCLs);
519 $totalCountShapes = 0;
522 foreach ($this->spreadsheet->getAllsheets() as $sheet) {
523 $sheetCountShapes = 0;
526 foreach ($sheet->getDrawingCollection() as $drawing) {
531 $spId = $sheetCountShapes | ($this->spreadsheet->getIndex($sheet) + 1) << 10;
532 $spIdMax = max($spId, $spIdMax);
534 $countDrawings += $addCount;
537 $dggContainer->setSpIdMax($spIdMax + 1);
538 $dggContainer->setCDgSaved($countDrawings);
539 $dggContainer->setCSpSaved($totalCountShapes + $countDrawings);
543 $dggContainer->setBstoreContainer($bstoreContainer);
546 foreach ($this->spreadsheet->getAllsheets() as $sheet) {
547 foreach ($sheet->getDrawingCollection() as $drawing) {
553 $this->writerWorkbook->setEscher($escher);
564 $data = pack(
'v', 0xFFFE);
566 $data .= pack(
'v', 0x0000);
568 $data .= pack(
'v', 0x0106);
570 $data .= pack(
'v', 0x0002);
572 $data .= pack(
'VVVV', 0x00, 0x00, 0x00, 0x00);
574 $data .= pack(
'V', 0x0001);
577 $data .= pack(
'vvvvvvvv', 0xD502, 0xD5CD, 0x2E9C, 0x101B, 0x9793, 0x0008, 0x2C2B, 0xAEF9);
579 $data .= pack(
'V', 0x30);
583 $dataSection_NumProps = 0;
584 $dataSection_Summary =
'';
585 $dataSection_Content =
'';
589 'summary' => [
'pack' =>
'V',
'data' => 0x01],
590 'offset' => [
'pack' =>
'V'],
591 'type' => [
'pack' =>
'V',
'data' => 0x02],
592 'data' => [
'data' => 1252],
594 ++$dataSection_NumProps;
597 $dataProp = $this->spreadsheet->getProperties()->getCategory();
600 'summary' => [
'pack' =>
'V',
'data' => 0x02],
601 'offset' => [
'pack' =>
'V'],
602 'type' => [
'pack' =>
'V',
'data' => 0x1E],
603 'data' => [
'data' => $dataProp,
'length' => strlen($dataProp)],
605 ++$dataSection_NumProps;
609 'summary' => [
'pack' =>
'V',
'data' => 0x17],
610 'offset' => [
'pack' =>
'V'],
611 'type' => [
'pack' =>
'V',
'data' => 0x03],
612 'data' => [
'pack' =>
'V',
'data' => 0x000C0000],
614 ++$dataSection_NumProps;
617 'summary' => [
'pack' =>
'V',
'data' => 0x0B],
618 'offset' => [
'pack' =>
'V'],
619 'type' => [
'pack' =>
'V',
'data' => 0x0B],
620 'data' => [
'data' =>
false],
622 ++$dataSection_NumProps;
625 'summary' => [
'pack' =>
'V',
'data' => 0x10],
626 'offset' => [
'pack' =>
'V'],
627 'type' => [
'pack' =>
'V',
'data' => 0x0B],
628 'data' => [
'data' =>
false],
630 ++$dataSection_NumProps;
633 'summary' => [
'pack' =>
'V',
'data' => 0x13],
634 'offset' => [
'pack' =>
'V'],
635 'type' => [
'pack' =>
'V',
'data' => 0x0B],
636 'data' => [
'data' =>
false],
638 ++$dataSection_NumProps;
641 'summary' => [
'pack' =>
'V',
'data' => 0x16],
642 'offset' => [
'pack' =>
'V'],
643 'type' => [
'pack' =>
'V',
'data' => 0x0B],
644 'data' => [
'data' =>
false],
646 ++$dataSection_NumProps;
652 $dataProp = pack(
'v', 0x0001);
653 $dataProp .= pack(
'v', 0x0000);
656 $dataProp .= pack(
'v', 0x000A);
657 $dataProp .= pack(
'v', 0x0000);
659 $dataProp .=
'Worksheet' . chr(0);
662 'summary' => [
'pack' =>
'V',
'data' => 0x0D],
663 'offset' => [
'pack' =>
'V'],
664 'type' => [
'pack' =>
'V',
'data' => 0x101E],
665 'data' => [
'data' => $dataProp,
'length' => strlen($dataProp)],
667 ++$dataSection_NumProps;
672 $dataProp = pack(
'v', 0x0002);
673 $dataProp .= pack(
'v', 0x0000);
677 $dataProp .= pack(
'v', 0x001E);
679 $dataProp .= pack(
'v', 0x0000);
682 $dataProp .= pack(
'v', 0x0013);
683 $dataProp .= pack(
'v', 0x0000);
685 $dataProp .=
'Feuilles de calcul';
688 $dataProp .= pack(
'v', 0x0300);
690 $dataProp .= pack(
'v', 0x0000);
692 $dataProp .= pack(
'v', 0x0100);
693 $dataProp .= pack(
'v', 0x0000);
694 $dataProp .= pack(
'v', 0x0000);
695 $dataProp .= pack(
'v', 0x0000);
698 'summary' => [
'pack' =>
'V',
'data' => 0x0C],
699 'offset' => [
'pack' =>
'V'],
700 'type' => [
'pack' =>
'V',
'data' => 0x100C],
701 'data' => [
'data' => $dataProp,
'length' => strlen($dataProp)],
703 ++$dataSection_NumProps;
708 $dataSection_Content_Offset = 8 + $dataSection_NumProps * 8;
709 foreach ($dataSection as $dataProp) {
711 $dataSection_Summary .= pack($dataProp[
'summary'][
'pack'], $dataProp[
'summary'][
'data']);
713 $dataSection_Summary .= pack($dataProp[
'offset'][
'pack'], $dataSection_Content_Offset);
715 $dataSection_Content .= pack($dataProp[
'type'][
'pack'], $dataProp[
'type'][
'data']);
717 if ($dataProp[
'type'][
'data'] == 0x02) {
718 $dataSection_Content .= pack(
'V', $dataProp[
'data'][
'data']);
720 $dataSection_Content_Offset += 4 + 4;
721 } elseif ($dataProp[
'type'][
'data'] == 0x03) {
722 $dataSection_Content .= pack(
'V', $dataProp[
'data'][
'data']);
724 $dataSection_Content_Offset += 4 + 4;
725 } elseif ($dataProp[
'type'][
'data'] == 0x0B) {
726 $dataSection_Content .= pack(
'V', (
int) $dataProp[
'data'][
'data']);
727 $dataSection_Content_Offset += 4 + 4;
728 } elseif ($dataProp[
'type'][
'data'] == 0x1E) {
730 $dataProp[
'data'][
'data'] .= chr(0);
732 ++$dataProp[
'data'][
'length'];
734 $dataProp[
'data'][
'length'] = $dataProp[
'data'][
'length'] + ((4 - $dataProp[
'data'][
'length'] % 4) == 4 ? 0 : (4 - $dataProp[
'data'][
'length'] % 4));
735 $dataProp[
'data'][
'data'] = str_pad($dataProp[
'data'][
'data'], $dataProp[
'data'][
'length'], chr(0), STR_PAD_RIGHT);
737 $dataSection_Content .= pack(
'V', $dataProp[
'data'][
'length']);
738 $dataSection_Content .= $dataProp[
'data'][
'data'];
740 $dataSection_Content_Offset += 4 + 4 + strlen($dataProp[
'data'][
'data']);
747 $dataSection_Content .= $dataProp[
'data'][
'data'];
750 $dataSection_Content_Offset += 4 + $dataProp[
'data'][
'length'];
758 $data .= pack(
'V', $dataSection_Content_Offset);
760 $data .= pack(
'V', $dataSection_NumProps);
762 $data .= $dataSection_Summary;
764 $data .= $dataSection_Content;
772 private function writeSummaryPropOle($dataProp,
int &$dataSection_NumProps, array &$dataSection,
int $sumdata,
int $typdata): void
776 'summary' => [
'pack' =>
'V',
'data' => $sumdata],
777 'offset' => [
'pack' =>
'V'],
778 'type' => [
'pack' =>
'V',
'data' => $typdata],
781 ++$dataSection_NumProps;
785 private function writeSummaryProp(
string $dataProp,
int &$dataSection_NumProps, array &$dataSection,
int $sumdata,
int $typdata): void
789 'summary' => [
'pack' =>
'V',
'data' => $sumdata],
790 'offset' => [
'pack' =>
'V'],
791 'type' => [
'pack' =>
'V',
'data' => $typdata],
792 'data' => [
'data' => $dataProp,
'length' => strlen($dataProp)],
794 ++$dataSection_NumProps;
806 $data = pack(
'v', 0xFFFE);
808 $data .= pack(
'v', 0x0000);
810 $data .= pack(
'v', 0x0106);
812 $data .= pack(
'v', 0x0002);
814 $data .= pack(
'VVVV', 0x00, 0x00, 0x00, 0x00);
816 $data .= pack(
'V', 0x0001);
819 $data .= pack(
'vvvvvvvv', 0x85E0, 0xF29F, 0x4FF9, 0x1068, 0x91AB, 0x0008, 0x272B, 0xD9B3);
821 $data .= pack(
'V', 0x30);
825 $dataSection_NumProps = 0;
826 $dataSection_Summary =
'';
827 $dataSection_Content =
'';
831 'summary' => [
'pack' =>
'V',
'data' => 0x01],
832 'offset' => [
'pack' =>
'V'],
833 'type' => [
'pack' =>
'V',
'data' => 0x02],
834 'data' => [
'data' => 1252],
836 ++$dataSection_NumProps;
838 $props = $this->spreadsheet->getProperties();
839 $this->
writeSummaryProp($props->getTitle(), $dataSection_NumProps, $dataSection, 0x02, 0x1e);
840 $this->
writeSummaryProp($props->getSubject(), $dataSection_NumProps, $dataSection, 0x03, 0x1e);
841 $this->
writeSummaryProp($props->getCreator(), $dataSection_NumProps, $dataSection, 0x04, 0x1e);
842 $this->
writeSummaryProp($props->getKeywords(), $dataSection_NumProps, $dataSection, 0x05, 0x1e);
843 $this->
writeSummaryProp($props->getDescription(), $dataSection_NumProps, $dataSection, 0x06, 0x1e);
844 $this->
writeSummaryProp($props->getLastModifiedBy(), $dataSection_NumProps, $dataSection, 0x08, 0x1e);
845 $this->
writeSummaryPropOle($props->getCreated(), $dataSection_NumProps, $dataSection, 0x0c, 0x40);
846 $this->
writeSummaryPropOle($props->getModified(), $dataSection_NumProps, $dataSection, 0x0d, 0x40);
850 'summary' => [
'pack' =>
'V',
'data' => 0x13],
851 'offset' => [
'pack' =>
'V'],
852 'type' => [
'pack' =>
'V',
'data' => 0x03],
853 'data' => [
'data' => 0x00],
855 ++$dataSection_NumProps;
860 $dataSection_Content_Offset = 8 + $dataSection_NumProps * 8;
861 foreach ($dataSection as $dataProp) {
863 $dataSection_Summary .= pack($dataProp[
'summary'][
'pack'], $dataProp[
'summary'][
'data']);
865 $dataSection_Summary .= pack($dataProp[
'offset'][
'pack'], $dataSection_Content_Offset);
867 $dataSection_Content .= pack($dataProp[
'type'][
'pack'], $dataProp[
'type'][
'data']);
869 if ($dataProp[
'type'][
'data'] == 0x02) {
870 $dataSection_Content .= pack(
'V', $dataProp[
'data'][
'data']);
872 $dataSection_Content_Offset += 4 + 4;
873 } elseif ($dataProp[
'type'][
'data'] == 0x03) {
874 $dataSection_Content .= pack(
'V', $dataProp[
'data'][
'data']);
876 $dataSection_Content_Offset += 4 + 4;
877 } elseif ($dataProp[
'type'][
'data'] == 0x1E) {
879 $dataProp[
'data'][
'data'] .= chr(0);
880 ++$dataProp[
'data'][
'length'];
882 $dataProp[
'data'][
'length'] = $dataProp[
'data'][
'length'] + ((4 - $dataProp[
'data'][
'length'] % 4) == 4 ? 0 : (4 - $dataProp[
'data'][
'length'] % 4));
883 $dataProp[
'data'][
'data'] = str_pad($dataProp[
'data'][
'data'], $dataProp[
'data'][
'length'], chr(0), STR_PAD_RIGHT);
885 $dataSection_Content .= pack(
'V', $dataProp[
'data'][
'length']);
886 $dataSection_Content .= $dataProp[
'data'][
'data'];
888 $dataSection_Content_Offset += 4 + 4 + strlen($dataProp[
'data'][
'data']);
889 } elseif ($dataProp[
'type'][
'data'] == 0x40) {
890 $dataSection_Content .= $dataProp[
'data'][
'data'];
892 $dataSection_Content_Offset += 4 + 8;
901 $data .= pack(
'V', $dataSection_Content_Offset);
903 $data .= pack(
'V', $dataSection_NumProps);
905 $data .= $dataSection_Summary;
907 $data .= $dataSection_Content;
writeSummaryProp(string $dataProp, int &$dataSection_NumProps, array &$dataSection, int $sumdata, int $typdata)
__construct(Spreadsheet $spreadsheet)
Create a new Xls Writer.
save($pFilename)
Save Spreadsheet to file.
static getReturnDateType()
Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object).
static ascToUcs($ascii)
Utility function to transform ASCII text to Unicode.
getImageResource()
Get image resource.
writeDocumentSummaryInformation()
Build the OLE Part for DocumentSummary Information.
static setReturnDateType($returnDateType)
Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric o...
static oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height)
Convert 1-cell anchor coordinates to 2-cell anchor coordinates This function is ported from PEAR Spre...
writeSummaryInformation()
Build the OLE Part for Summary Information.
processBaseDrawing(BstoreContainer &$bstoreContainer, BaseDrawing $drawing)
static localDateToOLE($date)
Utility function Returns a string for the OLE container with the date given.
writeSummaryPropOle($dataProp, int &$dataSection_NumProps, array &$dataSection, int $sumdata, int $typdata)
static getInstance(?Spreadsheet $spreadsheet=null)
Get an instance of this class.
$documentSummaryInformation
addBSE($BSE)
Add a BLIP Store Entry.
static rangeBoundaries($pRange)
Calculate range boundaries.
buildWorkbookEscher()
Build the Escher object corresponding to the MSODRAWINGGROUP record.
processDrawing(BstoreContainer &$bstoreContainer, Drawing $drawing)
processMemoryDrawing(BstoreContainer &$bstoreContainer, MemoryDrawing $drawing, string $renderingFunctionx)
static stringFromColumnIndex($columnIndex)
String from column index.
Class for creating Root PPS's for OLE containers.
openFileHandle($filename)
Open file handle.
buildWorksheetEschers()
Build the Worksheet Escher objects.
maybeCloseFileHandle()
Close file handle only if we opened it ourselves.