PluginProbe
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin / 6.5.1.7
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin v6.5.1.7
6.5.1.7 6.5.1.6 6.5.1.5 6.5.1.4 6.5.1.3 6.5.1.2 6.5.1.1 6.5.0.9 6.5.0.8 6.5.0.7 6.5.0.6 trunk 3.4.2.40 3.4.2.41 3.4.2.42 3.4.2.43 3.4.2.44 3.4.2.45 3.4.2.46 3.4.2.47 3.4.2.48 3.4.2.49 3.4.2.50 6.3.2 6.3.3.1 All 47 releases
wpdatatables / lib / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Reader / Csv.php

Csv.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin 6.5.1.7, at lib/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Csv.php

736 lines 22.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace PhpOffice\PhpSpreadsheet\Reader;
4
5 use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
6 use PhpOffice\PhpSpreadsheet\Cell\Cell;
7 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
8 use PhpOffice\PhpSpreadsheet\Reader\Csv\Delimiter;
9 use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
10 use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
11 use PhpOffice\PhpSpreadsheet\Spreadsheet;
12 use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
13 use Throwable;
14
15 class Csv extends BaseReader
16 {
17 const DEFAULT_FALLBACK_ENCODING = 'CP1252';
18 const GUESS_ENCODING = 'guess';
19 const UTF8_BOM = "\xEF\xBB\xBF";
20 const UTF8_BOM_LEN = 3;
21 const UTF16BE_BOM = "\xfe\xff";
22 const UTF16BE_BOM_LEN = 2;
23 const UTF16BE_LF = "\x00\x0a";
24 const UTF16LE_BOM = "\xff\xfe";
25 const UTF16LE_BOM_LEN = 2;
26 const UTF16LE_LF = "\x0a\x00";
27 const UTF32BE_BOM = "\x00\x00\xfe\xff";
28 const UTF32BE_BOM_LEN = 4;
29 const UTF32BE_LF = "\x00\x00\x00\x0a";
30 const UTF32LE_BOM = "\xff\xfe\x00\x00";
31 const UTF32LE_BOM_LEN = 4;
32 const UTF32LE_LF = "\x0a\x00\x00\x00";
33
34 /**
35 * Input encoding.
36 *
37 * @var string
38 */
39 private $inputEncoding = 'UTF-8';
40
41 /**
42 * Fallback encoding if guess strikes out.
43 *
44 * @var string
45 */
46 private $fallbackEncoding = self::DEFAULT_FALLBACK_ENCODING;
47
48 /**
49 * Delimiter.
50 *
51 * @var ?string
52 */
53 private $delimiter;
54
55 /**
56 * Enclosure.
57 *
58 * @var string
59 */
60 private $enclosure = '"';
61
62 /**
63 * Sheet index to read.
64 *
65 * @var int
66 */
67 private $sheetIndex = 0;
68
69 /**
70 * Load rows contiguously.
71 *
72 * @var bool
73 */
74 private $contiguous = false;
75
76 /**
77 * The character that can escape the enclosure.
78 *
79 * @var ?string
80 */
81 private $escapeCharacter;
82
83 /**
84 * The character that will be supplied to fgetcsv
85 * when escapeCharacter is null.
86 * It is anticipated that it will conditionally be set
87 * to null-string for Php9 and above.
88 */
89 private static string $defaultEscapeCharacter = PHP_VERSION_ID < 90000 ? '\\' : '';
90
91 /**
92 * Callback for setting defaults in construction.
93 *
94 * @var ?callable
95 */
96 private static $constructorCallback;
97
98 /**
99 * Attempt autodetect line endings (deprecated after PHP8.1)?
100 *
101 * @var bool
102 */
103 private $testAutodetect = true;
104
105 /**
106 * @var bool
107 */
108 protected $castFormattedNumberToNumeric = false;
109
110 /**
111 * @var bool
112 */
113 protected $preserveNumericFormatting = false;
114
115 /** @var bool */
116 private $preserveNullString = false;
117
118 /**
119 * Create a new CSV Reader instance.
120 */
121 public function __construct()
122 {
123 parent::__construct();
124 $callback = self::$constructorCallback;
125 if ($callback !== null) {
126 $callback($this);
127 }
128 }
129
130 /**
131 * Set a callback to change the defaults.
132 *
133 * The callback must accept the Csv Reader object as the first parameter,
134 * and it should return void.
135 */
136 public static function setConstructorCallback(?callable $callback): void
137 {
138 self::$constructorCallback = $callback;
139 }
140
141 public static function getConstructorCallback(): ?callable
142 {
143 return self::$constructorCallback;
144 }
145
146 public function setInputEncoding(string $encoding): self
147 {
148 $this->inputEncoding = $encoding;
149
150 return $this;
151 }
152
153 public function getInputEncoding(): string
154 {
155 return $this->inputEncoding;
156 }
157
158 public function setFallbackEncoding(string $fallbackEncoding): self
159 {
160 $this->fallbackEncoding = $fallbackEncoding;
161
162 return $this;
163 }
164
165 public function getFallbackEncoding(): string
166 {
167 return $this->fallbackEncoding;
168 }
169
170 /**
171 * Move filepointer past any BOM marker.
172 */
173 protected function skipBOM(): void
174 {
175 rewind($this->fileHandle);
176
177 if (fgets($this->fileHandle, self::UTF8_BOM_LEN + 1) !== self::UTF8_BOM) {
178 rewind($this->fileHandle);
179 }
180 }
181
182 /**
183 * Identify any separator that is explicitly set in the file.
184 */
185 protected function checkSeparator(): void
186 {
187 $line = fgets($this->fileHandle);
188 if ($line === false) {
189 return;
190 }
191
192 if ((strlen(trim($line, "\r\n")) == 5) && (stripos($line, 'sep=') === 0)) {
193 $this->delimiter = substr($line, 4, 1);
194
195 return;
196 }
197
198 $this->skipBOM();
199 }
200
201 /**
202 * Infer the separator if it isn't explicitly set in the file or specified by the user.
203 */
204 protected function inferSeparator(): void
205 {
206 if ($this->delimiter !== null) {
207 return;
208 }
209
210 $inferenceEngine = new Delimiter($this->fileHandle, $this->escapeCharacter ?? self::$defaultEscapeCharacter, $this->enclosure);
211
212 // If number of lines is 0, nothing to infer : fall back to the default
213 if ($inferenceEngine->linesCounted() === 0) {
214 $this->delimiter = $inferenceEngine->getDefaultDelimiter();
215 $this->skipBOM();
216
217 return;
218 }
219
220 $this->delimiter = $inferenceEngine->infer();
221
222 // If no delimiter could be detected, fall back to the default
223 if ($this->delimiter === null) {
224 $this->delimiter = $inferenceEngine->getDefaultDelimiter();
225 }
226
227 $this->skipBOM();
228 }
229
230 /**
231 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
232 */
233 public function listWorksheetInfo(string $filename): array
234 {
235 // Open file
236 $this->openFileOrMemory($filename);
237 $fileHandle = $this->fileHandle;
238
239 // Skip BOM, if any
240 $this->skipBOM();
241 $this->checkSeparator();
242 $this->inferSeparator();
243
244 $worksheetInfo = [];
245 $worksheetInfo[0]['worksheetName'] = 'Worksheet';
246 $worksheetInfo[0]['lastColumnLetter'] = 'A';
247 $worksheetInfo[0]['lastColumnIndex'] = 0;
248 $worksheetInfo[0]['totalRows'] = 0;
249 $worksheetInfo[0]['totalColumns'] = 0;
250
251 // Loop through each line of the file in turn
252 $rowData = self::getCsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
253 while (is_array($rowData)) {
254 ++$worksheetInfo[0]['totalRows'];
255 $worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1);
256 $rowData = self::getCsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
257 }
258
259 $worksheetInfo[0]['lastColumnLetter'] = Coordinate::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex'] + 1);
260 $worksheetInfo[0]['totalColumns'] = $worksheetInfo[0]['lastColumnIndex'] + 1;
261
262 // Close file
263 fclose($fileHandle);
264
265 return $worksheetInfo;
266 }
267
268 /**
269 * Loads Spreadsheet from file.
270 */
271 protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
272 {
273 // Create new Spreadsheet
274 $spreadsheet = new Spreadsheet();
275
276 // Load into this instance
277 return $this->loadIntoExisting($filename, $spreadsheet);
278 }
279
280 /**
281 * Loads Spreadsheet from string.
282 */
283 public function loadSpreadsheetFromString(string $contents): Spreadsheet
284 {
285 // Create new Spreadsheet
286 $spreadsheet = new Spreadsheet();
287
288 // Load into this instance
289 return $this->loadStringOrFile('data://text/plain,' . urlencode($contents), $spreadsheet, true);
290 }
291
292 private function openFileOrMemory(string $filename): void
293 {
294 // Open file
295 $fhandle = $this->canRead($filename);
296 if (!$fhandle) {
297 throw new Exception($filename . ' is an Invalid Spreadsheet file.');
298 }
299 if ($this->inputEncoding === 'UTF-8') {
300 $encoding = self::guessEncodingBom($filename);
301 if ($encoding !== '') {
302 $this->inputEncoding = $encoding;
303 }
304 }
305 if ($this->inputEncoding === self::GUESS_ENCODING) {
306 $this->inputEncoding = self::guessEncoding($filename, $this->fallbackEncoding);
307 }
308 $this->openFile($filename);
309 if ($this->inputEncoding !== 'UTF-8') {
310 fclose($this->fileHandle);
311 $entireFile = file_get_contents($filename);
312 $fileHandle = fopen('php://memory', 'r+b');
313 if ($fileHandle !== false && $entireFile !== false) {
314 $this->fileHandle = $fileHandle;
315 $data = StringHelper::convertEncoding($entireFile, 'UTF-8', $this->inputEncoding);
316 fwrite($this->fileHandle, $data);
317 $this->skipBOM();
318 }
319 }
320 }
321
322 public function setTestAutoDetect(bool $value): self
323 {
324 $this->testAutodetect = $value;
325
326 return $this;
327 }
328
329 private function setAutoDetect(?string $value): ?string
330 {
331 $retVal = null;
332 if ($value !== null && $this->testAutodetect && PHP_VERSION_ID < 90000) {
333 $retVal2 = @ini_set('auto_detect_line_endings', $value);
334 if (is_string($retVal2)) {
335 $retVal = $retVal2;
336 }
337 }
338
339 return $retVal;
340 }
341
342 public function castFormattedNumberToNumeric(
343 bool $castFormattedNumberToNumeric,
344 bool $preserveNumericFormatting = false
345 ): void {
346 $this->castFormattedNumberToNumeric = $castFormattedNumberToNumeric;
347 $this->preserveNumericFormatting = $preserveNumericFormatting;
348 }
349
350 /**
351 * Open data uri for reading.
352 */
353 private function openDataUri(string $filename): void
354 {
355 $fileHandle = fopen($filename, 'rb');
356 if ($fileHandle === false) {
357 // @codeCoverageIgnoreStart
358 throw new ReaderException('Could not open file ' . $filename . ' for reading.');
359 // @codeCoverageIgnoreEnd
360 }
361
362 $this->fileHandle = $fileHandle;
363 }
364
365 /**
366 * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
367 */
368 public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Spreadsheet
369 {
370 return $this->loadStringOrFile($filename, $spreadsheet, false);
371 }
372
373 /**
374 * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
375 */
376 private function loadStringOrFile(string $filename, Spreadsheet $spreadsheet, bool $dataUri): Spreadsheet
377 {
378 // Deprecated in Php8.1
379 $iniset = $this->setAutoDetect('1');
380
381 try {
382 $this->loadStringOrFile2($filename, $spreadsheet, $dataUri);
383 $this->setAutoDetect($iniset);
384 } catch (Throwable $e) {
385 $this->setAutoDetect($iniset);
386
387 throw $e;
388 }
389
390 return $spreadsheet;
391 }
392
393 private function loadStringOrFile2(string $filename, Spreadsheet $spreadsheet, bool $dataUri): void
394 {
395 // Open file
396 if ($dataUri) {
397 $this->openDataUri($filename);
398 } else {
399 $this->openFileOrMemory($filename);
400 }
401 $fileHandle = $this->fileHandle;
402
403 // Skip BOM, if any
404 $this->skipBOM();
405 $this->checkSeparator();
406 $this->inferSeparator();
407
408 // Create new PhpSpreadsheet object
409 while ($spreadsheet->getSheetCount() <= $this->sheetIndex) {
410 $spreadsheet->createSheet();
411 }
412 $sheet = $spreadsheet->setActiveSheetIndex($this->sheetIndex);
413
414 // Set our starting row based on whether we're in contiguous mode or not
415 $currentRow = 1;
416 $outRow = 0;
417
418 // Loop through each line of the file in turn
419 $rowData = self::getCsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
420 $valueBinder = Cell::getValueBinder();
421 $preserveBooleanString = method_exists($valueBinder, 'getBooleanConversion') && $valueBinder->getBooleanConversion();
422 while (is_array($rowData)) {
423 $noOutputYet = true;
424 $columnLetter = 'A';
425 foreach ($rowData as $rowDatum) {
426 $this->convertBoolean($rowDatum, $preserveBooleanString);
427 $numberFormatMask = $this->convertFormattedNumber($rowDatum);
428 if (($rowDatum !== '' || $this->preserveNullString) && $this->readFilter->readCell($columnLetter, $currentRow)) {
429 if ($this->contiguous) {
430 if ($noOutputYet) {
431 $noOutputYet = false;
432 ++$outRow;
433 }
434 } else {
435 $outRow = $currentRow;
436 }
437 // Set basic styling for the value (Note that this could be overloaded by styling in a value binder)
438 $sheet->getCell($columnLetter . $outRow)->getStyle()
439 ->getNumberFormat()
440 ->setFormatCode($numberFormatMask);
441 // Set cell value
442 $sheet->getCell($columnLetter . $outRow)->setValue($rowDatum);
443 }
444 ++$columnLetter;
445 }
446 $rowData = self::getCsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
447 ++$currentRow;
448 }
449
450 // Close file
451 fclose($fileHandle);
452 }
453
454 /**
455 * Convert string true/false to boolean, and null to null-string.
456 *
457 * @param mixed $rowDatum
458 */
459 private function convertBoolean(&$rowDatum, bool $preserveBooleanString): void
460 {
461 if (is_string($rowDatum) && !$preserveBooleanString) {
462 if (strcasecmp(Calculation::getTRUE(), $rowDatum) === 0 || strcasecmp('true', $rowDatum) === 0) {
463 $rowDatum = true;
464 } elseif (strcasecmp(Calculation::getFALSE(), $rowDatum) === 0 || strcasecmp('false', $rowDatum) === 0) {
465 $rowDatum = false;
466 }
467 } else {
468 $rowDatum = $rowDatum ?? '';
469 }
470 }
471
472 /**
473 * Convert numeric strings to int or float values.
474 *
475 * @param mixed $rowDatum
476 */
477 private function convertFormattedNumber(&$rowDatum): string
478 {
479 $numberFormatMask = NumberFormat::FORMAT_GENERAL;
480 if ($this->castFormattedNumberToNumeric === true && is_string($rowDatum)) {
481 $numeric = str_replace(
482 [StringHelper::getThousandsSeparator(), StringHelper::getDecimalSeparator()],
483 ['', '.'],
484 $rowDatum
485 );
486
487 if (is_numeric($numeric)) {
488 $decimalPos = strpos($rowDatum, StringHelper::getDecimalSeparator());
489 if ($this->preserveNumericFormatting === true) {
490 $numberFormatMask = (strpos($rowDatum, StringHelper::getThousandsSeparator()) !== false)
491 ? '#,##0' : '0';
492 if ($decimalPos !== false) {
493 $decimals = strlen($rowDatum) - $decimalPos - 1;
494 $numberFormatMask .= '.' . str_repeat('0', min($decimals, 6));
495 }
496 }
497
498 $rowDatum = ($decimalPos !== false) ? (float) $numeric : (int) $numeric;
499 }
500 }
501
502 return $numberFormatMask;
503 }
504
505 public function getDelimiter(): ?string
506 {
507 return $this->delimiter;
508 }
509
510 public function setDelimiter(?string $delimiter): self
511 {
512 $this->delimiter = $delimiter;
513
514 return $this;
515 }
516
517 public function getEnclosure(): string
518 {
519 return $this->enclosure;
520 }
521
522 public function setEnclosure(string $enclosure): self
523 {
524 if ($enclosure == '') {
525 $enclosure = '"';
526 }
527 $this->enclosure = $enclosure;
528
529 return $this;
530 }
531
532 public function getSheetIndex(): int
533 {
534 return $this->sheetIndex;
535 }
536
537 public function setSheetIndex(int $indexValue): self
538 {
539 $this->sheetIndex = $indexValue;
540
541 return $this;
542 }
543
544 public function setContiguous(bool $contiguous): self
545 {
546 $this->contiguous = $contiguous;
547
548 return $this;
549 }
550
551 public function getContiguous(): bool
552 {
553 return $this->contiguous;
554 }
555
556 /**
557 * Php9 intends to drop support for this parameter in fgetcsv.
558 * Not yet ready to mark deprecated in order to give users
559 * a migration path.
560 */
561 public function setEscapeCharacter(string $escapeCharacter): self
562 {
563 if (PHP_VERSION_ID >= 90000 && $escapeCharacter !== '') {
564 throw new ReaderException('Escape character must be null string for Php9+');
565 }
566
567 $this->escapeCharacter = $escapeCharacter;
568
569 return $this;
570 }
571
572 public function getEscapeCharacter(): string
573 {
574 return $this->escapeCharacter ?? self::$defaultEscapeCharacter;
575 }
576
577 /**
578 * Can the current IReader read the file?
579 */
580 public function canRead(string $filename): bool
581 {
582 // Check if file exists
583 try {
584 $this->openFile($filename);
585 } catch (ReaderException $e) {
586 return false;
587 }
588
589 fclose($this->fileHandle);
590
591 // Trust file extension if any
592 $extension = strtolower(/** @scrutinizer ignore-type */ pathinfo($filename, PATHINFO_EXTENSION));
593 if (in_array($extension, ['csv', 'tsv'])) {
594 return true;
595 }
596
597 // Attempt to guess mimetype
598 $type = mime_content_type($filename);
599 $supportedTypes = [
600 'application/csv',
601 'text/csv',
602 'text/plain',
603 'inode/x-empty',
604 ];
605
606 return in_array($type, $supportedTypes, true);
607 }
608
609 private static function guessEncodingTestNoBom(string &$encoding, string &$contents, string $compare, string $setEncoding): void
610 {
611 if ($encoding === '') {
612 $pos = strpos($contents, $compare);
613 if ($pos !== false && $pos % strlen($compare) === 0) {
614 $encoding = $setEncoding;
615 }
616 }
617 }
618
619 private static function guessEncodingNoBom(string $filename): string
620 {
621 $encoding = '';
622 $contents = file_get_contents($filename);
623 self::guessEncodingTestNoBom($encoding, $contents, self::UTF32BE_LF, 'UTF-32BE');
624 self::guessEncodingTestNoBom($encoding, $contents, self::UTF32LE_LF, 'UTF-32LE');
625 self::guessEncodingTestNoBom($encoding, $contents, self::UTF16BE_LF, 'UTF-16BE');
626 self::guessEncodingTestNoBom($encoding, $contents, self::UTF16LE_LF, 'UTF-16LE');
627 if ($encoding === '' && preg_match('//u', $contents) === 1) {
628 $encoding = 'UTF-8';
629 }
630
631 return $encoding;
632 }
633
634 private static function guessEncodingTestBom(string &$encoding, string $first4, string $compare, string $setEncoding): void
635 {
636 if ($encoding === '') {
637 if ($compare === substr($first4, 0, strlen($compare))) {
638 $encoding = $setEncoding;
639 }
640 }
641 }
642
643 public static function guessEncodingBom(string $filename, ?string $convertString = null): string
644 {
645 $encoding = '';
646 $first4 = $convertString ?? (string) file_get_contents($filename, false, null, 0, 4);
647 self::guessEncodingTestBom($encoding, $first4, self::UTF8_BOM, 'UTF-8');
648 self::guessEncodingTestBom($encoding, $first4, self::UTF16BE_BOM, 'UTF-16BE');
649 self::guessEncodingTestBom($encoding, $first4, self::UTF32BE_BOM, 'UTF-32BE');
650 self::guessEncodingTestBom($encoding, $first4, self::UTF32LE_BOM, 'UTF-32LE');
651 self::guessEncodingTestBom($encoding, $first4, self::UTF16LE_BOM, 'UTF-16LE');
652
653 return $encoding;
654 }
655
656 public static function guessEncoding(string $filename, string $dflt = self::DEFAULT_FALLBACK_ENCODING): string
657 {
658 $encoding = self::guessEncodingBom($filename);
659 if ($encoding === '') {
660 $encoding = self::guessEncodingNoBom($filename);
661 }
662
663 return ($encoding === '') ? $dflt : $encoding;
664 }
665
666 public function setPreserveNullString(bool $value): self
667 {
668 $this->preserveNullString = $value;
669
670 return $this;
671 }
672
673 public function getPreserveNullString(): bool
674 {
675 return $this->preserveNullString;
676 }
677
678 /**
679 * Php8.4 deprecates use of anything other than null string
680 * as escape Character.
681 *
682 * @param resource $stream
683 *
684 * @return array<int,?string>|false
685 */
686 private static function getCsv(
687 $stream,
688 ?int $length = null,
689 string $separator = ',',
690 string $enclosure = '"',
691 ?string $escape = null
692 ) {
693 $escape = $escape ?? self::$defaultEscapeCharacter;
694 if (PHP_VERSION_ID >= 80400 && $escape !== '') {
695 return @fgetcsv($stream, $length, $separator, $enclosure, $escape);
696 }
697
698 return fgetcsv($stream, $length, $separator, $enclosure, $escape);
699 }
700
701 public static function affectedByPhp9(
702 string $filename,
703 string $inputEncoding = 'UTF-8',
704 ?string $delimiter = null,
705 string $enclosure = '"',
706 string $escapeCharacter = '\\'
707 ): bool {
708 if (PHP_VERSION_ID < 70400 || PHP_VERSION_ID >= 90000) {
709 throw new ReaderException('Function valid only for Php7.4 or Php8'); // @codeCoverageIgnore
710 }
711 $reader1 = new self();
712 $reader1->setInputEncoding($inputEncoding)
713 ->setTestAutoDetect(true)
714 ->setEscapeCharacter($escapeCharacter)
715 ->setDelimiter($delimiter)
716 ->setEnclosure($enclosure);
717 $spreadsheet1 = $reader1->load($filename);
718 $sheet1 = $spreadsheet1->getActiveSheet();
719 $array1 = $sheet1->toArray(null, false, false);
720 $spreadsheet1->disconnectWorksheets();
721
722 $reader2 = new self();
723 $reader2->setInputEncoding($inputEncoding)
724 ->setTestAutoDetect(false)
725 ->setEscapeCharacter('')
726 ->setDelimiter($delimiter)
727 ->setEnclosure($enclosure);
728 $spreadsheet2 = $reader2->load($filename);
729 $sheet2 = $spreadsheet2->getActiveSheet();
730 $array2 = $sheet2->toArray(null, false, false);
731 $spreadsheet2->disconnectWorksheets();
732
733 return $array1 !== $array2;
734 }
735 }
736