diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
index 12b59e5cbebc3..93880f26455da 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -211,14 +211,28 @@ private function parseDefinition($id, $service, $file)
*/
private function parseFile($file)
{
+ $internalErrors = libxml_use_internal_errors(true);
+ $disableEntities = libxml_disable_entity_loader(true);
+ libxml_clear_errors();
+
$dom = new \DOMDocument();
- libxml_use_internal_errors(true);
- if (!$dom->load($file, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
- throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
- }
$dom->validateOnParse = true;
+ if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
+ libxml_disable_entity_loader($disableEntities);
+
+ throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($internalErrors)));
+ }
$dom->normalizeDocument();
- libxml_use_internal_errors(false);
+
+ libxml_use_internal_errors($internalErrors);
+ libxml_disable_entity_loader($disableEntities);
+
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ throw new \InvalidArgumentException('Document types are not allowed.');
+ }
+ }
+
$this->validate($dom, $file);
return simplexml_import_dom($dom, 'Symfony\\Component\\DependencyInjection\\SimpleXMLElement');
@@ -360,12 +374,14 @@ private function validateSchema(\DOMDocument $dom, $file)
;
$current = libxml_use_internal_errors(true);
+ libxml_clear_errors();
+
$valid = $dom->schemaValidateSource($source);
foreach ($tmpfiles as $tmpfile) {
@unlink($tmpfile);
}
if (!$valid) {
- throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
+ throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($current)));
}
libxml_use_internal_errors($current);
}
@@ -406,7 +422,7 @@ private function validateExtensions(\DOMDocument $dom, $file)
*
* @return array
*/
- private function getXmlErrors()
+ private function getXmlErrors($internalErrors)
{
$errors = array();
foreach (libxml_get_errors() as $error) {
@@ -421,6 +437,7 @@ private function getXmlErrors()
}
libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
return $errors;
}
diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php
index 02e07c8e6fbd5..f7edbd7b64450 100644
--- a/src/Symfony/Component/DomCrawler/Crawler.php
+++ b/src/Symfony/Component/DomCrawler/Crawler.php
@@ -119,10 +119,15 @@ public function addContent($content, $type = null)
*/
public function addHtmlContent($content, $charset = 'UTF-8')
{
+ $disableEntities = libxml_disable_entity_loader(true);
+
$dom = new \DOMDocument('1.0', $charset);
$dom->validateOnParse = true;
@$dom->loadHTML($content);
+
+ libxml_disable_entity_loader($disableEntities);
+
$this->addDocument($dom);
$base = $this->filter('base')->extract(array('href'));
@@ -142,11 +147,16 @@ public function addHtmlContent($content, $charset = 'UTF-8')
*/
public function addXmlContent($content, $charset = 'UTF-8')
{
+ $disableEntities = libxml_disable_entity_loader(true);
+
$dom = new \DOMDocument('1.0', $charset);
$dom->validateOnParse = true;
// remove the default namespace to make XPath expressions simpler
- @$dom->loadXML(str_replace('xmlns', 'ns', $content));
+ @$dom->loadXML(str_replace('xmlns', 'ns', $content), LIBXML_NONET);
+
+ libxml_disable_entity_loader($disableEntities);
+
$this->addDocument($dom);
}
diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
index 1203067d23ca8..5dad9db3fae05 100644
--- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
@@ -150,14 +150,28 @@ protected function parseRoute(RouteCollection $collection, \DOMElement $definiti
*/
protected function loadFile($file)
{
+ $internalErrors = libxml_use_internal_errors(true);
+ $disableEntities = libxml_disable_entity_loader(true);
+ libxml_clear_errors();
+
$dom = new \DOMDocument();
- libxml_use_internal_errors(true);
- if (!$dom->load($file, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
- throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
- }
$dom->validateOnParse = true;
+ if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
+ libxml_disable_entity_loader($disableEntities);
+
+ throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($internalErrors)));
+ }
$dom->normalizeDocument();
- libxml_use_internal_errors(false);
+
+ libxml_use_internal_errors($internalErrors);
+ libxml_disable_entity_loader($disableEntities);
+
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ throw new \InvalidArgumentException('Document types are not allowed.');
+ }
+ }
+
$this->validate($dom);
return $dom;
@@ -175,8 +189,10 @@ protected function validate(\DOMDocument $dom)
$location = __DIR__.'/schema/routing/routing-1.0.xsd';
$current = libxml_use_internal_errors(true);
+ libxml_clear_errors();
+
if (!$dom->schemaValidate($location)) {
- throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
+ throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($current)));
}
libxml_use_internal_errors($current);
}
@@ -186,7 +202,7 @@ protected function validate(\DOMDocument $dom)
*
* @return array An array of libxml error strings
*/
- private function getXmlErrors()
+ private function getXmlErrors($internalErrors)
{
$errors = array();
foreach (libxml_get_errors() as $error) {
@@ -201,6 +217,7 @@ private function getXmlErrors()
}
libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
return $errors;
}
diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
index 1d8d7216d286f..1b23c23f3f655 100644
--- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
+++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
@@ -58,10 +58,20 @@ public function decode($data, $format)
$disableEntities = libxml_disable_entity_loader(true);
libxml_clear_errors();
- $xml = simplexml_load_string($data);
+ $dom = new \DOMDocument();
+ $dom->loadXML($data, LIBXML_NONET);
+
libxml_use_internal_errors($internalErrors);
libxml_disable_entity_loader($disableEntities);
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ throw new UnexpectedValueException('Document types are not allowed.');
+ }
+ }
+
+ $xml = simplexml_import_dom($dom);
+
if ($error = libxml_get_last_error()) {
throw new UnexpectedValueException($error->message);
}
diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php
index 4bd6b69a4adf4..eb222fc552816 100644
--- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php
+++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php
@@ -55,10 +55,26 @@ public function load($resource, $locale, $domain = 'messages')
*/
private function parseFile($file)
{
+ $internalErrors = libxml_use_internal_errors(true);
+ $disableEntities = libxml_disable_entity_loader(true);
+ libxml_clear_errors();
+
$dom = new \DOMDocument();
- $current = libxml_use_internal_errors(true);
- if (!@$dom->load($file, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
- throw new \RuntimeException(implode("\n", $this->getXmlErrors()));
+ $dom->validateOnParse = true;
+ if (!@$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
+ libxml_disable_entity_loader($disableEntities);
+
+ throw new \RuntimeException(implode("\n", $this->getXmlErrors($internalErrors)));
+ }
+
+ libxml_disable_entity_loader($disableEntities);
+
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ libxml_use_internal_errors($internalErrors);
+
+ throw new \RuntimeException('Document types are not allowed.');
+ }
}
$location = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
@@ -77,11 +93,12 @@ private function parseFile($file)
$source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source);
if (!@$dom->schemaValidateSource($source)) {
- throw new \RuntimeException(implode("\n", $this->getXmlErrors()));
+ throw new \RuntimeException(implode("\n", $this->getXmlErrors($internalErrors)));
}
- $dom->validateOnParse = true;
+
$dom->normalizeDocument();
- libxml_use_internal_errors($current);
+
+ libxml_use_internal_errors($internalErrors);
return simplexml_import_dom($dom);
}
@@ -91,7 +108,7 @@ private function parseFile($file)
*
* @return array An array of errors
*/
- private function getXmlErrors()
+ private function getXmlErrors($internalErrors)
{
$errors = array();
foreach (libxml_get_errors() as $error) {
@@ -106,7 +123,7 @@ private function getXmlErrors()
}
libxml_clear_errors();
- libxml_use_internal_errors(false);
+ libxml_use_internal_errors($internalErrors);
return $errors;
}
diff --git a/src/Symfony/Component/Validator/Mapping/Loader/XmlFileLoader.php b/src/Symfony/Component/Validator/Mapping/Loader/XmlFileLoader.php
index d95d97537774c..e44ebfe136c28 100644
--- a/src/Symfony/Component/Validator/Mapping/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/Validator/Mapping/Loader/XmlFileLoader.php
@@ -180,22 +180,38 @@ protected function parseOptions(\SimpleXMLElement $nodes)
*/
protected function parseFile($file)
{
+ $internalErrors = libxml_use_internal_errors(true);
+ $disableEntities = libxml_disable_entity_loader(true);
+ libxml_clear_errors();
+
$dom = new \DOMDocument();
- libxml_use_internal_errors(true);
- if (!$dom->load($file, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
- throw new MappingException(implode("\n", $this->getXmlErrors()));
+ $dom->validateOnParse = true;
+ if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
+ libxml_disable_entity_loader($disableEntities);
+
+ throw new MappingException(implode("\n", $this->getXmlErrors($internalErrors)));
}
+
+ libxml_disable_entity_loader($disableEntities);
+
if (!$dom->schemaValidate(__DIR__.'/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd')) {
- throw new MappingException(implode("\n", $this->getXmlErrors()));
+ throw new MappingException(implode("\n", $this->getXmlErrors($internalErrors)));
}
- $dom->validateOnParse = true;
+
$dom->normalizeDocument();
- libxml_use_internal_errors(false);
+
+ libxml_use_internal_errors($internalErrors);
+
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ throw new MappingException('Document types are not allowed.');
+ }
+ }
return simplexml_import_dom($dom);
}
- protected function getXmlErrors()
+ protected function getXmlErrors($internalErrors)
{
$errors = array();
foreach (libxml_get_errors() as $error) {
@@ -210,7 +226,7 @@ protected function getXmlErrors()
}
libxml_clear_errors();
- libxml_use_internal_errors(false);
+ libxml_use_internal_errors($internalErrors);
return $errors;
}
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/xml/withdoctype.xml b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/xml/withdoctype.xml
new file mode 100644
index 0000000000000..f217d5bcacf54
--- /dev/null
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/xml/withdoctype.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Loader/XmlFileLoaderTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Loader/XmlFileLoaderTest.php
index c40003e669e71..e83fed4b31e64 100644
--- a/tests/Symfony/Tests/Component/DependencyInjection/Loader/XmlFileLoaderTest.php
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Loader/XmlFileLoaderTest.php
@@ -310,4 +310,16 @@ public function testNoNamingConflictsForAnonymousServices()
$inner2 = $services[(string) $args2[0]];
$this->assertEquals('BarClass2', $inner2->getClass(), '->load() uses the same configuration as for the anonymous ones');
}
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Document types are not allowed.
+ */
+ public function testDocTypeIsNotAllowed()
+ {
+ $container = new ContainerBuilder();
+
+ $loader1 = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
+ $loader1->load('withdoctype.xml');
+ }
}
diff --git a/tests/Symfony/Tests/Component/Routing/Fixtures/withdoctype.xml b/tests/Symfony/Tests/Component/Routing/Fixtures/withdoctype.xml
new file mode 100644
index 0000000000000..f217d5bcacf54
--- /dev/null
+++ b/tests/Symfony/Tests/Component/Routing/Fixtures/withdoctype.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/tests/Symfony/Tests/Component/Routing/Loader/XmlFileLoaderTest.php b/tests/Symfony/Tests/Component/Routing/Loader/XmlFileLoaderTest.php
index e19f1e089dca8..096386849b8ff 100644
--- a/tests/Symfony/Tests/Component/Routing/Loader/XmlFileLoaderTest.php
+++ b/tests/Symfony/Tests/Component/Routing/Loader/XmlFileLoaderTest.php
@@ -75,6 +75,16 @@ public function getPathsToInvalidFiles()
{
return array(array('nonvalidnode.xml'), array('nonvalidroute.xml'), array('nonvalid.xml'));
}
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Document types are not allowed.
+ */
+ public function testDocTypeIsNotAllowed()
+ {
+ $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
+ $loader->load('withdoctype.xml');
+ }
}
/**
diff --git a/tests/Symfony/Tests/Component/Serializer/Encoder/XmlEncoderTest.php b/tests/Symfony/Tests/Component/Serializer/Encoder/XmlEncoderTest.php
index e4aef6563acf2..3c3449a6e65bb 100644
--- a/tests/Symfony/Tests/Component/Serializer/Encoder/XmlEncoderTest.php
+++ b/tests/Symfony/Tests/Component/Serializer/Encoder/XmlEncoderTest.php
@@ -53,6 +53,15 @@ public function testSetRootNodeName()
$this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
}
+ /**
+ * @expectedException UnexpectedValueException
+ * @expectedExceptionMessage Document types are not allowed.
+ */
+ public function testDocTypeIsNotAllowed()
+ {
+ $this->encoder->decode('', 'foo');
+ }
+
public function testAttributes()
{
$obj = new ScalarDummy;
@@ -233,20 +242,22 @@ public function testDecodeArray()
$this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
}
- /**
- * @expectedException Symfony\Component\Serializer\Exception\UnexpectedValueException
- */
public function testPreventsComplexExternalEntities()
{
$oldCwd = getcwd();
chdir(__DIR__);
try {
- $decoded = $this->encoder->decode(']>&test;', 'xml');
+ $this->encoder->decode(']>&test;', 'xml');
chdir($oldCwd);
- } catch (UnexpectedValueException $e) {
+
+ $this->fail('No exception was thrown.');
+ } catch (\Exception $e) {
chdir($oldCwd);
- throw $e;
+
+ if (!$e instanceof UnexpectedValueException) {
+ $this->fail('Expected UnexpectedValueException');
+ }
}
}
diff --git a/tests/Symfony/Tests/Component/Translation/Loader/XliffFileLoaderTest.php b/tests/Symfony/Tests/Component/Translation/Loader/XliffFileLoaderTest.php
index 71b6d96fd581d..de1adfb37b0be 100644
--- a/tests/Symfony/Tests/Component/Translation/Loader/XliffFileLoaderTest.php
+++ b/tests/Symfony/Tests/Component/Translation/Loader/XliffFileLoaderTest.php
@@ -54,4 +54,14 @@ public function testLoadThrowsAnExceptionIfFileNotLocal()
$resource = 'http://example.com/resources.xliff';
$loader->load($resource, 'en', 'domain1');
}
+
+ /**
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage Document types are not allowed.
+ */
+ public function testDocTypeIsNotAllowed()
+ {
+ $loader = new XliffFileLoader();
+ $loader->load(__DIR__.'/../fixtures/withdoctype.xliff', 'en', 'domain1');
+ }
}
diff --git a/tests/Symfony/Tests/Component/Translation/fixtures/withdoctype.xliff b/tests/Symfony/Tests/Component/Translation/fixtures/withdoctype.xliff
new file mode 100644
index 0000000000000..f83e834ddc477
--- /dev/null
+++ b/tests/Symfony/Tests/Component/Translation/fixtures/withdoctype.xliff
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+ bar
+
+
+
+
diff --git a/tests/Symfony/Tests/Component/Validator/Mapping/Loader/XmlFileLoaderTest.php b/tests/Symfony/Tests/Component/Validator/Mapping/Loader/XmlFileLoaderTest.php
index 6b4450fa24663..9d9a8e7fc66d5 100644
--- a/tests/Symfony/Tests/Component/Validator/Mapping/Loader/XmlFileLoaderTest.php
+++ b/tests/Symfony/Tests/Component/Validator/Mapping/Loader/XmlFileLoaderTest.php
@@ -71,4 +71,16 @@ public function testLoadClassMetadata()
$this->assertEquals($expected, $metadata);
}
+
+ /**
+ * @expectedException Symfony\Component\Validator\Exception\MappingException
+ * @expectedExceptionMessage Document types are not allowed.
+ */
+ public function testDocTypeIsNotAllowed()
+ {
+ $loader = new XmlFileLoader(__DIR__.'/withdoctype.xml');
+ $metadata = new ClassMetadata('Symfony\Tests\Component\Validator\Fixtures\Entity');
+
+ $loader->loadClassMetadata($metadata);
+ }
}
diff --git a/tests/Symfony/Tests/Component/Validator/Mapping/Loader/withdoctype.xml b/tests/Symfony/Tests/Component/Validator/Mapping/Loader/withdoctype.xml
new file mode 100644
index 0000000000000..557cccb1a2de2
--- /dev/null
+++ b/tests/Symfony/Tests/Component/Validator/Mapping/Loader/withdoctype.xml
@@ -0,0 +1,7 @@
+
+
+
+
+