5 * Copyright (c) 2006 - 2010 PHPExcel
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.
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.
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
23 * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
24 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25 * @version 1.7.3c, 2010-06-01
29 /** PHPExcel root directory */
30 if (!defined('PHPEXCEL_ROOT')) {
31 define('PHPEXCEL_ROOT', dirname(__FILE__
) . '/');
32 require(PHPEXCEL_ROOT
. 'PHPExcel/Autoloader.php');
33 PHPExcel_Autoloader
::Register();
34 PHPExcel_Shared_ZipStreamWrapper
::register();
35 // check mbstring.func_overload
36 if (ini_get('mbstring.func_overload') & 2) {
37 throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).');
47 * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
54 * @var PHPExcel_DocumentProperties
61 * @var PHPExcel_DocumentSecurity
66 * Collection of Worksheet objects
68 * @var PHPExcel_Worksheet[]
70 private $_workSheetCollection = array();
77 private $_activeSheetIndex = 0;
82 * @var PHPExcel_NamedRange[]
84 private $_namedRanges = array();
91 private $_cellXfSupervisor;
96 * @var PHPExcel_Style[]
98 private $_cellXfCollection = array();
101 * CellStyleXf collection
103 * @var PHPExcel_Style[]
105 private $_cellStyleXfCollection = array();
108 * Create a new PHPExcel with one Worksheet
110 public function __construct()
112 // Initialise worksheet collection and add one worksheet
113 $this->_workSheetCollection
= array();
114 $this->_workSheetCollection
[] = new PHPExcel_Worksheet($this);
115 $this->_activeSheetIndex
= 0;
117 // Create document properties
118 $this->_properties
= new PHPExcel_DocumentProperties();
120 // Create document security
121 $this->_security
= new PHPExcel_DocumentSecurity();
124 $this->_namedRanges
= array();
126 // Create the cellXf supervisor
127 $this->_cellXfSupervisor
= new PHPExcel_Style(true);
128 $this->_cellXfSupervisor
->bindParent($this);
130 // Create the default style
131 $this->addCellXf(new PHPExcel_Style
);
132 $this->addCellStyleXf(new PHPExcel_Style
);
136 public function disconnectWorksheets() {
137 foreach($this->_workSheetCollection
as $k => &$worksheet) {
138 $worksheet->disconnectCells();
139 $this->_workSheetCollection
[$k] = null;
142 $this->_workSheetCollection
= array();
148 * @return PHPExcel_DocumentProperties
150 public function getProperties()
152 return $this->_properties
;
158 * @param PHPExcel_DocumentProperties $pValue
160 public function setProperties(PHPExcel_DocumentProperties
$pValue)
162 $this->_properties
= $pValue;
168 * @return PHPExcel_DocumentSecurity
170 public function getSecurity()
172 return $this->_security
;
178 * @param PHPExcel_DocumentSecurity $pValue
180 public function setSecurity(PHPExcel_DocumentSecurity
$pValue)
182 $this->_security
= $pValue;
188 * @return PHPExcel_Worksheet
190 public function getActiveSheet()
192 return $this->_workSheetCollection
[$this->_activeSheetIndex
];
196 * Create sheet and add it to this workbook
198 * @return PHPExcel_Worksheet
200 public function createSheet($iSheetIndex = null)
202 $newSheet = new PHPExcel_Worksheet($this);
203 $this->addSheet($newSheet, $iSheetIndex);
210 * @param PHPExcel_Worksheet $pSheet
211 * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
212 * @return PHPExcel_Worksheet
215 public function addSheet(PHPExcel_Worksheet
$pSheet = null, $iSheetIndex = null)
217 if(is_null($iSheetIndex))
219 $this->_workSheetCollection
[] = $pSheet;
223 // Insert the sheet at the requested index
225 $this->_workSheetCollection
,
231 // Adjust active sheet index if necessary
232 if ($this->_activeSheetIndex
>= $iSheetIndex) {
233 ++
$this->_activeSheetIndex
;
241 * Remove sheet by index
243 * @param int $pIndex Active sheet index
246 public function removeSheetByIndex($pIndex = 0)
248 if ($pIndex > count($this->_workSheetCollection
) - 1) {
249 throw new Exception("Sheet index is out of bounds.");
251 array_splice($this->_workSheetCollection
, $pIndex, 1);
258 * @param int $pIndex Sheet index
259 * @return PHPExcel_Worksheet
262 public function getSheet($pIndex = 0)
264 if ($pIndex > count($this->_workSheetCollection
) - 1) {
265 throw new Exception("Sheet index is out of bounds.");
267 return $this->_workSheetCollection
[$pIndex];
274 * @return PHPExcel_Worksheet[]
276 public function getAllSheets()
278 return $this->_workSheetCollection
;
284 * @param string $pName Sheet name
285 * @return PHPExcel_Worksheet
288 public function getSheetByName($pName = '')
290 $worksheetCount = count($this->_workSheetCollection
);
291 for ($i = 0; $i < $worksheetCount; ++
$i) {
292 if ($this->_workSheetCollection
[$i]->getTitle() == $pName) {
293 return $this->_workSheetCollection
[$i];
301 * Get index for sheet
303 * @param PHPExcel_Worksheet $pSheet
304 * @return Sheet index
307 public function getIndex(PHPExcel_Worksheet
$pSheet)
309 foreach ($this->_workSheetCollection
as $key => $value) {
310 if ($value->getHashCode() == $pSheet->getHashCode()) {
317 * Set index for sheet by sheet name.
319 * @param string $sheetName Sheet name to modify index for
320 * @param int $newIndex New index for the sheet
321 * @return New sheet index
324 public function setIndexByName($sheetName, $newIndex)
326 $oldIndex = $this->getIndex($this->getSheetByName($sheetName));
327 $pSheet = array_splice(
328 $this->_workSheetCollection
,
333 $this->_workSheetCollection
,
346 public function getSheetCount()
348 return count($this->_workSheetCollection
);
352 * Get active sheet index
354 * @return int Active sheet index
356 public function getActiveSheetIndex()
358 return $this->_activeSheetIndex
;
362 * Set active sheet index
364 * @param int $pIndex Active sheet index
366 * @return PHPExcel_Worksheet
368 public function setActiveSheetIndex($pIndex = 0)
370 if ($pIndex > count($this->_workSheetCollection
) - 1) {
371 throw new Exception("Active sheet index is out of bounds.");
373 $this->_activeSheetIndex
= $pIndex;
375 return $this->getActiveSheet();
379 * Set active sheet index by name
381 * @param string $pValue Sheet title
382 * @return PHPExcel_Worksheet
385 public function setActiveSheetIndexByName($pValue = '')
387 if (($worksheet = $this->getSheetByName($pValue)) instanceof PHPExcel_Worksheet
) {
388 $this->setActiveSheetIndex($worksheet->getParent()->getIndex($worksheet));
392 throw new Exception('Workbook does not contain sheet:' . $pValue);
400 public function getSheetNames()
402 $returnValue = array();
403 $worksheetCount = $this->getSheetCount();
404 for ($i = 0; $i < $worksheetCount; ++
$i) {
405 array_push($returnValue, $this->getSheet($i)->getTitle());
414 * @param PHPExcel_Worksheet $pSheet External sheet to add
415 * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
417 * @return PHPExcel_Worksheet
419 public function addExternalSheet(PHPExcel_Worksheet
$pSheet, $iSheetIndex = null) {
420 if (!is_null($this->getSheetByName($pSheet->getTitle()))) {
421 throw new Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename the external sheet first.");
424 // count how many cellXfs there are in this workbook currently, we will need this below
425 $countCellXfs = count($this->_cellXfCollection
);
427 // copy all the shared cellXfs from the external workbook and append them to the current
428 foreach ($pSheet->getParent()->getCellXfCollection() as $cellXf) {
429 $this->addCellXf(clone $cellXf);
432 // move sheet to this workbook
433 $pSheet->rebindParent($this);
435 // update the cellXfs
436 foreach ($pSheet->getCellCollection(false) as $cellID) {
437 $cell = $sheet->getCell($cellID);
438 $cell->setXfIndex( $cell->getXfIndex() +
$countCellXfs );
441 return $this->addSheet($pSheet, $iSheetIndex);
447 * @return PHPExcel_NamedRange[]
449 public function getNamedRanges() {
450 return $this->_namedRanges
;
456 * @param PHPExcel_NamedRange $namedRange
459 public function addNamedRange(PHPExcel_NamedRange
$namedRange) {
460 if ($namedRange->getScope() == null) {
462 $this->_namedRanges
[$namedRange->getName()] = $namedRange;
465 $this->_namedRanges
[$namedRange->getScope()->getTitle().'!'.$namedRange->getName()] = $namedRange;
473 * @param string $namedRange
474 * @param PHPExcel_Worksheet|null $pSheet Scope. Use null for global scope
475 * @return PHPExcel_NamedRange|null
477 public function getNamedRange($namedRange, PHPExcel_Worksheet
$pSheet = null) {
480 if ($namedRange != '' && !is_null($namedRange)) {
481 // first look for global defined name
482 if (isset($this->_namedRanges
[$namedRange])) {
483 $returnValue = $this->_namedRanges
[$namedRange];
486 // then look for local defined name (has priority over global defined name if both names exist)
487 if (!is_null($pSheet) && isset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange])) {
488 $returnValue = $this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange];
498 * @param string $namedRange
499 * @param PHPExcel_Worksheet|null $pSheet. Scope. Use null for global scope.
502 public function removeNamedRange($namedRange, PHPExcel_Worksheet
$pSheet = null) {
503 if (is_null($pSheet)) {
504 if (isset($this->_namedRanges
[$namedRange])) {
505 unset($this->_namedRanges
[$namedRange]);
508 if (isset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange])) {
509 unset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange]);
516 * Get worksheet iterator
518 * @return PHPExcel_WorksheetIterator
520 public function getWorksheetIterator() {
521 return new PHPExcel_WorksheetIterator($this);
525 * Copy workbook (!= clone!)
529 public function copy() {
530 $copied = clone $this;
532 $worksheetCount = count($this->_workSheetCollection
);
533 for ($i = 0; $i < $worksheetCount; ++
$i) {
534 $this->_workSheetCollection
[$i] = $this->_workSheetCollection
[$i]->copy();
535 $this->_workSheetCollection
[$i]->rebindParent($this);
542 * Implement PHP __clone to create a deep clone, not just a shallow copy.
544 public function __clone() {
545 foreach($this as $key => $val) {
546 if (is_object($val) ||
(is_array($val))) {
547 $this->{$key} = unserialize(serialize($val));
553 * Get the workbook collection of cellXfs
555 * @return PHPExcel_Style[]
557 public function getCellXfCollection()
559 return $this->_cellXfCollection
;
563 * Get cellXf by index
566 * @return PHPExcel_Style
568 public function getCellXfByIndex($pIndex = 0)
570 return $this->_cellXfCollection
[$pIndex];
574 * Get cellXf by hash code
576 * @param string $pValue
577 * @return PHPExcel_Style|false
579 public function getCellXfByHashCode($pValue = '')
581 foreach ($this->_cellXfCollection
as $cellXf) {
582 if ($cellXf->getHashCode() == $pValue) {
592 * @return PHPExcel_Style
595 public function getDefaultStyle()
597 if (isset($this->_cellXfCollection
[0])) {
598 return $this->_cellXfCollection
[0];
600 throw new Exception('No default style found for this workbook');
604 * Add a cellXf to the workbook
606 * @param PHPExcel_Style
608 public function addCellXf(PHPExcel_Style
$style)
610 $this->_cellXfCollection
[] = $style;
611 $style->setIndex(count($this->_cellXfCollection
) - 1);
615 * Remove cellXf by index. It is ensured that all cells get their xf index updated.
617 * @param int $pIndex Index to cellXf
620 public function removeCellXfByIndex($pIndex = 0)
622 if ($pIndex > count($this->_cellXfCollection
) - 1) {
623 throw new Exception("CellXf index is out of bounds.");
625 // first remove the cellXf
626 array_splice($this->_cellXfCollection
, $pIndex, 1);
628 // then update cellXf indexes for cells
629 foreach ($this->_workSheetCollection
as $worksheet) {
630 foreach ($worksheet->getCellCollection(false) as $cellID) {
631 $cell = $sheet->getCell($cellID);
632 $xfIndex = $cell->getXfIndex();
633 if ($xfIndex > $pIndex ) {
634 // decrease xf index by 1
635 $cell->setXfIndex($xfIndex - 1);
636 } else if ($xfIndex == $pIndex) {
637 // set to default xf index 0
638 $cell->setXfIndex(0);
646 * Get the cellXf supervisor
648 * @return PHPExcel_Style
650 public function getCellXfSupervisor()
652 return $this->_cellXfSupervisor
;
656 * Get the workbook collection of cellStyleXfs
658 * @return PHPExcel_Style[]
660 public function getCellStyleXfCollection()
662 return $this->_cellStyleXfCollection
;
666 * Get cellStyleXf by index
669 * @return PHPExcel_Style
671 public function getCellStyleXfByIndex($pIndex = 0)
673 return $this->_cellStyleXfCollection
[$pIndex];
677 * Get cellStyleXf by hash code
679 * @param string $pValue
680 * @return PHPExcel_Style|false
682 public function getCellStyleXfByHashCode($pValue = '')
684 foreach ($this->_cellXfStyleCollection
as $cellStyleXf) {
685 if ($cellStyleXf->getHashCode() == $pValue) {
693 * Add a cellStyleXf to the workbook
695 * @param PHPExcel_Style $pStyle
697 public function addCellStyleXf(PHPExcel_Style
$pStyle)
699 $this->_cellStyleXfCollection
[] = $pStyle;
700 $pStyle->setIndex(count($this->_cellStyleXfCollection
) - 1);
704 * Remove cellStyleXf by index
709 public function removeCellStyleXfByIndex($pIndex = 0)
711 if ($pIndex > count($this->_cellStyleXfCollection
) - 1) {
712 throw new Exception("CellStyleXf index is out of bounds.");
714 array_splice($this->_cellStyleXfCollection
, $pIndex, 1);
719 * Eliminate all unneeded cellXf and afterwards update the xfIndex for all cells
720 * and columns in the workbook
722 public function garbageCollect()
724 // how many references are there to each cellXf ?
725 $countReferencesCellXf = array();
726 foreach ($this->_cellXfCollection
as $index => $cellXf) {
727 $countReferencesCellXf[$index] = 0;
730 foreach ($this->getWorksheetIterator() as $sheet) {
733 foreach ($sheet->getCellCollection(false) as $cellID) {
734 $cell = $sheet->getCell($cellID);
735 ++
$countReferencesCellXf[$cell->getXfIndex()];
738 // from row dimensions
739 foreach ($sheet->getRowDimensions() as $rowDimension) {
740 if ($rowDimension->getXfIndex() !== null) {
741 ++
$countReferencesCellXf[$rowDimension->getXfIndex()];
745 // from column dimensions
746 foreach ($sheet->getColumnDimensions() as $columnDimension) {
747 ++
$countReferencesCellXf[$columnDimension->getXfIndex()];
751 // remove cellXfs without references and create mapping so we can update xfIndex
752 // for all cells and columns
753 $countNeededCellXfs = 0;
754 foreach ($this->_cellXfCollection
as $index => $cellXf) {
755 if ($countReferencesCellXf[$index] > 0 ||
$index == 0) { // we must never remove the first cellXf
756 ++
$countNeededCellXfs;
758 unset($this->_cellXfCollection
[$index]);
760 $map[$index] = $countNeededCellXfs - 1;
762 $this->_cellXfCollection
= array_values($this->_cellXfCollection
);
764 // update the index for all cellXfs
765 foreach ($this->_cellXfCollection
as $i => $cellXf) {
766 $cellXf->setIndex($i);
769 // make sure there is always at least one cellXf (there should be)
770 if (count($this->_cellXfCollection
) == 0) {
771 $this->_cellXfCollection
[] = new PHPExcel_Style();
774 // update the xfIndex for all cells, row dimensions, column dimensions
775 foreach ($this->getWorksheetIterator() as $sheet) {
778 foreach ($sheet->getCellCollection(false) as $cellID) {
779 $cell = $sheet->getCell($cellID);
780 $cell->setXfIndex( $map[$cell->getXfIndex()] );
783 // for all row dimensions
784 foreach ($sheet->getRowDimensions() as $rowDimension) {
785 if ($rowDimension->getXfIndex() !== null) {
786 $rowDimension->setXfIndex( $map[$rowDimension->getXfIndex()] );
790 // for all column dimensions
791 foreach ($sheet->getColumnDimensions() as $columnDimension) {
792 $columnDimension->setXfIndex( $map[$columnDimension->getXfIndex()] );
796 // also do garbage collection for all the sheets
797 foreach ($this->getWorksheetIterator() as $sheet) {
798 $sheet->garbageCollect();