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.

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

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet;
   4  
   5  use PhpOffice\PhpSpreadsheet\Shared\File;
   6  
   7  /**
   8   * Factory to create readers and writers easily.
   9   *
  10   * It is not required to use this class, but it should make it easier to read and write files.
  11   * Especially for reading files with an unknown format.
  12   */
  13  abstract class IOFactory
  14  {
  15      private static $readers = [
  16          'Xlsx' => Reader\Xlsx::class,
  17          'Xls' => Reader\Xls::class,
  18          'Xml' => Reader\Xml::class,
  19          'Ods' => Reader\Ods::class,
  20          'Slk' => Reader\Slk::class,
  21          'Gnumeric' => Reader\Gnumeric::class,
  22          'Html' => Reader\Html::class,
  23          'Csv' => Reader\Csv::class,
  24      ];
  25  
  26      private static $writers = [
  27          'Xls' => Writer\Xls::class,
  28          'Xlsx' => Writer\Xlsx::class,
  29          'Ods' => Writer\Ods::class,
  30          'Csv' => Writer\Csv::class,
  31          'Html' => Writer\Html::class,
  32          'Tcpdf' => Writer\Pdf\Tcpdf::class,
  33          'Dompdf' => Writer\Pdf\Dompdf::class,
  34          'Mpdf' => Writer\Pdf\Mpdf::class,
  35      ];
  36  
  37      /**
  38       * Create Writer\IWriter.
  39       *
  40       * @param string $writerType Example: Xlsx
  41       *
  42       * @return Writer\IWriter
  43       */
  44      public static function createWriter(Spreadsheet $spreadsheet, $writerType)
  45      {
  46          if (!isset(self::$writers[$writerType])) {
  47              throw new Writer\Exception("No writer found for type $writerType");
  48          }
  49  
  50          // Instantiate writer
  51          $className = self::$writers[$writerType];
  52  
  53          return new $className($spreadsheet);
  54      }
  55  
  56      /**
  57       * Create Reader\IReader.
  58       *
  59       * @param string $readerType Example: Xlsx
  60       *
  61       * @return Reader\IReader
  62       */
  63      public static function createReader($readerType)
  64      {
  65          if (!isset(self::$readers[$readerType])) {
  66              throw new Reader\Exception("No reader found for type $readerType");
  67          }
  68  
  69          // Instantiate reader
  70          $className = self::$readers[$readerType];
  71  
  72          return new $className();
  73      }
  74  
  75      /**
  76       * Loads Spreadsheet from file using automatic Reader\IReader resolution.
  77       *
  78       * @param string $pFilename The name of the spreadsheet file
  79       *
  80       * @return Spreadsheet
  81       */
  82      public static function load($pFilename)
  83      {
  84          $reader = self::createReaderForFile($pFilename);
  85  
  86          return $reader->load($pFilename);
  87      }
  88  
  89      /**
  90       * Identify file type using automatic Reader\IReader resolution.
  91       *
  92       * @param string $pFilename The name of the spreadsheet file to identify
  93       *
  94       * @return string
  95       */
  96      public static function identify($pFilename)
  97      {
  98          $reader = self::createReaderForFile($pFilename);
  99          $className = get_class($reader);
 100          $classType = explode('\\', $className);
 101          unset($reader);
 102  
 103          return array_pop($classType);
 104      }
 105  
 106      /**
 107       * Create Reader\IReader for file using automatic Reader\IReader resolution.
 108       *
 109       * @param string $filename The name of the spreadsheet file
 110       *
 111       * @return Reader\IReader
 112       */
 113      public static function createReaderForFile($filename)
 114      {
 115          File::assertFile($filename);
 116  
 117          // First, lucky guess by inspecting file extension
 118          $guessedReader = self::getReaderTypeFromExtension($filename);
 119          if ($guessedReader !== null) {
 120              $reader = self::createReader($guessedReader);
 121  
 122              // Let's see if we are lucky
 123              if (isset($reader) && $reader->canRead($filename)) {
 124                  return $reader;
 125              }
 126          }
 127  
 128          // If we reach here then "lucky guess" didn't give any result
 129          // Try walking through all the options in self::$autoResolveClasses
 130          foreach (self::$readers as $type => $class) {
 131              //    Ignore our original guess, we know that won't work
 132              if ($type !== $guessedReader) {
 133                  $reader = self::createReader($type);
 134                  if ($reader->canRead($filename)) {
 135                      return $reader;
 136                  }
 137              }
 138          }
 139  
 140          throw new Reader\Exception('Unable to identify a reader for this file');
 141      }
 142  
 143      /**
 144       * Guess a reader type from the file extension, if any.
 145       *
 146       * @param string $filename
 147       *
 148       * @return null|string
 149       */
 150      private static function getReaderTypeFromExtension($filename)
 151      {
 152          $pathinfo = pathinfo($filename);
 153          if (!isset($pathinfo['extension'])) {
 154              return null;
 155          }
 156  
 157          switch (strtolower($pathinfo['extension'])) {
 158              case 'xlsx': // Excel (OfficeOpenXML) Spreadsheet
 159              case 'xlsm': // Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded)
 160              case 'xltx': // Excel (OfficeOpenXML) Template
 161              case 'xltm': // Excel (OfficeOpenXML) Macro Template (macros will be discarded)
 162                  return 'Xlsx';
 163              case 'xls': // Excel (BIFF) Spreadsheet
 164              case 'xlt': // Excel (BIFF) Template
 165                  return 'Xls';
 166              case 'ods': // Open/Libre Offic Calc
 167              case 'ots': // Open/Libre Offic Calc Template
 168                  return 'Ods';
 169              case 'slk':
 170                  return 'Slk';
 171              case 'xml': // Excel 2003 SpreadSheetML
 172                  return 'Xml';
 173              case 'gnumeric':
 174                  return 'Gnumeric';
 175              case 'htm':
 176              case 'html':
 177                  return 'Html';
 178              case 'csv':
 179                  // Do nothing
 180                  // We must not try to use CSV reader since it loads
 181                  // all files including Excel files etc.
 182                  return null;
 183              default:
 184                  return null;
 185          }
 186      }
 187  
 188      /**
 189       * Register a writer with its type and class name.
 190       *
 191       * @param string $writerType
 192       * @param string $writerClass
 193       */
 194      public static function registerWriter($writerType, $writerClass): void
 195      {
 196          if (!is_a($writerClass, Writer\IWriter::class, true)) {
 197              throw new Writer\Exception('Registered writers must implement ' . Writer\IWriter::class);
 198          }
 199  
 200          self::$writers[$writerType] = $writerClass;
 201      }
 202  
 203      /**
 204       * Register a reader with its type and class name.
 205       *
 206       * @param string $readerType
 207       * @param string $readerClass
 208       */
 209      public static function registerReader($readerType, $readerClass): void
 210      {
 211          if (!is_a($readerClass, Reader\IReader::class, true)) {
 212              throw new Reader\Exception('Registered readers must implement ' . Reader\IReader::class);
 213          }
 214  
 215          self::$readers[$readerType] = $readerClass;
 216      }
 217  }