PHPExcel.php 32 KB

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