Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

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

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Helper;
   4  
   5  use PhpOffice\PhpSpreadsheet\IOFactory;
   6  use PhpOffice\PhpSpreadsheet\Spreadsheet;
   7  use PhpOffice\PhpSpreadsheet\Writer\IWriter;
   8  use RecursiveDirectoryIterator;
   9  use RecursiveIteratorIterator;
  10  use RecursiveRegexIterator;
  11  use ReflectionClass;
  12  use RegexIterator;
  13  use RuntimeException;
  14  
  15  /**
  16   * Helper class to be used in sample code.
  17   */
  18  class Sample
  19  {
  20      /**
  21       * Returns whether we run on CLI or browser.
  22       *
  23       * @return bool
  24       */
  25      public function isCli()
  26      {
  27          return PHP_SAPI === 'cli';
  28      }
  29  
  30      /**
  31       * Return the filename currently being executed.
  32       *
  33       * @return string
  34       */
  35      public function getScriptFilename()
  36      {
  37          return basename($_SERVER['SCRIPT_FILENAME'], '.php');
  38      }
  39  
  40      /**
  41       * Whether we are executing the index page.
  42       *
  43       * @return bool
  44       */
  45      public function isIndex()
  46      {
  47          return $this->getScriptFilename() === 'index';
  48      }
  49  
  50      /**
  51       * Return the page title.
  52       *
  53       * @return string
  54       */
  55      public function getPageTitle()
  56      {
  57          return $this->isIndex() ? 'PHPSpreadsheet' : $this->getScriptFilename();
  58      }
  59  
  60      /**
  61       * Return the page heading.
  62       *
  63       * @return string
  64       */
  65      public function getPageHeading()
  66      {
  67          return $this->isIndex() ? '' : '<h1>' . str_replace('_', ' ', $this->getScriptFilename()) . '</h1>';
  68      }
  69  
  70      /**
  71       * Returns an array of all known samples.
  72       *
  73       * @return string[][] [$name => $path]
  74       */
  75      public function getSamples()
  76      {
  77          // Populate samples
  78          $baseDir = realpath(__DIR__ . '/../../../samples');
  79          $directory = new RecursiveDirectoryIterator($baseDir);
  80          $iterator = new RecursiveIteratorIterator($directory);
  81          $regex = new RegexIterator($iterator, '/^.+\.php$/', RecursiveRegexIterator::GET_MATCH);
  82  
  83          $files = [];
  84          foreach ($regex as $file) {
  85              $file = str_replace(str_replace('\\', '/', $baseDir) . '/', '', str_replace('\\', '/', $file[0]));
  86              $info = pathinfo($file);
  87              $category = str_replace('_', ' ', $info['dirname']);
  88              $name = str_replace('_', ' ', preg_replace('/(|\.php)/', '', $info['filename']));
  89              if (!in_array($category, ['.', 'boostrap', 'templates'])) {
  90                  if (!isset($files[$category])) {
  91                      $files[$category] = [];
  92                  }
  93                  $files[$category][$name] = $file;
  94              }
  95          }
  96  
  97          // Sort everything
  98          ksort($files);
  99          foreach ($files as &$f) {
 100              asort($f);
 101          }
 102  
 103          return $files;
 104      }
 105  
 106      /**
 107       * Write documents.
 108       *
 109       * @param string $filename
 110       * @param string[] $writers
 111       */
 112      public function write(Spreadsheet $spreadsheet, $filename, array $writers = ['Xlsx', 'Xls']): void
 113      {
 114          // Set active sheet index to the first sheet, so Excel opens this as the first sheet
 115          $spreadsheet->setActiveSheetIndex(0);
 116  
 117          // Write documents
 118          foreach ($writers as $writerType) {
 119              $path = $this->getFilename($filename, mb_strtolower($writerType));
 120              $writer = IOFactory::createWriter($spreadsheet, $writerType);
 121              $callStartTime = microtime(true);
 122              $writer->save($path);
 123              $this->logWrite($writer, $path, $callStartTime);
 124          }
 125  
 126          $this->logEndingNotes();
 127      }
 128  
 129      protected function isDirOrMkdir(string $folder): bool
 130      {
 131          return \is_dir($folder) || \mkdir($folder);
 132      }
 133  
 134      /**
 135       * Returns the temporary directory and make sure it exists.
 136       *
 137       * @return string
 138       */
 139      private function getTemporaryFolder()
 140      {
 141          $tempFolder = sys_get_temp_dir() . '/phpspreadsheet';
 142          if (!$this->isDirOrMkdir($tempFolder)) {
 143              throw new RuntimeException(sprintf('Directory "%s" was not created', $tempFolder));
 144          }
 145  
 146          return $tempFolder;
 147      }
 148  
 149      /**
 150       * Returns the filename that should be used for sample output.
 151       *
 152       * @param string $filename
 153       * @param string $extension
 154       *
 155       * @return string
 156       */
 157      public function getFilename($filename, $extension = 'xlsx')
 158      {
 159          $originalExtension = pathinfo($filename, PATHINFO_EXTENSION);
 160  
 161          return $this->getTemporaryFolder() . '/' . str_replace('.' . $originalExtension, '.' . $extension, basename($filename));
 162      }
 163  
 164      /**
 165       * Return a random temporary file name.
 166       *
 167       * @param string $extension
 168       *
 169       * @return string
 170       */
 171      public function getTemporaryFilename($extension = 'xlsx')
 172      {
 173          $temporaryFilename = tempnam($this->getTemporaryFolder(), 'phpspreadsheet-');
 174          unlink($temporaryFilename);
 175  
 176          return $temporaryFilename . '.' . $extension;
 177      }
 178  
 179      public function log($message): void
 180      {
 181          $eol = $this->isCli() ? PHP_EOL : '<br />';
 182          echo date('H:i:s ') . $message . $eol;
 183      }
 184  
 185      /**
 186       * Log ending notes.
 187       */
 188      public function logEndingNotes(): void
 189      {
 190          // Do not show execution time for index
 191          $this->log('Peak memory usage: ' . (memory_get_peak_usage(true) / 1024 / 1024) . 'MB');
 192      }
 193  
 194      /**
 195       * Log a line about the write operation.
 196       *
 197       * @param string $path
 198       * @param float $callStartTime
 199       */
 200      public function logWrite(IWriter $writer, $path, $callStartTime): void
 201      {
 202          $callEndTime = microtime(true);
 203          $callTime = $callEndTime - $callStartTime;
 204          $reflection = new ReflectionClass($writer);
 205          $format = $reflection->getShortName();
 206          $message = "Write {$format} format to <code>{$path}</code>  in " . sprintf('%.4f', $callTime) . ' seconds';
 207  
 208          $this->log($message);
 209      }
 210  
 211      /**
 212       * Log a line about the read operation.
 213       *
 214       * @param string $format
 215       * @param string $path
 216       * @param float $callStartTime
 217       */
 218      public function logRead($format, $path, $callStartTime): void
 219      {
 220          $callEndTime = microtime(true);
 221          $callTime = $callEndTime - $callStartTime;
 222          $message = "Read {$format} format from <code>{$path}</code>  in " . sprintf('%.4f', $callTime) . ' seconds';
 223  
 224          $this->log($message);
 225      }
 226  }