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.

2051 lines
132 KiB

  1. <?php
  2. /** PHPExcel root directory */
  3. if (!defined('PHPEXCEL_ROOT')) {
  4. /**
  5. * @ignore
  6. */
  7. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
  8. require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  9. }
  10. /**
  11. * PHPExcel_Reader_Excel2007
  12. *
  13. * Copyright (c) 2006 - 2015 PHPExcel
  14. *
  15. * This library is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU Lesser General Public
  17. * License as published by the Free Software Foundation; either
  18. * version 2.1 of the License, or (at your option) any later version.
  19. *
  20. * This library is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  23. * Lesser General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Lesser General Public
  26. * License along with this library; if not, write to the Free Software
  27. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  28. *
  29. * @category PHPExcel
  30. * @package PHPExcel_Reader
  31. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  32. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  33. * @version ##VERSION##, ##DATE##
  34. */
  35. class PHPExcel_Reader_Excel2007 extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
  36. {
  37. /**
  38. * PHPExcel_ReferenceHelper instance
  39. *
  40. * @var PHPExcel_ReferenceHelper
  41. */
  42. private $referenceHelper = null;
  43. /**
  44. * PHPExcel_Reader_Excel2007_Theme instance
  45. *
  46. * @var PHPExcel_Reader_Excel2007_Theme
  47. */
  48. private static $theme = null;
  49. /**
  50. * Create a new PHPExcel_Reader_Excel2007 instance
  51. */
  52. public function __construct()
  53. {
  54. $this->readFilter = new PHPExcel_Reader_DefaultReadFilter();
  55. $this->referenceHelper = PHPExcel_ReferenceHelper::getInstance();
  56. }
  57. /**
  58. * Can the current PHPExcel_Reader_IReader read the file?
  59. *
  60. * @param string $pFilename
  61. * @return boolean
  62. * @throws PHPExcel_Reader_Exception
  63. */
  64. public function canRead($pFilename)
  65. {
  66. // Check if file exists
  67. if (!file_exists($pFilename)) {
  68. throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
  69. }
  70. $zipClass = PHPExcel_Settings::getZipClass();
  71. // Check if zip class exists
  72. // if (!class_exists($zipClass, false)) {
  73. // throw new PHPExcel_Reader_Exception($zipClass . " library is not enabled");
  74. // }
  75. $xl = false;
  76. // Load file
  77. $zip = new $zipClass;
  78. if ($zip->open($pFilename) === true) {
  79. // check if it is an OOXML archive
  80. $rels = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "_rels/.rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  81. if ($rels !== false) {
  82. foreach ($rels->Relationship as $rel) {
  83. switch ($rel["Type"]) {
  84. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
  85. if (basename($rel["Target"]) == 'workbook.xml') {
  86. $xl = true;
  87. }
  88. break;
  89. }
  90. }
  91. }
  92. $zip->close();
  93. }
  94. return $xl;
  95. }
  96. /**
  97. * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
  98. *
  99. * @param string $pFilename
  100. * @throws PHPExcel_Reader_Exception
  101. */
  102. public function listWorksheetNames($pFilename)
  103. {
  104. // Check if file exists
  105. if (!file_exists($pFilename)) {
  106. throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
  107. }
  108. $worksheetNames = array();
  109. $zipClass = PHPExcel_Settings::getZipClass();
  110. $zip = new $zipClass;
  111. $zip->open($pFilename);
  112. // The files we're looking at here are small enough that simpleXML is more efficient than XMLReader
  113. $rels = simplexml_load_string(
  114. $this->securityScan($this->getFromZipArchive($zip, "_rels/.rels"), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions())
  115. ); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  116. foreach ($rels->Relationship as $rel) {
  117. switch ($rel["Type"]) {
  118. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
  119. $xmlWorkbook = simplexml_load_string(
  120. $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}"), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions())
  121. ); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  122. if ($xmlWorkbook->sheets) {
  123. foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
  124. // Check if sheet should be skipped
  125. $worksheetNames[] = (string) $eleSheet["name"];
  126. }
  127. }
  128. }
  129. }
  130. $zip->close();
  131. return $worksheetNames;
  132. }
  133. /**
  134. * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
  135. *
  136. * @param string $pFilename
  137. * @throws PHPExcel_Reader_Exception
  138. */
  139. public function listWorksheetInfo($pFilename)
  140. {
  141. // Check if file exists
  142. if (!file_exists($pFilename)) {
  143. throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
  144. }
  145. $worksheetInfo = array();
  146. $zipClass = PHPExcel_Settings::getZipClass();
  147. $zip = new $zipClass;
  148. $zip->open($pFilename);
  149. $rels = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "_rels/.rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  150. foreach ($rels->Relationship as $rel) {
  151. if ($rel["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument") {
  152. $dir = dirname($rel["Target"]);
  153. $relsWorkbook = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel["Target"]) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  154. $relsWorkbook->registerXPathNamespace("rel", "http://schemas.openxmlformats.org/package/2006/relationships");
  155. $worksheets = array();
  156. foreach ($relsWorkbook->Relationship as $ele) {
  157. if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet") {
  158. $worksheets[(string) $ele["Id"]] = $ele["Target"];
  159. }
  160. }
  161. $xmlWorkbook = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  162. if ($xmlWorkbook->sheets) {
  163. $dir = dirname($rel["Target"]);
  164. foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
  165. $tmpInfo = array(
  166. 'worksheetName' => (string) $eleSheet["name"],
  167. 'lastColumnLetter' => 'A',
  168. 'lastColumnIndex' => 0,
  169. 'totalRows' => 0,
  170. 'totalColumns' => 0,
  171. );
  172. $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "id")];
  173. $xml = new XMLReader();
  174. $res = $xml->xml($this->securityScanFile('zip://'.PHPExcel_Shared_File::realpath($pFilename).'#'."$dir/$fileWorksheet"), null, PHPExcel_Settings::getLibXmlLoaderOptions());
  175. $xml->setParserProperty(2, true);
  176. $currCells = 0;
  177. while ($xml->read()) {
  178. if ($xml->name == 'row' && $xml->nodeType == XMLReader::ELEMENT) {
  179. $row = $xml->getAttribute('r');
  180. $tmpInfo['totalRows'] = $row;
  181. $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
  182. $currCells = 0;
  183. } elseif ($xml->name == 'c' && $xml->nodeType == XMLReader::ELEMENT) {
  184. $currCells++;
  185. }
  186. }
  187. $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
  188. $xml->close();
  189. $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
  190. $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
  191. $worksheetInfo[] = $tmpInfo;
  192. }
  193. }
  194. }
  195. }
  196. $zip->close();
  197. return $worksheetInfo;
  198. }
  199. private static function castToBoolean($c)
  200. {
  201. // echo 'Initial Cast to Boolean', PHP_EOL;
  202. $value = isset($c->v) ? (string) $c->v : null;
  203. if ($value == '0') {
  204. return false;
  205. } elseif ($value == '1') {
  206. return true;
  207. } else {
  208. return (bool)$c->v;
  209. }
  210. return $value;
  211. }
  212. private static function castToError($c)
  213. {
  214. // echo 'Initial Cast to Error', PHP_EOL;
  215. return isset($c->v) ? (string) $c->v : null;
  216. }
  217. private static function castToString($c)
  218. {
  219. // echo 'Initial Cast to String, PHP_EOL;
  220. return isset($c->v) ? (string) $c->v : null;
  221. }
  222. private function castToFormula($c, $r, &$cellDataType, &$value, &$calculatedValue, &$sharedFormulas, $castBaseType)
  223. {
  224. // echo 'Formula', PHP_EOL;
  225. // echo '$c->f is ', $c->f, PHP_EOL;
  226. $cellDataType = 'f';
  227. $value = "={$c->f}";
  228. $calculatedValue = self::$castBaseType($c);
  229. // Shared formula?
  230. if (isset($c->f['t']) && strtolower((string)$c->f['t']) == 'shared') {
  231. // echo 'SHARED FORMULA', PHP_EOL;
  232. $instance = (string)$c->f['si'];
  233. // echo 'Instance ID = ', $instance, PHP_EOL;
  234. //
  235. // echo 'Shared Formula Array:', PHP_EOL;
  236. // print_r($sharedFormulas);
  237. if (!isset($sharedFormulas[(string)$c->f['si']])) {
  238. // echo 'SETTING NEW SHARED FORMULA', PHP_EOL;
  239. // echo 'Master is ', $r, PHP_EOL;
  240. // echo 'Formula is ', $value, PHP_EOL;
  241. $sharedFormulas[$instance] = array('master' => $r, 'formula' => $value);
  242. // echo 'New Shared Formula Array:', PHP_EOL;
  243. // print_r($sharedFormulas);
  244. } else {
  245. // echo 'GETTING SHARED FORMULA', PHP_EOL;
  246. // echo 'Master is ', $sharedFormulas[$instance]['master'], PHP_EOL;
  247. // echo 'Formula is ', $sharedFormulas[$instance]['formula'], PHP_EOL;
  248. $master = PHPExcel_Cell::coordinateFromString($sharedFormulas[$instance]['master']);
  249. $current = PHPExcel_Cell::coordinateFromString($r);
  250. $difference = array(0, 0);
  251. $difference[0] = PHPExcel_Cell::columnIndexFromString($current[0]) - PHPExcel_Cell::columnIndexFromString($master[0]);
  252. $difference[1] = $current[1] - $master[1];
  253. $value = $this->referenceHelper->updateFormulaReferences($sharedFormulas[$instance]['formula'], 'A1', $difference[0], $difference[1]);
  254. // echo 'Adjusted Formula is ', $value, PHP_EOL;
  255. }
  256. }
  257. }
  258. private function getFromZipArchive($archive, $fileName = '')
  259. {
  260. // Root-relative paths
  261. if (strpos($fileName, '//') !== false) {
  262. $fileName = substr($fileName, strpos($fileName, '//') + 1);
  263. }
  264. $fileName = PHPExcel_Shared_File::realpath($fileName);
  265. // Sadly, some 3rd party xlsx generators don't use consistent case for filenaming
  266. // so we need to load case-insensitively from the zip file
  267. // Apache POI fixes
  268. $contents = $archive->getFromIndex(
  269. $archive->locateName($fileName, ZIPARCHIVE::FL_NOCASE)
  270. );
  271. if ($contents === false) {
  272. $contents = $archive->getFromIndex(
  273. $archive->locateName(substr($fileName, 1), ZIPARCHIVE::FL_NOCASE)
  274. );
  275. }
  276. return $contents;
  277. }
  278. /**
  279. * Loads PHPExcel from file
  280. *
  281. * @param string $pFilename
  282. * @return PHPExcel
  283. * @throws PHPExcel_Reader_Exception
  284. */
  285. public function load($pFilename)
  286. {
  287. // Check if file exists
  288. if (!file_exists($pFilename)) {
  289. throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
  290. }
  291. // Initialisations
  292. $excel = new PHPExcel;
  293. $excel->removeSheetByIndex(0);
  294. if (!$this->readDataOnly) {
  295. $excel->removeCellStyleXfByIndex(0); // remove the default style
  296. $excel->removeCellXfByIndex(0); // remove the default style
  297. }
  298. $zipClass = PHPExcel_Settings::getZipClass();
  299. $zip = new $zipClass;
  300. $zip->open($pFilename);
  301. // Read the theme first, because we need the colour scheme when reading the styles
  302. $wbRels = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "xl/_rels/workbook.xml.rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  303. foreach ($wbRels->Relationship as $rel) {
  304. switch ($rel["Type"]) {
  305. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme":
  306. $themeOrderArray = array('lt1', 'dk1', 'lt2', 'dk2');
  307. $themeOrderAdditional = count($themeOrderArray);
  308. $xmlTheme = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "xl/{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  309. if (is_object($xmlTheme)) {
  310. $xmlThemeName = $xmlTheme->attributes();
  311. $xmlTheme = $xmlTheme->children("http://schemas.openxmlformats.org/drawingml/2006/main");
  312. $themeName = (string)$xmlThemeName['name'];
  313. $colourScheme = $xmlTheme->themeElements->clrScheme->attributes();
  314. $colourSchemeName = (string)$colourScheme['name'];
  315. $colourScheme = $xmlTheme->themeElements->clrScheme->children("http://schemas.openxmlformats.org/drawingml/2006/main");
  316. $themeColours = array();
  317. foreach ($colourScheme as $k => $xmlColour) {
  318. $themePos = array_search($k, $themeOrderArray);
  319. if ($themePos === false) {
  320. $themePos = $themeOrderAdditional++;
  321. }
  322. if (isset($xmlColour->sysClr)) {
  323. $xmlColourData = $xmlColour->sysClr->attributes();
  324. $themeColours[$themePos] = $xmlColourData['lastClr'];
  325. } elseif (isset($xmlColour->srgbClr)) {
  326. $xmlColourData = $xmlColour->srgbClr->attributes();
  327. $themeColours[$themePos] = $xmlColourData['val'];
  328. }
  329. }
  330. self::$theme = new PHPExcel_Reader_Excel2007_Theme($themeName, $colourSchemeName, $themeColours);
  331. }
  332. break;
  333. }
  334. }
  335. $rels = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "_rels/.rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  336. foreach ($rels->Relationship as $rel) {
  337. switch ($rel["Type"]) {
  338. case "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties":
  339. $xmlCore = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  340. if (is_object($xmlCore)) {
  341. $xmlCore->registerXPathNamespace("dc", "http://purl.org/dc/elements/1.1/");
  342. $xmlCore->registerXPathNamespace("dcterms", "http://purl.org/dc/terms/");
  343. $xmlCore->registerXPathNamespace("cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
  344. $docProps = $excel->getProperties();
  345. $docProps->setCreator((string) self::getArrayItem($xmlCore->xpath("dc:creator")));
  346. $docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath("cp:lastModifiedBy")));
  347. $docProps->setCreated(strtotime(self::getArrayItem($xmlCore->xpath("dcterms:created")))); //! respect xsi:type
  348. $docProps->setModified(strtotime(self::getArrayItem($xmlCore->xpath("dcterms:modified")))); //! respect xsi:type
  349. $docProps->setTitle((string) self::getArrayItem($xmlCore->xpath("dc:title")));
  350. $docProps->setDescription((string) self::getArrayItem($xmlCore->xpath("dc:description")));
  351. $docProps->setSubject((string) self::getArrayItem($xmlCore->xpath("dc:subject")));
  352. $docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath("cp:keywords")));
  353. $docProps->setCategory((string) self::getArrayItem($xmlCore->xpath("cp:category")));
  354. }
  355. break;
  356. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties":
  357. $xmlCore = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  358. if (is_object($xmlCore)) {
  359. $docProps = $excel->getProperties();
  360. if (isset($xmlCore->Company)) {
  361. $docProps->setCompany((string) $xmlCore->Company);
  362. }
  363. if (isset($xmlCore->Manager)) {
  364. $docProps->setManager((string) $xmlCore->Manager);
  365. }
  366. }
  367. break;
  368. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties":
  369. $xmlCore = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  370. if (is_object($xmlCore)) {
  371. $docProps = $excel->getProperties();
  372. foreach ($xmlCore as $xmlProperty) {
  373. $cellDataOfficeAttributes = $xmlProperty->attributes();
  374. if (isset($cellDataOfficeAttributes['name'])) {
  375. $propertyName = (string) $cellDataOfficeAttributes['name'];
  376. $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
  377. $attributeType = $cellDataOfficeChildren->getName();
  378. $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
  379. $attributeValue = PHPExcel_DocumentProperties::convertProperty($attributeValue, $attributeType);
  380. $attributeType = PHPExcel_DocumentProperties::convertPropertyType($attributeType);
  381. $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
  382. }
  383. }
  384. }
  385. break;
  386. //Ribbon
  387. case "http://schemas.microsoft.com/office/2006/relationships/ui/extensibility":
  388. $customUI = $rel['Target'];
  389. if (!is_null($customUI)) {
  390. $this->readRibbon($excel, $customUI, $zip);
  391. }
  392. break;
  393. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
  394. $dir = dirname($rel["Target"]);
  395. $relsWorkbook = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel["Target"]) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  396. $relsWorkbook->registerXPathNamespace("rel", "http://schemas.openxmlformats.org/package/2006/relationships");
  397. $sharedStrings = array();
  398. $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
  399. $xmlStrings = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  400. if (isset($xmlStrings) && isset($xmlStrings->si)) {
  401. foreach ($xmlStrings->si as $val) {
  402. if (isset($val->t)) {
  403. $sharedStrings[] = PHPExcel_Shared_String::ControlCharacterOOXML2PHP((string) $val->t);
  404. } elseif (isset($val->r)) {
  405. $sharedStrings[] = $this->parseRichText($val);
  406. }
  407. }
  408. }
  409. $worksheets = array();
  410. $macros = $customUI = null;
  411. foreach ($relsWorkbook->Relationship as $ele) {
  412. switch ($ele['Type']) {
  413. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet":
  414. $worksheets[(string) $ele["Id"]] = $ele["Target"];
  415. break;
  416. // a vbaProject ? (: some macros)
  417. case "http://schemas.microsoft.com/office/2006/relationships/vbaProject":
  418. $macros = $ele["Target"];
  419. break;
  420. }
  421. }
  422. if (!is_null($macros)) {
  423. $macrosCode = $this->getFromZipArchive($zip, 'xl/vbaProject.bin');//vbaProject.bin always in 'xl' dir and always named vbaProject.bin
  424. if ($macrosCode !== false) {
  425. $excel->setMacrosCode($macrosCode);
  426. $excel->setHasMacros(true);
  427. //short-circuit : not reading vbaProject.bin.rel to get Signature =>allways vbaProjectSignature.bin in 'xl' dir
  428. $Certificate = $this->getFromZipArchive($zip, 'xl/vbaProjectSignature.bin');
  429. if ($Certificate !== false) {
  430. $excel->setMacrosCertificate($Certificate);
  431. }
  432. }
  433. }
  434. $styles = array();
  435. $cellStyles = array();
  436. $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
  437. $xmlStyles = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  438. //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  439. $numFmts = null;
  440. if ($xmlStyles && $xmlStyles->numFmts[0]) {
  441. $numFmts = $xmlStyles->numFmts[0];
  442. }
  443. if (isset($numFmts) && ($numFmts !== null)) {
  444. $numFmts->registerXPathNamespace("sml", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  445. }
  446. if (!$this->readDataOnly && $xmlStyles) {
  447. foreach ($xmlStyles->cellXfs->xf as $xf) {
  448. $numFmt = PHPExcel_Style_NumberFormat::FORMAT_GENERAL;
  449. if ($xf["numFmtId"]) {
  450. if (isset($numFmts)) {
  451. $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
  452. if (isset($tmpNumFmt["formatCode"])) {
  453. $numFmt = (string) $tmpNumFmt["formatCode"];
  454. }
  455. }
  456. // We shouldn't override any of the built-in MS Excel values (values below id 164)
  457. // But there's a lot of naughty homebrew xlsx writers that do use "reserved" id values that aren't actually used
  458. // So we make allowance for them rather than lose formatting masks
  459. if ((int)$xf["numFmtId"] < 164 && PHPExcel_Style_NumberFormat::builtInFormatCode((int)$xf["numFmtId"]) !== '') {
  460. $numFmt = PHPExcel_Style_NumberFormat::builtInFormatCode((int)$xf["numFmtId"]);
  461. }
  462. }
  463. $quotePrefix = false;
  464. if (isset($xf["quotePrefix"])) {
  465. $quotePrefix = (boolean) $xf["quotePrefix"];
  466. }
  467. $style = (object) array(
  468. "numFmt" => $numFmt,
  469. "font" => $xmlStyles->fonts->font[intval($xf["fontId"])],
  470. "fill" => $xmlStyles->fills->fill[intval($xf["fillId"])],
  471. "border" => $xmlStyles->borders->border[intval($xf["borderId"])],
  472. "alignment" => $xf->alignment,
  473. "protection" => $xf->protection,
  474. "quotePrefix" => $quotePrefix,
  475. );
  476. $styles[] = $style;
  477. // add style to cellXf collection
  478. $objStyle = new PHPExcel_Style;
  479. self::readStyle($objStyle, $style);
  480. $excel->addCellXf($objStyle);
  481. }
  482. foreach ($xmlStyles->cellStyleXfs->xf as $xf) {
  483. $numFmt = PHPExcel_Style_NumberFormat::FORMAT_GENERAL;
  484. if ($numFmts && $xf["numFmtId"]) {
  485. $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
  486. if (isset($tmpNumFmt["formatCode"])) {
  487. $numFmt = (string) $tmpNumFmt["formatCode"];
  488. } elseif ((int)$xf["numFmtId"] < 165) {
  489. $numFmt = PHPExcel_Style_NumberFormat::builtInFormatCode((int)$xf["numFmtId"]);
  490. }
  491. }
  492. $cellStyle = (object) array(
  493. "numFmt" => $numFmt,
  494. "font" => $xmlStyles->fonts->font[intval($xf["fontId"])],
  495. "fill" => $xmlStyles->fills->fill[intval($xf["fillId"])],
  496. "border" => $xmlStyles->borders->border[intval($xf["borderId"])],
  497. "alignment" => $xf->alignment,
  498. "protection" => $xf->protection,
  499. "quotePrefix" => $quotePrefix,
  500. );
  501. $cellStyles[] = $cellStyle;
  502. // add style to cellStyleXf collection
  503. $objStyle = new PHPExcel_Style;
  504. self::readStyle($objStyle, $cellStyle);
  505. $excel->addCellStyleXf($objStyle);
  506. }
  507. }
  508. $dxfs = array();
  509. if (!$this->readDataOnly && $xmlStyles) {
  510. // Conditional Styles
  511. if ($xmlStyles->dxfs) {
  512. foreach ($xmlStyles->dxfs->dxf as $dxf) {
  513. $style = new PHPExcel_Style(false, true);
  514. self::readStyle($style, $dxf);
  515. $dxfs[] = $style;
  516. }
  517. }
  518. // Cell Styles
  519. if ($xmlStyles->cellStyles) {
  520. foreach ($xmlStyles->cellStyles->cellStyle as $cellStyle) {
  521. if (intval($cellStyle['builtinId']) == 0) {
  522. if (isset($cellStyles[intval($cellStyle['xfId'])])) {
  523. // Set default style
  524. $style = new PHPExcel_Style;
  525. self::readStyle($style, $cellStyles[intval($cellStyle['xfId'])]);
  526. // normal style, currently not using it for anything
  527. }
  528. }
  529. }
  530. }
  531. }
  532. $xmlWorkbook = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  533. // Set base date
  534. if ($xmlWorkbook->workbookPr) {
  535. PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
  536. if (isset($xmlWorkbook->workbookPr['date1904'])) {
  537. if (self::boolean((string) $xmlWorkbook->workbookPr['date1904'])) {
  538. PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
  539. }
  540. }
  541. }
  542. $sheetId = 0; // keep track of new sheet id in final workbook
  543. $oldSheetId = -1; // keep track of old sheet id in final workbook
  544. $countSkippedSheets = 0; // keep track of number of skipped sheets
  545. $mapSheetId = array(); // mapping of sheet ids from old to new
  546. $charts = $chartDetails = array();
  547. if ($xmlWorkbook->sheets) {
  548. foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
  549. ++$oldSheetId;
  550. // Check if sheet should be skipped
  551. if (isset($this->loadSheetsOnly) && !in_array((string) $eleSheet["name"], $this->loadSheetsOnly)) {
  552. ++$countSkippedSheets;
  553. $mapSheetId[$oldSheetId] = null;
  554. continue;
  555. }
  556. // Map old sheet id in original workbook to new sheet id.
  557. // They will differ if loadSheetsOnly() is being used
  558. $mapSheetId[$oldSheetId] = $oldSheetId - $countSkippedSheets;
  559. // Load sheet
  560. $docSheet = $excel->createSheet();
  561. // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet
  562. // references in formula cells... during the load, all formulae should be correct,
  563. // and we're simply bringing the worksheet name in line with the formula, not the
  564. // reverse
  565. $docSheet->setTitle((string) $eleSheet["name"], false);
  566. $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "id")];
  567. $xmlSheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/$fileWorksheet")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  568. $sharedFormulas = array();
  569. if (isset($eleSheet["state"]) && (string) $eleSheet["state"] != '') {
  570. $docSheet->setSheetState((string) $eleSheet["state"]);
  571. }
  572. if (isset($xmlSheet->sheetViews) && isset($xmlSheet->sheetViews->sheetView)) {
  573. if (isset($xmlSheet->sheetViews->sheetView['zoomScale'])) {
  574. $docSheet->getSheetView()->setZoomScale(intval($xmlSheet->sheetViews->sheetView['zoomScale']));
  575. }
  576. if (isset($xmlSheet->sheetViews->sheetView['zoomScaleNormal'])) {
  577. $docSheet->getSheetView()->setZoomScaleNormal(intval($xmlSheet->sheetViews->sheetView['zoomScaleNormal']));
  578. }
  579. if (isset($xmlSheet->sheetViews->sheetView['view'])) {
  580. $docSheet->getSheetView()->setView((string) $xmlSheet->sheetViews->sheetView['view']);
  581. }
  582. if (isset($xmlSheet->sheetViews->sheetView['showGridLines'])) {
  583. $docSheet->setShowGridLines(self::boolean((string)$xmlSheet->sheetViews->sheetView['showGridLines']));
  584. }
  585. if (isset($xmlSheet->sheetViews->sheetView['showRowColHeaders'])) {
  586. $docSheet->setShowRowColHeaders(self::boolean((string)$xmlSheet->sheetViews->sheetView['showRowColHeaders']));
  587. }
  588. if (isset($xmlSheet->sheetViews->sheetView['rightToLeft'])) {
  589. $docSheet->setRightToLeft(self::boolean((string)$xmlSheet->sheetViews->sheetView['rightToLeft']));
  590. }
  591. if (isset($xmlSheet->sheetViews->sheetView->pane)) {
  592. if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
  593. $docSheet->freezePane((string)$xmlSheet->sheetViews->sheetView->pane['topLeftCell']);
  594. } else {
  595. $xSplit = 0;
  596. $ySplit = 0;
  597. if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
  598. $xSplit = 1 + intval($xmlSheet->sheetViews->sheetView->pane['xSplit']);
  599. }
  600. if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
  601. $ySplit = 1 + intval($xmlSheet->sheetViews->sheetView->pane['ySplit']);
  602. }
  603. $docSheet->freezePaneByColumnAndRow($xSplit, $ySplit);
  604. }
  605. }
  606. if (isset($xmlSheet->sheetViews->sheetView->selection)) {
  607. if (isset($xmlSheet->sheetViews->sheetView->selection['sqref'])) {
  608. $sqref = (string)$xmlSheet->sheetViews->sheetView->selection['sqref'];
  609. $sqref = explode(' ', $sqref);
  610. $sqref = $sqref[0];
  611. $docSheet->setSelectedCells($sqref);
  612. }
  613. }
  614. }
  615. if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->tabColor)) {
  616. if (isset($xmlSheet->sheetPr->tabColor['rgb'])) {
  617. $docSheet->getTabColor()->setARGB((string)$xmlSheet->sheetPr->tabColor['rgb']);
  618. }
  619. }
  620. if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr['codeName'])) {
  621. $docSheet->setCodeName((string) $xmlSheet->sheetPr['codeName']);
  622. }
  623. if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->outlinePr)) {
  624. if (isset($xmlSheet->sheetPr->outlinePr['summaryRight']) &&
  625. !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
  626. $docSheet->setShowSummaryRight(false);
  627. } else {
  628. $docSheet->setShowSummaryRight(true);
  629. }
  630. if (isset($xmlSheet->sheetPr->outlinePr['summaryBelow']) &&
  631. !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryBelow'])) {
  632. $docSheet->setShowSummaryBelow(false);
  633. } else {
  634. $docSheet->setShowSummaryBelow(true);
  635. }
  636. }
  637. if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->pageSetUpPr)) {
  638. if (isset($xmlSheet->sheetPr->pageSetUpPr['fitToPage']) &&
  639. !self::boolean((string) $xmlSheet->sheetPr->pageSetUpPr['fitToPage'])) {
  640. $docSheet->getPageSetup()->setFitToPage(false);
  641. } else {
  642. $docSheet->getPageSetup()->setFitToPage(true);
  643. }
  644. }
  645. if (isset($xmlSheet->sheetFormatPr)) {
  646. if (isset($xmlSheet->sheetFormatPr['customHeight']) &&
  647. self::boolean((string) $xmlSheet->sheetFormatPr['customHeight']) &&
  648. isset($xmlSheet->sheetFormatPr['defaultRowHeight'])) {
  649. $docSheet->getDefaultRowDimension()->setRowHeight((float)$xmlSheet->sheetFormatPr['defaultRowHeight']);
  650. }
  651. if (isset($xmlSheet->sheetFormatPr['defaultColWidth'])) {
  652. $docSheet->getDefaultColumnDimension()->setWidth((float)$xmlSheet->sheetFormatPr['defaultColWidth']);
  653. }
  654. if (isset($xmlSheet->sheetFormatPr['zeroHeight']) &&
  655. ((string)$xmlSheet->sheetFormatPr['zeroHeight'] == '1')) {
  656. $docSheet->getDefaultRowDimension()->setZeroHeight(true);
  657. }
  658. }
  659. if (isset($xmlSheet->cols) && !$this->readDataOnly) {
  660. foreach ($xmlSheet->cols->col as $col) {
  661. for ($i = intval($col["min"]) - 1; $i < intval($col["max"]); ++$i) {
  662. if ($col["style"] && !$this->readDataOnly) {
  663. $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setXfIndex(intval($col["style"]));
  664. }
  665. if (self::boolean($col["bestFit"])) {
  666. //$docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setAutoSize(true);
  667. }
  668. if (self::boolean($col["hidden"])) {
  669. // echo PHPExcel_Cell::stringFromColumnIndex($i), ': HIDDEN COLUMN',PHP_EOL;
  670. $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setVisible(false);
  671. }
  672. if (self::boolean($col["collapsed"])) {
  673. $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setCollapsed(true);
  674. }
  675. if ($col["outlineLevel"] > 0) {
  676. $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setOutlineLevel(intval($col["outlineLevel"]));
  677. }
  678. $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setWidth(floatval($col["width"]));
  679. if (intval($col["max"]) == 16384) {
  680. break;
  681. }
  682. }
  683. }
  684. }
  685. if (isset($xmlSheet->printOptions) && !$this->readDataOnly) {
  686. if (self::boolean((string) $xmlSheet->printOptions['gridLinesSet'])) {
  687. $docSheet->setShowGridlines(true);
  688. }
  689. if (self::boolean((string) $xmlSheet->printOptions['gridLines'])) {
  690. $docSheet->setPrintGridlines(true);
  691. }
  692. if (self::boolean((string) $xmlSheet->printOptions['horizontalCentered'])) {
  693. $docSheet->getPageSetup()->setHorizontalCentered(true);
  694. }
  695. if (self::boolean((string) $xmlSheet->printOptions['verticalCentered'])) {
  696. $docSheet->getPageSetup()->setVerticalCentered(true);
  697. }
  698. }
  699. if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
  700. foreach ($xmlSheet->sheetData->row as $row) {
  701. if ($row["ht"] && !$this->readDataOnly) {
  702. $docSheet->getRowDimension(intval($row["r"]))->setRowHeight(floatval($row["ht"]));
  703. }
  704. if (self::boolean($row["hidden"]) && !$this->readDataOnly) {
  705. $docSheet->getRowDimension(intval($row["r"]))->setVisible(false);
  706. }
  707. if (self::boolean($row["collapsed"])) {
  708. $docSheet->getRowDimension(intval($row["r"]))->setCollapsed(true);
  709. }
  710. if ($row["outlineLevel"] > 0) {
  711. $docSheet->getRowDimension(intval($row["r"]))->setOutlineLevel(intval($row["outlineLevel"]));
  712. }
  713. if ($row["s"] && !$this->readDataOnly) {
  714. $docSheet->getRowDimension(intval($row["r"]))->setXfIndex(intval($row["s"]));
  715. }
  716. foreach ($row->c as $c) {
  717. $r = (string) $c["r"];
  718. $cellDataType = (string) $c["t"];
  719. $value = null;
  720. $calculatedValue = null;
  721. // Read cell?
  722. if ($this->getReadFilter() !== null) {
  723. $coordinates = PHPExcel_Cell::coordinateFromString($r);
  724. if (!$this->getReadFilter()->readCell($coordinates[0], $coordinates[1], $docSheet->getTitle())) {
  725. continue;
  726. }
  727. }
  728. // echo 'Reading cell ', $coordinates[0], $coordinates[1], PHP_EOL;
  729. // print_r($c);
  730. // echo PHP_EOL;
  731. // echo 'Cell Data Type is ', $cellDataType, ': ';
  732. //
  733. // Read cell!
  734. switch ($cellDataType) {
  735. case "s":
  736. // echo 'String', PHP_EOL;
  737. if ((string)$c->v != '') {
  738. $value = $sharedStrings[intval($c->v)];
  739. if ($value instanceof PHPExcel_RichText) {
  740. $value = clone $value;
  741. }
  742. } else {
  743. $value = '';
  744. }
  745. break;
  746. case "b":
  747. // echo 'Boolean', PHP_EOL;
  748. if (!isset($c->f)) {
  749. $value = self::castToBoolean($c);
  750. } else {
  751. // Formula
  752. $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToBoolean');
  753. if (isset($c->f['t'])) {
  754. $att = array();
  755. $att = $c->f;
  756. $docSheet->getCell($r)->setFormulaAttributes($att);
  757. }
  758. // echo '$calculatedValue = ', $calculatedValue, PHP_EOL;
  759. }
  760. break;
  761. case "inlineStr":
  762. // echo 'Inline String', PHP_EOL;
  763. if (isset($c->f)) {
  764. $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
  765. } else {
  766. $value = $this->parseRichText($c->is);
  767. }
  768. break;
  769. case "e":
  770. // echo 'Error', PHP_EOL;
  771. if (!isset($c->f)) {
  772. $value = self::castToError($c);
  773. } else {
  774. // Formula
  775. $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
  776. // echo '$calculatedValue = ', $calculatedValue, PHP_EOL;
  777. }
  778. break;
  779. default:
  780. // echo 'Default', PHP_EOL;
  781. if (!isset($c->f)) {
  782. // echo 'Not a Formula', PHP_EOL;
  783. $value = self::castToString($c);
  784. } else {
  785. // echo 'Treat as Formula', PHP_EOL;
  786. // Formula
  787. $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString');
  788. // echo '$calculatedValue = ', $calculatedValue, PHP_EOL;
  789. }
  790. break;
  791. }
  792. // echo 'Value is ', $value, PHP_EOL;
  793. // Check for numeric values
  794. if (is_numeric($value) && $cellDataType != 's') {
  795. if ($value == (int)$value) {
  796. $value = (int)$value;
  797. } elseif ($value == (float)$value) {
  798. $value = (float)$value;
  799. } elseif ($value == (double)$value) {
  800. $value = (double)$value;
  801. }
  802. }
  803. // Rich text?
  804. if ($value instanceof PHPExcel_RichText && $this->readDataOnly) {
  805. $value = $value->getPlainText();
  806. }
  807. $cell = $docSheet->getCell($r);
  808. // Assign value
  809. if ($cellDataType != '') {
  810. $cell->setValueExplicit($value, $cellDataType);
  811. } else {
  812. $cell->setValue($value);
  813. }
  814. if ($calculatedValue !== null) {
  815. $cell->setCalculatedValue($calculatedValue);
  816. }
  817. // Style information?
  818. if ($c["s"] && !$this->readDataOnly) {
  819. // no style index means 0, it seems
  820. $cell->setXfIndex(isset($styles[intval($c["s"])]) ?
  821. intval($c["s"]) : 0);
  822. }
  823. }
  824. }
  825. }
  826. $conditionals = array();
  827. if (!$this->readDataOnly && $xmlSheet && $xmlSheet->conditionalFormatting) {
  828. foreach ($xmlSheet->conditionalFormatting as $conditional) {
  829. foreach ($conditional->cfRule as $cfRule) {
  830. if (((string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_NONE || (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_CELLIS || (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT || (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_EXPRESSION) && isset($dxfs[intval($cfRule["dxfId"])])) {
  831. $conditionals[(string) $conditional["sqref"]][intval($cfRule["priority"])] = $cfRule;
  832. }
  833. }
  834. }
  835. foreach ($conditionals as $ref => $cfRules) {
  836. ksort($cfRules);
  837. $conditionalStyles = array();
  838. foreach ($cfRules as $cfRule) {
  839. $objConditional = new PHPExcel_Style_Conditional();
  840. $objConditional->setConditionType((string)$cfRule["type"]);
  841. $objConditional->setOperatorType((string)$cfRule["operator"]);
  842. if ((string)$cfRule["text"] != '') {
  843. $objConditional->setText((string)$cfRule["text"]);
  844. }
  845. if (count($cfRule->formula) > 1) {
  846. foreach ($cfRule->formula as $formula) {
  847. $objConditional->addCondition((string)$formula);
  848. }
  849. } else {
  850. $objConditional->addCondition((string)$cfRule->formula);
  851. }
  852. $objConditional->setStyle(clone $dxfs[intval($cfRule["dxfId"])]);
  853. $conditionalStyles[] = $objConditional;
  854. }
  855. // Extract all cell references in $ref
  856. $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
  857. foreach ($cellBlocks as $cellBlock) {
  858. $docSheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles);
  859. }
  860. }
  861. }
  862. $aKeys = array("sheet", "objects", "scenarios", "formatCells", "formatColumns", "formatRows", "insertColumns", "insertRows", "insertHyperlinks", "deleteColumns", "deleteRows", "selectLockedCells", "sort", "autoFilter", "pivotTables", "selectUnlockedCells");
  863. if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
  864. foreach ($aKeys as $key) {
  865. $method = "set" . ucfirst($key);
  866. $docSheet->getProtection()->$method(self::boolean((string) $xmlSheet->sheetProtection[$key]));
  867. }
  868. }
  869. if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
  870. $docSheet->getProtection()->setPassword((string) $xmlSheet->sheetProtection["password"], true);
  871. if ($xmlSheet->protectedRanges->protectedRange) {
  872. foreach ($xmlSheet->protectedRanges->protectedRange as $protectedRange) {
  873. $docSheet->protectCells((string) $protectedRange["sqref"], (string) $protectedRange["password"], true);
  874. }
  875. }
  876. }
  877. if ($xmlSheet && $xmlSheet->autoFilter && !$this->readDataOnly) {
  878. $autoFilterRange = (string) $xmlSheet->autoFilter["ref"];
  879. if (strpos($autoFilterRange, ':') !== false) {
  880. $autoFilter = $docSheet->getAutoFilter();
  881. $autoFilter->setRange($autoFilterRange);
  882. foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
  883. $column = $autoFilter->getColumnByOffset((integer) $filterColumn["colId"]);
  884. // Check for standard filters
  885. if ($filterColumn->filters) {
  886. $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_FILTER);
  887. $filters = $filterColumn->filters;
  888. if ((isset($filters["blank"])) && ($filters["blank"] == 1)) {
  889. // Operator is undefined, but always treated as EQUAL
  890. $column->createRule()->setRule(null, '')->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_FILTER);
  891. }
  892. // Standard filters are always an OR join, so no join rule needs to be set
  893. // Entries can be either filter elements
  894. foreach ($filters->filter as $filterRule) {
  895. // Operator is undefined, but always treated as EQUAL
  896. $column->createRule()->setRule(null, (string) $filterRule["val"])->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_FILTER);
  897. }
  898. // Or Date Group elements
  899. foreach ($filters->dateGroupItem as $dateGroupItem) {
  900. $column->createRule()->setRule(
  901. // Operator is undefined, but always treated as EQUAL
  902. null,
  903. array(
  904. 'year' => (string) $dateGroupItem["year"],
  905. 'month' => (string) $dateGroupItem["month"],
  906. 'day' => (string) $dateGroupItem["day"],
  907. 'hour' => (string) $dateGroupItem["hour"],
  908. 'minute' => (string) $dateGroupItem["minute"],
  909. 'second' => (string) $dateGroupItem["second"],
  910. ),
  911. (string) $dateGroupItem["dateTimeGrouping"]
  912. )
  913. ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DATEGROUP);
  914. }
  915. }
  916. // Check for custom filters
  917. if ($filterColumn->customFilters) {
  918. $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
  919. $customFilters = $filterColumn->customFilters;
  920. // Custom filters can an AND or an OR join;
  921. // and there should only ever be one or two entries
  922. if ((isset($customFilters["and"])) && ($customFilters["and"] == 1)) {
  923. $column->setJoin(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_COLUMN_JOIN_AND);
  924. }
  925. foreach ($customFilters->customFilter as $filterRule) {
  926. $column->createRule()->setRule(
  927. (string) $filterRule["operator"],
  928. (string) $filterRule["val"]
  929. )
  930. ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
  931. }
  932. }
  933. // Check for dynamic filters
  934. if ($filterColumn->dynamicFilter) {
  935. $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
  936. // We should only ever have one dynamic filter
  937. foreach ($filterColumn->dynamicFilter as $filterRule) {
  938. $column->createRule()->setRule(
  939. // Operator is undefined, but always treated as EQUAL
  940. null,
  941. (string) $filterRule["val"],
  942. (string) $filterRule["type"]
  943. )
  944. ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
  945. if (isset($filterRule["val"])) {
  946. $column->setAttribute('val', (string) $filterRule["val"]);
  947. }
  948. if (isset($filterRule["maxVal"])) {
  949. $column->setAttribute('maxVal', (string) $filterRule["maxVal"]);
  950. }
  951. }
  952. }
  953. // Check for dynamic filters
  954. if ($filterColumn->top10) {
  955. $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER);
  956. // We should only ever have one top10 filter
  957. foreach ($filterColumn->top10 as $filterRule) {
  958. $column->createRule()->setRule(
  959. (((isset($filterRule["percent"])) && ($filterRule["percent"] == 1))
  960. ? PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT
  961. : PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE
  962. ),
  963. (string) $filterRule["val"],
  964. (((isset($filterRule["top"])) && ($filterRule["top"] == 1))
  965. ? PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
  966. : PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
  967. )
  968. )
  969. ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_TOPTENFILTER);
  970. }
  971. }
  972. }
  973. }
  974. }
  975. if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) {
  976. foreach ($xmlSheet->mergeCells->mergeCell as $mergeCell) {
  977. $mergeRef = (string) $mergeCell["ref"];
  978. if (strpos($mergeRef, ':') !== false) {
  979. $docSheet->mergeCells((string) $mergeCell["ref"]);
  980. }
  981. }
  982. }
  983. if ($xmlSheet && $xmlSheet->pageMargins && !$this->readDataOnly) {
  984. $docPageMargins = $docSheet->getPageMargins();
  985. $docPageMargins->setLeft(floatval($xmlSheet->pageMargins["left"]));
  986. $docPageMargins->setRight(floatval($xmlSheet->pageMargins["right"]));
  987. $docPageMargins->setTop(floatval($xmlSheet->pageMargins["top"]));
  988. $docPageMargins->setBottom(floatval($xmlSheet->pageMargins["bottom"]));
  989. $docPageMargins->setHeader(floatval($xmlSheet->pageMargins["header"]));
  990. $docPageMargins->setFooter(floatval($xmlSheet->pageMargins["footer"]));
  991. }
  992. if ($xmlSheet && $xmlSheet->pageSetup && !$this->readDataOnly) {
  993. $docPageSetup = $docSheet->getPageSetup();
  994. if (isset($xmlSheet->pageSetup["orientation"])) {
  995. $docPageSetup->setOrientation((string) $xmlSheet->pageSetup["orientation"]);
  996. }
  997. if (isset($xmlSheet->pageSetup["paperSize"])) {
  998. $docPageSetup->setPaperSize(intval($xmlSheet->pageSetup["paperSize"]));
  999. }
  1000. if (isset($xmlSheet->pageSetup["scale"])) {
  1001. $docPageSetup->setScale(intval($xmlSheet->pageSetup["scale"]), false);
  1002. }
  1003. if (isset($xmlSheet->pageSetup["fitToHeight"]) && intval($xmlSheet->pageSetup["fitToHeight"]) >= 0) {
  1004. $docPageSetup->setFitToHeight(intval($xmlSheet->pageSetup["fitToHeight"]), false);
  1005. }
  1006. if (isset($xmlSheet->pageSetup["fitToWidth"]) && intval($xmlSheet->pageSetup["fitToWidth"]) >= 0) {
  1007. $docPageSetup->setFitToWidth(intval($xmlSheet->pageSetup["fitToWidth"]), false);
  1008. }
  1009. if (isset($xmlSheet->pageSetup["firstPageNumber"]) && isset($xmlSheet->pageSetup["useFirstPageNumber"]) &&
  1010. self::boolean((string) $xmlSheet->pageSetup["useFirstPageNumber"])) {
  1011. $docPageSetup->setFirstPageNumber(intval($xmlSheet->pageSetup["firstPageNumber"]));
  1012. }
  1013. }
  1014. if ($xmlSheet && $xmlSheet->headerFooter && !$this->readDataOnly) {
  1015. $docHeaderFooter = $docSheet->getHeaderFooter();
  1016. if (isset($xmlSheet->headerFooter["differentOddEven"]) &&
  1017. self::boolean((string)$xmlSheet->headerFooter["differentOddEven"])) {
  1018. $docHeaderFooter->setDifferentOddEven(true);
  1019. } else {
  1020. $docHeaderFooter->setDifferentOddEven(false);
  1021. }
  1022. if (isset($xmlSheet->headerFooter["differentFirst"]) &&
  1023. self::boolean((string)$xmlSheet->headerFooter["differentFirst"])) {
  1024. $docHeaderFooter->setDifferentFirst(true);
  1025. } else {
  1026. $docHeaderFooter->setDifferentFirst(false);
  1027. }
  1028. if (isset($xmlSheet->headerFooter["scaleWithDoc"]) &&
  1029. !self::boolean((string)$xmlSheet->headerFooter["scaleWithDoc"])) {
  1030. $docHeaderFooter->setScaleWithDocument(false);
  1031. } else {
  1032. $docHeaderFooter->setScaleWithDocument(true);
  1033. }
  1034. if (isset($xmlSheet->headerFooter["alignWithMargins"]) &&
  1035. !self::boolean((string)$xmlSheet->headerFooter["alignWithMargins"])) {
  1036. $docHeaderFooter->setAlignWithMargins(false);
  1037. } else {
  1038. $docHeaderFooter->setAlignWithMargins(true);
  1039. }
  1040. $docHeaderFooter->setOddHeader((string) $xmlSheet->headerFooter->oddHeader);
  1041. $docHeaderFooter->setOddFooter((string) $xmlSheet->headerFooter->oddFooter);
  1042. $docHeaderFooter->setEvenHeader((string) $xmlSheet->headerFooter->evenHeader);
  1043. $docHeaderFooter->setEvenFooter((string) $xmlSheet->headerFooter->evenFooter);
  1044. $docHeaderFooter->setFirstHeader((string) $xmlSheet->headerFooter->firstHeader);
  1045. $docHeaderFooter->setFirstFooter((string) $xmlSheet->headerFooter->firstFooter);
  1046. }
  1047. if ($xmlSheet && $xmlSheet->rowBreaks && $xmlSheet->rowBreaks->brk && !$this->readDataOnly) {
  1048. foreach ($xmlSheet->rowBreaks->brk as $brk) {
  1049. if ($brk["man"]) {
  1050. $docSheet->setBreak("A$brk[id]", PHPExcel_Worksheet::BREAK_ROW);
  1051. }
  1052. }
  1053. }
  1054. if ($xmlSheet && $xmlSheet->colBreaks && $xmlSheet->colBreaks->brk && !$this->readDataOnly) {
  1055. foreach ($xmlSheet->colBreaks->brk as $brk) {
  1056. if ($brk["man"]) {
  1057. $docSheet->setBreak(PHPExcel_Cell::stringFromColumnIndex((string) $brk["id"]) . "1", PHPExcel_Worksheet::BREAK_COLUMN);
  1058. }
  1059. }
  1060. }
  1061. if ($xmlSheet && $xmlSheet->dataValidations && !$this->readDataOnly) {
  1062. foreach ($xmlSheet->dataValidations->dataValidation as $dataValidation) {
  1063. // Uppercase coordinate
  1064. $range = strtoupper($dataValidation["sqref"]);
  1065. $rangeSet = explode(' ', $range);
  1066. foreach ($rangeSet as $range) {
  1067. $stRange = $docSheet->shrinkRangeToFit($range);
  1068. // Extract all cell references in $range
  1069. foreach (PHPExcel_Cell::extractAllCellReferencesInRange($stRange) as $reference) {
  1070. // Create validation
  1071. $docValidation = $docSheet->getCell($reference)->getDataValidation();
  1072. $docValidation->setType((string) $dataValidation["type"]);
  1073. $docValidation->setErrorStyle((string) $dataValidation["errorStyle"]);
  1074. $docValidation->setOperator((string) $dataValidation["operator"]);
  1075. $docValidation->setAllowBlank($dataValidation["allowBlank"] != 0);
  1076. $docValidation->setShowDropDown($dataValidation["showDropDown"] == 0);
  1077. $docValidation->setShowInputMessage($dataValidation["showInputMessage"] != 0);
  1078. $docValidation->setShowErrorMessage($dataValidation["showErrorMessage"] != 0);
  1079. $docValidation->setErrorTitle((string) $dataValidation["errorTitle"]);
  1080. $docValidation->setError((string) $dataValidation["error"]);
  1081. $docValidation->setPromptTitle((string) $dataValidation["promptTitle"]);
  1082. $docValidation->setPrompt((string) $dataValidation["prompt"]);
  1083. $docValidation->setFormula1((string) $dataValidation->formula1);
  1084. $docValidation->setFormula2((string) $dataValidation->formula2);
  1085. }
  1086. }
  1087. }
  1088. }
  1089. // Add hyperlinks
  1090. $hyperlinks = array();
  1091. if (!$this->readDataOnly) {
  1092. // Locate hyperlink relations
  1093. if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
  1094. $relsWorksheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  1095. foreach ($relsWorksheet->Relationship as $ele) {
  1096. if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink") {
  1097. $hyperlinks[(string)$ele["Id"]] = (string)$ele["Target"];
  1098. }
  1099. }
  1100. }
  1101. // Loop through hyperlinks
  1102. if ($xmlSheet && $xmlSheet->hyperlinks) {
  1103. foreach ($xmlSheet->hyperlinks->hyperlink as $hyperlink) {
  1104. // Link url
  1105. $linkRel = $hyperlink->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
  1106. foreach (PHPExcel_Cell::extractAllCellReferencesInRange($hyperlink['ref']) as $cellReference) {
  1107. $cell = $docSheet->getCell($cellReference);
  1108. if (isset($linkRel['id'])) {
  1109. $hyperlinkUrl = $hyperlinks[ (string)$linkRel['id'] ];
  1110. if (isset($hyperlink['location'])) {
  1111. $hyperlinkUrl .= '#' . (string) $hyperlink['location'];
  1112. }
  1113. $cell->getHyperlink()->setUrl($hyperlinkUrl);
  1114. } elseif (isset($hyperlink['location'])) {
  1115. $cell->getHyperlink()->setUrl('sheet://' . (string)$hyperlink['location']);
  1116. }
  1117. // Tooltip
  1118. if (isset($hyperlink['tooltip'])) {
  1119. $cell->getHyperlink()->setTooltip((string)$hyperlink['tooltip']);
  1120. }
  1121. }
  1122. }
  1123. }
  1124. }
  1125. // Add comments
  1126. $comments = array();
  1127. $vmlComments = array();
  1128. if (!$this->readDataOnly) {
  1129. // Locate comment relations
  1130. if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
  1131. $relsWorksheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  1132. foreach ($relsWorksheet->Relationship as $ele) {
  1133. if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments") {
  1134. $comments[(string)$ele["Id"]] = (string)$ele["Target"];
  1135. }
  1136. if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing") {
  1137. $vmlComments[(string)$ele["Id"]] = (string)$ele["Target"];
  1138. }
  1139. }
  1140. }
  1141. // Loop through comments
  1142. foreach ($comments as $relName => $relPath) {
  1143. // Load comments file
  1144. $relPath = PHPExcel_Shared_File::realpath(dirname("$dir/$fileWorksheet") . "/" . $relPath);
  1145. $commentsFile = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $relPath)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  1146. // Utility variables
  1147. $authors = array();
  1148. // Loop through authors
  1149. foreach ($commentsFile->authors->author as $author) {
  1150. $authors[] = (string)$author;
  1151. }
  1152. // Loop through contents
  1153. foreach ($commentsFile->commentList->comment as $comment) {
  1154. if (!empty($comment['authorId'])) {
  1155. $docSheet->getComment((string)$comment['ref'])->setAuthor($authors[(string)$comment['authorId']]);
  1156. }
  1157. $docSheet->getComment((string)$comment['ref'])->setText($this->parseRichText($comment->text));
  1158. }
  1159. }
  1160. // Loop through VML comments
  1161. foreach ($vmlComments as $relName => $relPath) {
  1162. // Load VML comments file
  1163. $relPath = PHPExcel_Shared_File::realpath(dirname("$dir/$fileWorksheet") . "/" . $relPath);
  1164. $vmlCommentsFile = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $relPath)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  1165. $vmlCommentsFile->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
  1166. $shapes = $vmlCommentsFile->xpath('//v:shape');
  1167. foreach ($shapes as $shape) {
  1168. $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
  1169. if (isset($shape['style'])) {
  1170. $style = (string)$shape['style'];
  1171. $fillColor = strtoupper(substr((string)$shape['fillcolor'], 1));
  1172. $column = null;
  1173. $row = null;
  1174. $clientData = $shape->xpath('.//x:ClientData');
  1175. if (is_array($clientData) && !empty($clientData)) {
  1176. $clientData = $clientData[0];
  1177. if (isset($clientData['ObjectType']) && (string)$clientData['ObjectType'] == 'Note') {
  1178. $temp = $clientData->xpath('.//x:Row');
  1179. if (is_array($temp)) {
  1180. $row = $temp[0];
  1181. }
  1182. $temp = $clientData->xpath('.//x:Column');
  1183. if (is_array($temp)) {
  1184. $column = $temp[0];
  1185. }
  1186. }
  1187. }
  1188. if (($column !== null) && ($row !== null)) {
  1189. // Set comment properties
  1190. $comment = $docSheet->getCommentByColumnAndRow((string) $column, $row + 1);
  1191. $comment->getFillColor()->setRGB($fillColor);
  1192. // Parse style
  1193. $styleArray = explode(';', str_replace(' ', '', $style));
  1194. foreach ($styleArray as $stylePair) {
  1195. $stylePair = explode(':', $stylePair);
  1196. if ($stylePair[0] == 'margin-left') {
  1197. $comment->setMarginLeft($stylePair[1]);
  1198. }
  1199. if ($stylePair[0] == 'margin-top') {
  1200. $comment->setMarginTop($stylePair[1]);
  1201. }
  1202. if ($stylePair[0] == 'width') {
  1203. $comment->setWidth($stylePair[1]);
  1204. }
  1205. if ($stylePair[0] == 'height') {
  1206. $comment->setHeight($stylePair[1]);
  1207. }
  1208. if ($stylePair[0] == 'visibility') {
  1209. $comment->setVisible($stylePair[1] == 'visible');
  1210. }
  1211. }
  1212. }
  1213. }
  1214. }
  1215. }
  1216. // Header/footer images
  1217. if ($xmlSheet && $xmlSheet->legacyDrawingHF && !$this->readDataOnly) {
  1218. if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
  1219. $relsWorksheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  1220. $vmlRelationship = '';
  1221. foreach ($relsWorksheet->Relationship as $ele) {
  1222. if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing") {
  1223. $vmlRelationship = self::dirAdd("$dir/$fileWorksheet", $ele["Target"]);
  1224. }
  1225. }
  1226. if ($vmlRelationship != '') {
  1227. // Fetch linked images
  1228. $relsVML = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname($vmlRelationship) . '/_rels/' . basename($vmlRelationship) . '.rels')), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  1229. $drawings = array();
  1230. foreach ($relsVML->Relationship as $ele) {
  1231. if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image") {
  1232. $drawings[(string) $ele["Id"]] = self::dirAdd($vmlRelationship, $ele["Target"]);
  1233. }
  1234. }
  1235. // Fetch VML document
  1236. $vmlDrawing = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $vmlRelationship)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  1237. $vmlDrawing->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
  1238. $hfImages = array();
  1239. $shapes = $vmlDrawing->xpath('//v:shape');
  1240. foreach ($shapes as $idx => $shape) {
  1241. $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
  1242. $imageData = $shape->xpath('//v:imagedata');
  1243. $imageData = $imageData[$idx];
  1244. $imageData = $imageData->attributes('urn:schemas-microsoft-com:office:office');
  1245. $style = self::toCSSArray((string)$shape['style']);
  1246. $hfImages[ (string)$shape['id'] ] = new PHPExcel_Worksheet_HeaderFooterDrawing();
  1247. if (isset($imageData['title'])) {
  1248. $hfImages[ (string)$shape['id'] ]->setName((string)$imageData['title']);
  1249. }
  1250. $hfImages[ (string)$shape['id'] ]->setPath("zip://".PHPExcel_Shared_File::realpath($pFilename)."#" . $drawings[(string)$imageData['relid']], false);
  1251. $hfImages[ (string)$shape['id'] ]->setResizeProportional(false);
  1252. $hfImages[ (string)$shape['id'] ]->setWidth($style['width']);
  1253. $hfImages[ (string)$shape['id'] ]->setHeight($style['height']);
  1254. if (isset($style['margin-left'])) {
  1255. $hfImages[ (string)$shape['id'] ]->setOffsetX($style['margin-left']);
  1256. }
  1257. $hfImages[ (string)$shape['id'] ]->setOffsetY($style['margin-top']);
  1258. $hfImages[ (string)$shape['id'] ]->setResizeProportional(true);
  1259. }
  1260. $docSheet->getHeaderFooter()->setImages($hfImages);
  1261. }
  1262. }
  1263. }
  1264. }
  1265. // TODO: Autoshapes from twoCellAnchors!
  1266. if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
  1267. $relsWorksheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  1268. $drawings = array();
  1269. foreach ($relsWorksheet->Relationship as $ele) {
  1270. if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing") {
  1271. $drawings[(string) $ele["Id"]] = self::dirAdd("$dir/$fileWorksheet", $ele["Target"]);
  1272. }
  1273. }
  1274. if ($xmlSheet->drawing && !$this->readDataOnly) {
  1275. foreach ($xmlSheet->drawing as $drawing) {
  1276. $fileDrawing = $drawings[(string) self::getArrayItem($drawing->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "id")];
  1277. $relsDrawing = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname($fileDrawing) . "/_rels/" . basename($fileDrawing) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
  1278. $images = array();
  1279. if ($relsDrawing && $relsDrawing->Relationship) {
  1280. foreach ($relsDrawing->Relationship as $ele) {
  1281. if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image") {
  1282. $images[(string) $ele["Id"]] = self::dirAdd($fileDrawing, $ele["Target"]);
  1283. } elseif ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart") {
  1284. if ($this->includeCharts) {
  1285. $charts[self::dirAdd($fileDrawing, $ele["Target"])] = array(
  1286. 'id' => (string) $ele["Id"],
  1287. 'sheet' => $docSheet->getTitle()
  1288. );
  1289. }
  1290. }
  1291. }
  1292. }
  1293. $xmlDrawing = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $fileDrawing)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions())->children("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing");
  1294. if ($xmlDrawing->oneCellAnchor) {
  1295. foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
  1296. if ($oneCellAnchor->pic->blipFill) {
  1297. $blip = $oneCellAnchor->pic->blipFill->children("http://schemas.openxmlformats.org/drawingml/2006/main")->blip;
  1298. $xfrm = $oneCellAnchor->pic->spPr->children("http://schemas.openxmlformats.org/drawingml/2006/main")->xfrm;
  1299. $outerShdw = $oneCellAnchor->pic->spPr->children("http://schemas.openxmlformats.org/drawingml/2006/main")->effectLst->outerShdw;
  1300. $objDrawing = new PHPExcel_Worksheet_Drawing;
  1301. $objDrawing->setName((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), "name"));
  1302. $objDrawing->setDescription((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), "descr"));
  1303. $objDrawing->setPath("zip://".PHPExcel_Shared_File::realpath($pFilename)."#" . $images[(string) self::getArrayItem($blip->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "embed")], false);
  1304. $objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1));
  1305. $objDrawing->setOffsetX(PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->colOff));
  1306. $objDrawing->setOffsetY(PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->rowOff));
  1307. $objDrawing->setResizeProportional(false);
  1308. $objDrawing->setWidth(PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), "cx")));
  1309. $objDrawing->setHeight(PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), "cy")));
  1310. if ($xfrm) {
  1311. $objDrawing->setRotation(PHPExcel_Shared_Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), "rot")));
  1312. }
  1313. if ($outerShdw) {
  1314. $shadow = $objDrawing->getShadow();
  1315. $shadow->setVisible(true);
  1316. $shadow->setBlurRadius(PHPExcel_Shared_Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), "blurRad")));
  1317. $shadow->setDistance(PHPExcel_Shared_Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), "dist")));
  1318. $shadow->setDirection(PHPExcel_Shared_Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), "dir")));
  1319. $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), "algn"));
  1320. $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), "val"));
  1321. $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), "val") / 1000);
  1322. }
  1323. $objDrawing->setWorksheet($docSheet);
  1324. } else {
  1325. // ? Can charts be positioned with a oneCellAnchor ?
  1326. $coordinates = PHPExcel_Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1);
  1327. $offsetX = PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->colOff);
  1328. $offsetY = PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->rowOff);
  1329. $width = PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), "cx"));
  1330. $height = PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), "cy"));
  1331. }
  1332. }
  1333. }
  1334. if ($xmlDrawing->twoCellAnchor) {
  1335. foreach ($xmlDrawing->twoCellAnchor as $twoCellAnchor) {
  1336. if ($twoCellAnchor->pic->blipFill) {
  1337. $blip = $twoCellAnchor->pic->blipFill->children("http://schemas.openxmlformats.org/drawingml/2006/main")->blip;
  1338. $xfrm = $twoCellAnchor->pic->spPr->children("http://schemas.openxmlformats.org/drawingml/2006/main")->xfrm;
  1339. $outerShdw = $twoCellAnchor->pic->spPr->children("http://schemas.openxmlformats.org/drawingml/2006/main")->effectLst->outerShdw;
  1340. $objDrawing = new PHPExcel_Worksheet_Drawing;
  1341. $objDrawing->setName((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), "name"));
  1342. $objDrawing->setDescription((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), "descr"));
  1343. $objDrawing->setPath("zip://".PHPExcel_Shared_File::realpath($pFilename)."#" . $images[(string) self::getArrayItem($blip->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "embed")], false);
  1344. $objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1));
  1345. $objDrawing->setOffsetX(PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->colOff));
  1346. $objDrawing->setOffsetY(PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->rowOff));
  1347. $objDrawing->setResizeProportional(false);
  1348. if ($xfrm) {
  1349. $objDrawing->setWidth(PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), "cx")));
  1350. $objDrawing->setHeight(PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), "cy")));
  1351. $objDrawing->setRotation(PHPExcel_Shared_Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), "rot")));
  1352. }
  1353. if ($outerShdw) {
  1354. $shadow = $objDrawing->getShadow();
  1355. $shadow->setVisible(true);
  1356. $shadow->setBlurRadius(PHPExcel_Shared_Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), "blurRad")));
  1357. $shadow->setDistance(PHPExcel_Shared_Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), "dist")));
  1358. $shadow->setDirection(PHPExcel_Shared_Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), "dir")));
  1359. $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), "algn"));
  1360. $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), "val"));
  1361. $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), "val") / 1000);
  1362. }
  1363. $objDrawing->setWorksheet($docSheet);
  1364. } elseif (($this->includeCharts) && ($twoCellAnchor->graphicFrame)) {
  1365. $fromCoordinate = PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1);
  1366. $fromOffsetX = PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->colOff);
  1367. $fromOffsetY = PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->rowOff);
  1368. $toCoordinate = PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->to->col) . ($twoCellAnchor->to->row + 1);
  1369. $toOffsetX = PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->to->colOff);
  1370. $toOffsetY = PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->to->rowOff);
  1371. $graphic = $twoCellAnchor->graphicFrame->children("http://schemas.openxmlformats.org/drawingml/2006/main")->graphic;
  1372. $chartRef = $graphic->graphicData->children("http://schemas.openxmlformats.org/drawingml/2006/chart")->chart;
  1373. $thisChart = (string) $chartRef->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
  1374. $chartDetails[$docSheet->getTitle().'!'.$thisChart] = array(
  1375. 'fromCoordinate' => $fromCoordinate,
  1376. 'fromOffsetX' => $fromOffsetX,
  1377. 'fromOffsetY' => $fromOffsetY,
  1378. 'toCoordinate' => $toCoordinate,
  1379. 'toOffsetX' => $toOffsetX,
  1380. 'toOffsetY' => $toOffsetY,
  1381. 'worksheetTitle' => $docSheet->getTitle()
  1382. );
  1383. }
  1384. }
  1385. }
  1386. }
  1387. }
  1388. }
  1389. // Loop through definedNames
  1390. if ($xmlWorkbook->definedNames) {
  1391. foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
  1392. // Extract range
  1393. $extractedRange = (string)$definedName;
  1394. $extractedRange = preg_replace('/\'(\w+)\'\!/', '', $extractedRange);
  1395. if (($spos = strpos($extractedRange, '!')) !== false) {
  1396. $extractedRange = substr($extractedRange, 0, $spos).str_replace('$', '', substr($extractedRange, $spos));
  1397. } else {
  1398. $extractedRange = str_replace('$', '', $extractedRange);
  1399. }
  1400. // Valid range?
  1401. if (stripos((string)$definedName, '#REF!') !== false || $extractedRange == '') {
  1402. continue;
  1403. }
  1404. // Some definedNames are only applicable if we are on the same sheet...
  1405. if ((string)$definedName['localSheetId'] != '' && (string)$definedName['localSheetId'] == $sheetId) {
  1406. // Switch on type
  1407. switch ((string)$definedName['name']) {
  1408. case '_xlnm._FilterDatabase':
  1409. if ((string)$definedName['hidden'] !== '1') {
  1410. $extractedRange = explode(',', $extractedRange);
  1411. foreach ($extractedRange as $range) {
  1412. $autoFilterRange = $range;
  1413. if (strpos($autoFilterRange, ':') !== false) {
  1414. $docSheet->getAutoFilter()->setRange($autoFilterRange);
  1415. }
  1416. }
  1417. }
  1418. break;
  1419. case '_xlnm.Print_Titles':
  1420. // Split $extractedRange
  1421. $extractedRange = explode(',', $extractedRange);
  1422. // Set print titles
  1423. foreach ($extractedRange as $range) {
  1424. $matches = array();
  1425. $range = str_replace('$', '', $range);
  1426. // check for repeating columns, e g. 'A:A' or 'A:D'
  1427. if (preg_match('/!?([A-Z]+)\:([A-Z]+)$/', $range, $matches)) {
  1428. $docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($matches[1], $matches[2]));
  1429. } elseif (preg_match('/!?(\d+)\:(\d+)$/', $range, $matches)) {
  1430. // check for repeating rows, e.g. '1:1' or '1:5'
  1431. $docSheet->getPageSetup()->setRowsToRepeatAtTop(array($matches[1], $matches[2]));
  1432. }
  1433. }
  1434. break;
  1435. case '_xlnm.Print_Area':
  1436. $rangeSets = explode(',', $extractedRange); // FIXME: what if sheetname contains comma?
  1437. $newRangeSets = array();
  1438. foreach ($rangeSets as $rangeSet) {
  1439. $range = explode('!', $rangeSet); // FIXME: what if sheetname contains exclamation mark?
  1440. $rangeSet = isset($range[1]) ? $range[1] : $range[0];
  1441. if (strpos($rangeSet, ':') === false) {
  1442. $rangeSet = $rangeSet . ':' . $rangeSet;
  1443. }
  1444. $newRangeSets[] = str_replace('$', '', $rangeSet);
  1445. }
  1446. $docSheet->getPageSetup()->setPrintArea(implode(',', $newRangeSets));
  1447. break;
  1448. default:
  1449. break;
  1450. }
  1451. }
  1452. }
  1453. }
  1454. // Next sheet id
  1455. ++$sheetId;
  1456. }
  1457. // Loop through definedNames
  1458. if ($xmlWorkbook->definedNames) {
  1459. foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
  1460. // Extract range
  1461. $extractedRange = (string)$definedName;
  1462. $extractedRange = preg_replace('/\'(\w+)\'\!/', '', $extractedRange);
  1463. if (($spos = strpos($extractedRange, '!')) !== false) {
  1464. $extractedRange = substr($extractedRange, 0, $spos).str_replace('$', '', substr($extractedRange, $spos));
  1465. } else {
  1466. $extractedRange = str_replace('$', '', $extractedRange);
  1467. }
  1468. // Valid range?
  1469. if (stripos((string)$definedName, '#REF!') !== false || $extractedRange == '') {
  1470. continue;
  1471. }
  1472. // Some definedNames are only applicable if we are on the same sheet...
  1473. if ((string)$definedName['localSheetId'] != '') {
  1474. // Local defined name
  1475. // Switch on type
  1476. switch ((string)$definedName['name']) {
  1477. case '_xlnm._FilterDatabase':
  1478. case '_xlnm.Print_Titles':
  1479. case '_xlnm.Print_Area':
  1480. break;
  1481. default:
  1482. if ($mapSheetId[(integer) $definedName['localSheetId']] !== null) {
  1483. $range = explode('!', (string)$definedName);
  1484. if (count($range) == 2) {
  1485. $range[0] = str_replace("''", "'", $range[0]);
  1486. $range[0] = str_replace("'", "", $range[0]);
  1487. if ($worksheet = $docSheet->getParent()->getSheetByName($range[0])) {
  1488. $extractedRange = str_replace('$', '', $range[1]);
  1489. $scope = $docSheet->getParent()->getSheet($mapSheetId[(integer) $definedName['localSheetId']]);
  1490. $excel->addNamedRange(new PHPExcel_NamedRange((string)$definedName['name'], $worksheet, $extractedRange, true, $scope));
  1491. }
  1492. }
  1493. }
  1494. break;
  1495. }
  1496. } elseif (!isset($definedName['localSheetId'])) {
  1497. // "Global" definedNames
  1498. $locatedSheet = null;
  1499. $extractedSheetName = '';
  1500. if (strpos((string)$definedName, '!') !== false) {
  1501. // Extract sheet name
  1502. $extractedSheetName = PHPExcel_Worksheet::extractSheetTitle((string)$definedName, true);
  1503. $extractedSheetName = $extractedSheetName[0];
  1504. // Locate sheet
  1505. $locatedSheet = $excel->getSheetByName($extractedSheetName);
  1506. // Modify range
  1507. $range = explode('!', $extractedRange);
  1508. $extractedRange = isset($range[1]) ? $range[1] : $range[0];
  1509. }
  1510. if ($locatedSheet !== null) {
  1511. $excel->addNamedRange(new PHPExcel_NamedRange((string)$definedName['name'], $locatedSheet, $extractedRange, false));
  1512. }
  1513. }
  1514. }
  1515. }
  1516. }
  1517. if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
  1518. // active sheet index
  1519. $activeTab = intval($xmlWorkbook->bookViews->workbookView["activeTab"]); // refers to old sheet index
  1520. // keep active sheet index if sheet is still loaded, else first sheet is set as the active
  1521. if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
  1522. $excel->setActiveSheetIndex($mapSheetId[$activeTab]);
  1523. } else {
  1524. if ($excel->getSheetCount() == 0) {
  1525. $excel->createSheet();
  1526. }
  1527. $excel->setActiveSheetIndex(0);
  1528. }
  1529. }
  1530. break;
  1531. }
  1532. }
  1533. if (!$this->readDataOnly) {
  1534. $contentTypes = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "[Content_Types].xml")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  1535. foreach ($contentTypes->Override as $contentType) {
  1536. switch ($contentType["ContentType"]) {
  1537. case "application/vnd.openxmlformats-officedocument.drawingml.chart+xml":
  1538. if ($this->includeCharts) {
  1539. $chartEntryRef = ltrim($contentType['PartName'], '/');
  1540. $chartElements = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $chartEntryRef)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  1541. $objChart = PHPExcel_Reader_Excel2007_Chart::readChart($chartElements, basename($chartEntryRef, '.xml'));
  1542. // echo 'Chart ', $chartEntryRef, '<br />';
  1543. // var_dump($charts[$chartEntryRef]);
  1544. //
  1545. if (isset($charts[$chartEntryRef])) {
  1546. $chartPositionRef = $charts[$chartEntryRef]['sheet'].'!'.$charts[$chartEntryRef]['id'];
  1547. // echo 'Position Ref ', $chartPositionRef, '<br />';
  1548. if (isset($chartDetails[$chartPositionRef])) {
  1549. // var_dump($chartDetails[$chartPositionRef]);
  1550. $excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart);
  1551. $objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet']));
  1552. $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
  1553. $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']);
  1554. }
  1555. }
  1556. }
  1557. }
  1558. }
  1559. }
  1560. $zip->close();
  1561. return $excel;
  1562. }
  1563. private static function readColor($color, $background = false)
  1564. {
  1565. if (isset($color["rgb"])) {
  1566. return (string)$color["rgb"];
  1567. } elseif (isset($color["indexed"])) {
  1568. return PHPExcel_Style_Color::indexedColor($color["indexed"]-7, $background)->getARGB();
  1569. } elseif (isset($color["theme"])) {
  1570. if (self::$theme !== null) {
  1571. $returnColour = self::$theme->getColourByIndex((int)$color["theme"]);
  1572. if (isset($color["tint"])) {
  1573. $tintAdjust = (float) $color["tint"];
  1574. $returnColour = PHPExcel_Style_Color::changeBrightness($returnColour, $tintAdjust);
  1575. }
  1576. return 'FF'.$returnColour;
  1577. }
  1578. }
  1579. if ($background) {
  1580. return 'FFFFFFFF';
  1581. }
  1582. return 'FF000000';
  1583. }
  1584. private static function readStyle($docStyle, $style)
  1585. {
  1586. // format code
  1587. // if (isset($style->numFmt)) {
  1588. // if (isset($style->numFmt['formatCode'])) {
  1589. // $docStyle->getNumberFormat()->setFormatCode((string) $style->numFmt['formatCode']);
  1590. // } else {
  1591. $docStyle->getNumberFormat()->setFormatCode($style->numFmt);
  1592. // }
  1593. // }
  1594. // font
  1595. if (isset($style->font)) {
  1596. $docStyle->getFont()->setName((string) $style->font->name["val"]);
  1597. $docStyle->getFont()->setSize((string) $style->font->sz["val"]);
  1598. if (isset($style->font->b)) {
  1599. $docStyle->getFont()->setBold(!isset($style->font->b["val"]) || self::boolean((string) $style->font->b["val"]));
  1600. }
  1601. if (isset($style->font->i)) {
  1602. $docStyle->getFont()->setItalic(!isset($style->font->i["val"]) || self::boolean((string) $style->font->i["val"]));
  1603. }
  1604. if (isset($style->font->strike)) {
  1605. $docStyle->getFont()->setStrikethrough(!isset($style->font->strike["val"]) || self::boolean((string) $style->font->strike["val"]));
  1606. }
  1607. $docStyle->getFont()->getColor()->setARGB(self::readColor($style->font->color));
  1608. if (isset($style->font->u) && !isset($style->font->u["val"])) {
  1609. $docStyle->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
  1610. } elseif (isset($style->font->u) && isset($style->font->u["val"])) {
  1611. $docStyle->getFont()->setUnderline((string)$style->font->u["val"]);
  1612. }
  1613. if (isset($style->font->vertAlign) && isset($style->font->vertAlign["val"])) {
  1614. $vertAlign = strtolower((string)$style->font->vertAlign["val"]);
  1615. if ($vertAlign == 'superscript') {
  1616. $docStyle->getFont()->setSuperScript(true);
  1617. }
  1618. if ($vertAlign == 'subscript') {
  1619. $docStyle->getFont()->setSubScript(true);
  1620. }
  1621. }
  1622. }
  1623. // fill
  1624. if (isset($style->fill)) {
  1625. if ($style->fill->gradientFill) {
  1626. $gradientFill = $style->fill->gradientFill[0];
  1627. if (!empty($gradientFill["type"])) {
  1628. $docStyle->getFill()->setFillType((string) $gradientFill["type"]);
  1629. }
  1630. $docStyle->getFill()->setRotation(floatval($gradientFill["degree"]));
  1631. $gradientFill->registerXPathNamespace("sml", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  1632. $docStyle->getFill()->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath("sml:stop[@position=0]"))->color));
  1633. $docStyle->getFill()->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath("sml:stop[@position=1]"))->color));
  1634. } elseif ($style->fill->patternFill) {
  1635. $patternType = (string)$style->fill->patternFill["patternType"] != '' ? (string)$style->fill->patternFill["patternType"] : 'solid';
  1636. $docStyle->getFill()->setFillType($patternType);
  1637. if ($style->fill->patternFill->fgColor) {
  1638. $docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
  1639. } else {
  1640. $docStyle->getFill()->getStartColor()->setARGB('FF000000');
  1641. }
  1642. if ($style->fill->patternFill->bgColor) {
  1643. $docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
  1644. }
  1645. }
  1646. }
  1647. // border
  1648. if (isset($style->border)) {
  1649. $diagonalUp = self::boolean((string) $style->border["diagonalUp"]);
  1650. $diagonalDown = self::boolean((string) $style->border["diagonalDown"]);
  1651. if (!$diagonalUp && !$diagonalDown) {
  1652. $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_NONE);
  1653. } elseif ($diagonalUp && !$diagonalDown) {
  1654. $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_UP);
  1655. } elseif (!$diagonalUp && $diagonalDown) {
  1656. $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_DOWN);
  1657. } else {
  1658. $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH);
  1659. }
  1660. self::readBorder($docStyle->getBorders()->getLeft(), $style->border->left);
  1661. self::readBorder($docStyle->getBorders()->getRight(), $style->border->right);
  1662. self::readBorder($docStyle->getBorders()->getTop(), $style->border->top);
  1663. self::readBorder($docStyle->getBorders()->getBottom(), $style->border->bottom);
  1664. self::readBorder($docStyle->getBorders()->getDiagonal(), $style->border->diagonal);
  1665. }
  1666. // alignment
  1667. if (isset($style->alignment)) {
  1668. $docStyle->getAlignment()->setHorizontal((string) $style->alignment["horizontal"]);
  1669. $docStyle->getAlignment()->setVertical((string) $style->alignment["vertical"]);
  1670. $textRotation = 0;
  1671. if ((int)$style->alignment["textRotation"] <= 90) {
  1672. $textRotation = (int)$style->alignment["textRotation"];
  1673. } elseif ((int)$style->alignment["textRotation"] > 90) {
  1674. $textRotation = 90 - (int)$style->alignment["textRotation"];
  1675. }
  1676. $docStyle->getAlignment()->setTextRotation(intval($textRotation));
  1677. $docStyle->getAlignment()->setWrapText(self::boolean((string) $style->alignment["wrapText"]));
  1678. $docStyle->getAlignment()->setShrinkToFit(self::boolean((string) $style->alignment["shrinkToFit"]));
  1679. $docStyle->getAlignment()->setIndent(intval((string)$style->alignment["indent"]) > 0 ? intval((string)$style->alignment["indent"]) : 0);
  1680. $docStyle->getAlignment()->setReadorder(intval((string)$style->alignment["readingOrder"]) > 0 ? intval((string)$style->alignment["readingOrder"]) : 0);
  1681. }
  1682. // protection
  1683. if (isset($style->protection)) {
  1684. if (isset($style->protection['locked'])) {
  1685. if (self::boolean((string) $style->protection['locked'])) {
  1686. $docStyle->getProtection()->setLocked(PHPExcel_Style_Protection::PROTECTION_PROTECTED);
  1687. } else {
  1688. $docStyle->getProtection()->setLocked(PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
  1689. }
  1690. }
  1691. if (isset($style->protection['hidden'])) {
  1692. if (self::boolean((string) $style->protection['hidden'])) {
  1693. $docStyle->getProtection()->setHidden(PHPExcel_Style_Protection::PROTECTION_PROTECTED);
  1694. } else {
  1695. $docStyle->getProtection()->setHidden(PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
  1696. }
  1697. }
  1698. }
  1699. // top-level style settings
  1700. if (isset($style->quotePrefix)) {
  1701. $docStyle->setQuotePrefix($style->quotePrefix);
  1702. }
  1703. }
  1704. private static function readBorder($docBorder, $eleBorder)
  1705. {
  1706. if (isset($eleBorder["style"])) {
  1707. $docBorder->setBorderStyle((string) $eleBorder["style"]);
  1708. }
  1709. if (isset($eleBorder->color)) {
  1710. $docBorder->getColor()->setARGB(self::readColor($eleBorder->color));
  1711. }
  1712. }
  1713. private function parseRichText($is = null)
  1714. {
  1715. $value = new PHPExcel_RichText();
  1716. if (isset($is->t)) {
  1717. $value->createText(PHPExcel_Shared_String::ControlCharacterOOXML2PHP((string) $is->t));
  1718. } else {
  1719. if (is_object($is->r)) {
  1720. foreach ($is->r as $run) {
  1721. if (!isset($run->rPr)) {
  1722. $objText = $value->createText(PHPExcel_Shared_String::ControlCharacterOOXML2PHP((string) $run->t));
  1723. } else {
  1724. $objText = $value->createTextRun(PHPExcel_Shared_String::ControlCharacterOOXML2PHP((string) $run->t));
  1725. if (isset($run->rPr->rFont["val"])) {
  1726. $objText->getFont()->setName((string) $run->rPr->rFont["val"]);
  1727. }
  1728. if (isset($run->rPr->sz["val"])) {
  1729. $objText->getFont()->setSize((string) $run->rPr->sz["val"]);
  1730. }
  1731. if (isset($run->rPr->color)) {
  1732. $objText->getFont()->setColor(new PHPExcel_Style_Color(self::readColor($run->rPr->color)));
  1733. }
  1734. if ((isset($run->rPr->b["val"]) && self::boolean((string) $run->rPr->b["val"])) ||
  1735. (isset($run->rPr->b) && !isset($run->rPr->b["val"]))) {
  1736. $objText->getFont()->setBold(true);
  1737. }
  1738. if ((isset($run->rPr->i["val"]) && self::boolean((string) $run->rPr->i["val"])) ||
  1739. (isset($run->rPr->i) && !isset($run->rPr->i["val"]))) {
  1740. $objText->getFont()->setItalic(true);
  1741. }
  1742. if (isset($run->rPr->vertAlign) && isset($run->rPr->vertAlign["val"])) {
  1743. $vertAlign = strtolower((string)$run->rPr->vertAlign["val"]);
  1744. if ($vertAlign == 'superscript') {
  1745. $objText->getFont()->setSuperScript(true);
  1746. }
  1747. if ($vertAlign == 'subscript') {
  1748. $objText->getFont()->setSubScript(true);
  1749. }
  1750. }
  1751. if (isset($run->rPr->u) && !isset($run->rPr->u["val"])) {
  1752. $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
  1753. } elseif (isset($run->rPr->u) && isset($run->rPr->u["val"])) {
  1754. $objText->getFont()->setUnderline((string)$run->rPr->u["val"]);
  1755. }
  1756. if ((isset($run->rPr->strike["val"]) && self::boolean((string) $run->rPr->strike["val"])) ||
  1757. (isset($run->rPr->strike) && !isset($run->rPr->strike["val"]))) {
  1758. $objText->getFont()->setStrikethrough(true);
  1759. }
  1760. }
  1761. }
  1762. }
  1763. }
  1764. return $value;
  1765. }
  1766. private function readRibbon($excel, $customUITarget, $zip)
  1767. {
  1768. $baseDir = dirname($customUITarget);
  1769. $nameCustomUI = basename($customUITarget);
  1770. // get the xml file (ribbon)
  1771. $localRibbon = $this->getFromZipArchive($zip, $customUITarget);
  1772. $customUIImagesNames = array();
  1773. $customUIImagesBinaries = array();
  1774. // something like customUI/_rels/customUI.xml.rels
  1775. $pathRels = $baseDir . '/_rels/' . $nameCustomUI . '.rels';
  1776. $dataRels = $this->getFromZipArchive($zip, $pathRels);
  1777. if ($dataRels) {
  1778. // exists and not empty if the ribbon have some pictures (other than internal MSO)
  1779. $UIRels = simplexml_load_string($this->securityScan($dataRels), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
  1780. if ($UIRels) {
  1781. // we need to save id and target to avoid parsing customUI.xml and "guess" if it's a pseudo callback who load the image
  1782. foreach ($UIRels->Relationship as $ele) {
  1783. if ($ele["Type"] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
  1784. // an image ?
  1785. $customUIImagesNames[(string) $ele['Id']] = (string)$ele['Target'];
  1786. $customUIImagesBinaries[(string)$ele['Target']] = $this->getFromZipArchive($zip, $baseDir . '/' . (string) $ele['Target']);
  1787. }
  1788. }
  1789. }
  1790. }
  1791. if ($localRibbon) {
  1792. $excel->setRibbonXMLData($customUITarget, $localRibbon);
  1793. if (count($customUIImagesNames) > 0 && count($customUIImagesBinaries) > 0) {
  1794. $excel->setRibbonBinObjects($customUIImagesNames, $customUIImagesBinaries);
  1795. } else {
  1796. $excel->setRibbonBinObjects(null);
  1797. }
  1798. } else {
  1799. $excel->setRibbonXMLData(null);
  1800. $excel->setRibbonBinObjects(null);
  1801. }
  1802. }
  1803. private static function getArrayItem($array, $key = 0)
  1804. {
  1805. return (isset($array[$key]) ? $array[$key] : null);
  1806. }
  1807. private static function dirAdd($base, $add)
  1808. {
  1809. return preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add");
  1810. }
  1811. private static function toCSSArray($style)
  1812. {
  1813. $style = str_replace(array("\r","\n"), "", $style);
  1814. $temp = explode(';', $style);
  1815. $style = array();
  1816. foreach ($temp as $item) {
  1817. $item = explode(':', $item);
  1818. if (strpos($item[1], 'px') !== false) {
  1819. $item[1] = str_replace('px', '', $item[1]);
  1820. }
  1821. if (strpos($item[1], 'pt') !== false) {
  1822. $item[1] = str_replace('pt', '', $item[1]);
  1823. $item[1] = PHPExcel_Shared_Font::fontSizeToPixels($item[1]);
  1824. }
  1825. if (strpos($item[1], 'in') !== false) {
  1826. $item[1] = str_replace('in', '', $item[1]);
  1827. $item[1] = PHPExcel_Shared_Font::inchSizeToPixels($item[1]);
  1828. }
  1829. if (strpos($item[1], 'cm') !== false) {
  1830. $item[1] = str_replace('cm', '', $item[1]);
  1831. $item[1] = PHPExcel_Shared_Font::centimeterSizeToPixels($item[1]);
  1832. }
  1833. $style[$item[0]] = $item[1];
  1834. }
  1835. return $style;
  1836. }
  1837. private static function boolean($value = null)
  1838. {
  1839. if (is_object($value)) {
  1840. $value = (string) $value;
  1841. }
  1842. if (is_numeric($value)) {
  1843. return (bool) $value;
  1844. }
  1845. return ($value === 'true' || $value === 'TRUE');
  1846. }
  1847. }