PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/Auth/Yadis/XML.php

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