From 36b328a9fae1a91caee103c00c202cab4665cf68 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Tue, 29 Jun 2021 09:11:51 -0700 Subject: [PATCH 1/3] Fix Worksheet Passwords Fix for issue #1897. The existing hashing code seems to work correctly almost all the time, but there are exceptions. It is replaced by an exact implementation of the spec, including a link to the spec in the comments. Cases known to fail are added to the unit test suite. The spec expects the string to be at most 255 bytes (yes, bytes not characters). The program had permitted any length; it will now throw an exception when the maximum length is exceeded. Xls does not support any hashing algorithm except basic. The Xls writer had, nevertheless, accepted the results of any of the other possible algorithms. This leads to (a) a worksheet that can't be unprotected, and (b) deprecation notices during the write (because it is using hexdec, which expects only hex characters, and the other algorithms generate non-hex characters). I have changed Xls writer to ignore passwords generated by other algorithms. An alternative would be to have the password hasher generate both an algorithmic password (for use by Xlsx) and a basic password (for use by Xls); I think that is too complex a solution, but can look into it if you think it worthwhile. I do not see any current support for Worksheet passwords in ODS Reader or Writer. I did not add support in this PR. I added a new test to confirm the password for reading a spreadsheet is consistent with the one used for writing it. As you can see from the comments for the new test, it had an unusual problem with a somewhat unusual solution. --- phpstan-baseline.neon | 5 -- src/PhpSpreadsheet/Shared/PasswordHasher.php | 43 ++++++++----- src/PhpSpreadsheet/Writer/Xls/Worksheet.php | 2 +- .../Shared/PasswordHasherTest.php | 4 ++ .../Shared/PasswordReloadTest.php | 63 +++++++++++++++++++ tests/data/Shared/PasswordHashes.php | 5 ++ 6 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Shared/PasswordReloadTest.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3538d091c1..625c34298f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -4310,11 +4310,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/OLERead.php - - - message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/PasswordHasher.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:sanitizeUTF8\\(\\) should return string but returns string\\|false\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Shared/PasswordHasher.php b/src/PhpSpreadsheet/Shared/PasswordHasher.php index 9fefe88fb5..ba30fc3156 100644 --- a/src/PhpSpreadsheet/Shared/PasswordHasher.php +++ b/src/PhpSpreadsheet/Shared/PasswordHasher.php @@ -2,11 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Shared; -use PhpOffice\PhpSpreadsheet\Exception; +use PhpOffice\PhpSpreadsheet\Exception as SpException; use PhpOffice\PhpSpreadsheet\Worksheet\Protection; class PasswordHasher { + const MAX_PASSWORD_LENGTH = 255; + /** * Get algorithm name for PHP. */ @@ -34,36 +36,40 @@ private static function getAlgorithm(string $algorithmName): string return $mapping[$algorithmName]; } - throw new Exception('Unsupported password algorithm: ' . $algorithmName); + throw new SpException('Unsupported password algorithm: ' . $algorithmName); } /** * Create a password hash from a given string. * - * This method is based on the algorithm provided by + * This method is based on the spec at: + * https://interoperability.blob.core.windows.net/files/MS-OFFCRYPTO/[MS-OFFCRYPTO].pdf + * 2.3.7.1 Binary Document Password Verifier Derivation Method 1 + * + * It replaces a method based on the algorithm provided by * Daniel Rentz of OpenOffice and the PEAR package * Spreadsheet_Excel_Writer by Xavier Noguer . * + * Scrutinizer will squawk at the use of bitwise operations here, + * but it should ultimately pass. + * * @param string $pPassword Password to hash */ private static function defaultHashPassword(string $pPassword): string { - $password = 0x0000; - $charPos = 1; // char position - - // split the plain text password in its component characters - $chars = preg_split('//', $pPassword, -1, PREG_SPLIT_NO_EMPTY); - foreach ($chars as $char) { - $value = ord($char) << $charPos++; // shifted ASCII value - $rotated_bits = $value >> 15; // rotated bits beyond bit 15 - $value &= 0x7fff; // first 15 bits - $password ^= ($value | $rotated_bits); + $verifier = 0; + $pwlen = strlen($pPassword); + $passwordArray = pack('c', $pwlen) . $pPassword; + for ($i = $pwlen; $i >= 0; --$i) { + $intermediate1 = (($verifier & 0x4000) === 0) ? 0 : 1; + $intermediate2 = 2 * $verifier; + $intermediate2 = $intermediate2 & 0x7fff; + $intermediate3 = $intermediate1 | $intermediate2; + $verifier = $intermediate3 ^ ord($passwordArray[$i]); } + $verifier ^= 0xCE4B; - $password ^= strlen($pPassword); - $password ^= 0xCE4B; - - return strtoupper(dechex($password)); + return strtoupper(dechex($verifier)); } /** @@ -82,6 +88,9 @@ private static function defaultHashPassword(string $pPassword): string */ public static function hashPassword(string $password, string $algorithm = '', string $salt = '', int $spinCount = 10000): string { + if (strlen($password) > self::MAX_PASSWORD_LENGTH) { + throw new SpException('Password exceeds ' . self::MAX_PASSWORD_LENGTH . ' characters'); + } $phpAlgorithm = self::getAlgorithm($algorithm); if (!$phpAlgorithm) { return self::defaultHashPassword($password); diff --git a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php index 6b5fa6fd83..e8377ee94a 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php @@ -2138,7 +2138,7 @@ private function writeObjectProtect(): void private function writePassword(): void { // Exit unless sheet protection and password have been specified - if (!$this->phpSheet->getProtection()->getSheet() || !$this->phpSheet->getProtection()->getPassword()) { + if (!$this->phpSheet->getProtection()->getSheet() || !$this->phpSheet->getProtection()->getPassword() || $this->phpSheet->getProtection()->getAlgorithm() !== '') { return; } diff --git a/tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php b/tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php index e85b9fa34e..4b7923d8dc 100644 --- a/tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php +++ b/tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Shared; +use PhpOffice\PhpSpreadsheet\Exception as SpException; use PhpOffice\PhpSpreadsheet\Shared\PasswordHasher; use PHPUnit\Framework\TestCase; @@ -14,6 +15,9 @@ class PasswordHasherTest extends TestCase */ public function testHashPassword($expectedResult, ...$args): void { + if ($expectedResult === 'exception') { + $this->expectException(SpException::class); + } $result = PasswordHasher::hashPassword(...$args); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Shared/PasswordReloadTest.php b/tests/PhpSpreadsheetTests/Shared/PasswordReloadTest.php new file mode 100644 index 0000000000..6d12749660 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Shared/PasswordReloadTest.php @@ -0,0 +1,63 @@ +getActiveSheet(); + $sheet->getCell('A1')->setValue(1); + $protection = $sheet->getProtection(); + $protection->setAlgorithm($algorithm); + $protection->setPassword($password); + $protection->setSheet(true); + + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $format); + $resheet = $reloadedSpreadsheet->getActiveSheet(); + $reprot = $resheet->getProtection(); + $repassword = $reprot->getPassword(); + $hash = ''; + if ($supported) { + $readAlgorithm = $reprot->getAlgorithm(); + self::assertSame($algorithm, $readAlgorithm); + $salt = $reprot->getSalt(); + $spin = $reprot->getSpinCount(); + $hash = PasswordHasher::hashPassword($password, $readAlgorithm, $salt, $spin); + } + self::assertSame($repassword, $hash); + $spreadsheet->disconnectWorksheets(); + $reloadedSpreadsheet->disconnectWorksheets(); + } + + public function providerPasswords(): array + { + return [ + 'Xls basic algorithm' => ['Xls', ''], + 'Xls cannot use SHA512' => ['Xls', 'SHA-512', false], + 'Xlsx basic algorithm' => ['Xlsx', ''], + 'Xlsx can use SHA512' => ['Xlsx', 'SHA-512'], + ]; + } +} diff --git a/tests/data/Shared/PasswordHashes.php b/tests/data/Shared/PasswordHashes.php index 34c25cefca..c46adf1427 100644 --- a/tests/data/Shared/PasswordHashes.php +++ b/tests/data/Shared/PasswordHashes.php @@ -51,4 +51,9 @@ 'Symbols_salt', 100000, ], + // Additional tests suggested by Issue #1897 + ['DCDF', 'ABCDEFGHIJKLMNOPQRSTUVW'], + ['ECD1', 'ABCDEFGHIJKLMNOPQRSTUVWX'], + ['88D2', 'ABCDEFGHIJKLMNOPQRSTUVWXY'], + 'password too long' => ['exception', str_repeat('x', 256)], ]; From 3bb574c302c7233b41555d51229f1b52b53ec063 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Wed, 30 Jun 2021 11:33:35 -0700 Subject: [PATCH 2/3] Fix SettingsTest SettingsTest was changing the global LibXMLLoaderOptions without restoring the original. This caused problems for one of my new tests. --- tests/PhpSpreadsheetTests/SettingsTest.php | 2 ++ .../Shared/PasswordReloadTest.php | 12 ------------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/PhpSpreadsheetTests/SettingsTest.php b/tests/PhpSpreadsheetTests/SettingsTest.php index 11b93ae6e0..80dc07abb5 100644 --- a/tests/PhpSpreadsheetTests/SettingsTest.php +++ b/tests/PhpSpreadsheetTests/SettingsTest.php @@ -41,6 +41,7 @@ public function testGetXMLSettings(): void public function testSetXMLSettings(): void { + $original = Settings::getLibXmlLoaderOptions(); Settings::setLibXmlLoaderOptions(LIBXML_DTDLOAD | LIBXML_DTDATTR | LIBXML_DTDVALID); $result = Settings::getLibXmlLoaderOptions(); self::assertTrue((bool) ((LIBXML_DTDLOAD | LIBXML_DTDATTR | LIBXML_DTDVALID) & $result)); @@ -48,5 +49,6 @@ public function testSetXMLSettings(): void if (\PHP_VERSION_ID < 80000) { self::assertFalse(libxml_disable_entity_loader()); } + Settings::setLibXmlLoaderOptions($original); } } diff --git a/tests/PhpSpreadsheetTests/Shared/PasswordReloadTest.php b/tests/PhpSpreadsheetTests/Shared/PasswordReloadTest.php index 6d12749660..b6c28b1769 100644 --- a/tests/PhpSpreadsheetTests/Shared/PasswordReloadTest.php +++ b/tests/PhpSpreadsheetTests/Shared/PasswordReloadTest.php @@ -9,18 +9,6 @@ class PasswordReloadTest extends AbstractFunctional { /** - * I don't know why separate process is needed for this test. - * I get a weird error without it, and I would rather just scrap the test - * than spend any more time debugging it. - * The test works fine without separate process (on Windows) with: - * php vendor\phpunit\phpunit\phpunit tests\PhpSpreadsheetTests\Shared\ - * But it fails with: - * php vendor\phpunit\phpunit\phpunit tests\PhpSpreadsheetTests\ - * The error is a mysterious: - * simplexml_load_string(): validity error : Validation failed: no DTD found ! - * - * @runInSeparateProcess - * @preserveGlobalState disabled * @dataProvider providerPasswords */ public function testPasswordReload(string $format, string $algorithm, bool $supported = true): void From 7b3585c76ace9d245db60f6b821245e546837470 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Wed, 30 Jun 2021 13:15:20 -0700 Subject: [PATCH 3/3] Now That SettingsTest Is Well-Behaved 7 tests that needed to invoke Settings::setLibXmlLoaderOptions no longer need to do so. --- phpstan-baseline.neon | 25 ------------------- .../Worksheet/WorksheetNamedRangesTest.php | 3 --- .../Writer/Xlsx/ConditionalTest.php | 19 -------------- .../Writer/Xlsx/DrawingsTest.php | 19 -------------- .../Writer/Xlsx/FloatsRetainedTest.php | 2 -- .../Writer/Xlsx/StartsWithHashTest.php | 3 --- .../Writer/Xlsx/UnparsedDataCloneTest.php | 3 --- .../Writer/Xlsx/UnparsedDataTest.php | 1 - 8 files changed, 75 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 625c34298f..527d89b551 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6930,11 +6930,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php - - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Csv\\\\CsvEnclosureTest\\:\\:\\$cellValues has no typehint specified\\.$#" count: 1 @@ -6980,11 +6975,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Writer/Html/ImagesRootTest.php - - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - message: "#^Parameter \\#2 \\$locale of function setlocale expects string\\|null, string\\|false given\\.$#" count: 1 @@ -6995,16 +6985,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php - - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - message: "#^Cannot call method getDrawingCollection\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 4 @@ -7015,11 +6995,6 @@ parameters: count: 4 path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php - - message: "#^Parameter \\#1 \\$data of function simplexml_load_string expects string, string\\|false given\\.$#" count: 2 diff --git a/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php b/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php index 1560f1ed26..b367583b26 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php @@ -4,7 +4,6 @@ use PhpOffice\PhpSpreadsheet\Exception; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; -use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; @@ -17,8 +16,6 @@ class WorksheetNamedRangesTest extends TestCase protected function setUp(): void { - Settings::setLibXmlLoaderOptions(null); // reset to default options - $reader = new Xlsx(); $this->spreadsheet = $reader->load('tests/data/Worksheet/namedRangeTest.xlsx'); } diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/ConditionalTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/ConditionalTest.php index 21df6ed6ee..21659dadd6 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/ConditionalTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/ConditionalTest.php @@ -2,7 +2,6 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; -use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\Conditional; use PhpOffice\PhpSpreadsheet\Style\Fill; @@ -11,24 +10,6 @@ class ConditionalTest extends AbstractFunctional { - /** - * @var int - */ - private $prevValue; - - protected function setUp(): void - { - $this->prevValue = Settings::getLibXmlLoaderOptions(); - - // Disable validating XML with the DTD - Settings::setLibXmlLoaderOptions($this->prevValue & ~LIBXML_DTDVALID & ~LIBXML_DTDATTR & ~LIBXML_DTDLOAD); - } - - protected function tearDown(): void - { - Settings::setLibXmlLoaderOptions($this->prevValue); - } - /** * Test check if conditional style with type 'notContainsText' works on xlsx. */ diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php index 88c6330648..012cdbcd03 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php @@ -4,30 +4,11 @@ use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; -use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional; class DrawingsTest extends AbstractFunctional { - /** - * @var int - */ - private $prevValue; - - protected function setUp(): void - { - $this->prevValue = Settings::getLibXmlLoaderOptions(); - - // Disable validating XML with the DTD - Settings::setLibXmlLoaderOptions($this->prevValue & ~LIBXML_DTDVALID & ~LIBXML_DTDATTR & ~LIBXML_DTDLOAD); - } - - protected function tearDown(): void - { - Settings::setLibXmlLoaderOptions($this->prevValue); - } - /** * Test save and load XLSX file with drawing on 2nd worksheet. */ diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php index 22f3284b97..6ba8316b46 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php @@ -3,7 +3,6 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as Reader; -use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx as Writer; @@ -19,7 +18,6 @@ class FloatsRetainedTest extends TestCase public function testIntyFloatsRetainedByWriter($value): void { $outputFilename = File::temporaryFilename(); - Settings::setLibXmlLoaderOptions(null); $sheet = new Spreadsheet(); $sheet->getActiveSheet()->getCell('A1')->setValue($value); diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php index 826c482d44..ebc3c92f9d 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php @@ -4,7 +4,6 @@ use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as Reader; -use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx as Writer; @@ -16,7 +15,6 @@ class StartsWithHashTest extends TestCase public function testStartWithHash(): void { $outputFilename = File::temporaryFilename(); - Settings::setLibXmlLoaderOptions(null); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setCellValueExplicit('A1', '#define M', DataType::TYPE_STRING); @@ -41,7 +39,6 @@ public function testStartWithHashReadRaw(): void { // Make sure raw data indicates A3 is an error, but A2 isn't. $outputFilename = File::temporaryFilename(); - Settings::setLibXmlLoaderOptions(null); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setCellValueExplicit('A1', '#define M', DataType::TYPE_STRING); diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php index def6f70ea3..9a801015bd 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php @@ -2,7 +2,6 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; -use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Shared\File; use PHPUnit\Framework\TestCase; use ZipArchive; @@ -16,7 +15,6 @@ public function testLoadSaveXlsxWithUnparsedDataClone(): void { $sampleFilename = 'tests/data/Writer/XLSX/drawing_on_2nd_page.xlsx'; $resultFilename = File::temporaryFilename(); - Settings::setLibXmlLoaderOptions(null); // reset to default options $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); $spreadsheet = $reader->load($sampleFilename); $spreadsheet->setActiveSheetIndex(1); @@ -63,7 +61,6 @@ public function testSaveTwice(): void $resultFilename1 = File::temporaryFilename(); $resultFilename2 = File::temporaryFilename(); self::assertNotEquals($resultFilename1, $resultFilename2); - Settings::setLibXmlLoaderOptions(null); // reset to default options $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); $spreadsheet = $reader->load($sampleFilename); $sheet = $spreadsheet->setActiveSheetIndex(1); diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php index a2f21aef01..5619341904 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php @@ -17,7 +17,6 @@ public function testLoadSaveXlsxWithUnparsedData(): void { $sampleFilename = 'tests/data/Writer/XLSX/form_pass_print.xlsm'; $resultFilename = File::temporaryFilename(); - Settings::setLibXmlLoaderOptions(null); // reset to default options $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); $excel = $reader->load($sampleFilename);