Skip to content

Commit

Permalink
Allow XmlScanner to correctly restore libxml entity_loader setting (#…
Browse files Browse the repository at this point in the history
…1050)

XmlScanner was not restoring libxml_disable_entity_loader since
destruct was not being called until script shutdown. This is because
the shutdown handler required an XmlScanner instance.

Also fix an unrelated bug where the UTF-8 encoding test was
case sensitive.
  • Loading branch information
rtek authored and Mark Baker committed Jul 3, 2019
1 parent 352c700 commit 6ab969e
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 23 deletions.
17 changes: 1 addition & 16 deletions src/PhpSpreadsheet/Reader/BaseReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,6 @@ abstract class BaseReader implements IReader
public function __construct()
{
$this->readFilter = new DefaultReadFilter();

// A fatal error will bypass the destructor, so we register a shutdown here
register_shutdown_function([$this, '__destruct']);
}

private function shutdown()
{
if ($this->securityScanner !== null) {
$this->securityScanner = null;
}
}

public function __destruct()
{
$this->shutdown();
}

public function getReadDataOnly()
Expand Down Expand Up @@ -146,7 +131,7 @@ public function setReadFilter(IReadFilter $pValue)
return $this;
}

public function getSecuritySCanner()
public function getSecurityScanner()
{
if (property_exists($this, 'securityScanner')) {
return $this->securityScanner;
Expand Down
9 changes: 5 additions & 4 deletions src/PhpSpreadsheet/Reader/Security/XmlScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function __construct($pattern = '<!DOCTYPE')
$this->disableEntityLoaderCheck();

// A fatal error will bypass the destructor, so we register a shutdown here
register_shutdown_function([$this, '__destruct']);
register_shutdown_function([__CLASS__, 'shutdown']);
}

public static function getInstance(Reader\IReader $reader)
Expand Down Expand Up @@ -72,16 +72,17 @@ private function disableEntityLoaderCheck()
}
}

private function shutdown()
public static function shutdown()
{
if (self::$libxmlDisableEntityLoaderValue !== null) {
libxml_disable_entity_loader(self::$libxmlDisableEntityLoaderValue);
self::$libxmlDisableEntityLoaderValue = null;
}
}

public function __destruct()
{
$this->shutdown();
self::shutdown();
}

public function setAdditionalCallback(callable $callback)
Expand All @@ -93,7 +94,7 @@ private function toUtf8($xml)
{
$pattern = '/encoding="(.*?)"/';
$result = preg_match($pattern, $xml, $matches);
$charset = $result ? $matches[1] : 'UTF-8';
$charset = strtoupper($result ? $matches[1] : 'UTF-8');

if ($charset !== 'UTF-8') {
$xml = mb_convert_encoding($xml, 'UTF-8', $charset);
Expand Down
28 changes: 25 additions & 3 deletions tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@

class XmlScannerTest extends TestCase
{
protected function setUp()
{
libxml_disable_entity_loader(false);
}

/**
* @dataProvider providerValidXML
*
Expand Down Expand Up @@ -74,7 +79,7 @@ public function providerInvalidXML()
public function testGetSecurityScannerForXmlBasedReader()
{
$fileReader = new Xlsx();
$scanner = $fileReader->getSecuritySCanner();
$scanner = $fileReader->getSecurityScanner();

// Must return an object...
$this->assertInternalType('object', $scanner);
Expand All @@ -85,7 +90,7 @@ public function testGetSecurityScannerForXmlBasedReader()
public function testGetSecurityScannerForNonXmlBasedReader()
{
$fileReader = new Xls();
$scanner = $fileReader->getSecuritySCanner();
$scanner = $fileReader->getSecurityScanner();
// Must return a null...
$this->assertNull($scanner);
}
Expand All @@ -99,7 +104,7 @@ public function testGetSecurityScannerForNonXmlBasedReader()
public function testSecurityScanWithCallback($filename, $expectedResult)
{
$fileReader = new Xlsx();
$scanner = $fileReader->getSecuritySCanner();
$scanner = $fileReader->getSecurityScanner();
$scanner->setAdditionalCallback('strrev');
$xml = $scanner->scanFile($filename);

Expand All @@ -115,4 +120,21 @@ public function providerValidXMLForCallback()

return $tests;
}

public function testLibxmlDisableEntityLoaderIsRestoredWithoutShutdown()
{
$reader = new Xlsx();
unset($reader);

$reader = new \XMLReader();
$opened = $reader->open(__DIR__ . '/../../../data/Reader/Xml/SecurityScannerWithCallbackExample.xml');
$this->assertTrue($opened);
}

public function testEncodingAllowsMixedCase()
{
$scanner = new XmlScanner();
$output = $scanner->scan($input = '<?xml version="1.0" encoding="utf-8"?><foo>bar</foo>');
$this->assertSame($input, $output);
}
}

0 comments on commit 6ab969e

Please sign in to comment.