PHPExcel.php 30 KB

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