Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 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 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

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