1<?php 2 3/** 4 * XML-parsing classes to wrap the domxml and DOM extensions for PHP 4 5 * and 5, respectively. 6 * 7 * @package OpenID 8 */ 9 10/** 11 * The base class for wrappers for available PHP XML-parsing 12 * extensions. To work with this Yadis library, subclasses of this 13 * class MUST implement the API as defined in the remarks for this 14 * class. Subclasses of Auth_Yadis_XMLParser are used to wrap 15 * particular PHP XML extensions such as 'domxml'. These are used 16 * internally by the library depending on the availability of 17 * supported PHP XML extensions. 18 * 19 * @package OpenID 20 */ 21class Auth_Yadis_XMLParser { 22 /** 23 * Initialize an instance of Auth_Yadis_XMLParser with some 24 * XML and namespaces. This SHOULD NOT be overridden by 25 * subclasses. 26 * 27 * @param string $xml_string A string of XML to be parsed. 28 * @param array $namespace_map An array of ($ns_name => $ns_uri) 29 * to be registered with the XML parser. May be empty. 30 * @return boolean $result True if the initialization and 31 * namespace registration(s) succeeded; false otherwise. 32 */ 33 function init($xml_string, $namespace_map) 34 { 35 if (!$this->setXML($xml_string)) { 36 return false; 37 } 38 39 foreach ($namespace_map as $prefix => $uri) { 40 if (!$this->registerNamespace($prefix, $uri)) { 41 return false; 42 } 43 } 44 45 return true; 46 } 47 48 /** 49 * Register a namespace with the XML parser. This should be 50 * overridden by subclasses. 51 * 52 * @param string $prefix The namespace prefix to appear in XML tag 53 * names. 54 * 55 * @param string $uri The namespace URI to be used to identify the 56 * namespace in the XML. 57 * 58 * @return boolean $result True if the registration succeeded; 59 * false otherwise. 60 */ 61 function registerNamespace($prefix, $uri) 62 { 63 // Not implemented. 64 return false; 65 } 66 67 /** 68 * Set this parser object's XML payload. This should be 69 * overridden by subclasses. 70 * 71 * @param string $xml_string The XML string to pass to this 72 * object's XML parser. 73 * 74 * @return boolean $result True if the initialization succeeded; 75 * false otherwise. 76 */ 77 function setXML($xml_string) 78 { 79 // Not implemented. 80 return false; 81 } 82 83 /** 84 * Evaluate an XPath expression and return the resulting node 85 * list. This should be overridden by subclasses. 86 * 87 * @param string $xpath The XPath expression to be evaluated. 88 * 89 * @param mixed $node A node object resulting from a previous 90 * evalXPath call. This node, if specified, provides the context 91 * for the evaluation of this xpath expression. 92 * 93 * @return array $node_list An array of matching opaque node 94 * objects to be used with other methods of this parser class. 95 */ 96 function &evalXPath($xpath, $node = null) 97 { 98 // Not implemented. 99 return []; 100 } 101 102 /** 103 * Return the textual content of a specified node. 104 * 105 * @param mixed $node A node object from a previous call to 106 * $this->evalXPath(). 107 * 108 * @return string $content The content of this node. 109 */ 110 function content($node) 111 { 112 // Not implemented. 113 return ''; 114 } 115 116 /** 117 * Return the attributes of a specified node. 118 * 119 * @param mixed $node A node object from a previous call to 120 * $this->evalXPath(). 121 * 122 * @return array An array mapping attribute names to 123 * values. 124 */ 125 function attributes($node) 126 { 127 // Not implemented. 128 return []; 129 } 130} 131 132/** 133 * This concrete implementation of Auth_Yadis_XMLParser implements 134 * the appropriate API for the 'domxml' extension which is typically 135 * packaged with PHP 4. This class will be used whenever the 'domxml' 136 * extension is detected. See the Auth_Yadis_XMLParser class for 137 * details on this class's methods. 138 * 139 * @package OpenID 140 */ 141class Auth_Yadis_domxml extends Auth_Yadis_XMLParser { 142 function __construct() 143 { 144 $this->xml = null; 145 $this->doc = null; 146 $this->xpath = null; 147 $this->errors = []; 148 } 149 150 function setXML($xml_string) 151 { 152 $this->xml = $xml_string; 153 $this->doc = @domxml_open_mem($xml_string, DOMXML_LOAD_PARSING, 154 $this->errors); 155 156 if (!$this->doc) { 157 return false; 158 } 159 160 $this->xpath = $this->doc->xpath_new_context(); 161 162 return true; 163 } 164 165 function registerNamespace($prefix, $uri) 166 { 167 return xpath_register_ns($this->xpath, $prefix, $uri); 168 } 169 170 function &evalXPath($xpath, $node = null) 171 { 172 if ($node) { 173 $result = @$this->xpath->xpath_eval($xpath, $node); 174 } else { 175 $result = @$this->xpath->xpath_eval($xpath); 176 } 177 178 if (!$result) { 179 $n = []; 180 return $n; 181 } 182 183 if (!$result->nodeset) { 184 $n = []; 185 return $n; 186 } 187 188 return $result->nodeset; 189 } 190 191 function content($node) 192 { 193 if ($node) { 194 return $node->get_content(); 195 } 196 } 197 198 function attributes($node) 199 { 200 if ($node) { 201 $arr = $node->attributes(); 202 $result = []; 203 204 if ($arr) { 205 foreach ($arr as $attrnode) { 206 $result[$attrnode->name] = $attrnode->value; 207 } 208 } 209 210 return $result; 211 } 212 } 213} 214 215/** 216 * This concrete implementation of Auth_Yadis_XMLParser implements 217 * the appropriate API for the 'dom' extension which is typically 218 * packaged with PHP 5. This class will be used whenever the 'dom' 219 * extension is detected. See the Auth_Yadis_XMLParser class for 220 * details on this class's methods. 221 * 222 * @package OpenID 223 */ 224class Auth_Yadis_dom extends Auth_Yadis_XMLParser { 225 226 /** @var string */ 227 protected $xml = ''; 228 229 protected $doc = null; 230 231 /** @var DOMXPath */ 232 protected $xpath = null; 233 234 protected $errors = []; 235 236 function setXML($xml_string) 237 { 238 $this->xml = $xml_string; 239 $this->doc = new DOMDocument; 240 241 if (!$this->doc) { 242 return false; 243 } 244 245 // libxml_disable_entity_loader (PHP 5 >= 5.2.11) 246 if (function_exists('libxml_disable_entity_loader') && function_exists('libxml_use_internal_errors')) { 247 // disable external entities and libxml errors 248 $loader = libxml_disable_entity_loader(true); 249 $errors = libxml_use_internal_errors(true); 250 $parse_result = @$this->doc->loadXML($xml_string); 251 libxml_disable_entity_loader($loader); 252 libxml_use_internal_errors($errors); 253 } else { 254 $parse_result = @$this->doc->loadXML($xml_string); 255 } 256 257 if (!$parse_result) { 258 return false; 259 } 260 261 if (isset($this->doc->doctype)) { 262 return false; 263 } 264 265 $this->xpath = new DOMXPath($this->doc); 266 267 if ($this->xpath) { 268 return true; 269 } else { 270 return false; 271 } 272 } 273 274 function registerNamespace($prefix, $uri) 275 { 276 return $this->xpath->registerNamespace($prefix, $uri); 277 } 278 279 function &evalXPath($xpath, $node = null) 280 { 281 if ($node) { 282 $result = @$this->xpath->query($xpath, $node); 283 } else { 284 $result = @$this->xpath->query($xpath); 285 } 286 287 $n = []; 288 289 if (!$result) { 290 return $n; 291 } 292 293 for ($i = 0; $i < $result->length; $i++) { 294 $n[] = $result->item($i); 295 } 296 297 return $n; 298 } 299 300 function content($node) 301 { 302 if ($node) { 303 return $node->textContent; 304 } 305 return ''; 306 } 307 308 /** 309 * @param DOMNode $node 310 * @return array 311 */ 312 function attributes($node) 313 { 314 if ($node) { 315 /** @var DOMNamedNodeMap $arr */ 316 $arr = $node->attributes; 317 $result = []; 318 319 if ($arr) { 320 for ($i = 0; $i < $arr->length; $i++) { 321 $node = $arr->item($i); 322 $result[$node->nodeName] = $node->nodeValue; 323 } 324 } 325 326 return $result; 327 } 328 return []; 329 } 330} 331 332global $__Auth_Yadis_defaultParser; 333$__Auth_Yadis_defaultParser = null; 334 335/** 336 * Set a default parser to override the extension-driven selection of 337 * available parser classes. This is helpful in a test environment or 338 * one in which multiple parsers can be used but one is more 339 * desirable. 340 * 341 * @param Auth_Yadis_XMLParser $parser An instance of a 342 * Auth_Yadis_XMLParser subclass. 343 */ 344function Auth_Yadis_setDefaultParser($parser) 345{ 346 global $__Auth_Yadis_defaultParser; 347 $__Auth_Yadis_defaultParser = $parser; 348} 349 350function Auth_Yadis_getSupportedExtensions() 351{ 352 return [ 353 'dom' => 'Auth_Yadis_dom', 354 'domxml' => 'Auth_Yadis_domxml', 355 ]; 356} 357 358/** 359 * Returns an instance of a Auth_Yadis_XMLParser subclass based on 360 * the availability of PHP extensions for XML parsing. If 361 * Auth_Yadis_setDefaultParser has been called, the parser used in 362 * that call will be returned instead. 363 * 364 * @return Auth_Yadis_XMLParser|bool 365 */ 366function Auth_Yadis_getXMLParser() 367{ 368 global $__Auth_Yadis_defaultParser; 369 370 if (isset($__Auth_Yadis_defaultParser)) { 371 return $__Auth_Yadis_defaultParser; 372 } 373 374 foreach(Auth_Yadis_getSupportedExtensions() as $extension => $classname) 375 { 376 if (extension_loaded($extension)) 377 { 378 $p = new $classname(); 379 Auth_Yadis_setDefaultParser($p); 380 return $p; 381 } 382 } 383 384 return false; 385} 386 387 388