XmlScannerTest.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <?php
  2. namespace PhpOffice\PhpSpreadsheetTests\Reader\Security;
  3. use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
  4. use PhpOffice\PhpSpreadsheet\Reader\Xls;
  5. use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
  6. use PHPUnit\Framework\TestCase;
  7. use XMLReader;
  8. class XmlScannerTest extends TestCase
  9. {
  10. protected function setUp(): void
  11. {
  12. // php 8.+ deprecated libxml_disable_entity_loader() - It's on by default
  13. if (\PHP_VERSION_ID < 80000) {
  14. libxml_disable_entity_loader(false);
  15. }
  16. }
  17. /**
  18. * @dataProvider providerValidXML
  19. *
  20. * @param mixed $filename
  21. * @param mixed $expectedResult
  22. */
  23. public function testValidXML($filename, $expectedResult, bool $libxmlDisableEntityLoader): void
  24. {
  25. // php 8.+ deprecated libxml_disable_entity_loader() - It's on by default
  26. if (\PHP_VERSION_ID < 80000) {
  27. $oldDisableEntityLoaderState = libxml_disable_entity_loader($libxmlDisableEntityLoader);
  28. }
  29. $reader = XmlScanner::getInstance(new \PhpOffice\PhpSpreadsheet\Reader\Xml());
  30. $result = $reader->scanFile($filename);
  31. self::assertEquals($expectedResult, $result);
  32. // php 8.+ deprecated libxml_disable_entity_loader() - It's on by default
  33. if (isset($oldDisableEntityLoaderState)) {
  34. libxml_disable_entity_loader($oldDisableEntityLoaderState);
  35. }
  36. }
  37. public function providerValidXML(): array
  38. {
  39. $tests = [];
  40. $glob = glob('tests/data/Reader/Xml/XEETestValid*.xml');
  41. self::assertNotFalse($glob);
  42. foreach ($glob as $file) {
  43. $filename = realpath($file);
  44. $expectedResult = file_get_contents($file);
  45. $tests[basename($file) . '_libxml_entity_loader_disabled'] = [$filename, $expectedResult, true];
  46. $tests[basename($file) . '_libxml_entity_loader_enabled'] = [$filename, $expectedResult, false];
  47. }
  48. return $tests;
  49. }
  50. /**
  51. * @dataProvider providerInvalidXML
  52. *
  53. * @param mixed $filename
  54. */
  55. public function testInvalidXML($filename, bool $libxmlDisableEntityLoader): void
  56. {
  57. $this->expectException(\PhpOffice\PhpSpreadsheet\Reader\Exception::class);
  58. // php 8.+ deprecated libxml_disable_entity_loader() - It's on by default
  59. if (\PHP_VERSION_ID < 80000) {
  60. libxml_disable_entity_loader($libxmlDisableEntityLoader);
  61. }
  62. $reader = XmlScanner::getInstance(new \PhpOffice\PhpSpreadsheet\Reader\Xml());
  63. $expectedResult = 'FAILURE: Should throw an Exception rather than return a value';
  64. $result = $reader->scanFile($filename);
  65. self::assertEquals($expectedResult, $result);
  66. // php 8.+ deprecated libxml_disable_entity_loader() - It's on by default
  67. if (\PHP_VERSION_ID < 80000) {
  68. self::assertEquals($libxmlDisableEntityLoader, libxml_disable_entity_loader());
  69. }
  70. }
  71. public function providerInvalidXML(): array
  72. {
  73. $tests = [];
  74. $glob = glob('tests/data/Reader/Xml/XEETestInvalidUTF*.xml');
  75. self::assertNotFalse($glob);
  76. foreach ($glob as $file) {
  77. $filename = realpath($file);
  78. $tests[basename($file) . '_libxml_entity_loader_disabled'] = [$filename, true];
  79. $tests[basename($file) . '_libxml_entity_loader_enabled'] = [$filename, false];
  80. }
  81. return $tests;
  82. }
  83. public function testGetSecurityScannerForXmlBasedReader(): void
  84. {
  85. $fileReader = new Xlsx();
  86. $scanner = $fileReader->getSecurityScanner();
  87. // Must return an object...
  88. self::assertIsObject($scanner);
  89. // ... of the correct type
  90. self::assertInstanceOf(XmlScanner::class, $scanner);
  91. }
  92. public function testGetSecurityScannerForNonXmlBasedReader(): void
  93. {
  94. $fileReader = new Xls();
  95. $scanner = $fileReader->getSecurityScanner();
  96. // Must return a null...
  97. self::assertNull($scanner);
  98. }
  99. /**
  100. * @dataProvider providerValidXMLForCallback
  101. *
  102. * @param mixed $filename
  103. * @param mixed $expectedResult
  104. */
  105. public function testSecurityScanWithCallback($filename, $expectedResult): void
  106. {
  107. $fileReader = new Xlsx();
  108. $scanner = $fileReader->getSecurityScanner();
  109. $scanner->setAdditionalCallback('strrev');
  110. $xml = $scanner->scanFile($filename);
  111. self::assertEquals(strrev($expectedResult), $xml);
  112. }
  113. public function providerValidXMLForCallback(): array
  114. {
  115. $tests = [];
  116. $glob = glob('tests/data/Reader/Xml/SecurityScannerWithCallback*.xml');
  117. self::assertNotFalse($glob);
  118. foreach ($glob as $file) {
  119. $tests[basename($file)] = [realpath($file), file_get_contents($file)];
  120. }
  121. return $tests;
  122. }
  123. public function testLibxmlDisableEntityLoaderIsRestoredWithoutShutdown(): void
  124. {
  125. $reader = new Xlsx();
  126. unset($reader);
  127. $reader = new XMLReader();
  128. $opened = $reader->open('tests/data/Reader/Xml/SecurityScannerWithCallbackExample.xml');
  129. self::assertTrue($opened);
  130. }
  131. public function testEncodingAllowsMixedCase(): void
  132. {
  133. $scanner = new XmlScanner();
  134. $output = $scanner->scan($input = '<?xml version="1.0" encoding="utf-8"?><foo>bar</foo>');
  135. self::assertSame($input, $output);
  136. }
  137. }