PHPExcelReader.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. /**
  3. * PHPExcelReader class
  4. *
  5. * @version 1.0.0
  6. * @author Janson Leung
  7. */
  8. /** PHPExcel root directory */
  9. if ( ! defined('PHPEXCEL_ROOT')) {
  10. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/');
  11. require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  12. }
  13. class PHPExcelReader implements SeekableIterator, Countable {
  14. const TYPE_XLSX = 'XLSX';
  15. const TYPE_XLS = 'XLS';
  16. const TYPE_CSV = 'CSV';
  17. private $handle;
  18. private $type;
  19. private $index = 0;
  20. /**
  21. * @param string Path to file
  22. * @param string Original filename (in case of an uploaded file), used to determine file type, optional
  23. * @param string MIME type from an upload, used to determine file type, optional
  24. */
  25. public function __construct($filePath, $originalFileName = false, $mimeType = false) {
  26. if ( ! is_readable($filePath)) {
  27. throw new Exception('PHPExcel_Reader: File (' . $filePath . ') not readable');
  28. }
  29. $defaultTimeZone = @date_default_timezone_get();
  30. if ($defaultTimeZone) {
  31. date_default_timezone_set($defaultTimeZone);
  32. }
  33. // Checking the other parameters for correctness
  34. // This should be a check for string but we're lenient
  35. if ( ! empty($originalFileName) && ! is_scalar($originalFileName)) {
  36. throw new Exception('PHPExcel_Reader: Original file (2nd parameter) is not a string or a scalar value.');
  37. }
  38. if ( ! empty($mimeType) && ! is_scalar($mimeType)) {
  39. throw new Exception('PHPExcel_Reader: Mime type (3nd parameter) is not a string or a scalar value.');
  40. }
  41. // 1. Determine type
  42. if ( ! $originalFileName) {
  43. $originalFileName = $filePath;
  44. }
  45. $Extension = strtolower(pathinfo($originalFileName, PATHINFO_EXTENSION));
  46. if($mimeType) {
  47. switch ($mimeType) {
  48. case 'application/octet-stream':
  49. $this->type = $Extension == 'xlsx' ? self::TYPE_XLSX : self::TYPE_CSV;
  50. break;
  51. case 'text/x-comma-separated-values':
  52. case 'text/comma-separated-values':
  53. case 'application/x-csv':
  54. case 'text/x-csv':
  55. case 'text/csv':
  56. case 'application/csv':
  57. case 'application/vnd.msexcel':
  58. case 'text/plain':
  59. $this->type = self::TYPE_CSV;
  60. break;
  61. case 'application/msexcel':
  62. case 'application/x-msexcel':
  63. case 'application/x-ms-excel':
  64. case 'application/x-excel':
  65. case 'application/x-dos_ms_excel':
  66. case 'application/xls':
  67. case 'application/x-xls':
  68. case 'application/download':
  69. case 'application/vnd.ms-office':
  70. case 'application/msword':
  71. case 'application/xlt':
  72. $this->type = self::TYPE_XLS;
  73. break;
  74. case 'application/vnd.ms-excel':
  75. case 'application/excel':
  76. $this->type = $Extension == 'csv' ? self::TYPE_CSV : self::TYPE_XLS;
  77. break;
  78. case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
  79. case 'application/vnd.openxmlformats-officedocument.spreadsheetml.template':
  80. case 'application/zip':
  81. case 'application/msword':
  82. case 'application/x-zip':
  83. case 'application/xlsx':
  84. case 'application/xltx':
  85. $this->type = self::TYPE_XLSX;
  86. break;
  87. }
  88. }
  89. if ( ! $this->type) {
  90. switch ($Extension) {
  91. case 'xlsx':
  92. case 'xltx': // XLSX template
  93. case 'xlsm': // Macro-enabled XLSX
  94. case 'xltm': // Macro-enabled XLSX template
  95. $this->type = self::TYPE_XLSX;
  96. break;
  97. case 'xls':
  98. case 'xlt':
  99. $this->type = self::TYPE_XLS;
  100. break;
  101. default:
  102. $this->type = self::TYPE_CSV;
  103. break;
  104. }
  105. }
  106. // Pre-checking XLS files, in case they are renamed CSV or XLSX files
  107. if ($this->type == self::TYPE_XLS) {
  108. $this->handle = new PHPExcel_Reader_XLS($filePath);
  109. if ($this->handle->error) {
  110. $this->handle->__destruct();
  111. if (is_resource($Ziphandle = zip_open($filePath))) {
  112. $this->type = self::TYPE_XLSX;
  113. zip_close($Ziphandle);
  114. }
  115. else {
  116. $this->type = self::TYPE_CSV;
  117. }
  118. }
  119. }
  120. // 2. Create handle
  121. switch ($this->type) {
  122. case self::TYPE_XLSX:
  123. $this->handle = new PHPExcel_Reader_XLSX($filePath);
  124. break;
  125. case self::TYPE_CSV:
  126. $this->handle = new PHPExcel_Reader_CSV($filePath, 1);
  127. break;
  128. case self::TYPE_XLS:
  129. // Everything already happens above
  130. break;
  131. }
  132. }
  133. /**
  134. * get the type of file
  135. * @return string
  136. */
  137. public function getFileType() {
  138. return $this->type;
  139. }
  140. /**
  141. * Gets information about separate sheets in the given file
  142. *
  143. * @return array Associative array where key is sheet index and value is sheet name
  144. */
  145. public function Sheets() {
  146. return $this->handle->Sheets();
  147. }
  148. /**
  149. * Changes the current sheet to another from the file.
  150. * Note that changing the sheet will rewind the file to the beginning, even if
  151. * the current sheet index is provided.
  152. *
  153. * @param int Sheet index
  154. *
  155. * @return bool True if sheet could be changed to the specified one,
  156. * false if not (for example, if incorrect index was provided.
  157. */
  158. public function ChangeSheet($index) {
  159. return $this->handle->ChangeSheet($index);
  160. }
  161. /**
  162. * Rewind the Iterator to the first element.
  163. * Similar to the reset() function for arrays in PHP
  164. */
  165. public function rewind() {
  166. $this->index = 0;
  167. if ($this->handle) {
  168. $this->handle->rewind();
  169. }
  170. }
  171. /**
  172. * Return the current element.
  173. * Similar to the current() function for arrays in PHP
  174. *
  175. * @return mixed current element from the collection
  176. */
  177. public function current() {
  178. if ($this->handle) {
  179. return $this->handle->current();
  180. }
  181. return null;
  182. }
  183. /**
  184. * Move forward to next element.
  185. * Similar to the next() function for arrays in PHP
  186. */
  187. public function next() {
  188. if ($this->handle) {
  189. $this->index++;
  190. return $this->handle->next();
  191. }
  192. return null;
  193. }
  194. /**
  195. * Return the identifying key of the current element.
  196. * Similar to the key() function for arrays in PHP
  197. *
  198. * @return mixed either an integer or a string
  199. */
  200. public function key() {
  201. if ($this->handle) {
  202. return $this->handle->key();
  203. }
  204. return null;
  205. }
  206. /**
  207. * Check if there is a current element after calls to rewind() or next().
  208. * Used to check if we've iterated to the end of the collection
  209. *
  210. * @return boolean FALSE if there's nothing more to iterate over
  211. */
  212. public function valid() {
  213. if ($this->handle) {
  214. return $this->handle->valid();
  215. }
  216. return false;
  217. }
  218. /**
  219. * total of file number
  220. * return int
  221. */
  222. public function count() {
  223. if ($this->handle) {
  224. return $this->handle->count();
  225. }
  226. return 0;
  227. }
  228. /**
  229. * Method for SeekableIterator interface. Takes a posiiton and traverses the file to that position
  230. * The value can be retrieved with a `current()` call afterwards.
  231. *
  232. * @param int position in file
  233. */
  234. public function seek($position) {
  235. if ( ! $this->handle) {
  236. throw new OutOfBoundsException('PHPExcel_Reader: No file opened');
  237. }
  238. $Currentindex = $this->handle->key();
  239. if ($Currentindex != $position) {
  240. if ($position < $Currentindex || is_null($Currentindex) || $position == 0) {
  241. $this->rewind();
  242. }
  243. while ($this->handle->valid() && ($position > $this->handle->key())) {
  244. $this->handle->next();
  245. }
  246. if ( ! $this->handle->valid()) {
  247. throw new OutOfBoundsException('PHPExcel_Reader: position ' . $position . ' not found');
  248. }
  249. }
  250. return null;
  251. }
  252. }