PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/v1.7.2/Classes/PHPExcel/Reader/SYLK.php

#
PHP | 506 lines | 265 code | 45 blank | 196 comment | 46 complexity | 8340a751bd3494d764585533957784c4 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.0, LGPL-2.1, GPL-3.0, LGPL-3.0
  1. <?php
  2. /**
  3. * PHPExcel
  4. *
  5. * Copyright (c) 2006 - 2010 PHPExcel
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * @category PHPExcel
  22. * @package PHPExcel_Reader
  23. * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
  24. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  25. * @version ##VERSION##, ##DATE##
  26. */
  27. /** PHPExcel root directory */
  28. if (!defined('PHPEXCEL_ROOT')) {
  29. /**
  30. * @ignore
  31. */
  32. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
  33. }
  34. /** PHPExcel */
  35. require_once PHPEXCEL_ROOT . 'PHPExcel.php';
  36. /** PHPExcel_Reader_IReader */
  37. require_once PHPEXCEL_ROOT . 'PHPExcel/Reader/IReader.php';
  38. /** PHPExcel_Worksheet */
  39. require_once PHPEXCEL_ROOT . 'PHPExcel/Worksheet.php';
  40. /** PHPExcel_Cell */
  41. require_once PHPEXCEL_ROOT . 'PHPExcel/Cell.php';
  42. /** PHPExcel_Calculation */
  43. require_once PHPEXCEL_ROOT . 'PHPExcel/Calculation.php';
  44. /** PHPExcel_Reader_DefaultReadFilter */
  45. require_once PHPEXCEL_ROOT . 'PHPExcel/Reader/DefaultReadFilter.php';
  46. /**
  47. * PHPExcel_Reader_SYLK
  48. *
  49. * @category PHPExcel
  50. * @package PHPExcel_Reader
  51. * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
  52. */
  53. class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
  54. {
  55. /**
  56. * Input encoding
  57. *
  58. * @var string
  59. */
  60. private $_inputEncoding;
  61. /**
  62. * Delimiter
  63. *
  64. * @var string
  65. */
  66. private $_delimiter;
  67. /**
  68. * Enclosure
  69. *
  70. * @var string
  71. */
  72. private $_enclosure;
  73. /**
  74. * Line ending
  75. *
  76. * @var string
  77. */
  78. private $_lineEnding;
  79. /**
  80. * Sheet index to read
  81. *
  82. * @var int
  83. */
  84. private $_sheetIndex;
  85. /**
  86. * Formats
  87. *
  88. * @var array
  89. */
  90. private $_formats = array();
  91. /**
  92. * Format Count
  93. *
  94. * @var int
  95. */
  96. private $_format = 0;
  97. /**
  98. * PHPExcel_Reader_IReadFilter instance
  99. *
  100. * @var PHPExcel_Reader_IReadFilter
  101. */
  102. private $_readFilter = null;
  103. /**
  104. * Create a new PHPExcel_Reader_SYLK
  105. */
  106. public function __construct() {
  107. $this->_inputEncoding = 'ANSI';
  108. $this->_delimiter = ';';
  109. $this->_enclosure = '"';
  110. $this->_lineEnding = PHP_EOL;
  111. $this->_sheetIndex = 0;
  112. $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
  113. }
  114. /**
  115. * Can the current PHPExcel_Reader_IReader read the file?
  116. *
  117. * @param string $pFileName
  118. * @return boolean
  119. */
  120. public function canRead($pFilename)
  121. {
  122. // Check if file exists
  123. if (!file_exists($pFilename)) {
  124. throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
  125. }
  126. // Read sample data (first 2 KB will do)
  127. $fh = fopen($pFilename, 'r');
  128. $data = fread($fh, 2048);
  129. fclose($fh);
  130. // Count delimiters in file
  131. $delimiterCount = substr_count($data, ';');
  132. if ($delimiterCount < 1) {
  133. return false;
  134. }
  135. // Analyze first line looking for ID; signature
  136. $lines = explode("\n", $data);
  137. if (substr($lines[0],0,4) != 'ID;P') {
  138. return false;
  139. }
  140. return true;
  141. }
  142. /**
  143. * Loads PHPExcel from file
  144. *
  145. * @param string $pFilename
  146. * @throws Exception
  147. */
  148. public function load($pFilename)
  149. {
  150. // Create new PHPExcel
  151. $objPHPExcel = new PHPExcel();
  152. // Load into this instance
  153. return $this->loadIntoExisting($pFilename, $objPHPExcel);
  154. }
  155. /**
  156. * Read filter
  157. *
  158. * @return PHPExcel_Reader_IReadFilter
  159. */
  160. public function getReadFilter() {
  161. return $this->_readFilter;
  162. }
  163. /**
  164. * Set read filter
  165. *
  166. * @param PHPExcel_Reader_IReadFilter $pValue
  167. */
  168. public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) {
  169. $this->_readFilter = $pValue;
  170. }
  171. /**
  172. * Set input encoding
  173. *
  174. * @param string $pValue Input encoding
  175. */
  176. public function setInputEncoding($pValue = 'ANSI')
  177. {
  178. $this->_inputEncoding = $pValue;
  179. }
  180. /**
  181. * Get input encoding
  182. *
  183. * @return string
  184. */
  185. public function getInputEncoding()
  186. {
  187. return $this->_inputEncoding;
  188. }
  189. /**
  190. * Loads PHPExcel from file into PHPExcel instance
  191. *
  192. * @param string $pFilename
  193. * @param PHPExcel $objPHPExcel
  194. * @throws Exception
  195. */
  196. public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
  197. {
  198. // Check if file exists
  199. if (!file_exists($pFilename)) {
  200. throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
  201. }
  202. // Create new PHPExcel
  203. while ($objPHPExcel->getSheetCount() <= $this->_sheetIndex) {
  204. $objPHPExcel->createSheet();
  205. }
  206. $objPHPExcel->setActiveSheetIndex( $this->_sheetIndex );
  207. $fromFormats = array('\-', '\ ');
  208. $toFormats = array('-', ' ');
  209. // Open file
  210. $fileHandle = fopen($pFilename, 'r');
  211. if ($fileHandle === false) {
  212. throw new Exception("Could not open file $pFilename for reading.");
  213. }
  214. // Loop through file
  215. $rowData = array();
  216. $column = $row = '';
  217. while (($rowData = fgets($fileHandle)) !== FALSE) {
  218. $rowData = explode("\t",str_replace('¤',';',str_replace(';',"\t",str_replace(';;','¤',rtrim($rowData)))));
  219. $dataType = array_shift($rowData);
  220. // Read shared styles
  221. if ($dataType == 'P') {
  222. $formatArray = array();
  223. foreach($rowData as $rowDatum) {
  224. switch($rowDatum{0}) {
  225. case 'P' : $formatArray['numberformat']['code'] = str_replace($fromFormats,$toFormats,substr($rowDatum,1));
  226. break;
  227. case 'E' :
  228. case 'F' : $formatArray['font']['name'] = substr($rowDatum,1);
  229. break;
  230. case 'L' : $formatArray['font']['size'] = substr($rowDatum,1);
  231. break;
  232. case 'S' : $styleSettings = substr($rowDatum,1);
  233. for ($i=0;$i<strlen($styleSettings);++$i) {
  234. switch ($styleSettings{$i}) {
  235. case 'I' : $formatArray['font']['italic'] = true;
  236. break;
  237. case 'D' : $formatArray['font']['bold'] = true;
  238. break;
  239. case 'T' : $formatArray['borders']['top']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  240. break;
  241. case 'B' : $formatArray['borders']['bottom']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  242. break;
  243. case 'L' : $formatArray['borders']['left']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  244. break;
  245. case 'R' : $formatArray['borders']['right']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  246. break;
  247. }
  248. }
  249. break;
  250. }
  251. }
  252. $this->_formats['P'.$this->_format++] = $formatArray;
  253. // Read cell value data
  254. } elseif ($dataType == 'C') {
  255. $hasCalculatedValue = false;
  256. $cellData = $cellDataFormula = '';
  257. foreach($rowData as $rowDatum) {
  258. switch($rowDatum{0}) {
  259. case 'C' :
  260. case 'X' : $column = substr($rowDatum,1);
  261. break;
  262. case 'R' :
  263. case 'Y' : $row = substr($rowDatum,1);
  264. break;
  265. case 'K' : $cellData = substr($rowDatum,1);
  266. break;
  267. case 'E' : $cellDataFormula = '='.substr($rowDatum,1);
  268. // Convert R1C1 style references to A1 style references (but only when not quoted)
  269. $temp = explode('"',$cellDataFormula);
  270. foreach($temp as $key => &$value) {
  271. // Only count/replace in alternate array entries
  272. if (($key % 2) == 0) {
  273. preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/',$value, $cellReferences,PREG_SET_ORDER+PREG_OFFSET_CAPTURE);
  274. // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way
  275. // through the formula from left to right. Reversing means that we work right to left.through
  276. // the formula
  277. $cellReferences = array_reverse($cellReferences);
  278. // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent,
  279. // then modify the formula to use that new reference
  280. foreach($cellReferences as $cellReference) {
  281. $rowReference = $cellReference[2][0];
  282. // Empty R reference is the current row
  283. if ($rowReference == '') $rowReference = $row;
  284. // Bracketed R references are relative to the current row
  285. if ($rowReference{0} == '[') $rowReference = $row + trim($rowReference,'[]');
  286. $columnReference = $cellReference[4][0];
  287. // Empty C reference is the current column
  288. if ($columnReference == '') $columnReference = $column;
  289. // Bracketed C references are relative to the current column
  290. if ($columnReference{0} == '[') $columnReference = $column + trim($columnReference,'[]');
  291. $A1CellReference = PHPExcel_Cell::stringFromColumnIndex($columnReference-1).$rowReference;
  292. $value = substr_replace($value,$A1CellReference,$cellReference[0][1],strlen($cellReference[0][0]));
  293. }
  294. }
  295. }
  296. unset($value);
  297. // Then rebuild the formula string
  298. $cellDataFormula = implode('"',$temp);
  299. $hasCalculatedValue = true;
  300. break;
  301. }
  302. }
  303. $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
  304. $cellData = PHPExcel_Calculation::_unwrapResult($cellData);
  305. // Set cell value
  306. $objPHPExcel->getActiveSheet()->setCellValue($columnLetter.$row, (($hasCalculatedValue) ? $cellDataFormula : $cellData));
  307. if ($hasCalculatedValue) {
  308. $cellData = PHPExcel_Calculation::_unwrapResult($cellData);
  309. $objPHPExcel->getActiveSheet()->getCell($columnLetter.$row)->setCalculatedValue($cellData);
  310. }
  311. // Read cell formatting
  312. } elseif ($dataType == 'F') {
  313. $formatStyle = $columnWidth = $styleSettings = '';
  314. $styleData = array();
  315. foreach($rowData as $rowDatum) {
  316. switch($rowDatum{0}) {
  317. case 'C' :
  318. case 'X' : $column = substr($rowDatum,1);
  319. break;
  320. case 'R' :
  321. case 'Y' : $row = substr($rowDatum,1);
  322. break;
  323. case 'P' : $formatStyle = $rowDatum;
  324. break;
  325. case 'W' : list($startCol,$endCol,$columnWidth) = explode(' ',substr($rowDatum,1));
  326. break;
  327. case 'S' : $styleSettings = substr($rowDatum,1);
  328. for ($i=0;$i<strlen($styleSettings);++$i) {
  329. switch ($styleSettings{$i}) {
  330. case 'I' : $styleData['font']['italic'] = true;
  331. break;
  332. case 'D' : $styleData['font']['bold'] = true;
  333. break;
  334. case 'T' : $styleData['borders']['top']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  335. break;
  336. case 'B' : $styleData['borders']['bottom']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  337. break;
  338. case 'L' : $styleData['borders']['left']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  339. break;
  340. case 'R' : $styleData['borders']['right']['style'] = PHPExcel_Style_Border::BORDER_THIN;
  341. break;
  342. }
  343. }
  344. break;
  345. }
  346. }
  347. if (($formatStyle > '') && ($column > '') && ($row > '')) {
  348. $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
  349. $objPHPExcel->getActiveSheet()->getStyle($columnLetter.$row)->applyFromArray($this->_formats[$formatStyle]);
  350. }
  351. if ((count($styleData) > 0) && ($column > '') && ($row > '')) {
  352. $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
  353. $objPHPExcel->getActiveSheet()->getStyle($columnLetter.$row)->applyFromArray($styleData);
  354. }
  355. if ($columnWidth > '') {
  356. if ($startCol == $endCol) {
  357. $startCol = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
  358. $objPHPExcel->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth);
  359. } else {
  360. $startCol = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
  361. $endCol = PHPExcel_Cell::stringFromColumnIndex($endCol-1);
  362. $objPHPExcel->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth);
  363. do {
  364. $objPHPExcel->getActiveSheet()->getColumnDimension(++$startCol)->setWidth($columnWidth);
  365. } while ($startCol != $endCol);
  366. }
  367. }
  368. } else {
  369. foreach($rowData as $rowDatum) {
  370. switch($rowDatum{0}) {
  371. case 'C' :
  372. case 'X' : $column = substr($rowDatum,1);
  373. break;
  374. case 'R' :
  375. case 'Y' : $row = substr($rowDatum,1);
  376. break;
  377. }
  378. }
  379. }
  380. }
  381. // Close file
  382. fclose($fileHandle);
  383. // Return
  384. return $objPHPExcel;
  385. }
  386. /**
  387. * Get delimiter
  388. *
  389. * @return string
  390. */
  391. public function getDelimiter() {
  392. return $this->_delimiter;
  393. }
  394. /**
  395. * Set delimiter
  396. *
  397. * @param string $pValue Delimiter, defaults to ,
  398. * @return PHPExcel_Reader_SYLK
  399. */
  400. public function setDelimiter($pValue = ',') {
  401. $this->_delimiter = $pValue;
  402. return $this;
  403. }
  404. /**
  405. * Get enclosure
  406. *
  407. * @return string
  408. */
  409. public function getEnclosure() {
  410. return $this->_enclosure;
  411. }
  412. /**
  413. * Set enclosure
  414. *
  415. * @param string $pValue Enclosure, defaults to "
  416. * @return PHPExcel_Reader_SYLK
  417. */
  418. public function setEnclosure($pValue = '"') {
  419. if ($pValue == '') {
  420. $pValue = '"';
  421. }
  422. $this->_enclosure = $pValue;
  423. return $this;
  424. }
  425. /**
  426. * Get line ending
  427. *
  428. * @return string
  429. */
  430. public function getLineEnding() {
  431. return $this->_lineEnding;
  432. }
  433. /**
  434. * Set line ending
  435. *
  436. * @param string $pValue Line ending, defaults to OS line ending (PHP_EOL)
  437. * @return PHPExcel_Reader_SYLK
  438. */
  439. public function setLineEnding($pValue = PHP_EOL) {
  440. $this->_lineEnding = $pValue;
  441. return $this;
  442. }
  443. /**
  444. * Get sheet index
  445. *
  446. * @return int
  447. */
  448. public function getSheetIndex() {
  449. return $this->_sheetIndex;
  450. }
  451. /**
  452. * Set sheet index
  453. *
  454. * @param int $pValue Sheet index
  455. * @return PHPExcel_Reader_SYLK
  456. */
  457. public function setSheetIndex($pValue = 0) {
  458. $this->_sheetIndex = $pValue;
  459. return $this;
  460. }
  461. }