Fix shared strings XML Entities auto decode (#411)

When converting an XMLReader node to a SimpleXMLElement, the conversion would automatically decode the XML entities. This resulted in a double decode.
For example: """ was converted to """ when imported into a SimpleXMLElement and was again converted into " (quote).

This commit changes the way the XLSX Shared Strings file is processed. It also changes the unescaping logic for both XLSX and ODS.

Finally, it removes any usage of the SimpleXML library (yay!).
This commit is contained in:
Adrien Loison authored and GitHub committed 2017-04-28 02:27:33 +02:00
1 parent 1eb01a3d2a
commit 048105461c
17 files changed
+120 -405

No files matched your search

@@ -98,6 +98,22 @@ class SharedStringsHelperTest extends \PHPUnit_Framework_TestCase
$sharedStringsHelper->cleanup();
}
/**
* @return void
*/
public function testGetStringAtIndexShouldNotDoubleDecodeHTMLEntities()
{
$resourcePath = $this->getResourcePath('one_sheet_with_pre_encoded_html_entities.xlsx');
$sharedStringsHelper = new SharedStringsHelper($resourcePath);
$sharedStringsHelper->extractSharedStrings();
$sharedString = $sharedStringsHelper->getStringAtIndex(0);
$this->assertEquals('quote: " - ampersand: &', $sharedString);
$sharedStringsHelper->cleanup();
}
/**
* @return void
*/
+21 -17
View File
@@ -426,42 +426,46 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($expectedRow, $allRows[0], 'Pronunciation data should be removed.');
}
/**
* @return array
*/
public function dataProviderForTestReadShouldBeProtectedAgainstAttacks()
{
return [
['attack_billion_laughs.xlsx'],
['attack_quadratic_blowup.xlsx'],
];
}
/**
* @dataProvider dataProviderForTestReadShouldBeProtectedAgainstAttacks
* @NOTE: The LIBXML_NOENT is used to ACTUALLY substitute entities (and should therefore not be used)
*
* @param string $fileName
* @return void
*/
public function testReadShouldBeProtectedAgainstAttacks($fileName)
public function testReadShouldBeProtectedAgainstBillionLaughsAttack()
{
$startTime = microtime(true);
try {
// using @ to prevent warnings/errors from being displayed
@$this->getAllRowsForFile($fileName);
@$this->getAllRowsForFile('attack_billion_laughs.xlsx');
$this->fail('An exception should have been thrown');
} catch (IOException $exception) {
$duration = microtime(true) - $startTime;
$this->assertLessThan(10, $duration, 'Entities should not be expanded and therefore take more than 10 seconds to be parsed.');
$expectedMaxMemoryUsage = 30 * 1024 * 1024; // 30MB
$expectedMaxMemoryUsage = 40 * 1024 * 1024; // 40MB
$this->assertLessThan($expectedMaxMemoryUsage, memory_get_peak_usage(true), 'Entities should not be expanded and therefore consume all the memory.');
}
}
/**
* @NOTE: The LIBXML_NOENT is used to ACTUALLY substitute entities (and should therefore not be used)
*
* @return void
*/
public function testReadShouldBeProtectedAgainstQuadraticBlowupAttack()
{
$startTime = microtime(true);
$this->getAllRowsForFile('attack_quadratic_blowup.xlsx');
$duration = microtime(true) - $startTime;
$this->assertLessThan(10, $duration, 'Entities should not be expanded and therefore take more than 10 seconds to be parsed.');
$expectedMaxMemoryUsage = 40 * 1024 * 1024; // 40MB
$this->assertLessThan($expectedMaxMemoryUsage, memory_get_peak_usage(true), 'Entities should not be expanded and therefore consume all the memory.');
}
/**
* @return void
*/