|
10 | 10 | use PhpOffice\PhpSpreadsheet\Shared\StringHelper; |
11 | 11 | use PhpOffice\PhpSpreadsheet\Spreadsheet; |
12 | 12 | use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; |
| 13 | +use Throwable; |
13 | 14 |
|
14 | 15 | class Csv extends BaseReader |
15 | 16 | { |
@@ -74,7 +75,7 @@ class Csv extends BaseReader |
74 | 75 | * It is anticipated that it will conditionally be set |
75 | 76 | * to null-string for Php9 and above. |
76 | 77 | */ |
77 | | - private static string $defaultEscapeCharacter = '\\'; |
| 78 | + private static string $defaultEscapeCharacter = PHP_VERSION_ID < 90000 ? '\\' : ''; |
78 | 79 |
|
79 | 80 | /** |
80 | 81 | * Callback for setting defaults in construction. |
@@ -286,6 +287,12 @@ private function openFileOrMemory(string $filename): void |
286 | 287 | if (!$fhandle) { |
287 | 288 | throw new ReaderException($filename . ' is an Invalid Spreadsheet file.'); |
288 | 289 | } |
| 290 | + if ($this->inputEncoding === 'UTF-8') { |
| 291 | + $encoding = self::guessEncodingBom($filename); |
| 292 | + if ($encoding !== '') { |
| 293 | + $this->inputEncoding = $encoding; |
| 294 | + } |
| 295 | + } |
289 | 296 | if ($this->inputEncoding === self::GUESS_ENCODING) { |
290 | 297 | $this->inputEncoding = self::guessEncoding($filename, $this->fallbackEncoding); |
291 | 298 | } |
@@ -313,7 +320,7 @@ public function setTestAutoDetect(bool $value): self |
313 | 320 | private function setAutoDetect(?string $value): ?string |
314 | 321 | { |
315 | 322 | $retVal = null; |
316 | | - if ($value !== null && $this->testAutodetect) { |
| 323 | + if ($value !== null && $this->testAutodetect && PHP_VERSION_ID < 90000) { |
317 | 324 | $retVal2 = @ini_set('auto_detect_line_endings', $value); |
318 | 325 | if (is_string($retVal2)) { |
319 | 326 | $retVal = $retVal2; |
@@ -362,6 +369,20 @@ private function loadStringOrFile(string $filename, Spreadsheet $spreadsheet, bo |
362 | 369 | // Deprecated in Php8.1 |
363 | 370 | $iniset = $this->setAutoDetect('1'); |
364 | 371 |
|
| 372 | + try { |
| 373 | + $this->loadStringOrFile2($filename, $spreadsheet, $dataUri); |
| 374 | + $this->setAutoDetect($iniset); |
| 375 | + } catch (Throwable $e) { |
| 376 | + $this->setAutoDetect($iniset); |
| 377 | + |
| 378 | + throw $e; |
| 379 | + } |
| 380 | + |
| 381 | + return $spreadsheet; |
| 382 | + } |
| 383 | + |
| 384 | + private function loadStringOrFile2(string $filename, Spreadsheet $spreadsheet, bool $dataUri): void |
| 385 | + { |
365 | 386 | // Open file |
366 | 387 | if ($dataUri) { |
367 | 388 | $this->openDataUri($filename); |
@@ -433,11 +454,6 @@ private function loadStringOrFile(string $filename, Spreadsheet $spreadsheet, bo |
433 | 454 |
|
434 | 455 | // Close file |
435 | 456 | fclose($fileHandle); |
436 | | - |
437 | | - $this->setAutoDetect($iniset); |
438 | | - |
439 | | - // Return |
440 | | - return $spreadsheet; |
441 | 457 | } |
442 | 458 |
|
443 | 459 | /** |
@@ -545,6 +561,10 @@ public function getContiguous(): bool |
545 | 561 | */ |
546 | 562 | public function setEscapeCharacter(string $escapeCharacter): self |
547 | 563 | { |
| 564 | + if (PHP_VERSION_ID >= 90000 && $escapeCharacter !== '') { |
| 565 | + throw new ReaderException('Escape character must be null string for Php9+'); |
| 566 | + } |
| 567 | + |
548 | 568 | $this->escapeCharacter = $escapeCharacter; |
549 | 569 |
|
550 | 570 | return $this; |
@@ -621,17 +641,15 @@ private static function guessEncodingTestBom(string &$encoding, string $first4, |
621 | 641 | } |
622 | 642 | } |
623 | 643 |
|
624 | | - private static function guessEncodingBom(string $filename): string |
| 644 | + public static function guessEncodingBom(string $filename, ?string $convertString = null): string |
625 | 645 | { |
626 | 646 | $encoding = ''; |
627 | | - $first4 = file_get_contents($filename, false, null, 0, 4); |
628 | | - if ($first4 !== false) { |
629 | | - self::guessEncodingTestBom($encoding, $first4, self::UTF8_BOM, 'UTF-8'); |
630 | | - self::guessEncodingTestBom($encoding, $first4, self::UTF16BE_BOM, 'UTF-16BE'); |
631 | | - self::guessEncodingTestBom($encoding, $first4, self::UTF32BE_BOM, 'UTF-32BE'); |
632 | | - self::guessEncodingTestBom($encoding, $first4, self::UTF32LE_BOM, 'UTF-32LE'); |
633 | | - self::guessEncodingTestBom($encoding, $first4, self::UTF16LE_BOM, 'UTF-16LE'); |
634 | | - } |
| 647 | + $first4 = $convertString ?? (string) file_get_contents($filename, false, null, 0, 4); |
| 648 | + self::guessEncodingTestBom($encoding, $first4, self::UTF8_BOM, 'UTF-8'); |
| 649 | + self::guessEncodingTestBom($encoding, $first4, self::UTF16BE_BOM, 'UTF-16BE'); |
| 650 | + self::guessEncodingTestBom($encoding, $first4, self::UTF32BE_BOM, 'UTF-32BE'); |
| 651 | + self::guessEncodingTestBom($encoding, $first4, self::UTF32LE_BOM, 'UTF-32LE'); |
| 652 | + self::guessEncodingTestBom($encoding, $first4, self::UTF16LE_BOM, 'UTF-16LE'); |
635 | 653 |
|
636 | 654 | return $encoding; |
637 | 655 | } |
@@ -688,4 +706,39 @@ private static function getCsv( |
688 | 706 |
|
689 | 707 | return fgetcsv($stream, $length, $separator, $enclosure, $escape); |
690 | 708 | } |
| 709 | + |
| 710 | + public static function affectedByPhp9( |
| 711 | + string $filename, |
| 712 | + string $inputEncoding = 'UTF-8', |
| 713 | + ?string $delimiter = null, |
| 714 | + string $enclosure = '"', |
| 715 | + string $escapeCharacter = '\\' |
| 716 | + ): bool { |
| 717 | + if (PHP_VERSION_ID < 70400 || PHP_VERSION_ID >= 90000) { |
| 718 | + throw new ReaderException('Function valid only for Php7.4 or Php8'); // @codeCoverageIgnore |
| 719 | + } |
| 720 | + $reader1 = new self(); |
| 721 | + $reader1->setInputEncoding($inputEncoding) |
| 722 | + ->setTestAutoDetect(true) |
| 723 | + ->setEscapeCharacter($escapeCharacter) |
| 724 | + ->setDelimiter($delimiter) |
| 725 | + ->setEnclosure($enclosure); |
| 726 | + $spreadsheet1 = $reader1->load($filename); |
| 727 | + $sheet1 = $spreadsheet1->getActiveSheet(); |
| 728 | + $array1 = $sheet1->toArray(null, false, false); |
| 729 | + $spreadsheet1->disconnectWorksheets(); |
| 730 | + |
| 731 | + $reader2 = new self(); |
| 732 | + $reader2->setInputEncoding($inputEncoding) |
| 733 | + ->setTestAutoDetect(false) |
| 734 | + ->setEscapeCharacter('') |
| 735 | + ->setDelimiter($delimiter) |
| 736 | + ->setEnclosure($enclosure); |
| 737 | + $spreadsheet2 = $reader2->load($filename); |
| 738 | + $sheet2 = $spreadsheet2->getActiveSheet(); |
| 739 | + $array2 = $sheet2->toArray(null, false, false); |
| 740 | + $spreadsheet2->disconnectWorksheets(); |
| 741 | + |
| 742 | + return $array1 !== $array2; |
| 743 | + } |
691 | 744 | } |
0 commit comments