$xml = <<<XML <!DOCTYPE foo PUBLIC "-//FOO/BAR" "http://example.com/foobar"> <foo>bar&fooz;</foo> XML; $dtd = <<<DTD <!ELEMENT foo (#PCDATA)> <!ENTITY % fooentity PUBLIC "-//FOO/ENTITY" "fooentity.ent"> %fooentity; DTD; $entity = <<<ENT <!ENTITY fooz "baz"> ENT; libxml_set_external_entity_loader(function ($public, $system, $context) use($dtd, $entity) { static $first = true; var_dump($public); var_dump($system); var_dump($context); $f = fopen("php://temp", "r+"); fwrite($f, $first ? $dtd : $entity); $first = false; rewind($f); return $f; }); $dd = new DOMDocument(); $dd->substituteEntities = true; $dd->resolveExternals = true; $r = $dd->loadXML($xml); var_dump($dd->validate()); echo "Done.\n";
public function __construct() { libxml_set_external_entity_loader(function ($public, $system, $context) { $catalogDir = __DIR__ . '/../../../xml-catalog/'; switch ($public) { case '-//W3C//DTD XHTML 1.0 Strict//EN': return $catalogDir . 'xhtml1-strict.dtd'; case '-//W3C//ENTITIES Latin 1 for XHTML//EN': return $catalogDir . 'xhtml-lat1.ent'; case '-//W3C//ENTITIES Symbols for XHTML//EN': return $catalogDir . 'xhtml-symbol.ent'; case '-//W3C//ENTITIES Special for XHTML//EN': return $catalogDir . 'xhtml-special.ent'; default: return $system; } }); }
/** * Validate dom document * * @param \DOMDocument $dom * @param string $schema Absolute schema file path or URN * @param string $errorFormat * @return array of errors * @throws \Exception */ public static function validateDomDocument( \DOMDocument $dom, $schema, $errorFormat = self::ERROR_FORMAT_DEFAULT ) { if (!self::$urnResolver) { self::$urnResolver = new UrnResolver(); } $schema = self::$urnResolver->getRealPath($schema); libxml_use_internal_errors(true); libxml_set_external_entity_loader([self::$urnResolver, 'registerEntityLoader']); try { $result = $dom->schemaValidate($schema); $errors = []; if (!$result) { $validationErrors = libxml_get_errors(); if (count($validationErrors)) { foreach ($validationErrors as $error) { $errors[] = self::_renderErrorMessage($error, $errorFormat); } } else { $errors[] = 'Unknown validation error'; } } } catch (\Exception $exception) { libxml_use_internal_errors(false); throw $exception; } libxml_set_external_entity_loader(null); libxml_use_internal_errors(false); return $errors; }
<?php $xml = <<<XML <!DOCTYPE foo PUBLIC "-//FOO/BAR" "http://example.com/foobar"> <foo>bar</foo> XML; $dtd = <<<DTD <!ELEMENT foo (#PCDATA)> DTD; libxml_set_external_entity_loader(function ($public, $system, $context) use($dtd) { var_dump($public); var_dump($system); var_dump($context); $f = fopen("php://temp", "r+"); fwrite($f, $dtd); rewind($f); return $f; }); $dd = new DOMDocument(); $r = $dd->loadXML($xml); var_dump($dd->validate()); echo "Done.\n";
<?php chdir(__DIR__); $xml = <<<XML <!DOCTYPE foo PUBLIC "-//FOO/BAR" "foobar.dtd"> <foo>bar</foo> XML; $dtd = <<<DTD <!ELEMENT foo (#PCDATA)> DTD; libxml_set_external_entity_loader(function ($public, $system, $context) { var_dump($public, $system); return null; }); $dd = new DOMDocument(); $r = $dd->loadXML($xml); var_dump($dd->validate()); libxml_set_external_entity_loader(NULL); file_put_contents(__DIR__ . "/foobar.dtd", $dtd); var_dump($dd->validate()); echo "Done.\n"; error_reporting(0); @unlink(__DIR__ . "/foobar.dtd");
<?php $xml = <<<XML <!DOCTYPE foo PUBLIC "-//FOO/BAR" "http://example.com/foobar"> <foo>bar</foo> XML; $dd = new DOMDocument(); $r = $dd->loadXML($xml); var_dump(libxml_set_external_entity_loader([])); var_dump(libxml_set_external_entity_loader()); var_dump(libxml_set_external_entity_loader(function () { }, 2)); var_dump(libxml_set_external_entity_loader(function ($a, $b, $c, $d) { })); var_dump($dd->validate()); echo "Done.\n";
<?php /** * @link http://stackoverflow.com/questions/13865149/speeding-up-xml-schema-validations-of-a-batch-of-xml-files-against-the-same-xml */ $mapping = ['http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd' => 'schema/xhtml1-transitional.xsd', 'http://www.w3.org/2001/xml.xsd' => 'schema/xml.xsd']; libxml_set_external_entity_loader(function ($public, $system, $context) use($mapping) { if (is_file($system)) { return $system; } if (isset($mapping[$system])) { return __DIR__ . '/' . $mapping[$system]; } $message = sprintf("Failed to load external entity: Public: %s; System: %s; Context: %s", var_export($public, 1), var_export($system, 1), strtr(var_export($context, 1), [" (\n " => '(', "\n " => '', "\n" => ''])); throw new RuntimeException($message); }); $data_dom = new DOMDocument(); $data_dom->load('test-data.xml'); $data_dom->xinclude(); // Multiple validations using the schemaValidate method. for ($attempt = 1; $attempt <= 3; $attempt++) { $start = time(); echo "schemaValidate: Attempt #{$attempt} returns "; if (!$data_dom->schemaValidate('test-schema.xsd')) { echo "Invalid!"; } else { echo "Valid!"; } $end = time(); echo " in " . ($end - $start) . " seconds.\n"; }
/** * Validate dom document * * @param \DOMDocument $dom * @param string $schema Absolute schema file path or URN * @param string $errorFormat * @return array of errors * @throws \Exception */ public static function validateDomDocument(\DOMDocument $dom, $schema, $errorFormat = self::ERROR_FORMAT_DEFAULT) { if (!function_exists('libxml_set_external_entity_loader')) { return []; } if (!self::$urnResolver) { self::$urnResolver = new UrnResolver(); } $schema = self::$urnResolver->getRealPath($schema); libxml_use_internal_errors(true); libxml_set_external_entity_loader([self::$urnResolver, 'registerEntityLoader']); $errors = []; try { $result = $dom->schemaValidate($schema); if (!$result) { $errors = self::getXmlErrors($errorFormat); } } catch (\Exception $exception) { libxml_use_internal_errors(false); throw $exception; } libxml_set_external_entity_loader(null); libxml_use_internal_errors(false); return $errors; }