3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
15 * Class used to initialize DomDocument from string, with proper verifications
22 const DOC_HTML
= 'DOC_HTML';
23 const DOC_XHTML
= 'DOC_XHTML';
24 const DOC_XML
= 'DOC_XML';
31 protected $stringDocument;
34 * DOMDocument generated from raw string document
37 protected $domDocument;
40 * Type of the document provided
46 * Error list generated from transformation of document to DOMDocument
49 protected $errors = array();
55 protected $xpathNamespaces = array();
61 protected $xpathPhpFunctions;
66 * @param string|null $document String containing the document
67 * @param string|null $type Force the document to be of a certain type, bypassing setStringDocument's detection
68 * @param string|null $encoding Encoding for the document (used for DOMDocument generation)
70 public function __construct($document = null, $type = null, $encoding = null)
72 $this->setStringDocument($document, $type, $encoding);
76 * Get raw set document
80 public function getStringDocument()
82 return $this->stringDocument
;
88 * @param string|null $document
89 * @param string|null $forcedType Type for the provided document (see constants)
90 * @param string|null $forcedEncoding Encoding for the provided document
93 protected function setStringDocument($document, $forcedType = null, $forcedEncoding = null)
95 $type = static::DOC_HTML
;
96 if (strstr($document, 'DTD XHTML')) {
97 $type = static::DOC_XHTML
;
100 // Breaking XML declaration to make syntax highlighting work
101 if ('<' . '?xml' == substr(trim($document), 0, 5)) {
102 $type = static::DOC_XML
;
103 if (preg_match('/<html[^>]*xmlns="([^"]+)"[^>]*>/i', $document, $matches)) {
104 $this->xpathNamespaces
[] = $matches[1];
105 $type = static::DOC_XHTML
;
109 // Unsetting previously registered DOMDocument
110 $this->domDocument
= null;
111 $this->stringDocument
= !empty($document) ?
$document : null;
113 $this->setType($forcedType ?
: (!empty($document) ?
$type : null));
114 $this->setEncoding($forcedEncoding);
115 $this->setErrors(array());
121 * Get raw document type
123 * @return string|null
125 public function getType()
131 * Set raw document type
133 * @param string $type
136 protected function setType($type)
144 * Get DOMDocument generated from set raw document
146 * @return DOMDocument
147 * @throws Exception\RuntimeException If cannot get DOMDocument; no document registered
149 public function getDomDocument()
151 if (null === ($stringDocument = $this->getStringDocument())) {
152 throw new Exception\
RuntimeException('Cannot get DOMDocument; no document registered');
155 if (null === $this->domDocument
) {
156 $this->domDocument
= $this->getDomDocumentFromString($stringDocument);
159 return $this->domDocument
;
165 * @param DOMDocument $domDocument
168 protected function setDomDocument(DOMDocument
$domDocument)
170 $this->domDocument
= $domDocument;
176 * Get set document encoding
178 * @return string|null
180 public function getEncoding()
182 return $this->encoding
;
186 * Set raw document encoding for DOMDocument generation
188 * @param string|null $encoding
191 public function setEncoding($encoding)
193 $this->encoding
= $encoding;
195 return $this->encoding
;
199 * Get DOMDocument generation errors
203 public function getErrors()
205 return $this->errors
;
209 * Set document errors from DOMDocument generation
211 * @param array $errors
214 protected function setErrors($errors)
216 $this->errors
= $errors;
222 * Get DOMDocument from set raw document
224 * @return DOMDocument
225 * @throws Exception\RuntimeException
227 protected function getDomDocumentFromString($stringDocument)
229 libxml_use_internal_errors(true);
230 libxml_disable_entity_loader(true);
232 $encoding = $this->getEncoding();
233 $domDoc = null === $encoding ?
new DOMDocument('1.0') : new DOMDocument('1.0', $encoding);
234 $type = $this->getType();
237 case static::DOC_XML
:
238 $success = $domDoc->loadXML($stringDocument);
239 foreach ($domDoc->childNodes
as $child) {
240 if ($child->nodeType
=== XML_DOCUMENT_TYPE_NODE
) {
241 throw new Exception\
RuntimeException(
242 'Invalid XML: Detected use of illegal DOCTYPE'
247 case static::DOC_HTML
:
248 case static::DOC_XHTML
:
250 $success = $domDoc->loadHTML($stringDocument);
254 $errors = libxml_get_errors();
255 if (!empty($errors)) {
256 $this->setErrors($errors);
257 libxml_clear_errors();
260 libxml_disable_entity_loader(false);
261 libxml_use_internal_errors(false);
264 throw new Exception\
RuntimeException(sprintf('Error parsing document (type == %s)', $type));
271 * Get Document's registered XPath namespaces
275 public function getXpathNamespaces()
277 return $this->xpathNamespaces
;
281 * Register XPath namespaces
283 * @param array $xpathNamespaces
286 public function registerXpathNamespaces($xpathNamespaces)
288 $this->xpathNamespaces
= $xpathNamespaces;
292 * Get Document's registered XPath PHP Functions
294 * @return string|null
296 public function getXpathPhpFunctions()
298 return $this->xpathPhpFunctions
;
301 * Register PHP Functions to use in internal DOMXPath
303 * @param bool $xpathPhpFunctions
306 public function registerXpathPhpFunctions($xpathPhpFunctions = true)
308 $this->xpathPhpFunctions
= $xpathPhpFunctions;