Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
<?php

namespace PhpOffice\PhpSpreadsheet\Writer;

use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

class Csv extends BaseWriter
{
    /**
     * PhpSpreadsheet object.
     *
     * @var Spreadsheet
     */
    private $spreadsheet;

    /**
     * Delimiter.
     *
     * @var string
     */
    private $delimiter = ',';

    /**
     * Enclosure.
     *
     * @var string
     */
    private $enclosure = '"';

    /**
     * Line ending.
     *
     * @var string
     */
    private $lineEnding = PHP_EOL;

    /**
     * Sheet index to write.
     *
     * @var int
     */
    private $sheetIndex = 0;

    /**
< * Whether to write a BOM (for UTF8).
> * Whether to write a UTF8 BOM.
* * @var bool */ private $useBOM = false; /** * Whether to write a Separator line as the first line of the file * sep=x. * * @var bool */ private $includeSeparatorLine = false; /** * Whether to write a fully Excel compatible CSV file. * * @var bool */ private $excelCompatibility = false; /**
< * Create a new CSV.
> * Output encoding.
*
< * @param Spreadsheet $spreadsheet Spreadsheet object
> * @var string > */ > private $outputEncoding = ''; > > /** > * Create a new CSV.
*/ public function __construct(Spreadsheet $spreadsheet) { $this->spreadsheet = $spreadsheet; } /** * Save PhpSpreadsheet to file. *
< * @param resource|string $pFilename
> * @param resource|string $filename
*/
< public function save($pFilename): void
> public function save($filename, int $flags = 0): void
{
> $this->processFlags($flags); // Fetch sheet >
$sheet = $this->spreadsheet->getSheet($this->sheetIndex); $saveDebugLog = Calculation::getInstance($this->spreadsheet)->getDebugLog()->getWriteDebugLog(); Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog(false); $saveArrayReturnType = Calculation::getArrayReturnType(); Calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_VALUE); // Open file
< $this->openFileHandle($pFilename);
> $this->openFileHandle($filename);
if ($this->excelCompatibility) { $this->setUseBOM(true); // Enforce UTF-8 BOM Header $this->setIncludeSeparatorLine(true); // Set separator line $this->setEnclosure('"'); // Set enclosure to " $this->setDelimiter(';'); // Set delimiter to a semi-colon $this->setLineEnding("\r\n"); } if ($this->useBOM) { // Write the UTF-8 BOM code if required fwrite($this->fileHandle, "\xEF\xBB\xBF"); } if ($this->includeSeparatorLine) { // Write the separator line if required fwrite($this->fileHandle, 'sep=' . $this->getDelimiter() . $this->lineEnding); } // Identify the range that we need to extract from the worksheet $maxCol = $sheet->getHighestDataColumn(); $maxRow = $sheet->getHighestDataRow(); // Write rows to file for ($row = 1; $row <= $maxRow; ++$row) { // Convert the row to an array... $cellsArray = $sheet->rangeToArray('A' . $row . ':' . $maxCol . $row, '', $this->preCalculateFormulas); // ... and write to the file $this->writeLine($this->fileHandle, $cellsArray[0]); } $this->maybeCloseFileHandle(); Calculation::setArrayReturnType($saveArrayReturnType); Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog); }
< /** < * Get delimiter. < * < * @return string < */ < public function getDelimiter()
> public function getDelimiter(): string
{ return $this->delimiter; }
< /** < * Set delimiter. < * < * @param string $pValue Delimiter, defaults to ',' < * < * @return $this < */ < public function setDelimiter($pValue)
> public function setDelimiter(string $delimiter): self
{
< $this->delimiter = $pValue;
> $this->delimiter = $delimiter;
return $this; }
< /** < * Get enclosure. < * < * @return string < */ < public function getEnclosure()
> public function getEnclosure(): string
{ return $this->enclosure; }
< /** < * Set enclosure. < * < * @param string $pValue Enclosure, defaults to " < * < * @return $this < */ < public function setEnclosure($pValue = '"')
> public function setEnclosure(string $enclosure = '"'): self
{
< $this->enclosure = $pValue;
> $this->enclosure = $enclosure;
return $this; }
< /** < * Get line ending. < * < * @return string < */ < public function getLineEnding()
> public function getLineEnding(): string
{ return $this->lineEnding; }
< /** < * Set line ending. < * < * @param string $pValue Line ending, defaults to OS line ending (PHP_EOL) < * < * @return $this < */ < public function setLineEnding($pValue)
> public function setLineEnding(string $lineEnding): self
{
< $this->lineEnding = $pValue;
> $this->lineEnding = $lineEnding;
return $this; } /** * Get whether BOM should be used.
< * < * @return bool
*/
< public function getUseBOM()
> public function getUseBOM(): bool
{ return $this->useBOM; } /**
< * Set whether BOM should be used. < * < * @param bool $pValue Use UTF-8 byte-order mark? Defaults to false < * < * @return $this
> * Set whether BOM should be used, typically when non-ASCII characters are used.
*/
< public function setUseBOM($pValue)
> public function setUseBOM(bool $useBOM): self
{
< $this->useBOM = $pValue;
> $this->useBOM = $useBOM;
return $this; } /** * Get whether a separator line should be included.
< * < * @return bool
*/
< public function getIncludeSeparatorLine()
> public function getIncludeSeparatorLine(): bool
{ return $this->includeSeparatorLine; } /** * Set whether a separator line should be included as the first line of the file.
< * < * @param bool $pValue Use separator line? Defaults to false < * < * @return $this
*/
< public function setIncludeSeparatorLine($pValue)
> public function setIncludeSeparatorLine(bool $includeSeparatorLine): self
{
< $this->includeSeparatorLine = $pValue;
> $this->includeSeparatorLine = $includeSeparatorLine;
return $this; } /** * Get whether the file should be saved with full Excel Compatibility.
< * < * @return bool
*/
< public function getExcelCompatibility()
> public function getExcelCompatibility(): bool
{ return $this->excelCompatibility; } /** * Set whether the file should be saved with full Excel Compatibility. *
< * @param bool $pValue Set the file to be written as a fully Excel compatible csv file
> * @param bool $excelCompatibility Set the file to be written as a fully Excel compatible csv file
* Note that this overrides other settings such as useBOM, enclosure and delimiter
< * < * @return $this
*/
< public function setExcelCompatibility($pValue)
> public function setExcelCompatibility(bool $excelCompatibility): self
{
< $this->excelCompatibility = $pValue;
> $this->excelCompatibility = $excelCompatibility;
return $this; }
< /** < * Get sheet index. < * < * @return int < */ < public function getSheetIndex()
> public function getSheetIndex(): int
{ return $this->sheetIndex; }
< /** < * Set sheet index. < * < * @param int $pValue Sheet index < * < * @return $this < */ < public function setSheetIndex($pValue)
> public function setSheetIndex(int $sheetIndex): self
{
< $this->sheetIndex = $pValue;
> $this->sheetIndex = $sheetIndex;
return $this; }
> public function getOutputEncoding(): string private $enclosureRequired = true; > { > return $this->outputEncoding; public function setEnclosureRequired(bool $value): self > } { > $this->enclosureRequired = $value; > public function setOutputEncoding(string $outputEnconding): self > { return $this; > $this->outputEncoding = $outputEnconding; } > > return $this; public function getEnclosureRequired(): bool > } { > return $this->enclosureRequired; > /** @var bool */
} /**
> * Convert boolean to TRUE/FALSE; otherwise return element cast to string. * Write line to CSV file. > * * > * @param mixed $element * @param resource $pFileHandle PHP filehandle > */ * @param array $pValues Array containing values in a row > private static function elementToString($element): string */ > { private function writeLine($pFileHandle, array $pValues): void > if (is_bool($element)) { { > return $element ? 'TRUE' : 'FALSE'; // No leading delimiter > } $delimiter = ''; > > return (string) $element; // Build the line > } $line = ''; > > /**
< * @param resource $pFileHandle PHP filehandle < * @param array $pValues Array containing values in a row
> * @param resource $fileHandle PHP filehandle > * @param array $values Array containing values in a row
< private function writeLine($pFileHandle, array $pValues): void
> private function writeLine($fileHandle, array $values): void
< foreach ($pValues as $element) {
> foreach ($values as $element) { > $element = self::elementToString($element);
// Escape enclosures $enclosure = $this->enclosure; if ($enclosure) { // If enclosure is not required, use enclosure only if // element contains newline, delimiter, or enclosure. if (!$this->enclosureRequired && strpbrk($element, "$delimiter$enclosure\n") === false) { $enclosure = ''; } else { $element = str_replace($enclosure, $enclosure . $enclosure, $element); } } // Add enclosed string $line .= $enclosure . $element . $enclosure; } // Add line ending $line .= $this->lineEnding; // Write to file
< fwrite($pFileHandle, $line);
> if ($this->outputEncoding != '') { > $line = mb_convert_encoding($line, $this->outputEncoding); > } > fwrite($fileHandle, /** @scrutinizer ignore-type */ $line);
} }