/lib/spout/src/Spout/Reader/AbstractReader.php

https://gitlab.com/unofficial-mirrors/moodle · PHP · 238 lines · 99 code · 27 blank · 112 comment · 17 complexity · 0b6ac4db4c14b75db24103a574bc16c1 MD5 · raw file

  1. <?php
  2. namespace Box\Spout\Reader;
  3. use Box\Spout\Common\Exception\IOException;
  4. use Box\Spout\Reader\Exception\ReaderNotOpenedException;
  5. /**
  6. * Class AbstractReader
  7. *
  8. * @package Box\Spout\Reader
  9. * @abstract
  10. */
  11. abstract class AbstractReader implements ReaderInterface
  12. {
  13. /** @var bool Indicates whether the stream is currently open */
  14. protected $isStreamOpened = false;
  15. /** @var \Box\Spout\Common\Helper\GlobalFunctionsHelper Helper to work with global functions */
  16. protected $globalFunctionsHelper;
  17. /** @var \Box\Spout\Reader\Common\ReaderOptions Reader's customized options */
  18. protected $options;
  19. /**
  20. * Returns the reader's current options
  21. *
  22. * @return \Box\Spout\Reader\Common\ReaderOptions
  23. */
  24. abstract protected function getOptions();
  25. /**
  26. * Returns whether stream wrappers are supported
  27. *
  28. * @return bool
  29. */
  30. abstract protected function doesSupportStreamWrapper();
  31. /**
  32. * Opens the file at the given file path to make it ready to be read
  33. *
  34. * @param string $filePath Path of the file to be read
  35. * @return void
  36. */
  37. abstract protected function openReader($filePath);
  38. /**
  39. * Returns an iterator to iterate over sheets.
  40. *
  41. * @return \Iterator To iterate over sheets
  42. */
  43. abstract protected function getConcreteSheetIterator();
  44. /**
  45. * Closes the reader. To be used after reading the file.
  46. *
  47. * @return AbstractReader
  48. */
  49. abstract protected function closeReader();
  50. /**
  51. * @param \Box\Spout\Common\Helper\GlobalFunctionsHelper $globalFunctionsHelper
  52. * @return AbstractReader
  53. */
  54. public function setGlobalFunctionsHelper($globalFunctionsHelper)
  55. {
  56. $this->globalFunctionsHelper = $globalFunctionsHelper;
  57. return $this;
  58. }
  59. /**
  60. * Sets whether date/time values should be returned as PHP objects or be formatted as strings.
  61. *
  62. * @api
  63. * @param bool $shouldFormatDates
  64. * @return AbstractReader
  65. */
  66. public function setShouldFormatDates($shouldFormatDates)
  67. {
  68. $this->getOptions()->setShouldFormatDates($shouldFormatDates);
  69. return $this;
  70. }
  71. /**
  72. * Sets whether empty rows should be returned or skipped.
  73. *
  74. * @api
  75. * @param bool $shouldPreserveEmptyRows
  76. * @return AbstractReader
  77. */
  78. public function setShouldPreserveEmptyRows($shouldPreserveEmptyRows)
  79. {
  80. $this->getOptions()->setShouldPreserveEmptyRows($shouldPreserveEmptyRows);
  81. return $this;
  82. }
  83. /**
  84. * Prepares the reader to read the given file. It also makes sure
  85. * that the file exists and is readable.
  86. *
  87. * @api
  88. * @param string $filePath Path of the file to be read
  89. * @return void
  90. * @throws \Box\Spout\Common\Exception\IOException If the file at the given path does not exist, is not readable or is corrupted
  91. */
  92. public function open($filePath)
  93. {
  94. if ($this->isStreamWrapper($filePath) && (!$this->doesSupportStreamWrapper() || !$this->isSupportedStreamWrapper($filePath))) {
  95. throw new IOException("Could not open $filePath for reading! Stream wrapper used is not supported for this type of file.");
  96. }
  97. if (!$this->isPhpStream($filePath)) {
  98. // we skip the checks if the provided file path points to a PHP stream
  99. if (!$this->globalFunctionsHelper->file_exists($filePath)) {
  100. throw new IOException("Could not open $filePath for reading! File does not exist.");
  101. } else if (!$this->globalFunctionsHelper->is_readable($filePath)) {
  102. throw new IOException("Could not open $filePath for reading! File is not readable.");
  103. }
  104. }
  105. try {
  106. $fileRealPath = $this->getFileRealPath($filePath);
  107. $this->openReader($fileRealPath);
  108. $this->isStreamOpened = true;
  109. } catch (\Exception $exception) {
  110. throw new IOException("Could not open $filePath for reading! ({$exception->getMessage()})");
  111. }
  112. }
  113. /**
  114. * Returns the real path of the given path.
  115. * If the given path is a valid stream wrapper, returns the path unchanged.
  116. *
  117. * @param string $filePath
  118. * @return string
  119. */
  120. protected function getFileRealPath($filePath)
  121. {
  122. if ($this->isSupportedStreamWrapper($filePath)) {
  123. return $filePath;
  124. }
  125. // Need to use realpath to fix "Can't open file" on some Windows setup
  126. return realpath($filePath);
  127. }
  128. /**
  129. * Returns the scheme of the custom stream wrapper, if the path indicates a stream wrapper is used.
  130. * For example, php://temp => php, s3://path/to/file => s3...
  131. *
  132. * @param string $filePath Path of the file to be read
  133. * @return string|null The stream wrapper scheme or NULL if not a stream wrapper
  134. */
  135. protected function getStreamWrapperScheme($filePath)
  136. {
  137. $streamScheme = null;
  138. if (preg_match('/^(\w+):\/\//', $filePath, $matches)) {
  139. $streamScheme = $matches[1];
  140. }
  141. return $streamScheme;
  142. }
  143. /**
  144. * Checks if the given path is an unsupported stream wrapper
  145. * (like local path, php://temp, mystream://foo/bar...).
  146. *
  147. * @param string $filePath Path of the file to be read
  148. * @return bool Whether the given path is an unsupported stream wrapper
  149. */
  150. protected function isStreamWrapper($filePath)
  151. {
  152. return ($this->getStreamWrapperScheme($filePath) !== null);
  153. }
  154. /**
  155. * Checks if the given path is an supported stream wrapper
  156. * (like php://temp, mystream://foo/bar...).
  157. * If the given path is a local path, returns true.
  158. *
  159. * @param string $filePath Path of the file to be read
  160. * @return bool Whether the given path is an supported stream wrapper
  161. */
  162. protected function isSupportedStreamWrapper($filePath)
  163. {
  164. $streamScheme = $this->getStreamWrapperScheme($filePath);
  165. return ($streamScheme !== null) ?
  166. in_array($streamScheme, $this->globalFunctionsHelper->stream_get_wrappers()) :
  167. true;
  168. }
  169. /**
  170. * Checks if a path is a PHP stream (like php://output, php://memory, ...)
  171. *
  172. * @param string $filePath Path of the file to be read
  173. * @return bool Whether the given path maps to a PHP stream
  174. */
  175. protected function isPhpStream($filePath)
  176. {
  177. $streamScheme = $this->getStreamWrapperScheme($filePath);
  178. return ($streamScheme === 'php');
  179. }
  180. /**
  181. * Returns an iterator to iterate over sheets.
  182. *
  183. * @api
  184. * @return \Iterator To iterate over sheets
  185. * @throws \Box\Spout\Reader\Exception\ReaderNotOpenedException If called before opening the reader
  186. */
  187. public function getSheetIterator()
  188. {
  189. if (!$this->isStreamOpened) {
  190. throw new ReaderNotOpenedException('Reader should be opened first.');
  191. }
  192. return $this->getConcreteSheetIterator();
  193. }
  194. /**
  195. * Closes the reader, preventing any additional reading
  196. *
  197. * @api
  198. * @return void
  199. */
  200. public function close()
  201. {
  202. if ($this->isStreamOpened) {
  203. $this->closeReader();
  204. $sheetIterator = $this->getConcreteSheetIterator();
  205. if ($sheetIterator) {
  206. $sheetIterator->end();
  207. }
  208. $this->isStreamOpened = false;
  209. }
  210. }
  211. }