PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
tablepress / libraries / vendor / PhpSpreadsheet / IOFactory.php

IOFactory.php in TablePress – Tables in WordPress made easy 3.4, at libraries/vendor/PhpSpreadsheet/IOFactory.php

222 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace TablePress\PhpOffice\PhpSpreadsheet;
4
5 use TablePress\PhpOffice\PhpSpreadsheet\Reader\CsvNoEscape;
6 use TablePress\PhpOffice\PhpSpreadsheet\Reader\IReader2 as IReader;
7 use TablePress\PhpOffice\PhpSpreadsheet\Shared\File;
8
9 /**
10 * Factory to create readers easily.
11 *
12 * It is not required to use this class, but it should make it easier to read files.
13 * Especially for reading files with an unknown format.
14 */
15 abstract class IOFactory
16 {
17 public const READER_XLSX = 'Xlsx';
18 public const READER_XLS = 'Xls';
19 public const READER_XML = 'Xml';
20 public const READER_ODS = 'Ods';
21 public const READER_SYLK = 'Slk';
22 public const READER_SLK = 'Slk';
23 public const READER_GNUMERIC = 'Gnumeric';
24 public const READER_HTML = 'Html';
25 public const READER_CSV = 'Csv';
26
27 public const USE_CSV_NO_ESCAPE = [self::READER_CSV => CsvNoEscape::class];
28
29 /** @var array<string, class-string<IReader>> */
30 private static array $readers = [
31 self::READER_XLSX => Reader\Xlsx::class,
32 self::READER_XLS => Reader\Xls::class,
33 self::READER_XML => Reader\Xml::class,
34 self::READER_ODS => Reader\Ods::class,
35 self::READER_SLK => Reader\Slk::class,
36 self::READER_GNUMERIC => Reader\Gnumeric::class,
37 self::READER_HTML => Reader\Html::class,
38 self::READER_CSV => Reader\Csv::class,
39 ];
40
41 /**
42 * Create IReader.
43 *
44 * @param array<string, class-string<IReader>> $mergeArray
45 * Array to use to find reader, self::$readers will be used if $readers is empty.
46 */
47 public static function createReader(string $readerType, array $mergeArray = []): IReader
48 {
49 /** @var class-string<IReader> */
50 $className = $readerType;
51 $readers = empty($mergeArray) ? self::$readers : $mergeArray;
52 if (!in_array($readerType, $readers, true)) {
53 if (!isset($readers[$readerType])) {
54 throw new Reader\Exception("No reader found for type $readerType");
55 }
56
57 // Instantiate reader
58 $className = $readers[$readerType];
59 }
60
61 return new $className();
62 }
63
64 /**
65 * Loads Spreadsheet from file using automatic Reader\IReader resolution.
66 *
67 * @param string $filename The name of the spreadsheet file
68 * @param int $flags the optional second parameter flags may be used to identify specific elements
69 * that should be loaded, but which won't be loaded by default, using these values:
70 * IReader::LOAD_WITH_CHARTS - Include any charts that are defined in the loaded file.
71 * IReader::READ_DATA_ONLY - Read cell values only, not formatting or merge structure.
72 * IReader::IGNORE_EMPTY_CELLS - Don't load empty cells into the model.
73 * @param string[] $readers An array of Readers to use to identify the file type. By default, load() will try
74 * all possible Readers until it finds a match; but this allows you to pass in a
75 * list of Readers so it will only try the subset that you specify here.
76 * Values in this list can be any of the constant values defined in the set
77 * IOFactory::READER_*.
78 * @param array<string, class-string<IReader>> $mergeArray
79 */
80 public static function load(string $filename, int $flags = 0, ?array $readers = null, array $mergeArray = []): Spreadsheet
81 {
82 $reader = self::createReaderForFile($filename, $readers, $mergeArray);
83
84 return $reader->load($filename, $flags);
85 }
86
87 /**
88 * Identify file type using automatic IReader resolution.
89 *
90 * @param string[] $readers
91 * @param array<string, class-string<IReader>> $mergeArray
92 */
93 public static function identify(string $filename, ?array $readers = null, bool $fullClassName = false, array $mergeArray = []): string
94 {
95 $reader = self::createReaderForFile($filename, $readers, $mergeArray);
96 $className = get_class($reader);
97 if ($fullClassName) {
98 return $className;
99 }
100 $classType = explode('\\', $className);
101
102 return array_pop($classType);
103 }
104
105 /**
106 * Create Reader\IReader for file using automatic IReader resolution.
107 *
108 * @param string[] $readers An array of Readers to use to identify the file type. By default, load() will try
109 * all possible Readers until it finds a match; but this allows you to pass in a
110 * list of Readers so it will only try the subset that you specify here.
111 * Values in this list can be any of the constant values defined in the set
112 * IOFactory::READER_*.
113 * @param array<string, class-string<IReader>> $mergeArray supplied readers will be merged with
114 * default readers, allowing specification of a partial list.
115 *
116 * @throws Reader\Exception
117 */
118 public static function createReaderForFile(string $filename, ?array $readers = null, array $mergeArray = []): IReader
119 {
120 File::assertFile($filename);
121
122 $testReaders = array_merge(self::$readers, $mergeArray);
123 if ($readers !== null) {
124 $readers = array_map('strtoupper', $readers);
125 $testReaders = array_filter(
126 self::$readers,
127 fn (string $readerType): bool => in_array(strtoupper($readerType), $readers, true),
128 ARRAY_FILTER_USE_KEY
129 );
130 }
131
132 // First, lucky guess by inspecting file extension
133 $guessedReader = self::getReaderTypeFromExtension($filename);
134 if (($guessedReader !== null) && array_key_exists($guessedReader, $testReaders)) {
135 $reader = self::createReader($guessedReader, $testReaders);
136
137 // Let's see if we are lucky
138 if ($reader->canRead($filename)) {
139 return $reader;
140 }
141 }
142
143 // If we reach here then "lucky guess" didn't give any result
144 // Try walking through all the options in self::$readers (or the selected subset)
145 foreach ($testReaders as $readerType => $class) {
146 // Ignore our original guess, we know that won't work
147 if ($readerType !== $guessedReader) {
148 $reader = self::createReader($readerType, $testReaders);
149 if ($reader->canRead($filename)) {
150 return $reader;
151 }
152 }
153 }
154
155 throw new Reader\Exception('Unable to identify a reader for this file');
156 }
157
158 /**
159 * Guess a reader type from the file extension, if any.
160 */
161 private static function getReaderTypeFromExtension(string $filename): ?string
162 {
163 $pathinfo = pathinfo($filename);
164 if (!isset($pathinfo['extension'])) {
165 return null;
166 }
167
168 switch (strtolower($pathinfo['extension'])) {
169 case 'xlsx':
170 case 'xlsm':
171 case 'xltx':
172 case 'xltm':
173 return 'Xlsx';
174 case 'xls':
175 case 'xlt':
176 return 'Xls';
177 case 'ods':
178 case 'ots':
179 return 'Ods';
180 case 'slk':
181 return 'Slk';
182 case 'xml':
183 return 'Xml';
184 case 'gnumeric':
185 return 'Gnumeric';
186 case 'htm':
187 case 'html':
188 return 'Html';
189 case 'csv':
190 return null;
191 default:
192 return null;
193 }
194 }
195
196 /**
197 * Register a reader with its type and class name.
198 *
199 * @param class-string<IReader> $readerClass
200 */
201 public static function registerReader(string $readerType, string $readerClass): void
202 {
203 if (!is_a($readerClass, IReader::class, true)) {
204 throw new Reader\Exception('Registered readers must implement ' . IReader::class);
205 }
206
207 self::$readers[$readerType] = $readerClass;
208 }
209
210 /**
211 * @return array<string, class-string<IReader>>
212 *
213 * @internal
214 *
215 * @codeCoverageIgnore
216 */
217 public static function getReaders(): array
218 {
219 return self::$readers;
220 }
221 }
222