source: sourcecode/application/libraries/PHPExcel/Writer/Excel5.php @ 1

Last change on this file since 1 was 1, checked in by dungnv, 11 years ago
File size: 33.0 KB
Line 
1<?php
2/**
3 * PHPExcel
4 *
5 * Copyright (c) 2006 - 2014 PHPExcel
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 *
21 * @category   PHPExcel
22 * @package    PHPExcel_Writer_Excel5
23 * @copyright  Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24 * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt   LGPL
25 * @version     1.8.0, 2014-03-02
26 */
27
28
29/**
30 * PHPExcel_Writer_Excel5
31 *
32 * @category   PHPExcel
33 * @package    PHPExcel_Writer_Excel5
34 * @copyright  Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35 */
36class PHPExcel_Writer_Excel5 extends PHPExcel_Writer_Abstract implements PHPExcel_Writer_IWriter
37{
38        /**
39         * PHPExcel object
40         *
41         * @var PHPExcel
42         */
43        private $_phpExcel;
44
45        /**
46         * Total number of shared strings in workbook
47         *
48         * @var int
49         */
50        private $_str_total             = 0;
51
52        /**
53         * Number of unique shared strings in workbook
54         *
55         * @var int
56         */
57        private $_str_unique    = 0;
58
59        /**
60         * Array of unique shared strings in workbook
61         *
62         * @var array
63         */
64        private $_str_table             = array();
65
66        /**
67         * Color cache. Mapping between RGB value and color index.
68         *
69         * @var array
70         */
71        private $_colors;
72
73        /**
74         * Formula parser
75         *
76         * @var PHPExcel_Writer_Excel5_Parser
77         */
78        private $_parser;
79
80        /**
81         * Identifier clusters for drawings. Used in MSODRAWINGGROUP record.
82         *
83         * @var array
84         */
85        private $_IDCLs;
86
87        /**
88         * Basic OLE object summary information
89         *
90         * @var array
91         */
92        private $_summaryInformation;
93
94        /**
95         * Extended OLE object document summary information
96         *
97         * @var array
98         */
99        private $_documentSummaryInformation;
100
101        /**
102         * Create a new PHPExcel_Writer_Excel5
103         *
104         * @param       PHPExcel        $phpExcel       PHPExcel object
105         */
106        public function __construct(PHPExcel $phpExcel) {
107                $this->_phpExcel        = $phpExcel;
108
109                $this->_parser          = new PHPExcel_Writer_Excel5_Parser();
110        }
111
112        /**
113         * Save PHPExcel to file
114         *
115         * @param       string          $pFilename
116         * @throws      PHPExcel_Writer_Exception
117         */
118        public function save($pFilename = null) {
119
120                // garbage collect
121                $this->_phpExcel->garbageCollect();
122
123                $saveDebugLog = PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->getWriteDebugLog();
124                PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->setWriteDebugLog(FALSE);
125                $saveDateReturnType = PHPExcel_Calculation_Functions::getReturnDateType();
126                PHPExcel_Calculation_Functions::setReturnDateType(PHPExcel_Calculation_Functions::RETURNDATE_EXCEL);
127
128                // initialize colors array
129                $this->_colors          = array();
130
131                // Initialise workbook writer
132                $this->_writerWorkbook = new PHPExcel_Writer_Excel5_Workbook($this->_phpExcel,
133                                                                                                                                         $this->_str_total, $this->_str_unique, $this->_str_table,
134                                                                                                                                         $this->_colors, $this->_parser);
135
136                // Initialise worksheet writers
137                $countSheets = $this->_phpExcel->getSheetCount();
138                for ($i = 0; $i < $countSheets; ++$i) {
139                        $this->_writerWorksheets[$i] = new PHPExcel_Writer_Excel5_Worksheet($this->_str_total, $this->_str_unique,
140                                                                                                                                                           $this->_str_table, $this->_colors,
141                                                                                                                                                           $this->_parser,
142                                                                                                                                                           $this->_preCalculateFormulas,
143                                                                                                                                                           $this->_phpExcel->getSheet($i));
144                }
145
146                // build Escher objects. Escher objects for workbooks needs to be build before Escher object for workbook.
147                $this->_buildWorksheetEschers();
148                $this->_buildWorkbookEscher();
149
150                // add 15 identical cell style Xfs
151                // for now, we use the first cellXf instead of cellStyleXf
152                $cellXfCollection = $this->_phpExcel->getCellXfCollection();
153                for ($i = 0; $i < 15; ++$i) {
154                        $this->_writerWorkbook->addXfWriter($cellXfCollection[0], true);
155                }
156
157                // add all the cell Xfs
158                foreach ($this->_phpExcel->getCellXfCollection() as $style) {
159                        $this->_writerWorkbook->addXfWriter($style, false);
160                }
161
162                // add fonts from rich text eleemnts
163                for ($i = 0; $i < $countSheets; ++$i) {
164                        foreach ($this->_writerWorksheets[$i]->_phpSheet->getCellCollection() as $cellID) {
165                                $cell = $this->_writerWorksheets[$i]->_phpSheet->getCell($cellID);
166                                $cVal = $cell->getValue();
167                                if ($cVal instanceof PHPExcel_RichText) {
168                                        $elements = $cVal->getRichTextElements();
169                                        foreach ($elements as $element) {
170                                                if ($element instanceof PHPExcel_RichText_Run) {
171                                                        $font = $element->getFont();
172                                                        $this->_writerWorksheets[$i]->_fntHashIndex[$font->getHashCode()] = $this->_writerWorkbook->_addFont($font);
173                                                }
174                                        }
175                                }
176                        }
177                }
178
179                // initialize OLE file
180                $workbookStreamName = 'Workbook';
181                $OLE = new PHPExcel_Shared_OLE_PPS_File(PHPExcel_Shared_OLE::Asc2Ucs($workbookStreamName));
182
183                // Write the worksheet streams before the global workbook stream,
184                // because the byte sizes of these are needed in the global workbook stream
185                $worksheetSizes = array();
186                for ($i = 0; $i < $countSheets; ++$i) {
187                        $this->_writerWorksheets[$i]->close();
188                        $worksheetSizes[] = $this->_writerWorksheets[$i]->_datasize;
189                }
190
191                // add binary data for global workbook stream
192                $OLE->append($this->_writerWorkbook->writeWorkbook($worksheetSizes));
193
194                // add binary data for sheet streams
195                for ($i = 0; $i < $countSheets; ++$i) {
196                        $OLE->append($this->_writerWorksheets[$i]->getData());
197                }
198
199                $this->_documentSummaryInformation = $this->_writeDocumentSummaryInformation();
200                // initialize OLE Document Summary Information
201                if(isset($this->_documentSummaryInformation) && !empty($this->_documentSummaryInformation)){
202                        $OLE_DocumentSummaryInformation = new PHPExcel_Shared_OLE_PPS_File(PHPExcel_Shared_OLE::Asc2Ucs(chr(5) . 'DocumentSummaryInformation'));
203                        $OLE_DocumentSummaryInformation->append($this->_documentSummaryInformation);
204                }
205
206                $this->_summaryInformation = $this->_writeSummaryInformation();
207                // initialize OLE Summary Information
208                if(isset($this->_summaryInformation) && !empty($this->_summaryInformation)){
209                  $OLE_SummaryInformation = new PHPExcel_Shared_OLE_PPS_File(PHPExcel_Shared_OLE::Asc2Ucs(chr(5) . 'SummaryInformation'));
210                  $OLE_SummaryInformation->append($this->_summaryInformation);
211                }
212
213                // define OLE Parts
214                $arrRootData = array($OLE);
215                // initialize OLE Properties file
216                if(isset($OLE_SummaryInformation)){
217                        $arrRootData[] = $OLE_SummaryInformation;
218                }
219                // initialize OLE Extended Properties file
220                if(isset($OLE_DocumentSummaryInformation)){
221                        $arrRootData[] = $OLE_DocumentSummaryInformation;
222                }
223
224                $root = new PHPExcel_Shared_OLE_PPS_Root(time(), time(), $arrRootData);
225                // save the OLE file
226                $res = $root->save($pFilename);
227
228                PHPExcel_Calculation_Functions::setReturnDateType($saveDateReturnType);
229                PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->setWriteDebugLog($saveDebugLog);
230        }
231
232        /**
233         * Set temporary storage directory
234         *
235         * @deprecated
236         * @param       string  $pValue         Temporary storage directory
237         * @throws      PHPExcel_Writer_Exception       when directory does not exist
238         * @return PHPExcel_Writer_Excel5
239         */
240        public function setTempDir($pValue = '') {
241                return $this;
242        }
243
244        /**
245         * Build the Worksheet Escher objects
246         *
247         */
248        private function _buildWorksheetEschers()
249        {
250                // 1-based index to BstoreContainer
251                $blipIndex = 0;
252                $lastReducedSpId = 0;
253                $lastSpId = 0;
254
255                foreach ($this->_phpExcel->getAllsheets() as $sheet) {
256                        // sheet index
257                        $sheetIndex = $sheet->getParent()->getIndex($sheet);
258
259                        $escher = null;
260
261                        // check if there are any shapes for this sheet
262                        $filterRange = $sheet->getAutoFilter()->getRange();
263                        if (count($sheet->getDrawingCollection()) == 0 && empty($filterRange)) {
264                                continue;
265                        }
266
267                        // create intermediate Escher object
268                        $escher = new PHPExcel_Shared_Escher();
269
270                        // dgContainer
271                        $dgContainer = new PHPExcel_Shared_Escher_DgContainer();
272
273                        // set the drawing index (we use sheet index + 1)
274                        $dgId = $sheet->getParent()->getIndex($sheet) + 1;
275                        $dgContainer->setDgId($dgId);
276                        $escher->setDgContainer($dgContainer);
277
278                        // spgrContainer
279                        $spgrContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer();
280                        $dgContainer->setSpgrContainer($spgrContainer);
281
282                        // add one shape which is the group shape
283                        $spContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
284                        $spContainer->setSpgr(true);
285                        $spContainer->setSpType(0);
286                        $spContainer->setSpId(($sheet->getParent()->getIndex($sheet) + 1) << 10);
287                        $spgrContainer->addChild($spContainer);
288
289                        // add the shapes
290
291                        $countShapes[$sheetIndex] = 0; // count number of shapes (minus group shape), in sheet
292
293                        foreach ($sheet->getDrawingCollection() as $drawing) {
294                                ++$blipIndex;
295
296                                ++$countShapes[$sheetIndex];
297
298                                // add the shape
299                                $spContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
300
301                                // set the shape type
302                                $spContainer->setSpType(0x004B);
303                                // set the shape flag
304                                $spContainer->setSpFlag(0x02);
305
306                                // set the shape index (we combine 1-based sheet index and $countShapes to create unique shape index)
307                                $reducedSpId = $countShapes[$sheetIndex];
308                                $spId = $reducedSpId
309                                        | ($sheet->getParent()->getIndex($sheet) + 1) << 10;
310                                $spContainer->setSpId($spId);
311
312                                // keep track of last reducedSpId
313                                $lastReducedSpId = $reducedSpId;
314
315                                // keep track of last spId
316                                $lastSpId = $spId;
317
318                                // set the BLIP index
319                                $spContainer->setOPT(0x4104, $blipIndex);
320
321                                // set coordinates and offsets, client anchor
322                                $coordinates = $drawing->getCoordinates();
323                                $offsetX = $drawing->getOffsetX();
324                                $offsetY = $drawing->getOffsetY();
325                                $width = $drawing->getWidth();
326                                $height = $drawing->getHeight();
327
328                                $twoAnchor = PHPExcel_Shared_Excel5::oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height);
329
330                                $spContainer->setStartCoordinates($twoAnchor['startCoordinates']);
331                                $spContainer->setStartOffsetX($twoAnchor['startOffsetX']);
332                                $spContainer->setStartOffsetY($twoAnchor['startOffsetY']);
333                                $spContainer->setEndCoordinates($twoAnchor['endCoordinates']);
334                                $spContainer->setEndOffsetX($twoAnchor['endOffsetX']);
335                                $spContainer->setEndOffsetY($twoAnchor['endOffsetY']);
336
337                                $spgrContainer->addChild($spContainer);
338                        }
339
340                        // AutoFilters
341                        if(!empty($filterRange)){
342                                $rangeBounds = PHPExcel_Cell::rangeBoundaries($filterRange);
343                                $iNumColStart = $rangeBounds[0][0];
344                                $iNumColEnd = $rangeBounds[1][0];
345
346                                $iInc = $iNumColStart;
347                                while($iInc <= $iNumColEnd){
348                                        ++$countShapes[$sheetIndex];
349
350                                        // create an Drawing Object for the dropdown
351                                        $oDrawing  = new PHPExcel_Worksheet_BaseDrawing();
352                                        // get the coordinates of drawing
353                                        $cDrawing   = PHPExcel_Cell::stringFromColumnIndex($iInc - 1) . $rangeBounds[0][1];
354                                        $oDrawing->setCoordinates($cDrawing);
355                                        $oDrawing->setWorksheet($sheet);
356
357                                        // add the shape
358                                        $spContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
359                                        // set the shape type
360                                        $spContainer->setSpType(0x00C9);
361                                        // set the shape flag
362                                        $spContainer->setSpFlag(0x01);
363
364                                        // set the shape index (we combine 1-based sheet index and $countShapes to create unique shape index)
365                                        $reducedSpId = $countShapes[$sheetIndex];
366                                        $spId = $reducedSpId
367                                                | ($sheet->getParent()->getIndex($sheet) + 1) << 10;
368                                        $spContainer->setSpId($spId);
369
370                                        // keep track of last reducedSpId
371                                        $lastReducedSpId = $reducedSpId;
372
373                                        // keep track of last spId
374                                        $lastSpId = $spId;
375
376                                        $spContainer->setOPT(0x007F, 0x01040104); // Protection -> fLockAgainstGrouping
377                                        $spContainer->setOPT(0x00BF, 0x00080008); // Text -> fFitTextToShape
378                                        $spContainer->setOPT(0x01BF, 0x00010000); // Fill Style -> fNoFillHitTest
379                                        $spContainer->setOPT(0x01FF, 0x00080000); // Line Style -> fNoLineDrawDash
380                                        $spContainer->setOPT(0x03BF, 0x000A0000); // Group Shape -> fPrint
381
382                                        // set coordinates and offsets, client anchor
383                                        $endCoordinates = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::stringFromColumnIndex($iInc - 1));
384                                        $endCoordinates .= $rangeBounds[0][1] + 1;
385
386                                        $spContainer->setStartCoordinates($cDrawing);
387                                        $spContainer->setStartOffsetX(0);
388                                        $spContainer->setStartOffsetY(0);
389                                        $spContainer->setEndCoordinates($endCoordinates);
390                                        $spContainer->setEndOffsetX(0);
391                                        $spContainer->setEndOffsetY(0);
392
393                                        $spgrContainer->addChild($spContainer);
394                                        $iInc++;
395                                }
396                        }
397
398                        // identifier clusters, used for workbook Escher object
399                        $this->_IDCLs[$dgId] = $lastReducedSpId;
400
401                        // set last shape index
402                        $dgContainer->setLastSpId($lastSpId);
403
404                        // set the Escher object
405                        $this->_writerWorksheets[$sheetIndex]->setEscher($escher);
406                }
407        }
408
409        /**
410         * Build the Escher object corresponding to the MSODRAWINGGROUP record
411         */
412        private function _buildWorkbookEscher()
413        {
414                $escher = null;
415
416                // any drawings in this workbook?
417                $found = false;
418                foreach ($this->_phpExcel->getAllSheets() as $sheet) {
419                        if (count($sheet->getDrawingCollection()) > 0) {
420                                $found = true;
421                                break;
422                        }
423                }
424
425                // nothing to do if there are no drawings
426                if (!$found) {
427                        return;
428                }
429
430                // if we reach here, then there are drawings in the workbook
431                $escher = new PHPExcel_Shared_Escher();
432
433                // dggContainer
434                $dggContainer = new PHPExcel_Shared_Escher_DggContainer();
435                $escher->setDggContainer($dggContainer);
436
437                // set IDCLs (identifier clusters)
438                $dggContainer->setIDCLs($this->_IDCLs);
439
440                // this loop is for determining maximum shape identifier of all drawing
441                $spIdMax = 0;
442                $totalCountShapes = 0;
443                $countDrawings = 0;
444
445                foreach ($this->_phpExcel->getAllsheets() as $sheet) {
446                        $sheetCountShapes = 0; // count number of shapes (minus group shape), in sheet
447
448                        if (count($sheet->getDrawingCollection()) > 0) {
449                                ++$countDrawings;
450
451                                foreach ($sheet->getDrawingCollection() as $drawing) {
452                                        ++$sheetCountShapes;
453                                        ++$totalCountShapes;
454
455                                        $spId = $sheetCountShapes
456                                                | ($this->_phpExcel->getIndex($sheet) + 1) << 10;
457                                        $spIdMax = max($spId, $spIdMax);
458                                }
459                        }
460                }
461
462                $dggContainer->setSpIdMax($spIdMax + 1);
463                $dggContainer->setCDgSaved($countDrawings);
464                $dggContainer->setCSpSaved($totalCountShapes + $countDrawings); // total number of shapes incl. one group shapes per drawing
465
466                // bstoreContainer
467                $bstoreContainer = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer();
468                $dggContainer->setBstoreContainer($bstoreContainer);
469
470                // the BSE's (all the images)
471                foreach ($this->_phpExcel->getAllsheets() as $sheet) {
472                        foreach ($sheet->getDrawingCollection() as $drawing) {
473                                if ($drawing instanceof PHPExcel_Worksheet_Drawing) {
474
475                                        $filename = $drawing->getPath();
476
477                                        list($imagesx, $imagesy, $imageFormat) = getimagesize($filename);
478
479                                        switch ($imageFormat) {
480
481                                        case 1: // GIF, not supported by BIFF8, we convert to PNG
482                                                $blipType = PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG;
483                                                ob_start();
484                                                imagepng(imagecreatefromgif($filename));
485                                                $blipData = ob_get_contents();
486                                                ob_end_clean();
487                                                break;
488
489                                        case 2: // JPEG
490                                                $blipType = PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG;
491                                                $blipData = file_get_contents($filename);
492                                                break;
493
494                                        case 3: // PNG
495                                                $blipType = PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG;
496                                                $blipData = file_get_contents($filename);
497                                                break;
498
499                                        case 6: // Windows DIB (BMP), we convert to PNG
500                                                $blipType = PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG;
501                                                ob_start();
502                                                imagepng(PHPExcel_Shared_Drawing::imagecreatefrombmp($filename));
503                                                $blipData = ob_get_contents();
504                                                ob_end_clean();
505                                                break;
506
507                                        default: continue 2;
508
509                                        }
510
511                                        $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
512                                        $blip->setData($blipData);
513
514                                        $BSE = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE();
515                                        $BSE->setBlipType($blipType);
516                                        $BSE->setBlip($blip);
517
518                                        $bstoreContainer->addBSE($BSE);
519
520                                } else if ($drawing instanceof PHPExcel_Worksheet_MemoryDrawing) {
521
522                                        switch ($drawing->getRenderingFunction()) {
523
524                                        case PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG:
525                                                $blipType = PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG;
526                                                $renderingFunction = 'imagejpeg';
527                                                break;
528
529                                        case PHPExcel_Worksheet_MemoryDrawing::RENDERING_GIF:
530                                        case PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG:
531                                        case PHPExcel_Worksheet_MemoryDrawing::RENDERING_DEFAULT:
532                                                $blipType = PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG;
533                                                $renderingFunction = 'imagepng';
534                                                break;
535
536                                        }
537
538                                        ob_start();
539                                        call_user_func($renderingFunction, $drawing->getImageResource());
540                                        $blipData = ob_get_contents();
541                                        ob_end_clean();
542
543                                        $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
544                                        $blip->setData($blipData);
545
546                                        $BSE = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE();
547                                        $BSE->setBlipType($blipType);
548                                        $BSE->setBlip($blip);
549
550                                        $bstoreContainer->addBSE($BSE);
551                                }
552                        }
553                }
554
555                // Set the Escher object
556                $this->_writerWorkbook->setEscher($escher);
557        }
558
559        /**
560         * Build the OLE Part for DocumentSummary Information
561         * @return string
562         */
563        private function _writeDocumentSummaryInformation(){
564
565                // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
566                $data = pack('v', 0xFFFE);
567                // offset: 2; size: 2;
568                $data .= pack('v', 0x0000);
569                // offset: 4; size: 2; OS version
570                $data .= pack('v', 0x0106);
571                // offset: 6; size: 2; OS indicator
572                $data .= pack('v', 0x0002);
573                // offset: 8; size: 16
574                $data .= pack('VVVV', 0x00, 0x00, 0x00, 0x00);
575                // offset: 24; size: 4; section count
576                $data .= pack('V', 0x0001);
577
578                // offset: 28; size: 16; first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
579                $data .= pack('vvvvvvvv', 0xD502, 0xD5CD, 0x2E9C, 0x101B, 0x9793, 0x0008, 0x2C2B, 0xAEF9);
580                // offset: 44; size: 4; offset of the start
581                $data .= pack('V', 0x30);
582
583                // SECTION
584                $dataSection = array();
585                $dataSection_NumProps = 0;
586                $dataSection_Summary = '';
587                $dataSection_Content = '';
588
589                // GKPIDDSI_CODEPAGE: CodePage
590                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x01),
591                                                           'offset' => array('pack' => 'V'),
592                                                           'type'       => array('pack' => 'V', 'data' => 0x02), // 2 byte signed integer
593                                                           'data'       => array('data' => 1252));
594                $dataSection_NumProps++;
595
596                // GKPIDDSI_CATEGORY : Category
597                if($this->_phpExcel->getProperties()->getCategory()){
598                        $dataProp = $this->_phpExcel->getProperties()->getCategory();
599                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x02),
600                                                                   'offset' => array('pack' => 'V'),
601                                                                   'type'       => array('pack' => 'V', 'data' => 0x1E),
602                                                                   'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
603                        $dataSection_NumProps++;
604                }
605                // GKPIDDSI_VERSION :Version of the application that wrote the property storage
606                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x17),
607                                                           'offset' => array('pack' => 'V'),
608                                                           'type'       => array('pack' => 'V', 'data' => 0x03),
609                                                           'data'       => array('pack' => 'V', 'data' => 0x000C0000));
610                $dataSection_NumProps++;
611                // GKPIDDSI_SCALE : FALSE
612                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x0B),
613                                                           'offset' => array('pack' => 'V'),
614                                                           'type'       => array('pack' => 'V', 'data' => 0x0B),
615                                                           'data'       => array('data' => false));
616                $dataSection_NumProps++;
617                // GKPIDDSI_LINKSDIRTY : True if any of the values for the linked properties have changed outside of the application
618                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x10),
619                                                           'offset' => array('pack' => 'V'),
620                                                           'type'       => array('pack' => 'V', 'data' => 0x0B),
621                                                           'data'       => array('data' => false));
622                $dataSection_NumProps++;
623                // GKPIDDSI_SHAREDOC : FALSE
624                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x13),
625                                                           'offset' => array('pack' => 'V'),
626                                                           'type'       => array('pack' => 'V', 'data' => 0x0B),
627                                                           'data'       => array('data' => false));
628                $dataSection_NumProps++;
629                // GKPIDDSI_HYPERLINKSCHANGED : True if any of the values for the _PID_LINKS (hyperlink text) have changed outside of the application
630                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x16),
631                                                           'offset' => array('pack' => 'V'),
632                                                           'type'       => array('pack' => 'V', 'data' => 0x0B),
633                                                           'data'       => array('data' => false));
634                $dataSection_NumProps++;
635
636                // GKPIDDSI_DOCSPARTS
637                // MS-OSHARED p75 (2.3.3.2.2.1)
638                // Structure is VtVecUnalignedLpstrValue (2.3.3.1.9)
639                // cElements
640                $dataProp = pack('v', 0x0001);
641                $dataProp .= pack('v', 0x0000);
642                // array of UnalignedLpstr
643                  // cch
644                  $dataProp .= pack('v', 0x000A);
645                  $dataProp .= pack('v', 0x0000);
646                  // value
647                  $dataProp .= 'Worksheet'.chr(0);
648
649                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x0D),
650                                                           'offset' => array('pack' => 'V'),
651                                                           'type'       => array('pack' => 'V', 'data' => 0x101E),
652                                                           'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
653                $dataSection_NumProps++;
654
655                // GKPIDDSI_HEADINGPAIR
656                // VtVecHeadingPairValue
657                  // cElements
658                  $dataProp = pack('v', 0x0002);
659                  $dataProp .= pack('v', 0x0000);
660                  // Array of vtHeadingPair
661                    // vtUnalignedString - headingString
662                      // stringType
663                      $dataProp .= pack('v', 0x001E);
664                      // padding
665                      $dataProp .= pack('v', 0x0000);
666                      // UnalignedLpstr
667                        // cch
668                        $dataProp .= pack('v', 0x0013);
669                        $dataProp .= pack('v', 0x0000);
670                        // value
671                        $dataProp .= 'Feuilles de calcul';
672                    // vtUnalignedString - headingParts
673                      // wType : 0x0003 = 32 bit signed integer
674                      $dataProp .= pack('v', 0x0300);
675                      // padding
676                      $dataProp .= pack('v', 0x0000);
677                      // value
678                      $dataProp .= pack('v', 0x0100);
679                      $dataProp .= pack('v', 0x0000);
680                          $dataProp .= pack('v', 0x0000);
681                      $dataProp .= pack('v', 0x0000);
682
683        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x0C),
684                                                   'offset' => array('pack' => 'V'),
685                                                   'type'       => array('pack' => 'V', 'data' => 0x100C),
686                                                   'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
687        $dataSection_NumProps++;
688
689                //              4       Section Length
690                //              4       Property count
691                //              8 * $dataSection_NumProps (8 =  ID (4) + OffSet(4))
692                $dataSection_Content_Offset = 8 + $dataSection_NumProps * 8;
693                foreach ($dataSection as $dataProp){
694                        // Summary
695                        $dataSection_Summary .= pack($dataProp['summary']['pack'], $dataProp['summary']['data']);
696                        // Offset
697                        $dataSection_Summary .= pack($dataProp['offset']['pack'], $dataSection_Content_Offset);
698                        // DataType
699                        $dataSection_Content .= pack($dataProp['type']['pack'], $dataProp['type']['data']);
700                        // Data
701                        if($dataProp['type']['data'] == 0x02){ // 2 byte signed integer
702                                $dataSection_Content .= pack('V', $dataProp['data']['data']);
703
704                                $dataSection_Content_Offset += 4 + 4;
705                        }
706                        elseif($dataProp['type']['data'] == 0x03){ // 4 byte signed integer
707                                $dataSection_Content .= pack('V', $dataProp['data']['data']);
708
709                                $dataSection_Content_Offset += 4 + 4;
710                        }
711                        elseif($dataProp['type']['data'] == 0x0B){ // Boolean
712                                if($dataProp['data']['data'] == false){
713                                        $dataSection_Content .= pack('V', 0x0000);
714                                } else {
715                                        $dataSection_Content .= pack('V', 0x0001);
716                                }
717                                $dataSection_Content_Offset += 4 + 4;
718                        }
719                        elseif($dataProp['type']['data'] == 0x1E){ // null-terminated string prepended by dword string length
720                                // Null-terminated string
721                                $dataProp['data']['data'] .= chr(0);
722                                $dataProp['data']['length'] += 1;
723                                // Complete the string with null string for being a %4
724                                $dataProp['data']['length'] = $dataProp['data']['length'] + ((4 - $dataProp['data']['length'] % 4)==4 ? 0 : (4 - $dataProp['data']['length'] % 4));
725                                $dataProp['data']['data'] = str_pad($dataProp['data']['data'], $dataProp['data']['length'], chr(0), STR_PAD_RIGHT);
726
727                                $dataSection_Content .= pack('V', $dataProp['data']['length']);
728                                $dataSection_Content .= $dataProp['data']['data'];
729
730                                $dataSection_Content_Offset += 4 + 4 + strlen($dataProp['data']['data']);
731                        }
732                        elseif($dataProp['type']['data'] == 0x40){ // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
733                                $dataSection_Content .= $dataProp['data']['data'];
734
735                                $dataSection_Content_Offset += 4 + 8;
736                        }
737                        else {
738                                // Data Type Not Used at the moment
739                                $dataSection_Content .= $dataProp['data']['data'];
740
741                                $dataSection_Content_Offset += 4 + $dataProp['data']['length'];
742                        }
743                }
744                // Now $dataSection_Content_Offset contains the size of the content
745
746                // section header
747                // offset: $secOffset; size: 4; section length
748                //              + x  Size of the content (summary + content)
749                $data .= pack('V', $dataSection_Content_Offset);
750                // offset: $secOffset+4; size: 4; property count
751                $data .= pack('V', $dataSection_NumProps);
752                // Section Summary
753                $data .= $dataSection_Summary;
754                // Section Content
755                $data .= $dataSection_Content;
756
757                return $data;
758        }
759
760        /**
761         * Build the OLE Part for Summary Information
762         * @return string
763         */
764        private function _writeSummaryInformation(){
765                // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
766                $data = pack('v', 0xFFFE);
767                // offset: 2; size: 2;
768                $data .= pack('v', 0x0000);
769                // offset: 4; size: 2; OS version
770                $data .= pack('v', 0x0106);
771                // offset: 6; size: 2; OS indicator
772                $data .= pack('v', 0x0002);
773                // offset: 8; size: 16
774                $data .= pack('VVVV', 0x00, 0x00, 0x00, 0x00);
775                // offset: 24; size: 4; section count
776                $data .= pack('V', 0x0001);
777
778                // offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
779                $data .= pack('vvvvvvvv', 0x85E0, 0xF29F, 0x4FF9, 0x1068, 0x91AB, 0x0008, 0x272B, 0xD9B3);
780                // offset: 44; size: 4; offset of the start
781                $data .= pack('V', 0x30);
782
783                // SECTION
784                $dataSection = array();
785                $dataSection_NumProps = 0;
786                $dataSection_Summary = '';
787                $dataSection_Content = '';
788
789                // CodePage : CP-1252
790                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x01),
791                                                           'offset' => array('pack' => 'V'),
792                                                           'type'       => array('pack' => 'V', 'data' => 0x02), // 2 byte signed integer
793                                                           'data'       => array('data' => 1252));
794                $dataSection_NumProps++;
795
796                //      Title
797                if($this->_phpExcel->getProperties()->getTitle()){
798                        $dataProp = $this->_phpExcel->getProperties()->getTitle();
799                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x02),
800                                                                   'offset' => array('pack' => 'V'),
801                                                                   'type'       => array('pack' => 'V', 'data' => 0x1E), // null-terminated string prepended by dword string length
802                                                                   'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
803                        $dataSection_NumProps++;
804                }
805                //      Subject
806                if($this->_phpExcel->getProperties()->getSubject()){
807                        $dataProp = $this->_phpExcel->getProperties()->getSubject();
808                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x03),
809                                                                   'offset' => array('pack' => 'V'),
810                                                                   'type'       => array('pack' => 'V', 'data' => 0x1E), // null-terminated string prepended by dword string length
811                                                                   'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
812                        $dataSection_NumProps++;
813                }
814                //      Author (Creator)
815                if($this->_phpExcel->getProperties()->getCreator()){
816                        $dataProp = $this->_phpExcel->getProperties()->getCreator();
817                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x04),
818                                                                   'offset' => array('pack' => 'V'),
819                                                                   'type'       => array('pack' => 'V', 'data' => 0x1E), // null-terminated string prepended by dword string length
820                                                                   'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
821                        $dataSection_NumProps++;
822                }
823                //      Keywords
824                if($this->_phpExcel->getProperties()->getKeywords()){
825                        $dataProp = $this->_phpExcel->getProperties()->getKeywords();
826                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x05),
827                                                                   'offset' => array('pack' => 'V'),
828                                                                   'type'       => array('pack' => 'V', 'data' => 0x1E), // null-terminated string prepended by dword string length
829                                                                   'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
830                        $dataSection_NumProps++;
831                }
832                //      Comments (Description)
833                if($this->_phpExcel->getProperties()->getDescription()){
834                        $dataProp = $this->_phpExcel->getProperties()->getDescription();
835                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x06),
836                                                                   'offset' => array('pack' => 'V'),
837                                                                   'type'       => array('pack' => 'V', 'data' => 0x1E), // null-terminated string prepended by dword string length
838                                                                   'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
839                        $dataSection_NumProps++;
840                }
841                //      Last Saved By (LastModifiedBy)
842                if($this->_phpExcel->getProperties()->getLastModifiedBy()){
843                        $dataProp = $this->_phpExcel->getProperties()->getLastModifiedBy();
844                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x08),
845                                                                   'offset' => array('pack' => 'V'),
846                                                                   'type'       => array('pack' => 'V', 'data' => 0x1E), // null-terminated string prepended by dword string length
847                                                                   'data'       => array('data' => $dataProp, 'length' => strlen($dataProp)));
848                        $dataSection_NumProps++;
849                }
850                //      Created Date/Time
851                if($this->_phpExcel->getProperties()->getCreated()){
852                        $dataProp = $this->_phpExcel->getProperties()->getCreated();
853                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x0C),
854                                                                   'offset' => array('pack' => 'V'),
855                                                                   'type'       => array('pack' => 'V', 'data' => 0x40), // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
856                                                                   'data'       => array('data' => PHPExcel_Shared_OLE::LocalDate2OLE($dataProp)));
857                        $dataSection_NumProps++;
858                }
859                //      Modified Date/Time
860                if($this->_phpExcel->getProperties()->getModified()){
861                        $dataProp = $this->_phpExcel->getProperties()->getModified();
862                        $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x0D),
863                                                                   'offset' => array('pack' => 'V'),
864                                                                   'type'       => array('pack' => 'V', 'data' => 0x40), // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
865                                                                   'data'       => array('data' => PHPExcel_Shared_OLE::LocalDate2OLE($dataProp)));
866                        $dataSection_NumProps++;
867                }
868                //      Security
869                $dataSection[] = array('summary'=> array('pack' => 'V', 'data' => 0x13),
870                                                           'offset' => array('pack' => 'V'),
871                                                           'type'       => array('pack' => 'V', 'data' => 0x03), // 4 byte signed integer
872                                                           'data'       => array('data' => 0x00));
873                $dataSection_NumProps++;
874
875
876                //              4       Section Length
877                //              4       Property count
878                //              8 * $dataSection_NumProps (8 =  ID (4) + OffSet(4))
879                $dataSection_Content_Offset = 8 + $dataSection_NumProps * 8;
880                foreach ($dataSection as $dataProp){
881                        // Summary
882                        $dataSection_Summary .= pack($dataProp['summary']['pack'], $dataProp['summary']['data']);
883                        // Offset
884                        $dataSection_Summary .= pack($dataProp['offset']['pack'], $dataSection_Content_Offset);
885                        // DataType
886                        $dataSection_Content .= pack($dataProp['type']['pack'], $dataProp['type']['data']);
887                        // Data
888                        if($dataProp['type']['data'] == 0x02){ // 2 byte signed integer
889                                $dataSection_Content .= pack('V', $dataProp['data']['data']);
890
891                                $dataSection_Content_Offset += 4 + 4;
892                        }
893                        elseif($dataProp['type']['data'] == 0x03){ // 4 byte signed integer
894                                $dataSection_Content .= pack('V', $dataProp['data']['data']);
895
896                                $dataSection_Content_Offset += 4 + 4;
897                        }
898                        elseif($dataProp['type']['data'] == 0x1E){ // null-terminated string prepended by dword string length
899                                // Null-terminated string
900                                $dataProp['data']['data'] .= chr(0);
901                                $dataProp['data']['length'] += 1;
902                                // Complete the string with null string for being a %4
903                                $dataProp['data']['length'] = $dataProp['data']['length'] + ((4 - $dataProp['data']['length'] % 4)==4 ? 0 : (4 - $dataProp['data']['length'] % 4));
904                                $dataProp['data']['data'] = str_pad($dataProp['data']['data'], $dataProp['data']['length'], chr(0), STR_PAD_RIGHT);
905
906                                $dataSection_Content .= pack('V', $dataProp['data']['length']);
907                                $dataSection_Content .= $dataProp['data']['data'];
908
909                                $dataSection_Content_Offset += 4 + 4 + strlen($dataProp['data']['data']);
910                        }
911                        elseif($dataProp['type']['data'] == 0x40){ // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
912                                $dataSection_Content .= $dataProp['data']['data'];
913
914                                $dataSection_Content_Offset += 4 + 8;
915                        }
916                        else {
917                                // Data Type Not Used at the moment
918                        }
919                }
920                // Now $dataSection_Content_Offset contains the size of the content
921
922                // section header
923                // offset: $secOffset; size: 4; section length
924                //              + x  Size of the content (summary + content)
925                $data .= pack('V', $dataSection_Content_Offset);
926                // offset: $secOffset+4; size: 4; property count
927                $data .= pack('V', $dataSection_NumProps);
928                // Section Summary
929                $data .= $dataSection_Summary;
930                // Section Content
931                $data .= $dataSection_Content;
932
933                return $data;
934        }
935}
Note: See TracBrowser for help on using the repository browser.