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.

478 lines
19 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_SYLK
  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_SYLK extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
  36. {
  37. /**
  38. * Input encoding
  39. *
  40. * @var string
  41. */
  42. private $inputEncoding = 'ANSI';
  43. /**
  44. * Sheet index to read
  45. *
  46. * @var int
  47. */
  48. private $sheetIndex = 0;
  49. /**
  50. * Formats
  51. *
  52. * @var array
  53. */
  54. private $formats = array();
  55. /**
  56. * Format Count
  57. *
  58. * @var int
  59. */
  60. private $format = 0;
  61. /**
  62. * Create a new PHPExcel_Reader_SYLK
  63. */
  64. public function __construct()
  65. {
  66. $this->readFilter = new PHPExcel_Reader_DefaultReadFilter();
  67. }
  68. /**
  69. * Validate that the current file is a SYLK file
  70. *
  71. * @return boolean
  72. */
  73. protected function isValidFormat()
  74. {
  75. // Read sample data (first 2 KB will do)
  76. $data = fread($this->fileHandle, 2048);
  77. // Count delimiters in file
  78. $delimiterCount = substr_count($data, ';');
  79. if ($delimiterCount < 1) {
  80. return false;
  81. }
  82. // Analyze first line looking for ID; signature
  83. $lines = explode("\n", $data);
  84. if (substr($lines[0], 0, 4) != 'ID;P') {
  85. return false;
  86. }
  87. return true;
  88. }
  89. /**
  90. * Set input encoding
  91. *
  92. * @param string $pValue Input encoding
  93. */
  94. public function setInputEncoding($pValue = 'ANSI')
  95. {
  96. $this->inputEncoding = $pValue;
  97. return $this;
  98. }
  99. /**
  100. * Get input encoding
  101. *
  102. * @return string
  103. */
  104. public function getInputEncoding()
  105. {
  106. return $this->inputEncoding;
  107. }
  108. /**
  109. * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
  110. *
  111. * @param string $pFilename
  112. * @throws PHPExcel_Reader_Exception
  113. */
  114. public function listWorksheetInfo($pFilename)
  115. {
  116. // Open file
  117. $this->openFile($pFilename);
  118. if (!$this->isValidFormat()) {
  119. fclose($this->fileHandle);
  120. throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
  121. }
  122. $fileHandle = $this->fileHandle;
  123. rewind($fileHandle);
  124. $worksheetInfo = array();
  125. $worksheetInfo[0]['worksheetName'] = 'Worksheet';
  126. $worksheetInfo[0]['lastColumnLetter'] = 'A';
  127. $worksheetInfo[0]['lastColumnIndex'] = 0;
  128. $worksheetInfo[0]['totalRows'] = 0;
  129. $worksheetInfo[0]['totalColumns'] = 0;
  130. // Loop through file
  131. $rowData = array();
  132. // loop through one row (line) at a time in the file
  133. $rowIndex = 0;
  134. while (($rowData = fgets($fileHandle)) !== false) {
  135. $columnIndex = 0;
  136. // convert SYLK encoded $rowData to UTF-8
  137. $rowData = PHPExcel_Shared_String::SYLKtoUTF8($rowData);
  138. // explode each row at semicolons while taking into account that literal semicolon (;)
  139. // is escaped like this (;;)
  140. $rowData = explode("\t", str_replace('¤', ';', str_replace(';', "\t", str_replace(';;', '¤', rtrim($rowData)))));
  141. $dataType = array_shift($rowData);
  142. if ($dataType == 'C') {
  143. // Read cell value data
  144. foreach ($rowData as $rowDatum) {
  145. switch ($rowDatum{0}) {
  146. case 'C':
  147. case 'X':
  148. $columnIndex = substr($rowDatum, 1) - 1;
  149. break;
  150. case 'R':
  151. case 'Y':
  152. $rowIndex = substr($rowDatum, 1);
  153. break;
  154. }
  155. $worksheetInfo[0]['totalRows'] = max($worksheetInfo[0]['totalRows'], $rowIndex);
  156. $worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], $columnIndex);
  157. }
  158. }
  159. }
  160. $worksheetInfo[0]['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex']);
  161. $worksheetInfo[0]['totalColumns'] = $worksheetInfo[0]['lastColumnIndex'] + 1;
  162. // Close file
  163. fclose($fileHandle);
  164. return $worksheetInfo;
  165. }
  166. /**
  167. * Loads PHPExcel from file
  168. *
  169. * @param string $pFilename
  170. * @return PHPExcel
  171. * @throws PHPExcel_Reader_Exception
  172. */
  173. public function load($pFilename)
  174. {
  175. // Create new PHPExcel
  176. $objPHPExcel = new PHPExcel();
  177. // Load into this instance
  178. return $this->loadIntoExisting($pFilename, $objPHPExcel);
  179. }
  180. /**
  181. * Loads PHPExcel from file into PHPExcel instance
  182. *
  183. * @param string $pFilename
  184. * @param PHPExcel $objPHPExcel
  185. * @return PHPExcel
  186. * @throws PHPExcel_Reader_Exception
  187. */
  188. public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
  189. {
  190. // Open file
  191. $this->openFile($pFilename);
  192. if (!$this->isValidFormat()) {
  193. fclose($this->fileHandle);
  194. throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
  195. }
  196. $fileHandle = $this->fileHandle;
  197. rewind($fileHandle);
  198. // Create new PHPExcel
  199. while ($objPHPExcel->getSheetCount() <= $this->sheetIndex) {
  200. $objPHPExcel->createSheet();
  201. }
  202. $objPHPExcel->setActiveSheetIndex($this->sheetIndex);
  203. $fromFormats = array('\-', '\ ');
  204. $toFormats = array('-', ' ');
  205. // Loop through file
  206. $rowData = array();
  207. $column = $row = '';
  208. // loop through one row (line) at a time in the file
  209. while (($rowData = fgets($fileHandle)) !== false) {
  210. // convert SYLK encoded $rowData to UTF-8
  211. $rowData = PHPExcel_Shared_String::SYLKtoUTF8($rowData);
  212. // explode each row at semicolons while taking into account that literal semicolon (;)
  213. // is escaped like this (;;)
  214. $rowData = explode("\t", str_replace('¤', ';', str_replace(';', "\t", str_replace(';;', '¤', rtrim($rowData)))));
  215. $dataType = array_shift($rowData);
  216. // Read shared styles
  217. if ($dataType == 'P') {
  218. $formatArray = array();
  219. foreach ($rowData as $rowDatum) {
  220. switch ($rowDatum{0}) {
  221. case 'P':
  222. $formatArray['numberformat']['code'] = str_replace($fromFormats, $toFormats, substr($rowDatum, 1));
  223. break;
  224. case 'E':
  225. case 'F':
  226. $formatArray['font']['name'] = substr($rowDatum, 1);
  227. break;
  228. case 'L':
  229. $formatArray['font']['size'] = substr($rowDatum, 1);
  230. break;
  231. case 'S':
  232. $styleSettings = substr($rowDatum, 1);
  233. for ($i=0; $i<strlen($styleSettings); ++$i) {
  234. switch ($styleSettings{$i}) {
  235. case 'I':
  236. $formatArray['font']['italic'] = true;
  237. break;
  238. case 'D':
  239. $formatArray['font']['bold'] = true;
  240. break;
  241. case 'T':
  242. $formatArray['borders']['top']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  243. break;
  244. case 'B':
  245. $formatArray['borders']['bottom']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  246. break;
  247. case 'L':
  248. $formatArray['borders']['left']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  249. break;
  250. case 'R':
  251. $formatArray['borders']['right']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  252. break;
  253. }
  254. }
  255. break;
  256. }
  257. }
  258. $this->formats['P'.$this->format++] = $formatArray;
  259. // Read cell value data
  260. } elseif ($dataType == 'C') {
  261. $hasCalculatedValue = false;
  262. $cellData = $cellDataFormula = '';
  263. foreach ($rowData as $rowDatum) {
  264. switch ($rowDatum{0}) {
  265. case 'C':
  266. case 'X':
  267. $column = substr($rowDatum, 1);
  268. break;
  269. case 'R':
  270. case 'Y':
  271. $row = substr($rowDatum, 1);
  272. break;
  273. case 'K':
  274. $cellData = substr($rowDatum, 1);
  275. break;
  276. case 'E':
  277. $cellDataFormula = '='.substr($rowDatum, 1);
  278. // Convert R1C1 style references to A1 style references (but only when not quoted)
  279. $temp = explode('"', $cellDataFormula);
  280. $key = false;
  281. foreach ($temp as &$value) {
  282. // Only count/replace in alternate array entries
  283. if ($key = !$key) {
  284. preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/', $value, $cellReferences, PREG_SET_ORDER+PREG_OFFSET_CAPTURE);
  285. // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way
  286. // through the formula from left to right. Reversing means that we work right to left.through
  287. // the formula
  288. $cellReferences = array_reverse($cellReferences);
  289. // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent,
  290. // then modify the formula to use that new reference
  291. foreach ($cellReferences as $cellReference) {
  292. $rowReference = $cellReference[2][0];
  293. // Empty R reference is the current row
  294. if ($rowReference == '') {
  295. $rowReference = $row;
  296. }
  297. // Bracketed R references are relative to the current row
  298. if ($rowReference{0} == '[') {
  299. $rowReference = $row + trim($rowReference, '[]');
  300. }
  301. $columnReference = $cellReference[4][0];
  302. // Empty C reference is the current column
  303. if ($columnReference == '') {
  304. $columnReference = $column;
  305. }
  306. // Bracketed C references are relative to the current column
  307. if ($columnReference{0} == '[') {
  308. $columnReference = $column + trim($columnReference, '[]');
  309. }
  310. $A1CellReference = PHPExcel_Cell::stringFromColumnIndex($columnReference-1).$rowReference;
  311. $value = substr_replace($value, $A1CellReference, $cellReference[0][1], strlen($cellReference[0][0]));
  312. }
  313. }
  314. }
  315. unset($value);
  316. // Then rebuild the formula string
  317. $cellDataFormula = implode('"', $temp);
  318. $hasCalculatedValue = true;
  319. break;
  320. }
  321. }
  322. $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
  323. $cellData = PHPExcel_Calculation::unwrapResult($cellData);
  324. // Set cell value
  325. $objPHPExcel->getActiveSheet()->getCell($columnLetter.$row)->setValue(($hasCalculatedValue) ? $cellDataFormula : $cellData);
  326. if ($hasCalculatedValue) {
  327. $cellData = PHPExcel_Calculation::unwrapResult($cellData);
  328. $objPHPExcel->getActiveSheet()->getCell($columnLetter.$row)->setCalculatedValue($cellData);
  329. }
  330. // Read cell formatting
  331. } elseif ($dataType == 'F') {
  332. $formatStyle = $columnWidth = $styleSettings = '';
  333. $styleData = array();
  334. foreach ($rowData as $rowDatum) {
  335. switch ($rowDatum{0}) {
  336. case 'C':
  337. case 'X':
  338. $column = substr($rowDatum, 1);
  339. break;
  340. case 'R':
  341. case 'Y':
  342. $row = substr($rowDatum, 1);
  343. break;
  344. case 'P':
  345. $formatStyle = $rowDatum;
  346. break;
  347. case 'W':
  348. list($startCol, $endCol, $columnWidth) = explode(' ', substr($rowDatum, 1));
  349. break;
  350. case 'S':
  351. $styleSettings = substr($rowDatum, 1);
  352. for ($i=0; $i<strlen($styleSettings); ++$i) {
  353. switch ($styleSettings{$i}) {
  354. case 'I':
  355. $styleData['font']['italic'] = true;
  356. break;
  357. case 'D':
  358. $styleData['font']['bold'] = true;
  359. break;
  360. case 'T':
  361. $styleData['borders']['top']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  362. break;
  363. case 'B':
  364. $styleData['borders']['bottom']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  365. break;
  366. case 'L':
  367. $styleData['borders']['left']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  368. break;
  369. case 'R':
  370. $styleData['borders']['right']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  371. break;
  372. }
  373. }
  374. break;
  375. }
  376. }
  377. if (($formatStyle > '') && ($column > '') && ($row > '')) {
  378. $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
  379. if (isset($this->formats[$formatStyle])) {
  380. $objPHPExcel->getActiveSheet()->getStyle($columnLetter.$row)->applyFromArray($this->formats[$formatStyle]);
  381. }
  382. }
  383. if ((!empty($styleData)) && ($column > '') && ($row > '')) {
  384. $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
  385. $objPHPExcel->getActiveSheet()->getStyle($columnLetter.$row)->applyFromArray($styleData);
  386. }
  387. if ($columnWidth > '') {
  388. if ($startCol == $endCol) {
  389. $startCol = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
  390. $objPHPExcel->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth);
  391. } else {
  392. $startCol = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
  393. $endCol = PHPExcel_Cell::stringFromColumnIndex($endCol-1);
  394. $objPHPExcel->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth);
  395. do {
  396. $objPHPExcel->getActiveSheet()->getColumnDimension(++$startCol)->setWidth($columnWidth);
  397. } while ($startCol != $endCol);
  398. }
  399. }
  400. } else {
  401. foreach ($rowData as $rowDatum) {
  402. switch ($rowDatum{0}) {
  403. case 'C':
  404. case 'X':
  405. $column = substr($rowDatum, 1);
  406. break;
  407. case 'R':
  408. case 'Y':
  409. $row = substr($rowDatum, 1);
  410. break;
  411. }
  412. }
  413. }
  414. }
  415. // Close file
  416. fclose($fileHandle);
  417. // Return
  418. return $objPHPExcel;
  419. }
  420. /**
  421. * Get sheet index
  422. *
  423. * @return int
  424. */
  425. public function getSheetIndex()
  426. {
  427. return $this->sheetIndex;
  428. }
  429. /**
  430. * Set sheet index
  431. *
  432. * @param int $pValue Sheet index
  433. * @return PHPExcel_Reader_SYLK
  434. */
  435. public function setSheetIndex($pValue = 0)
  436. {
  437. $this->sheetIndex = $pValue;
  438. return $this;
  439. }
  440. }