SYLK.php 20 KB

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