nfTlWNl rn Ѻq$³*GQ4Iמ((GrJsf]ZV hu=J͕X}׃i|@/SgZ_#1Iķխ}`hɩ]&|V53C/. vu˼ƒPQ?ltjd3 %$ \=J c׫u׏׫&p~pۣ|k'#Ad98'fg'/3u ^Is 75zLdďHK~j{݌R"8yqܮT&B82?x]kc gk ][s #=q8 F~|zLUw0֞JZxɑ]>(NVԒxk4t̅D]r">trg2g,=&]8 %[[ͷ0F~|zLUw0F/@$&:ml(NVԒx2}GVb6 iOc—d#>jU%+%ef,' XYA 6`<dYNҳ+3Հ$ihB'y(ﲦף3^yt*j麛s$;e66;ՙմ$!W$:ly Nu?UGW`8|Ȫ|'.40!ކxA՘y=LAFt nr IЄ8iϮ[!vx Ԡa]$m"\n+N5v2zC|N㴨Y˹uL8vF e8[}y#?3qIvss"g 5vM" |ů,W|mxK5hSNns=w*Q3Wϴ .^9+6lĞ'"PLbs)28Suuv5T͞E0سZzKՈ=hijdkMLO5'|S)t-B[o;*1Ydm܋4ˑbQKJRiȏxՙdP7C-~v];?mg9 ڛЭ%۞ck7ρn 6]Sn7U+͋6%1KŶfaDD}UV}0 qBCLc|̥hv@~;*Yuۇ_%9Ĩl(!Kf$ѸCyh9l"ƫQKJRiȏxՙp& TFG=Fá'M-&2D%CڝHrU:p-"j{QKJRiȏxՙϱGg-1 0G[JB${`r\ɥY-i JST+ńIo$Y ;jQKJRiȏxՙ5GZˈI y됂' T~n^z8S/p >4+(Ņs7}ڌ-Xe;bU'%I{3~RE<0-{lVY+{,_vZ/rJÖ /s=!>+0TClݘPTB I @Qp)|}h+Ԝ +sJ |d%H΃C C. B-R I%m_:m3Q֦6E N$I0co A^C۔ nJ'י$#h#>%࿢(:c/iA: GuaY2o;bS#О*Q9Eu%|1OA؛.vEtS \p dIWRUDj}v,~᳘scadSm+9N? :Luؐ?j' lo'3<2UJ3Iz2E;!#)~ e`+dg?Ŷ ujM@ /ڒ#te `arTĭao&p̪khpl>=0NWeŶH],uf}عWwĭ1VB?u\Jҵp1zxZ^ }u-9&=S*# wTk6-I? GRS10[R,b:K{ϟ02` /nbI8R} Yָ X$o(U}E `R [E )9EuvN|ӣ4)\oVTz,9r[ =u[fBgկw? Uq ۖDz1cAuk4zA ĢQ$3BǓ Z;] -Ve ~"~ }KM*xTzI\8~#۰hU63^?o~yYh/O+JjCm0@TT W7rg_Jɶz#M$j b35 ĢQ$3yZw3؟"/곃TJDrhg q!1 RvIw"A[)7s39嬢S35)-i$Mv>q|,`d?KP-g*yD(4!load($filename, $flags); } /** * Identify file type using automatic IReader resolution. */ public static function identify(string $filename, ?array $readers = null): string { $reader = self::createReaderForFile($filename, $readers); $className = get_class($reader); $classType = explode('\\', $className); unset($reader); return array_pop($classType); } /** * Create Reader\IReader for file using automatic IReader resolution. * * @param string[] $readers An array of Readers to use to identify the file type. By default, load() will try * all possible Readers until it finds a match; but this allows you to pass in a * list of Readers so it will only try the subset that you specify here. * Values in this list can be any of the constant values defined in the set * IOFactory::READER_*. */ public static function createReaderForFile(string $filename, ?array $readers = null): IReader { File::assertFile($filename); $testReaders = self::$readers; if ($readers !== null) { $readers = array_map('strtoupper', $readers); $testReaders = array_filter( self::$readers, function (string $readerType) use ($readers) { return in_array(strtoupper($readerType), $readers, true); }, ARRAY_FILTER_USE_KEY ); } // First, lucky guess by inspecting file extension $guessedReader = self::getReaderTypeFromExtension($filename); if (($guessedReader !== null) && array_key_exists($guessedReader, $testReaders)) { $reader = self::createReader($guessedReader); // Let's see if we are lucky if ($reader->canRead($filename)) { return $reader; } } // If we reach here then "lucky guess" didn't give any result // Try walking through all the options in self::$readers (or the selected subset) foreach ($testReaders as $readerType => $class) { // Ignore our original guess, we know that won't work if ($readerType !== $guessedReader) { $reader = self::createReader($readerType); if ($reader->canRead($filename)) { return $reader; } } } throw new Reader\Exception('Unable to identify a reader for this file'); } /** * Guess a reader type from the file extension, if any. */ private static function getReaderTypeFromExtension(string $filename): ?string { $pathinfo = pathinfo($filename); if (!isset($pathinfo['extension'])) { return null; } switch (strtolower($pathinfo['extension'])) { case 'xlsx': // Excel (OfficeOpenXML) Spreadsheet case 'xlsm': // Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded) case 'xltx': // Excel (OfficeOpenXML) Template case 'xltm': // Excel (OfficeOpenXML) Macro Template (macros will be discarded) return 'Xlsx'; case 'xls': // Excel (BIFF) Spreadsheet case 'xlt': // Excel (BIFF) Template return 'Xls'; case 'ods': // Open/Libre Offic Calc case 'ots': // Open/Libre Offic Calc Template return 'Ods'; case 'slk': return 'Slk'; case 'xml': // Excel 2003 SpreadSheetML return 'Xml'; case 'gnumeric': return 'Gnumeric'; case 'htm': case 'html': return 'Html'; case 'csv': // Do nothing // We must not try to use CSV reader since it loads // all files including Excel files etc. return null; default: return null; } } /** * Register a writer with its type and class name. */ public static function registerWriter(string $writerType, string $writerClass): void { if (!is_a($writerClass, IWriter::class, true)) { throw new Writer\Exception('Registered writers must implement ' . IWriter::class); } self::$writers[$writerType] = $writerClass; } /** * Register a reader with its type and class name. */ public static function registerReader(string $readerType, string $readerClass): void { if (!is_a($readerClass, IReader::class, true)) { throw new Reader\Exception('Registered readers must implement ' . IReader::class); } self::$readers[$readerType] = $readerClass; } }