Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

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