PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Csv.php

https://github.com/mackensen/moodle
PHP | 404 lines | 165 code | 57 blank | 182 comment | 11 complexity | 7676f238346776bc3370f50367f37ec4 MD5 | raw file
  1. <?php
  2. namespace PhpOffice\PhpSpreadsheet\Writer;
  3. use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
  4. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  5. class Csv extends BaseWriter
  6. {
  7. /**
  8. * PhpSpreadsheet object.
  9. *
  10. * @var Spreadsheet
  11. */
  12. private $spreadsheet;
  13. /**
  14. * Delimiter.
  15. *
  16. * @var string
  17. */
  18. private $delimiter = ',';
  19. /**
  20. * Enclosure.
  21. *
  22. * @var string
  23. */
  24. private $enclosure = '"';
  25. /**
  26. * Line ending.
  27. *
  28. * @var string
  29. */
  30. private $lineEnding = PHP_EOL;
  31. /**
  32. * Sheet index to write.
  33. *
  34. * @var int
  35. */
  36. private $sheetIndex = 0;
  37. /**
  38. * Whether to write a BOM (for UTF8).
  39. *
  40. * @var bool
  41. */
  42. private $useBOM = false;
  43. /**
  44. * Whether to write a Separator line as the first line of the file
  45. * sep=x.
  46. *
  47. * @var bool
  48. */
  49. private $includeSeparatorLine = false;
  50. /**
  51. * Whether to write a fully Excel compatible CSV file.
  52. *
  53. * @var bool
  54. */
  55. private $excelCompatibility = false;
  56. /**
  57. * Output encoding.
  58. *
  59. * @var string
  60. */
  61. private $outputEncoding = '';
  62. /**
  63. * Create a new CSV.
  64. *
  65. * @param Spreadsheet $spreadsheet Spreadsheet object
  66. */
  67. public function __construct(Spreadsheet $spreadsheet)
  68. {
  69. $this->spreadsheet = $spreadsheet;
  70. }
  71. /**
  72. * Save PhpSpreadsheet to file.
  73. *
  74. * @param resource|string $filename
  75. */
  76. public function save($filename, int $flags = 0): void
  77. {
  78. $this->processFlags($flags);
  79. // Fetch sheet
  80. $sheet = $this->spreadsheet->getSheet($this->sheetIndex);
  81. $saveDebugLog = Calculation::getInstance($this->spreadsheet)->getDebugLog()->getWriteDebugLog();
  82. Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog(false);
  83. $saveArrayReturnType = Calculation::getArrayReturnType();
  84. Calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_VALUE);
  85. // Open file
  86. $this->openFileHandle($filename);
  87. if ($this->excelCompatibility) {
  88. $this->setUseBOM(true); // Enforce UTF-8 BOM Header
  89. $this->setIncludeSeparatorLine(true); // Set separator line
  90. $this->setEnclosure('"'); // Set enclosure to "
  91. $this->setDelimiter(';'); // Set delimiter to a semi-colon
  92. $this->setLineEnding("\r\n");
  93. }
  94. if ($this->useBOM) {
  95. // Write the UTF-8 BOM code if required
  96. fwrite($this->fileHandle, "\xEF\xBB\xBF");
  97. }
  98. if ($this->includeSeparatorLine) {
  99. // Write the separator line if required
  100. fwrite($this->fileHandle, 'sep=' . $this->getDelimiter() . $this->lineEnding);
  101. }
  102. // Identify the range that we need to extract from the worksheet
  103. $maxCol = $sheet->getHighestDataColumn();
  104. $maxRow = $sheet->getHighestDataRow();
  105. // Write rows to file
  106. for ($row = 1; $row <= $maxRow; ++$row) {
  107. // Convert the row to an array...
  108. $cellsArray = $sheet->rangeToArray('A' . $row . ':' . $maxCol . $row, '', $this->preCalculateFormulas);
  109. // ... and write to the file
  110. $this->writeLine($this->fileHandle, $cellsArray[0]);
  111. }
  112. $this->maybeCloseFileHandle();
  113. Calculation::setArrayReturnType($saveArrayReturnType);
  114. Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
  115. }
  116. /**
  117. * Get delimiter.
  118. *
  119. * @return string
  120. */
  121. public function getDelimiter()
  122. {
  123. return $this->delimiter;
  124. }
  125. /**
  126. * Set delimiter.
  127. *
  128. * @param string $delimiter Delimiter, defaults to ','
  129. *
  130. * @return $this
  131. */
  132. public function setDelimiter($delimiter)
  133. {
  134. $this->delimiter = $delimiter;
  135. return $this;
  136. }
  137. /**
  138. * Get enclosure.
  139. *
  140. * @return string
  141. */
  142. public function getEnclosure()
  143. {
  144. return $this->enclosure;
  145. }
  146. /**
  147. * Set enclosure.
  148. *
  149. * @param string $enclosure Enclosure, defaults to "
  150. *
  151. * @return $this
  152. */
  153. public function setEnclosure($enclosure = '"')
  154. {
  155. $this->enclosure = $enclosure;
  156. return $this;
  157. }
  158. /**
  159. * Get line ending.
  160. *
  161. * @return string
  162. */
  163. public function getLineEnding()
  164. {
  165. return $this->lineEnding;
  166. }
  167. /**
  168. * Set line ending.
  169. *
  170. * @param string $lineEnding Line ending, defaults to OS line ending (PHP_EOL)
  171. *
  172. * @return $this
  173. */
  174. public function setLineEnding($lineEnding)
  175. {
  176. $this->lineEnding = $lineEnding;
  177. return $this;
  178. }
  179. /**
  180. * Get whether BOM should be used.
  181. *
  182. * @return bool
  183. */
  184. public function getUseBOM()
  185. {
  186. return $this->useBOM;
  187. }
  188. /**
  189. * Set whether BOM should be used.
  190. *
  191. * @param bool $useBOM Use UTF-8 byte-order mark? Defaults to false
  192. *
  193. * @return $this
  194. */
  195. public function setUseBOM($useBOM)
  196. {
  197. $this->useBOM = $useBOM;
  198. return $this;
  199. }
  200. /**
  201. * Get whether a separator line should be included.
  202. *
  203. * @return bool
  204. */
  205. public function getIncludeSeparatorLine()
  206. {
  207. return $this->includeSeparatorLine;
  208. }
  209. /**
  210. * Set whether a separator line should be included as the first line of the file.
  211. *
  212. * @param bool $includeSeparatorLine Use separator line? Defaults to false
  213. *
  214. * @return $this
  215. */
  216. public function setIncludeSeparatorLine($includeSeparatorLine)
  217. {
  218. $this->includeSeparatorLine = $includeSeparatorLine;
  219. return $this;
  220. }
  221. /**
  222. * Get whether the file should be saved with full Excel Compatibility.
  223. *
  224. * @return bool
  225. */
  226. public function getExcelCompatibility()
  227. {
  228. return $this->excelCompatibility;
  229. }
  230. /**
  231. * Set whether the file should be saved with full Excel Compatibility.
  232. *
  233. * @param bool $excelCompatibility Set the file to be written as a fully Excel compatible csv file
  234. * Note that this overrides other settings such as useBOM, enclosure and delimiter
  235. *
  236. * @return $this
  237. */
  238. public function setExcelCompatibility($excelCompatibility)
  239. {
  240. $this->excelCompatibility = $excelCompatibility;
  241. return $this;
  242. }
  243. /**
  244. * Get sheet index.
  245. *
  246. * @return int
  247. */
  248. public function getSheetIndex()
  249. {
  250. return $this->sheetIndex;
  251. }
  252. /**
  253. * Set sheet index.
  254. *
  255. * @param int $sheetIndex Sheet index
  256. *
  257. * @return $this
  258. */
  259. public function setSheetIndex($sheetIndex)
  260. {
  261. $this->sheetIndex = $sheetIndex;
  262. return $this;
  263. }
  264. /**
  265. * Get output encoding.
  266. *
  267. * @return string
  268. */
  269. public function getOutputEncoding()
  270. {
  271. return $this->outputEncoding;
  272. }
  273. /**
  274. * Set output encoding.
  275. *
  276. * @param string $outputEnconding Output encoding
  277. *
  278. * @return $this
  279. */
  280. public function setOutputEncoding($outputEnconding)
  281. {
  282. $this->outputEncoding = $outputEnconding;
  283. return $this;
  284. }
  285. /** @var bool */
  286. private $enclosureRequired = true;
  287. public function setEnclosureRequired(bool $value): self
  288. {
  289. $this->enclosureRequired = $value;
  290. return $this;
  291. }
  292. public function getEnclosureRequired(): bool
  293. {
  294. return $this->enclosureRequired;
  295. }
  296. /**
  297. * Convert boolean to TRUE/FALSE; otherwise return element cast to string.
  298. *
  299. * @param mixed $element
  300. */
  301. private static function elementToString($element): string
  302. {
  303. if (is_bool($element)) {
  304. return $element ? 'TRUE' : 'FALSE';
  305. }
  306. return (string) $element;
  307. }
  308. /**
  309. * Write line to CSV file.
  310. *
  311. * @param resource $fileHandle PHP filehandle
  312. * @param array $values Array containing values in a row
  313. */
  314. private function writeLine($fileHandle, array $values): void
  315. {
  316. // No leading delimiter
  317. $delimiter = '';
  318. // Build the line
  319. $line = '';
  320. foreach ($values as $element) {
  321. $element = self::elementToString($element);
  322. // Add delimiter
  323. $line .= $delimiter;
  324. $delimiter = $this->delimiter;
  325. // Escape enclosures
  326. $enclosure = $this->enclosure;
  327. if ($enclosure) {
  328. // If enclosure is not required, use enclosure only if
  329. // element contains newline, delimiter, or enclosure.
  330. if (!$this->enclosureRequired && strpbrk($element, "$delimiter$enclosure\n") === false) {
  331. $enclosure = '';
  332. } else {
  333. $element = str_replace($enclosure, $enclosure . $enclosure, $element);
  334. }
  335. }
  336. // Add enclosed string
  337. $line .= $enclosure . $element . $enclosure;
  338. }
  339. // Add line ending
  340. $line .= $this->lineEnding;
  341. // Write to file
  342. if ($this->outputEncoding != '') {
  343. $line = mb_convert_encoding($line, $this->outputEncoding);
  344. }
  345. fwrite($fileHandle, $line);
  346. }
  347. }