For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1153 lines
31 KiB

  1. <?php
  2. /** PHPExcel root directory */
  3. if (!defined('PHPEXCEL_ROOT')) {
  4. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/');
  5. require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  6. }
  7. /**
  8. * PHPExcel
  9. *
  10. * Copyright (c) 2006 - 2015 PHPExcel
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation; either
  15. * version 2.1 of the License, or (at your option) any later version.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public
  23. * License along with this library; if not, write to the Free Software
  24. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  25. *
  26. * @category PHPExcel
  27. * @package PHPExcel
  28. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  29. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  30. * @version ##VERSION##, ##DATE##
  31. */
  32. class PHPExcel
  33. {
  34. /**
  35. * Unique ID
  36. *
  37. * @var string
  38. */
  39. private $uniqueID;
  40. /**
  41. * Document properties
  42. *
  43. * @var PHPExcel_DocumentProperties
  44. */
  45. private $properties;
  46. /**
  47. * Document security
  48. *
  49. * @var PHPExcel_DocumentSecurity
  50. */
  51. private $security;
  52. /**
  53. * Collection of Worksheet objects
  54. *
  55. * @var PHPExcel_Worksheet[]
  56. */
  57. private $workSheetCollection = array();
  58. /**
  59. * Calculation Engine
  60. *
  61. * @var PHPExcel_Calculation
  62. */
  63. private $calculationEngine;
  64. /**
  65. * Active sheet index
  66. *
  67. * @var integer
  68. */
  69. private $activeSheetIndex = 0;
  70. /**
  71. * Named ranges
  72. *
  73. * @var PHPExcel_NamedRange[]
  74. */
  75. private $namedRanges = array();
  76. /**
  77. * CellXf supervisor
  78. *
  79. * @var PHPExcel_Style
  80. */
  81. private $cellXfSupervisor;
  82. /**
  83. * CellXf collection
  84. *
  85. * @var PHPExcel_Style[]
  86. */
  87. private $cellXfCollection = array();
  88. /**
  89. * CellStyleXf collection
  90. *
  91. * @var PHPExcel_Style[]
  92. */
  93. private $cellStyleXfCollection = array();
  94. /**
  95. * hasMacros : this workbook have macros ?
  96. *
  97. * @var bool
  98. */
  99. private $hasMacros = false;
  100. /**
  101. * macrosCode : all macros code (the vbaProject.bin file, this include form, code, etc.), null if no macro
  102. *
  103. * @var binary
  104. */
  105. private $macrosCode;
  106. /**
  107. * macrosCertificate : if macros are signed, contains vbaProjectSignature.bin file, null if not signed
  108. *
  109. * @var binary
  110. */
  111. private $macrosCertificate;
  112. /**
  113. * ribbonXMLData : null if workbook is'nt Excel 2007 or not contain a customized UI
  114. *
  115. * @var null|string
  116. */
  117. private $ribbonXMLData;
  118. /**
  119. * ribbonBinObjects : null if workbook is'nt Excel 2007 or not contain embedded objects (picture(s)) for Ribbon Elements
  120. * ignored if $ribbonXMLData is null
  121. *
  122. * @var null|array
  123. */
  124. private $ribbonBinObjects;
  125. /**
  126. * The workbook has macros ?
  127. *
  128. * @return boolean true if workbook has macros, false if not
  129. */
  130. public function hasMacros()
  131. {
  132. return $this->hasMacros;
  133. }
  134. /**
  135. * Define if a workbook has macros
  136. *
  137. * @param boolean $hasMacros true|false
  138. */
  139. public function setHasMacros($hasMacros = false)
  140. {
  141. $this->hasMacros = (bool) $hasMacros;
  142. }
  143. /**
  144. * Set the macros code
  145. *
  146. * @param string $MacrosCode string|null
  147. */
  148. public function setMacrosCode($MacrosCode = null)
  149. {
  150. $this->macrosCode=$MacrosCode;
  151. $this->setHasMacros(!is_null($MacrosCode));
  152. }
  153. /**
  154. * Return the macros code
  155. *
  156. * @return string|null
  157. */
  158. public function getMacrosCode()
  159. {
  160. return $this->macrosCode;
  161. }
  162. /**
  163. * Set the macros certificate
  164. *
  165. * @param string|null $Certificate
  166. */
  167. public function setMacrosCertificate($Certificate = null)
  168. {
  169. $this->macrosCertificate=$Certificate;
  170. }
  171. /**
  172. * Is the project signed ?
  173. *
  174. * @return boolean true|false
  175. */
  176. public function hasMacrosCertificate()
  177. {
  178. return !is_null($this->macrosCertificate);
  179. }
  180. /**
  181. * Return the macros certificate
  182. *
  183. * @return string|null
  184. */
  185. public function getMacrosCertificate()
  186. {
  187. return $this->macrosCertificate;
  188. }
  189. /**
  190. * Remove all macros, certificate from spreadsheet
  191. *
  192. */
  193. public function discardMacros()
  194. {
  195. $this->hasMacros=false;
  196. $this->macrosCode=null;
  197. $this->macrosCertificate=null;
  198. }
  199. /**
  200. * set ribbon XML data
  201. *
  202. */
  203. public function setRibbonXMLData($Target = null, $XMLData = null)
  204. {
  205. if (!is_null($Target) && !is_null($XMLData)) {
  206. $this->ribbonXMLData = array('target' => $Target, 'data' => $XMLData);
  207. } else {
  208. $this->ribbonXMLData = null;
  209. }
  210. }
  211. /**
  212. * retrieve ribbon XML Data
  213. *
  214. * return string|null|array
  215. */
  216. public function getRibbonXMLData($What = 'all') //we need some constants here...
  217. {
  218. $ReturnData = null;
  219. $What = strtolower($What);
  220. switch ($What){
  221. case 'all':
  222. $ReturnData = $this->ribbonXMLData;
  223. break;
  224. case 'target':
  225. case 'data':
  226. if (is_array($this->ribbonXMLData) && array_key_exists($What, $this->ribbonXMLData)) {
  227. $ReturnData = $this->ribbonXMLData[$What];
  228. }
  229. break;
  230. }
  231. return $ReturnData;
  232. }
  233. /**
  234. * store binaries ribbon objects (pictures)
  235. *
  236. */
  237. public function setRibbonBinObjects($BinObjectsNames = null, $BinObjectsData = null)
  238. {
  239. if (!is_null($BinObjectsNames) && !is_null($BinObjectsData)) {
  240. $this->ribbonBinObjects = array('names' => $BinObjectsNames, 'data' => $BinObjectsData);
  241. } else {
  242. $this->ribbonBinObjects = null;
  243. }
  244. }
  245. /**
  246. * return the extension of a filename. Internal use for a array_map callback (php<5.3 don't like lambda function)
  247. *
  248. */
  249. private function getExtensionOnly($ThePath)
  250. {
  251. return pathinfo($ThePath, PATHINFO_EXTENSION);
  252. }
  253. /**
  254. * retrieve Binaries Ribbon Objects
  255. *
  256. */
  257. public function getRibbonBinObjects($What = 'all')
  258. {
  259. $ReturnData = null;
  260. $What = strtolower($What);
  261. switch($What) {
  262. case 'all':
  263. return $this->ribbonBinObjects;
  264. break;
  265. case 'names':
  266. case 'data':
  267. if (is_array($this->ribbonBinObjects) && array_key_exists($What, $this->ribbonBinObjects)) {
  268. $ReturnData=$this->ribbonBinObjects[$What];
  269. }
  270. break;
  271. case 'types':
  272. if (is_array($this->ribbonBinObjects) &&
  273. array_key_exists('data', $this->ribbonBinObjects) && is_array($this->ribbonBinObjects['data'])) {
  274. $tmpTypes=array_keys($this->ribbonBinObjects['data']);
  275. $ReturnData = array_unique(array_map(array($this, 'getExtensionOnly'), $tmpTypes));
  276. } else {
  277. $ReturnData=array(); // the caller want an array... not null if empty
  278. }
  279. break;
  280. }
  281. return $ReturnData;
  282. }
  283. /**
  284. * This workbook have a custom UI ?
  285. *
  286. * @return boolean true|false
  287. */
  288. public function hasRibbon()
  289. {
  290. return !is_null($this->ribbonXMLData);
  291. }
  292. /**
  293. * This workbook have additionnal object for the ribbon ?
  294. *
  295. * @return boolean true|false
  296. */
  297. public function hasRibbonBinObjects()
  298. {
  299. return !is_null($this->ribbonBinObjects);
  300. }
  301. /**
  302. * Check if a sheet with a specified code name already exists
  303. *
  304. * @param string $pSheetCodeName Name of the worksheet to check
  305. * @return boolean
  306. */
  307. public function sheetCodeNameExists($pSheetCodeName)
  308. {
  309. return ($this->getSheetByCodeName($pSheetCodeName) !== null);
  310. }
  311. /**
  312. * Get sheet by code name. Warning : sheet don't have always a code name !
  313. *
  314. * @param string $pName Sheet name
  315. * @return PHPExcel_Worksheet
  316. */
  317. public function getSheetByCodeName($pName = '')
  318. {
  319. $worksheetCount = count($this->workSheetCollection);
  320. for ($i = 0; $i < $worksheetCount; ++$i) {
  321. if ($this->workSheetCollection[$i]->getCodeName() == $pName) {
  322. return $this->workSheetCollection[$i];
  323. }
  324. }
  325. return null;
  326. }
  327. /**
  328. * Create a new PHPExcel with one Worksheet
  329. */
  330. public function __construct()
  331. {
  332. $this->uniqueID = uniqid();
  333. $this->calculationEngine = new PHPExcel_Calculation($this);
  334. // Initialise worksheet collection and add one worksheet
  335. $this->workSheetCollection = array();
  336. $this->workSheetCollection[] = new PHPExcel_Worksheet($this);
  337. $this->activeSheetIndex = 0;
  338. // Create document properties
  339. $this->properties = new PHPExcel_DocumentProperties();
  340. // Create document security
  341. $this->security = new PHPExcel_DocumentSecurity();
  342. // Set named ranges
  343. $this->namedRanges = array();
  344. // Create the cellXf supervisor
  345. $this->cellXfSupervisor = new PHPExcel_Style(true);
  346. $this->cellXfSupervisor->bindParent($this);
  347. // Create the default style
  348. $this->addCellXf(new PHPExcel_Style);
  349. $this->addCellStyleXf(new PHPExcel_Style);
  350. }
  351. /**
  352. * Code to execute when this worksheet is unset()
  353. *
  354. */
  355. public function __destruct()
  356. {
  357. $this->calculationEngine = null;
  358. $this->disconnectWorksheets();
  359. }
  360. /**
  361. * Disconnect all worksheets from this PHPExcel workbook object,
  362. * typically so that the PHPExcel object can be unset
  363. *
  364. */
  365. public function disconnectWorksheets()
  366. {
  367. $worksheet = null;
  368. foreach ($this->workSheetCollection as $k => &$worksheet) {
  369. $worksheet->disconnectCells();
  370. $this->workSheetCollection[$k] = null;
  371. }
  372. unset($worksheet);
  373. $this->workSheetCollection = array();
  374. }
  375. /**
  376. * Return the calculation engine for this worksheet
  377. *
  378. * @return PHPExcel_Calculation
  379. */
  380. public function getCalculationEngine()
  381. {
  382. return $this->calculationEngine;
  383. } // function getCellCacheController()
  384. /**
  385. * Get properties
  386. *
  387. * @return PHPExcel_DocumentProperties
  388. */
  389. public function getProperties()
  390. {
  391. return $this->properties;
  392. }
  393. /**
  394. * Set properties
  395. *
  396. * @param PHPExcel_DocumentProperties $pValue
  397. */
  398. public function setProperties(PHPExcel_DocumentProperties $pValue)
  399. {
  400. $this->properties = $pValue;
  401. }
  402. /**
  403. * Get security
  404. *
  405. * @return PHPExcel_DocumentSecurity
  406. */
  407. public function getSecurity()
  408. {
  409. return $this->security;
  410. }
  411. /**
  412. * Set security
  413. *
  414. * @param PHPExcel_DocumentSecurity $pValue
  415. */
  416. public function setSecurity(PHPExcel_DocumentSecurity $pValue)
  417. {
  418. $this->security = $pValue;
  419. }
  420. /**
  421. * Get active sheet
  422. *
  423. * @return PHPExcel_Worksheet
  424. *
  425. * @throws PHPExcel_Exception
  426. */
  427. public function getActiveSheet()
  428. {
  429. return $this->getSheet($this->activeSheetIndex);
  430. }
  431. /**
  432. * Create sheet and add it to this workbook
  433. *
  434. * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
  435. * @return PHPExcel_Worksheet
  436. * @throws PHPExcel_Exception
  437. */
  438. public function createSheet($iSheetIndex = null)
  439. {
  440. $newSheet = new PHPExcel_Worksheet($this);
  441. $this->addSheet($newSheet, $iSheetIndex);
  442. return $newSheet;
  443. }
  444. /**
  445. * Check if a sheet with a specified name already exists
  446. *
  447. * @param string $pSheetName Name of the worksheet to check
  448. * @return boolean
  449. */
  450. public function sheetNameExists($pSheetName)
  451. {
  452. return ($this->getSheetByName($pSheetName) !== null);
  453. }
  454. /**
  455. * Add sheet
  456. *
  457. * @param PHPExcel_Worksheet $pSheet
  458. * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
  459. * @return PHPExcel_Worksheet
  460. * @throws PHPExcel_Exception
  461. */
  462. public function addSheet(PHPExcel_Worksheet $pSheet, $iSheetIndex = null)
  463. {
  464. if ($this->sheetNameExists($pSheet->getTitle())) {
  465. throw new PHPExcel_Exception(
  466. "Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename this worksheet first."
  467. );
  468. }
  469. if ($iSheetIndex === null) {
  470. if ($this->activeSheetIndex < 0) {
  471. $this->activeSheetIndex = 0;
  472. }
  473. $this->workSheetCollection[] = $pSheet;
  474. } else {
  475. // Insert the sheet at the requested index
  476. array_splice(
  477. $this->workSheetCollection,
  478. $iSheetIndex,
  479. 0,
  480. array($pSheet)
  481. );
  482. // Adjust active sheet index if necessary
  483. if ($this->activeSheetIndex >= $iSheetIndex) {
  484. ++$this->activeSheetIndex;
  485. }
  486. }
  487. if ($pSheet->getParent() === null) {
  488. $pSheet->rebindParent($this);
  489. }
  490. return $pSheet;
  491. }
  492. /**
  493. * Remove sheet by index
  494. *
  495. * @param int $pIndex Active sheet index
  496. * @throws PHPExcel_Exception
  497. */
  498. public function removeSheetByIndex($pIndex = 0)
  499. {
  500. $numSheets = count($this->workSheetCollection);
  501. if ($pIndex > $numSheets - 1) {
  502. throw new PHPExcel_Exception(
  503. "You tried to remove a sheet by the out of bounds index: {$pIndex}. The actual number of sheets is {$numSheets}."
  504. );
  505. } else {
  506. array_splice($this->workSheetCollection, $pIndex, 1);
  507. }
  508. // Adjust active sheet index if necessary
  509. if (($this->activeSheetIndex >= $pIndex) &&
  510. ($pIndex > count($this->workSheetCollection) - 1)) {
  511. --$this->activeSheetIndex;
  512. }
  513. }
  514. /**
  515. * Get sheet by index
  516. *
  517. * @param int $pIndex Sheet index
  518. * @return PHPExcel_Worksheet
  519. * @throws PHPExcel_Exception
  520. */
  521. public function getSheet($pIndex = 0)
  522. {
  523. if (!isset($this->workSheetCollection[$pIndex])) {
  524. $numSheets = $this->getSheetCount();
  525. throw new PHPExcel_Exception(
  526. "Your requested sheet index: {$pIndex} is out of bounds. The actual number of sheets is {$numSheets}."
  527. );
  528. }
  529. return $this->workSheetCollection[$pIndex];
  530. }
  531. /**
  532. * Get all sheets
  533. *
  534. * @return PHPExcel_Worksheet[]
  535. */
  536. public function getAllSheets()
  537. {
  538. return $this->workSheetCollection;
  539. }
  540. /**
  541. * Get sheet by name
  542. *
  543. * @param string $pName Sheet name
  544. * @return PHPExcel_Worksheet
  545. */
  546. public function getSheetByName($pName = '')
  547. {
  548. $worksheetCount = count($this->workSheetCollection);
  549. for ($i = 0; $i < $worksheetCount; ++$i) {
  550. if ($this->workSheetCollection[$i]->getTitle() === $pName) {
  551. return $this->workSheetCollection[$i];
  552. }
  553. }
  554. return null;
  555. }
  556. /**
  557. * Get index for sheet
  558. *
  559. * @param PHPExcel_Worksheet $pSheet
  560. * @return int Sheet index
  561. * @throws PHPExcel_Exception
  562. */
  563. public function getIndex(PHPExcel_Worksheet $pSheet)
  564. {
  565. foreach ($this->workSheetCollection as $key => $value) {
  566. if ($value->getHashCode() == $pSheet->getHashCode()) {
  567. return $key;
  568. }
  569. }
  570. throw new PHPExcel_Exception("Sheet does not exist.");
  571. }
  572. /**
  573. * Set index for sheet by sheet name.
  574. *
  575. * @param string $sheetName Sheet name to modify index for
  576. * @param int $newIndex New index for the sheet
  577. * @return int New sheet index
  578. * @throws PHPExcel_Exception
  579. */
  580. public function setIndexByName($sheetName, $newIndex)
  581. {
  582. $oldIndex = $this->getIndex($this->getSheetByName($sheetName));
  583. $pSheet = array_splice(
  584. $this->workSheetCollection,
  585. $oldIndex,
  586. 1
  587. );
  588. array_splice(
  589. $this->workSheetCollection,
  590. $newIndex,
  591. 0,
  592. $pSheet
  593. );
  594. return $newIndex;
  595. }
  596. /**
  597. * Get sheet count
  598. *
  599. * @return int
  600. */
  601. public function getSheetCount()
  602. {
  603. return count($this->workSheetCollection);
  604. }
  605. /**
  606. * Get active sheet index
  607. *
  608. * @return int Active sheet index
  609. */
  610. public function getActiveSheetIndex()
  611. {
  612. return $this->activeSheetIndex;
  613. }
  614. /**
  615. * Set active sheet index
  616. *
  617. * @param int $pIndex Active sheet index
  618. * @throws PHPExcel_Exception
  619. * @return PHPExcel_Worksheet
  620. */
  621. public function setActiveSheetIndex($pIndex = 0)
  622. {
  623. $numSheets = count($this->workSheetCollection);
  624. if ($pIndex > $numSheets - 1) {
  625. throw new PHPExcel_Exception(
  626. "You tried to set a sheet active by the out of bounds index: {$pIndex}. The actual number of sheets is {$numSheets}."
  627. );
  628. } else {
  629. $this->activeSheetIndex = $pIndex;
  630. }
  631. return $this->getActiveSheet();
  632. }
  633. /**
  634. * Set active sheet index by name
  635. *
  636. * @param string $pValue Sheet title
  637. * @return PHPExcel_Worksheet
  638. * @throws PHPExcel_Exception
  639. */
  640. public function setActiveSheetIndexByName($pValue = '')
  641. {
  642. if (($worksheet = $this->getSheetByName($pValue)) instanceof PHPExcel_Worksheet) {
  643. $this->setActiveSheetIndex($this->getIndex($worksheet));
  644. return $worksheet;
  645. }
  646. throw new PHPExcel_Exception('Workbook does not contain sheet:' . $pValue);
  647. }
  648. /**
  649. * Get sheet names
  650. *
  651. * @return string[]
  652. */
  653. public function getSheetNames()
  654. {
  655. $returnValue = array();
  656. $worksheetCount = $this->getSheetCount();
  657. for ($i = 0; $i < $worksheetCount; ++$i) {
  658. $returnValue[] = $this->getSheet($i)->getTitle();
  659. }
  660. return $returnValue;
  661. }
  662. /**
  663. * Add external sheet
  664. *
  665. * @param PHPExcel_Worksheet $pSheet External sheet to add
  666. * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
  667. * @throws PHPExcel_Exception
  668. * @return PHPExcel_Worksheet
  669. */
  670. public function addExternalSheet(PHPExcel_Worksheet $pSheet, $iSheetIndex = null)
  671. {
  672. if ($this->sheetNameExists($pSheet->getTitle())) {
  673. throw new PHPExcel_Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename the external sheet first.");
  674. }
  675. // count how many cellXfs there are in this workbook currently, we will need this below
  676. $countCellXfs = count($this->cellXfCollection);
  677. // copy all the shared cellXfs from the external workbook and append them to the current
  678. foreach ($pSheet->getParent()->getCellXfCollection() as $cellXf) {
  679. $this->addCellXf(clone $cellXf);
  680. }
  681. // move sheet to this workbook
  682. $pSheet->rebindParent($this);
  683. // update the cellXfs
  684. foreach ($pSheet->getCellCollection(false) as $cellID) {
  685. $cell = $pSheet->getCell($cellID);
  686. $cell->setXfIndex($cell->getXfIndex() + $countCellXfs);
  687. }
  688. return $this->addSheet($pSheet, $iSheetIndex);
  689. }
  690. /**
  691. * Get named ranges
  692. *
  693. * @return PHPExcel_NamedRange[]
  694. */
  695. public function getNamedRanges()
  696. {
  697. return $this->namedRanges;
  698. }
  699. /**
  700. * Add named range
  701. *
  702. * @param PHPExcel_NamedRange $namedRange
  703. * @return boolean
  704. */
  705. public function addNamedRange(PHPExcel_NamedRange $namedRange)
  706. {
  707. if ($namedRange->getScope() == null) {
  708. // global scope
  709. $this->namedRanges[$namedRange->getName()] = $namedRange;
  710. } else {
  711. // local scope
  712. $this->namedRanges[$namedRange->getScope()->getTitle().'!'.$namedRange->getName()] = $namedRange;
  713. }
  714. return true;
  715. }
  716. /**
  717. * Get named range
  718. *
  719. * @param string $namedRange
  720. * @param PHPExcel_Worksheet|null $pSheet Scope. Use null for global scope
  721. * @return PHPExcel_NamedRange|null
  722. */
  723. public function getNamedRange($namedRange, PHPExcel_Worksheet $pSheet = null)
  724. {
  725. $returnValue = null;
  726. if ($namedRange != '' && ($namedRange !== null)) {
  727. // first look for global defined name
  728. if (isset($this->namedRanges[$namedRange])) {
  729. $returnValue = $this->namedRanges[$namedRange];
  730. }
  731. // then look for local defined name (has priority over global defined name if both names exist)
  732. if (($pSheet !== null) && isset($this->namedRanges[$pSheet->getTitle() . '!' . $namedRange])) {
  733. $returnValue = $this->namedRanges[$pSheet->getTitle() . '!' . $namedRange];
  734. }
  735. }
  736. return $returnValue;
  737. }
  738. /**
  739. * Remove named range
  740. *
  741. * @param string $namedRange
  742. * @param PHPExcel_Worksheet|null $pSheet Scope: use null for global scope.
  743. * @return PHPExcel
  744. */
  745. public function removeNamedRange($namedRange, PHPExcel_Worksheet $pSheet = null)
  746. {
  747. if ($pSheet === null) {
  748. if (isset($this->namedRanges[$namedRange])) {
  749. unset($this->namedRanges[$namedRange]);
  750. }
  751. } else {
  752. if (isset($this->namedRanges[$pSheet->getTitle() . '!' . $namedRange])) {
  753. unset($this->namedRanges[$pSheet->getTitle() . '!' . $namedRange]);
  754. }
  755. }
  756. return $this;
  757. }
  758. /**
  759. * Get worksheet iterator
  760. *
  761. * @return PHPExcel_WorksheetIterator
  762. */
  763. public function getWorksheetIterator()
  764. {
  765. return new PHPExcel_WorksheetIterator($this);
  766. }
  767. /**
  768. * Copy workbook (!= clone!)
  769. *
  770. * @return PHPExcel
  771. */
  772. public function copy()
  773. {
  774. $copied = clone $this;
  775. $worksheetCount = count($this->workSheetCollection);
  776. for ($i = 0; $i < $worksheetCount; ++$i) {
  777. $this->workSheetCollection[$i] = $this->workSheetCollection[$i]->copy();
  778. $this->workSheetCollection[$i]->rebindParent($this);
  779. }
  780. return $copied;
  781. }
  782. /**
  783. * Implement PHP __clone to create a deep clone, not just a shallow copy.
  784. */
  785. public function __clone()
  786. {
  787. foreach ($this as $key => $val) {
  788. if (is_object($val) || (is_array($val))) {
  789. $this->{$key} = unserialize(serialize($val));
  790. }
  791. }
  792. }
  793. /**
  794. * Get the workbook collection of cellXfs
  795. *
  796. * @return PHPExcel_Style[]
  797. */
  798. public function getCellXfCollection()
  799. {
  800. return $this->cellXfCollection;
  801. }
  802. /**
  803. * Get cellXf by index
  804. *
  805. * @param int $pIndex
  806. * @return PHPExcel_Style
  807. */
  808. public function getCellXfByIndex($pIndex = 0)
  809. {
  810. return $this->cellXfCollection[$pIndex];
  811. }
  812. /**
  813. * Get cellXf by hash code
  814. *
  815. * @param string $pValue
  816. * @return PHPExcel_Style|boolean False if no match found
  817. */
  818. public function getCellXfByHashCode($pValue = '')
  819. {
  820. foreach ($this->cellXfCollection as $cellXf) {
  821. if ($cellXf->getHashCode() == $pValue) {
  822. return $cellXf;
  823. }
  824. }
  825. return false;
  826. }
  827. /**
  828. * Check if style exists in style collection
  829. *
  830. * @param PHPExcel_Style $pCellStyle
  831. * @return boolean
  832. */
  833. public function cellXfExists($pCellStyle = null)
  834. {
  835. return in_array($pCellStyle, $this->cellXfCollection, true);
  836. }
  837. /**
  838. * Get default style
  839. *
  840. * @return PHPExcel_Style
  841. * @throws PHPExcel_Exception
  842. */
  843. public function getDefaultStyle()
  844. {
  845. if (isset($this->cellXfCollection[0])) {
  846. return $this->cellXfCollection[0];
  847. }
  848. throw new PHPExcel_Exception('No default style found for this workbook');
  849. }
  850. /**
  851. * Add a cellXf to the workbook
  852. *
  853. * @param PHPExcel_Style $style
  854. */
  855. public function addCellXf(PHPExcel_Style $style)
  856. {
  857. $this->cellXfCollection[] = $style;
  858. $style->setIndex(count($this->cellXfCollection) - 1);
  859. }
  860. /**
  861. * Remove cellXf by index. It is ensured that all cells get their xf index updated.
  862. *
  863. * @param integer $pIndex Index to cellXf
  864. * @throws PHPExcel_Exception
  865. */
  866. public function removeCellXfByIndex($pIndex = 0)
  867. {
  868. if ($pIndex > count($this->cellXfCollection) - 1) {
  869. throw new PHPExcel_Exception("CellXf index is out of bounds.");
  870. } else {
  871. // first remove the cellXf
  872. array_splice($this->cellXfCollection, $pIndex, 1);
  873. // then update cellXf indexes for cells
  874. foreach ($this->workSheetCollection as $worksheet) {
  875. foreach ($worksheet->getCellCollection(false) as $cellID) {
  876. $cell = $worksheet->getCell($cellID);
  877. $xfIndex = $cell->getXfIndex();
  878. if ($xfIndex > $pIndex) {
  879. // decrease xf index by 1
  880. $cell->setXfIndex($xfIndex - 1);
  881. } elseif ($xfIndex == $pIndex) {
  882. // set to default xf index 0
  883. $cell->setXfIndex(0);
  884. }
  885. }
  886. }
  887. }
  888. }
  889. /**
  890. * Get the cellXf supervisor
  891. *
  892. * @return PHPExcel_Style
  893. */
  894. public function getCellXfSupervisor()
  895. {
  896. return $this->cellXfSupervisor;
  897. }
  898. /**
  899. * Get the workbook collection of cellStyleXfs
  900. *
  901. * @return PHPExcel_Style[]
  902. */
  903. public function getCellStyleXfCollection()
  904. {
  905. return $this->cellStyleXfCollection;
  906. }
  907. /**
  908. * Get cellStyleXf by index
  909. *
  910. * @param integer $pIndex Index to cellXf
  911. * @return PHPExcel_Style
  912. */
  913. public function getCellStyleXfByIndex($pIndex = 0)
  914. {
  915. return $this->cellStyleXfCollection[$pIndex];
  916. }
  917. /**
  918. * Get cellStyleXf by hash code
  919. *
  920. * @param string $pValue
  921. * @return PHPExcel_Style|boolean False if no match found
  922. */
  923. public function getCellStyleXfByHashCode($pValue = '')
  924. {
  925. foreach ($this->cellStyleXfCollection as $cellStyleXf) {
  926. if ($cellStyleXf->getHashCode() == $pValue) {
  927. return $cellStyleXf;
  928. }
  929. }
  930. return false;
  931. }
  932. /**
  933. * Add a cellStyleXf to the workbook
  934. *
  935. * @param PHPExcel_Style $pStyle
  936. */
  937. public function addCellStyleXf(PHPExcel_Style $pStyle)
  938. {
  939. $this->cellStyleXfCollection[] = $pStyle;
  940. $pStyle->setIndex(count($this->cellStyleXfCollection) - 1);
  941. }
  942. /**
  943. * Remove cellStyleXf by index
  944. *
  945. * @param integer $pIndex Index to cellXf
  946. * @throws PHPExcel_Exception
  947. */
  948. public function removeCellStyleXfByIndex($pIndex = 0)
  949. {
  950. if ($pIndex > count($this->cellStyleXfCollection) - 1) {
  951. throw new PHPExcel_Exception("CellStyleXf index is out of bounds.");
  952. } else {
  953. array_splice($this->cellStyleXfCollection, $pIndex, 1);
  954. }
  955. }
  956. /**
  957. * Eliminate all unneeded cellXf and afterwards update the xfIndex for all cells
  958. * and columns in the workbook
  959. */
  960. public function garbageCollect()
  961. {
  962. // how many references are there to each cellXf ?
  963. $countReferencesCellXf = array();
  964. foreach ($this->cellXfCollection as $index => $cellXf) {
  965. $countReferencesCellXf[$index] = 0;
  966. }
  967. foreach ($this->getWorksheetIterator() as $sheet) {
  968. // from cells
  969. foreach ($sheet->getCellCollection(false) as $cellID) {
  970. $cell = $sheet->getCell($cellID);
  971. ++$countReferencesCellXf[$cell->getXfIndex()];
  972. }
  973. // from row dimensions
  974. foreach ($sheet->getRowDimensions() as $rowDimension) {
  975. if ($rowDimension->getXfIndex() !== null) {
  976. ++$countReferencesCellXf[$rowDimension->getXfIndex()];
  977. }
  978. }
  979. // from column dimensions
  980. foreach ($sheet->getColumnDimensions() as $columnDimension) {
  981. ++$countReferencesCellXf[$columnDimension->getXfIndex()];
  982. }
  983. }
  984. // remove cellXfs without references and create mapping so we can update xfIndex
  985. // for all cells and columns
  986. $countNeededCellXfs = 0;
  987. $map = array();
  988. foreach ($this->cellXfCollection as $index => $cellXf) {
  989. if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf
  990. ++$countNeededCellXfs;
  991. } else {
  992. unset($this->cellXfCollection[$index]);
  993. }
  994. $map[$index] = $countNeededCellXfs - 1;
  995. }
  996. $this->cellXfCollection = array_values($this->cellXfCollection);
  997. // update the index for all cellXfs
  998. foreach ($this->cellXfCollection as $i => $cellXf) {
  999. $cellXf->setIndex($i);
  1000. }
  1001. // make sure there is always at least one cellXf (there should be)
  1002. if (empty($this->cellXfCollection)) {
  1003. $this->cellXfCollection[] = new PHPExcel_Style();
  1004. }
  1005. // update the xfIndex for all cells, row dimensions, column dimensions
  1006. foreach ($this->getWorksheetIterator() as $sheet) {
  1007. // for all cells
  1008. foreach ($sheet->getCellCollection(false) as $cellID) {
  1009. $cell = $sheet->getCell($cellID);
  1010. $cell->setXfIndex($map[$cell->getXfIndex()]);
  1011. }
  1012. // for all row dimensions
  1013. foreach ($sheet->getRowDimensions() as $rowDimension) {
  1014. if ($rowDimension->getXfIndex() !== null) {
  1015. $rowDimension->setXfIndex($map[$rowDimension->getXfIndex()]);
  1016. }
  1017. }
  1018. // for all column dimensions
  1019. foreach ($sheet->getColumnDimensions() as $columnDimension) {
  1020. $columnDimension->setXfIndex($map[$columnDimension->getXfIndex()]);
  1021. }
  1022. // also do garbage collection for all the sheets
  1023. $sheet->garbageCollect();
  1024. }
  1025. }
  1026. /**
  1027. * Return the unique ID value assigned to this spreadsheet workbook
  1028. *
  1029. * @return string
  1030. */
  1031. public function getID()
  1032. {
  1033. return $this->uniqueID;
  1034. }
  1035. }