[ Index ]

PHP Cross Reference of Joomla 1.5.26 DE

title

Body

[close]

/libraries/openid/Auth/Yadis/ -> XRDS.php (source)

   1  <?php
   2  
   3  /**
   4   * This module contains the XRDS parsing code.
   5   *
   6   * PHP versions 4 and 5
   7   *
   8   * LICENSE: See the COPYING file included in this distribution.
   9   *
  10   * @package OpenID
  11   * @author JanRain, Inc. <openid@janrain.com>
  12   * @copyright 2005-2008 Janrain, Inc.
  13   * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
  14   */
  15  
  16  // Do not allow direct access
  17  defined( '_JEXEC' ) or die( 'Restricted access' );
  18  
  19  /**
  20   * Require the XPath implementation.
  21   */
  22  require_once 'Auth/Yadis/XML.php';
  23  
  24  /**
  25   * This match mode means a given service must match ALL filters passed
  26   * to the Auth_Yadis_XRDS::services() call.
  27   */
  28  define('SERVICES_YADIS_MATCH_ALL', 101);
  29  
  30  /**
  31   * This match mode means a given service must match ANY filters (at
  32   * least one) passed to the Auth_Yadis_XRDS::services() call.
  33   */
  34  define('SERVICES_YADIS_MATCH_ANY', 102);
  35  
  36  /**
  37   * The priority value used for service elements with no priority
  38   * specified.
  39   */
  40  define('SERVICES_YADIS_MAX_PRIORITY', pow(2, 30));
  41  
  42  /**
  43   * XRD XML namespace
  44   */
  45  define('Auth_Yadis_XMLNS_XRD_2_0', 'xri://$xrd*($v*2.0)');
  46  
  47  /**
  48   * XRDS XML namespace
  49   */
  50  define('Auth_Yadis_XMLNS_XRDS', 'xri://$xrds');
  51  
  52  function Auth_Yadis_getNSMap()
  53  {
  54      return array('xrds' => Auth_Yadis_XMLNS_XRDS,
  55                   'xrd' => Auth_Yadis_XMLNS_XRD_2_0);
  56  }
  57  
  58  /**
  59   * @access private
  60   */
  61  function Auth_Yadis_array_scramble($arr)
  62  {
  63      $result = array();
  64  
  65      while (count($arr)) {
  66          $index = array_rand($arr, 1);
  67          $result[] = $arr[$index];
  68          unset($arr[$index]);
  69      }
  70  
  71      return $result;
  72  }
  73  
  74  /**
  75   * This class represents a <Service> element in an XRDS document.
  76   * Objects of this type are returned by
  77   * Auth_Yadis_XRDS::services() and
  78   * Auth_Yadis_Yadis::services().  Each object corresponds directly
  79   * to a <Service> element in the XRDS and supplies a
  80   * getElements($name) method which you should use to inspect the
  81   * element's contents.  See {@link Auth_Yadis_Yadis} for more
  82   * information on the role this class plays in Yadis discovery.
  83   *
  84   * @package OpenID
  85   */
  86  class Auth_Yadis_Service {
  87  
  88      /**
  89       * Creates an empty service object.
  90       */
  91      function Auth_Yadis_Service()
  92      {
  93          $this->element = null;
  94          $this->parser = null;
  95      }
  96  
  97      /**
  98       * Return the URIs in the "Type" elements, if any, of this Service
  99       * element.
 100       *
 101       * @return array $type_uris An array of Type URI strings.
 102       */
 103      function getTypes()
 104      {
 105          $t = array();
 106          foreach ($this->getElements('xrd:Type') as $elem) {
 107              $c = $this->parser->content($elem);
 108              if ($c) {
 109                  $t[] = $c;
 110              }
 111          }
 112          return $t;
 113      }
 114  
 115      function matchTypes($type_uris)
 116      {
 117          $result = array();
 118  
 119          foreach ($this->getTypes() as $typ) {
 120              if (in_array($typ, $type_uris)) {
 121                  $result[] = $typ;
 122              }
 123          }
 124  
 125          return $result;
 126      }
 127  
 128      /**
 129       * Return the URIs in the "URI" elements, if any, of this Service
 130       * element.  The URIs are returned sorted in priority order.
 131       *
 132       * @return array $uris An array of URI strings.
 133       */
 134      function getURIs()
 135      {
 136          $uris = array();
 137          $last = array();
 138  
 139          foreach ($this->getElements('xrd:URI') as $elem) {
 140              $uri_string = $this->parser->content($elem);
 141              $attrs = $this->parser->attributes($elem);
 142              if ($attrs &&
 143                  array_key_exists('priority', $attrs)) {
 144                  $priority = intval($attrs['priority']);
 145                  if (!array_key_exists($priority, $uris)) {
 146                      $uris[$priority] = array();
 147                  }
 148  
 149                  $uris[$priority][] = $uri_string;
 150              } else {
 151                  $last[] = $uri_string;
 152              }
 153          }
 154  
 155          $keys = array_keys($uris);
 156          sort($keys);
 157  
 158          // Rebuild array of URIs.
 159          $result = array();
 160          foreach ($keys as $k) {
 161              $new_uris = Auth_Yadis_array_scramble($uris[$k]);
 162              $result = array_merge($result, $new_uris);
 163          }
 164  
 165          $result = array_merge($result,
 166                                Auth_Yadis_array_scramble($last));
 167  
 168          return $result;
 169      }
 170  
 171      /**
 172       * Returns the "priority" attribute value of this <Service>
 173       * element, if the attribute is present.  Returns null if not.
 174       *
 175       * @return mixed $result Null or integer, depending on whether
 176       * this Service element has a 'priority' attribute.
 177       */
 178      function getPriority()
 179      {
 180          $attributes = $this->parser->attributes($this->element);
 181  
 182          if (array_key_exists('priority', $attributes)) {
 183              return intval($attributes['priority']);
 184          }
 185  
 186          return null;
 187      }
 188  
 189      /**
 190       * Used to get XML elements from this object's <Service> element.
 191       *
 192       * This is what you should use to get all custom information out
 193       * of this element. This is used by service filter functions to
 194       * determine whether a service element contains specific tags,
 195       * etc.  NOTE: this only considers elements which are direct
 196       * children of the <Service> element for this object.
 197       *
 198       * @param string $name The name of the element to look for
 199       * @return array $list An array of elements with the specified
 200       * name which are direct children of the <Service> element.  The
 201       * nodes returned by this function can be passed to $this->parser
 202       * methods (see {@link Auth_Yadis_XMLParser}).
 203       */
 204      function getElements($name)
 205      {
 206          return $this->parser->evalXPath($name, $this->element);
 207      }
 208  }
 209  
 210  /*
 211   * Return the expiration date of this XRD element, or None if no
 212   * expiration was specified.
 213   *
 214   * @param $default The value to use as the expiration if no expiration
 215   * was specified in the XRD.
 216   */
 217  function Auth_Yadis_getXRDExpiration($xrd_element, $default=null)
 218  {
 219      $expires_element = $xrd_element->$parser->evalXPath('/xrd:Expires');
 220      if ($expires_element === null) {
 221          return $default;
 222      } else {
 223          $expires_string = $expires_element->text;
 224  
 225          // Will raise ValueError if the string is not the expected
 226          // format
 227          $t = strptime($expires_string, "%Y-%m-%dT%H:%M:%SZ");
 228  
 229          if ($t === false) {
 230              return false;
 231          }
 232  
 233          // [int $hour [, int $minute [, int $second [,
 234          //  int $month [, int $day [, int $year ]]]]]]
 235          return mktime($t['tm_hour'], $t['tm_min'], $t['tm_sec'],
 236                        $t['tm_mon'], $t['tm_day'], $t['tm_year']);
 237      }
 238  }
 239  
 240  /**
 241   * This class performs parsing of XRDS documents.
 242   *
 243   * You should not instantiate this class directly; rather, call
 244   * parseXRDS statically:
 245   *
 246   * <pre>  $xrds = Auth_Yadis_XRDS::parseXRDS($xml_string);</pre>
 247   *
 248   * If the XRDS can be parsed and is valid, an instance of
 249   * Auth_Yadis_XRDS will be returned.  Otherwise, null will be
 250   * returned.  This class is used by the Auth_Yadis_Yadis::discover
 251   * method.
 252   *
 253   * @package OpenID
 254   */
 255  class Auth_Yadis_XRDS {
 256  
 257      /**
 258       * Instantiate a Auth_Yadis_XRDS object.  Requires an XPath
 259       * instance which has been used to parse a valid XRDS document.
 260       */
 261      function Auth_Yadis_XRDS(&$xmlParser, &$xrdNodes)
 262      {
 263          $this->parser =& $xmlParser;
 264          $this->xrdNode = $xrdNodes[count($xrdNodes) - 1];
 265          $this->allXrdNodes =& $xrdNodes;
 266          $this->serviceList = array();
 267          $this->_parse();
 268      }
 269  
 270      /**
 271       * Parse an XML string (XRDS document) and return either a
 272       * Auth_Yadis_XRDS object or null, depending on whether the
 273       * XRDS XML is valid.
 274       *
 275       * @param string $xml_string An XRDS XML string.
 276       * @return mixed $xrds An instance of Auth_Yadis_XRDS or null,
 277       * depending on the validity of $xml_string
 278       */
 279      function &parseXRDS($xml_string, $extra_ns_map = null)
 280      {
 281          $_null = null;
 282  
 283          if (!$xml_string) {
 284              return $_null;
 285          }
 286  
 287          $parser = Auth_Yadis_getXMLParser();
 288  
 289          $ns_map = Auth_Yadis_getNSMap();
 290  
 291          if ($extra_ns_map && is_array($extra_ns_map)) {
 292              $ns_map = array_merge($ns_map, $extra_ns_map);
 293          }
 294  
 295          if (!($parser && $parser->init($xml_string, $ns_map))) {
 296              return $_null;
 297          }
 298  
 299          // Try to get root element.
 300          $root = $parser->evalXPath('/xrds:XRDS[1]');
 301          if (!$root) {
 302              return $_null;
 303          }
 304  
 305          if (is_array($root)) {
 306              $root = $root[0];
 307          }
 308  
 309          $attrs = $parser->attributes($root);
 310  
 311          if (array_key_exists('xmlns:xrd', $attrs) &&
 312              $attrs['xmlns:xrd'] != Auth_Yadis_XMLNS_XRDS) {
 313              return $_null;
 314          } else if (array_key_exists('xmlns', $attrs) &&
 315                     preg_match('/xri/', $attrs['xmlns']) &&
 316                     $attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_2_0) {
 317              return $_null;
 318          }
 319  
 320          // Get the last XRD node.
 321          $xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
 322  
 323          if (!$xrd_nodes) {
 324              return $_null;
 325          }
 326  
 327          $xrds = new Auth_Yadis_XRDS($parser, $xrd_nodes);
 328          return $xrds;
 329      }
 330  
 331      /**
 332       * @access private
 333       */
 334      function _addService($priority, $service)
 335      {
 336          $priority = intval($priority);
 337  
 338          if (!array_key_exists($priority, $this->serviceList)) {
 339              $this->serviceList[$priority] = array();
 340          }
 341  
 342          $this->serviceList[$priority][] = $service;
 343      }
 344  
 345      /**
 346       * Creates the service list using nodes from the XRDS XML
 347       * document.
 348       *
 349       * @access private
 350       */
 351      function _parse()
 352      {
 353          $this->serviceList = array();
 354  
 355          $services = $this->parser->evalXPath('xrd:Service', $this->xrdNode);
 356  
 357          foreach ($services as $node) {
 358              $s =& new Auth_Yadis_Service();
 359              $s->element = $node;
 360              $s->parser =& $this->parser;
 361  
 362              $priority = $s->getPriority();
 363  
 364              if ($priority === null) {
 365                  $priority = SERVICES_YADIS_MAX_PRIORITY;
 366              }
 367  
 368              $this->_addService($priority, $s);
 369          }
 370      }
 371  
 372      /**
 373       * Returns a list of service objects which correspond to <Service>
 374       * elements in the XRDS XML document for this object.
 375       *
 376       * Optionally, an array of filter callbacks may be given to limit
 377       * the list of returned service objects.  Furthermore, the default
 378       * mode is to return all service objects which match ANY of the
 379       * specified filters, but $filter_mode may be
 380       * SERVICES_YADIS_MATCH_ALL if you want to be sure that the
 381       * returned services match all the given filters.  See {@link
 382       * Auth_Yadis_Yadis} for detailed usage information on filter
 383       * functions.
 384       *
 385       * @param mixed $filters An array of callbacks to filter the
 386       * returned services, or null if all services are to be returned.
 387       * @param integer $filter_mode SERVICES_YADIS_MATCH_ALL or
 388       * SERVICES_YADIS_MATCH_ANY, depending on whether the returned
 389       * services should match ALL or ANY of the specified filters,
 390       * respectively.
 391       * @return mixed $services An array of {@link
 392       * Auth_Yadis_Service} objects if $filter_mode is a valid
 393       * mode; null if $filter_mode is an invalid mode (i.e., not
 394       * SERVICES_YADIS_MATCH_ANY or SERVICES_YADIS_MATCH_ALL).
 395       */
 396      function services($filters = null,
 397                        $filter_mode = SERVICES_YADIS_MATCH_ANY)
 398      {
 399  
 400          $pri_keys = array_keys($this->serviceList);
 401          sort($pri_keys, SORT_NUMERIC);
 402  
 403          // If no filters are specified, return the entire service
 404          // list, ordered by priority.
 405          if (!$filters ||
 406              (!is_array($filters))) {
 407  
 408              $result = array();
 409              foreach ($pri_keys as $pri) {
 410                  $result = array_merge($result, $this->serviceList[$pri]);
 411              }
 412  
 413              return $result;
 414          }
 415  
 416          // If a bad filter mode is specified, return null.
 417          if (!in_array($filter_mode, array(SERVICES_YADIS_MATCH_ANY,
 418                                            SERVICES_YADIS_MATCH_ALL))) {
 419              return null;
 420          }
 421  
 422          // Otherwise, use the callbacks in the filter list to
 423          // determine which services are returned.
 424          $filtered = array();
 425  
 426          foreach ($pri_keys as $priority_value) {
 427              $service_obj_list = $this->serviceList[$priority_value];
 428  
 429              foreach ($service_obj_list as $service) {
 430  
 431                  $matches = 0;
 432  
 433                  foreach ($filters as $filter) {
 434                      if (call_user_func_array($filter, array($service))) {
 435                          $matches++;
 436  
 437                          if ($filter_mode == SERVICES_YADIS_MATCH_ANY) {
 438                              $pri = $service->getPriority();
 439                              if ($pri === null) {
 440                                  $pri = SERVICES_YADIS_MAX_PRIORITY;
 441                              }
 442  
 443                              if (!array_key_exists($pri, $filtered)) {
 444                                  $filtered[$pri] = array();
 445                              }
 446  
 447                              $filtered[$pri][] = $service;
 448                              break;
 449                          }
 450                      }
 451                  }
 452  
 453                  if (($filter_mode == SERVICES_YADIS_MATCH_ALL) &&
 454                      ($matches == count($filters))) {
 455  
 456                      $pri = $service->getPriority();
 457                      if ($pri === null) {
 458                          $pri = SERVICES_YADIS_MAX_PRIORITY;
 459                      }
 460  
 461                      if (!array_key_exists($pri, $filtered)) {
 462                          $filtered[$pri] = array();
 463                      }
 464                      $filtered[$pri][] = $service;
 465                  }
 466              }
 467          }
 468  
 469          $pri_keys = array_keys($filtered);
 470          sort($pri_keys, SORT_NUMERIC);
 471  
 472          $result = array();
 473          foreach ($pri_keys as $pri) {
 474              $result = array_merge($result, $filtered[$pri]);
 475          }
 476  
 477          return $result;
 478      }
 479  }
 480  
 481  ?>


Generated: Wed Mar 28 15:54:07 2012 Cross-referenced by PHPXref 0.7.1