code:
<?php

/**
 * This module contains the CURL-based HTTP fetcher implementation.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * Interface import
 */
require_once "Auth/Yadis/HTTPFetcher.php";

require_once "Auth/OpenID.php";

/**
 * A paranoid {@link Auth_Yadis_HTTPFetcher} class which uses CURL
 * for fetching.
 *
 * @package OpenID
 */
class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
    function Auth_Yadis_ParanoidHTTPFetcher()
    {
        $this->reset();
    }

    function reset()
    {
        $this->headers = array();
        $this->data = "";
    }

    /**
     * @access private
     */
    function _writeHeader($ch, $header)
    {
        array_push($this->headers, rtrim($header));
        return strlen($header);
    }

    /**
     * @access private
     */
    function _writeData($ch, $data)
    {
        if (strlen($this->data) > 1024*Auth_OpenID_FETCHER_MAX_RESPONSE_KB) {
            return 0;
        } else {
            $this->data .= $data;
            return strlen($data);
        }
    }

    /**
     * Does this fetcher support SSL URLs?
     */
    function supportsSSL()
    {
        $v = curl_version();
        if(is_array($v)) {
            return in_array('https', $v['protocols']);
        } elseif (is_string($v)) {
            return preg_match('/OpenSSL/i', $v);
        } else {
            return 0;
        }
    }

    function get($url, $extra_headers = null)
    {
        if (!$this->canFetchURL($url)) {
            return null;
        }

        $stop = time() + $this->timeout;
        $off = $this->timeout;

        $redir = true;

        while ($redir && ($off > 0)) {
            $this->reset();

            $c = curl_init();
            if (defined('Auth_OpenID_DISABLE_SSL_VERIFYPEER')
                    && Auth_OpenID_DISABLE_SSL_VERIFYPEER === true) {
                trigger_error(
                    'You have disabled SSL verifcation, this is a TERRIBLE ' .
                    'idea in almost all cases. Set Auth_OpenID_DISABLE_SSL_' .
                    'VERIFYPEER to false if you want to be safe again',
                    E_USER_WARNING);
                curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
            }

            if ($c === false) {
                Auth_OpenID::log(
                    "curl_init returned false; could not " .
                    "initialize for URL '%s'", $url);
                return null;
            }

            if (defined('CURLOPT_NOSIGNAL')) {
                curl_setopt($c, CURLOPT_NOSIGNAL, true);
            }

            if (!$this->allowedURL($url)) {
                Auth_OpenID::log("Fetching URL not allowed: %s",
                                 $url);
                return null;
            }

            curl_setopt($c, CURLOPT_WRITEFUNCTION,
                        array($this, "_writeData"));
            curl_setopt($c, CURLOPT_HEADERFUNCTION,
                        array($this, "_writeHeader"));

            if ($extra_headers) {
                curl_setopt($c, CURLOPT_HTTPHEADER, $extra_headers);
            }

            $cv = curl_version();
            if(is_array($cv)) {
              $curl_user_agent = 'curl/'.$cv['version'];
            } else {
              $curl_user_agent = $cv;
            }
            curl_setopt($c, CURLOPT_USERAGENT,
                        Auth_OpenID_USER_AGENT.' '.$curl_user_agent);
            curl_setopt($c, CURLOPT_TIMEOUT, $off);
            curl_setopt($c, CURLOPT_URL, $url);

            if (defined('Auth_OpenID_VERIFY_HOST')) {
                // set SSL verification options only if Auth_OpenID_VERIFY_HOST
                // is explicitly set, otherwise use system default.
                if (Auth_OpenID_VERIFY_HOST) {
                    curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
                    curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
                    if (defined('Auth_OpenID_CAINFO')) {
                        curl_setopt($c, CURLOPT_CAINFO, Auth_OpenID_CAINFO);
                    }
                } else {
                    curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
                }
            }
            if (defined('Auth_OpenID_HTTP_PROXY')) {
                curl_setopt($c, CURLOPT_PROXY, Auth_OpenID_HTTP_PROXY);
            }
            curl_exec($c);

            $code = curl_getinfo($c, CURLINFO_HTTP_CODE);
            $body = $this->data;
            $headers = $this->headers;

            if (!$code) {
                Auth_OpenID::log("Got no response code when fetching %s", $url);
                Auth_OpenID::log("CURL error (%s): %s",
                                 curl_errno($c), curl_error($c));
                return null;
            }

            if (in_array($code, array(301, 302, 303, 307))) {
                $url = $this->_findRedirect($headers, $url);
                $redir = true;
            } else {
                $redir = false;
                curl_close($c);

                if (defined('Auth_OpenID_VERIFY_HOST') &&
                    Auth_OpenID_VERIFY_HOST == true &&
                    $this->isHTTPS($url)) {
                    Auth_OpenID::log('OpenID: Verified SSL host %s using '.
                                     'curl/get', $url);
                }
                $new_headers = array();

                foreach ($headers as $header) {
                    if (strpos($header, ': ')) {
                        list($name, $value) = explode(': ', $header, 2);
                        $new_headers[$name] = $value;
                    }
                }

                return new Auth_Yadis_HTTPResponse($url, $code,
                                                    $new_headers, $body);
            }

            $off = $stop - time();
        }

        return null;
    }

    function post($url, $body, $extra_headers = null)
    {
        if (!$this->canFetchURL($url)) {
            return null;
        }

        $this->reset();

        $c = curl_init();

        if (defined('CURLOPT_NOSIGNAL')) {
            curl_setopt($c, CURLOPT_NOSIGNAL, true);
        }

        if (defined('Auth_OpenID_HTTP_PROXY')) {
            curl_setopt($c, CURLOPT_PROXY, Auth_OpenID_HTTP_PROXY);
        }

        curl_setopt($c, CURLOPT_POST, true);
        curl_setopt($c, CURLOPT_POSTFIELDS, $body);
        curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
        curl_setopt($c, CURLOPT_URL, $url);
        curl_setopt($c, CURLOPT_WRITEFUNCTION,
                    array($this, "_writeData"));

        if (defined('Auth_OpenID_VERIFY_HOST')) {
            // set SSL verification options only if Auth_OpenID_VERIFY_HOST
            // is explicitly set, otherwise use system default.
            if (Auth_OpenID_VERIFY_HOST) {
                curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
                curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
                if (defined('Auth_OpenID_CAINFO')) {
                    curl_setopt($c, CURLOPT_CAINFO, Auth_OpenID_CAINFO);
                }
            } else {
                curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
            }
        }

        curl_exec($c);

        $code = curl_getinfo($c, CURLINFO_HTTP_CODE);

        if (!$code) {
            Auth_OpenID::log("Got no response code when fetching %s", $url);
            Auth_OpenID::log("CURL error (%s): %s",
                             curl_errno($c), curl_error($c));
            return null;
        }

        if (defined('Auth_OpenID_VERIFY_HOST') &&
            Auth_OpenID_VERIFY_HOST == true &&
            $this->isHTTPS($url)) {
            Auth_OpenID::log('OpenID: Verified SSL host %s using '.
                             'curl/post', $url);
        }
        $body = $this->data;

        curl_close($c);

        $new_headers = $extra_headers;

        foreach ($this->headers as $header) {
            if (strpos($header, ': ')) {
                list($name, $value) = explode(': ', $header, 2);
                $new_headers[$name] = $value;
            }

        }

        return new Auth_Yadis_HTTPResponse($url, $code,
                                           $new_headers, $body);
    }
}


code:
<?php

/**
 * This is the HTML pseudo-parser for the Yadis library.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * This class is responsible for scanning an HTML string to find META
 * tags and their attributes.  This is used by the Yadis discovery
 * process.  This class must be instantiated to be used.
 *
 * @package OpenID
 */
class Auth_Yadis_ParseHTML {

    /**
     * @access private
     */
    var $_re_flags = "si";

    /**
     * @access private
     */
    var $_removed_re =
           "<!--.*?-->|<!\[CDATA\[.*?\]\]>|<script\b(?!:)[^>]*>.*?<\/script>";

    /**
     * @access private
     */
    var $_tag_expr = "<%s%s(?:\s.*?)?%s>";

    /**
     * @access private
     */
    var $_attr_find = '\b([-\w]+)=(".*?"|\'.*?\'|.+?)[\/\s>]';

    function Auth_Yadis_ParseHTML()
    {
        $this->_attr_find = sprintf("/%s/%s",
                                    $this->_attr_find,
                                    $this->_re_flags);

        $this->_removed_re = sprintf("/%s/%s",
                                     $this->_removed_re,
                                     $this->_re_flags);

        $this->_entity_replacements = array(
                                            'amp' => '&',
                                            'lt' => '<',
                                            'gt' => '>',
                                            'quot' => '"'
                                            );

        $this->_ent_replace =
            sprintf("&(%s);", implode("|",
                                      $this->_entity_replacements));
    }

    /**
     * Strip single and double quotes off of a string, if they are
     * present.
     *
     * @access private
     * @param string $str The original string
     * @return string $new_str The new string with leading and
     * trailing quotes removed
     */
    function removeQuotes($str)
    {
        $matches = array();
        $double = '/^"(.*)"$/';
        $single = "/^\'(.*)\'$/";

        if (preg_match($double, $str, $matches)) {
            return $matches[1];
        } else if (preg_match($single, $str, $matches)) {
            return $matches[1];
        } else {
            return $str;
        }
    }

    /**
     * Create a regular expression that will match an opening
     * or closing tag from a set of names.
     *
     * @access private
     * @param mixed $tag_names Tag names to match
     * @param mixed $close false/0 = no, true/1 = yes, other = maybe
     * @param mixed $self_close false/0 = no, true/1 = yes, other = maybe
     * @return string $regex A regular expression string to be used
     * in, say, preg_match.
     */
    function tagPattern($tag_names, $close, $self_close)
    {
        if (is_array($tag_names)) {
            $tag_names = '(?:'.implode('|',$tag_names).')';
        }
        if ($close) {
            $close = '\/' . (($close == 1)? '' : '?');
        } else {
            $close = '';
        }
        if ($self_close) {
            $self_close = '(?:\/\s*)' . (($self_close == 1)? '' : '?');
        } else {
            $self_close = '';
        }
        $expr = sprintf($this->_tag_expr, $close, $tag_names, $self_close);

        return sprintf("/%s/%s", $expr, $this->_re_flags);
    }

    /**
     * Given an HTML document string, this finds all the META tags in
     * the document, provided they are found in the
     * <HTML><HEAD>...</HEAD> section of the document.  The <HTML> tag
     * may be missing.
     *
     * @access private
     * @param string $html_string An HTMl document string
     * @return array $tag_list Array of tags; each tag is an array of
     * attribute -> value.
     */
    function getMetaTags($html_string)
    {
        $html_string = preg_replace($this->_removed_re,
                                    "",
                                    $html_string);

        $key_tags = array($this->tagPattern('html', false, false),
                          $this->tagPattern('head', false, false),
                          $this->tagPattern('head', true, false),
                          $this->tagPattern('html', true, false),
                          $this->tagPattern(array(
                          'body', 'frameset', 'frame', 'p', 'div',
                          'table','span','a'), 'maybe', 'maybe'));
        $key_tags_pos = array();
        foreach ($key_tags as $pat) {
            $matches = array();
            preg_match($pat, $html_string, $matches, PREG_OFFSET_CAPTURE);
            if($matches) {
                $key_tags_pos[] = $matches[0][1];
            } else {
                $key_tags_pos[] = null;
            }
        }
        // no opening head tag
        if (is_null($key_tags_pos[1])) {
            return array();
        }
        // the effective </head> is the min of the following
        if (is_null($key_tags_pos[2])) {
            $key_tags_pos[2] = strlen($html_string);
        }
        foreach (array($key_tags_pos[3], $key_tags_pos[4]) as $pos) {
            if (!is_null($pos) && $pos < $key_tags_pos[2]) {
                $key_tags_pos[2] = $pos;
            }
        }
        // closing head tag comes before opening head tag
        if ($key_tags_pos[1] > $key_tags_pos[2]) {
            return array();
        }
        // if there is an opening html tag, make sure the opening head tag
        // comes after it
        if (!is_null($key_tags_pos[0]) && $key_tags_pos[1] < $key_tags_pos[0]) {
            return array();
        }
        $html_string = substr($html_string, $key_tags_pos[1],
                              ($key_tags_pos[2]-$key_tags_pos[1]));

        $link_data = array();
        $link_matches = array();

        if (!preg_match_all($this->tagPattern('meta', false, 'maybe'),
                            $html_string, $link_matches)) {
            return array();
        }

        foreach ($link_matches[0] as $link) {
            $attr_matches = array();
            preg_match_all($this->_attr_find, $link, $attr_matches);
            $link_attrs = array();
            foreach ($attr_matches[0] as $index => $full_match) {
                $name = $attr_matches[1][$index];
                $value = html_entity_decode(
                              $this->removeQuotes($attr_matches[2][$index]));

                $link_attrs[strtolower($name)] = $value;
            }
            $link_data[] = $link_attrs;
        }

        return $link_data;
    }

    /**
     * Looks for a META tag with an "http-equiv" attribute whose value
     * is one of ("x-xrds-location", "x-yadis-location"), ignoring
     * case.  If such a META tag is found, its "content" attribute
     * value is returned.
     *
     * @param string $html_string An HTML document in string format
     * @return mixed $content The "content" attribute value of the
     * META tag, if found, or null if no such tag was found.
     */
    function getHTTPEquiv($html_string)
    {
        $meta_tags = $this->getMetaTags($html_string);

        if ($meta_tags) {
            foreach ($meta_tags as $tag) {
                if (array_key_exists('http-equiv', $tag) &&
                    (in_array(strtolower($tag['http-equiv']),
                              array('x-xrds-location', 'x-yadis-location'))) &&
                    array_key_exists('content', $tag)) {
                    return $tag['content'];
                }
            }
        }

        return null;
    }
}

repo_name: andremichelle/gnu

license: mit


code:
<?php

/**
 * This module contains the plain non-curl HTTP fetcher
 * implementation.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * Interface import
 */
require_once "Auth/Yadis/HTTPFetcher.php";

/**
 * This class implements a plain, hand-built socket-based fetcher
 * which will be used in the event that CURL is unavailable.
 *
 * @package OpenID
 */
class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher {
    /**
     * Does this fetcher support SSL URLs?
     */
    function supportsSSL()
    {
        return function_exists('openssl_open');
    }

    function get($url, $extra_headers = null)
    {
        if (!$this->canFetchURL($url)) {
            return null;
        }

        $redir = true;

        $stop = time() + $this->timeout;
        $off = $this->timeout;

        while ($redir && ($off > 0)) {

            $parts = parse_url($url);

            $specify_port = true;

            // Set a default port.
            if (!array_key_exists('port', $parts)) {
                $specify_port = false;
                if ($parts['scheme'] == 'http') {
                    $parts['port'] = 80;
                } elseif ($parts['scheme'] == 'https') {
                    $parts['port'] = 443;
                } else {
                    return null;
                }
            }

            if (!array_key_exists('path', $parts)) {
                $parts['path'] = '/';
            }

            $host = $parts['host'];

            if ($parts['scheme'] == 'https') {
                $host = 'ssl://' . $host;
            }

            $user_agent = Auth_OpenID_USER_AGENT;

            $headers = array(
                             "GET ".$parts['path'].
                             (array_key_exists('query', $parts) ?
                              "?".$parts['query'] : "").
                                 " HTTP/1.0",
                             "User-Agent: $user_agent",
                             "Host: ".$parts['host'].
                                ($specify_port ? ":".$parts['port'] : ""),
                             "Port: ".$parts['port']);

            $errno = 0;
            $errstr = '';

            if ($extra_headers) {
                foreach ($extra_headers as $h) {
                    $headers[] = $h;
                }
            }

            @$sock = fsockopen($host, $parts['port'], $errno, $errstr,
                               $this->timeout);
            if ($sock === false) {
                return false;
            }

            stream_set_timeout($sock, $this->timeout);

            fputs($sock, implode("\r\n", $headers) . "\r\n\r\n");

            $data = "";
            $kilobytes = 0;
            while (!feof($sock) &&
                   $kilobytes < Auth_OpenID_FETCHER_MAX_RESPONSE_KB ) {
                $data .= fgets($sock, 1024);
                $kilobytes += 1;
            }

            fclose($sock);

            // Split response into header and body sections
            list($headers, $body) = explode("\r\n\r\n", $data, 2);
            $headers = explode("\r\n", $headers);

            $http_code = explode(" ", $headers[0]);
            $code = $http_code[1];

            if (in_array($code, array('301', '302'))) {
                $url = $this->_findRedirect($headers, $url);
                $redir = true;
            } else {
                $redir = false;
            }

            $off = $stop - time();
        }

        $new_headers = array();

        foreach ($headers as $header) {
            if (preg_match("/:/", $header)) {
                $parts = explode(": ", $header, 2);

                if (count($parts) == 2) {
                    list($name, $value) = $parts;
                    $new_headers[$name] = $value;
                }
            }

        }

        return new Auth_Yadis_HTTPResponse($url, $code, $new_headers, $body);
    }

    function post($url, $body, $extra_headers = null)
    {
        if (!$this->canFetchURL($url)) {
            return null;
        }

        $parts = parse_url($url);

        $headers = array();

        $post_path = $parts['path'];
        if (isset($parts['query'])) {
            $post_path .= '?' . $parts['query'];
        }

        $headers[] = "POST ".$post_path." HTTP/1.0";
        $headers[] = "Host: " . $parts['host'];
        $headers[] = "Content-type: application/x-www-form-urlencoded";
        $headers[] = "Content-length: " . strval(strlen($body));

        if ($extra_headers &&
            is_array($extra_headers)) {
            $headers = array_merge($headers, $extra_headers);
        }

        // Join all headers together.
        $all_headers = implode("\r\n", $headers);

        // Add headers, two newlines, and request body.
        $request = $all_headers . "\r\n\r\n" . $body;

        // Set a default port.
        if (!array_key_exists('port', $parts)) {
            if ($parts['scheme'] == 'http') {
                $parts['port'] = 80;
            } elseif ($parts['scheme'] == 'https') {
                $parts['port'] = 443;
            } else {
                return null;
            }
        }

        if ($parts['scheme'] == 'https') {
            $parts['host'] = sprintf("ssl://%s", $parts['host']);
        }

        // Connect to the remote server.
        $errno = 0;
        $errstr = '';

        $sock = fsockopen($parts['host'], $parts['port'], $errno, $errstr,
                          $this->timeout);

        if ($sock === false) {
            return null;
        }

        stream_set_timeout($sock, $this->timeout);

        // Write the POST request.
        fputs($sock, $request);

        // Get the response from the server.
        $response = "";
        while (!feof($sock)) {
            if ($data = fgets($sock, 128)) {
                $response .= $data;
            } else {
                break;
            }
        }

        // Split the request into headers and body.
        list($headers, $response_body) = explode("\r\n\r\n", $response, 2);

        $headers = explode("\r\n", $headers);

        // Expect the first line of the headers data to be something
        // like HTTP/1.1 200 OK.  Split the line on spaces and take
        // the second token, which should be the return code.
        $http_code = explode(" ", $headers[0]);
        $code = $http_code[1];

        $new_headers = array();

        foreach ($headers as $header) {
            if (preg_match("/:/", $header)) {
                list($name, $value) = explode(": ", $header, 2);
                $new_headers[$name] = $value;
            }

        }

        return new Auth_Yadis_HTTPResponse($url, $code,
                                           $new_headers, $response_body);
    }
}


code:
<?php

/**
 * XML-parsing classes to wrap the domxml and DOM extensions for PHP 4
 * and 5, respectively.
 *
 * @package OpenID
 */

/**
 * The base class for wrappers for available PHP XML-parsing
 * extensions.  To work with this Yadis library, subclasses of this
 * class MUST implement the API as defined in the remarks for this
 * class.  Subclasses of Auth_Yadis_XMLParser are used to wrap
 * particular PHP XML extensions such as 'domxml'.  These are used
 * internally by the library depending on the availability of
 * supported PHP XML extensions.
 *
 * @package OpenID
 */
class Auth_Yadis_XMLParser {
    /**
     * Initialize an instance of Auth_Yadis_XMLParser with some
     * XML and namespaces.  This SHOULD NOT be overridden by
     * subclasses.
     *
     * @param string $xml_string A string of XML to be parsed.
     * @param array $namespace_map An array of ($ns_name => $ns_uri)
     * to be registered with the XML parser.  May be empty.
     * @return boolean $result True if the initialization and
     * namespace registration(s) succeeded; false otherwise.
     */
    function init($xml_string, $namespace_map)
    {
        if (!$this->setXML($xml_string)) {
            return false;
        }

        foreach ($namespace_map as $prefix => $uri) {
            if (!$this->registerNamespace($prefix, $uri)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Register a namespace with the XML parser.  This should be
     * overridden by subclasses.
     *
     * @param string $prefix The namespace prefix to appear in XML tag
     * names.
     *
     * @param string $uri The namespace URI to be used to identify the
     * namespace in the XML.
     *
     * @return boolean $result True if the registration succeeded;
     * false otherwise.
     */
    function registerNamespace($prefix, $uri)
    {
        // Not implemented.
    }

    /**
     * Set this parser object's XML payload.  This should be
     * overridden by subclasses.
     *
     * @param string $xml_string The XML string to pass to this
     * object's XML parser.
     *
     * @return boolean $result True if the initialization succeeded;
     * false otherwise.
     */
    function setXML($xml_string)
    {
        // Not implemented.
    }

    /**
     * Evaluate an XPath expression and return the resulting node
     * list.  This should be overridden by subclasses.
     *
     * @param string $xpath The XPath expression to be evaluated.
     *
     * @param mixed $node A node object resulting from a previous
     * evalXPath call.  This node, if specified, provides the context
     * for the evaluation of this xpath expression.
     *
     * @return array $node_list An array of matching opaque node
     * objects to be used with other methods of this parser class.
     */
    function &evalXPath($xpath, $node = null)
    {
        // Not implemented.
    }

    /**
     * Return the textual content of a specified node.
     *
     * @param mixed $node A node object from a previous call to
     * $this->evalXPath().
     *
     * @return string $content The content of this node.
     */
    function content($node)
    {
        // Not implemented.
    }

    /**
     * Return the attributes of a specified node.
     *
     * @param mixed $node A node object from a previous call to
     * $this->evalXPath().
     *
     * @return array $attrs An array mapping attribute names to
     * values.
     */
    function attributes($node)
    {
        // Not implemented.
    }
}

/**
 * This concrete implementation of Auth_Yadis_XMLParser implements
 * the appropriate API for the 'domxml' extension which is typically
 * packaged with PHP 4.  This class will be used whenever the 'domxml'
 * extension is detected.  See the Auth_Yadis_XMLParser class for
 * details on this class's methods.
 *
 * @package OpenID
 */
class Auth_Yadis_domxml extends Auth_Yadis_XMLParser {
    function Auth_Yadis_domxml()
    {
        $this->xml = null;
        $this->doc = null;
        $this->xpath = null;
        $this->errors = array();
    }

    function setXML($xml_string)
    {
        $this->xml = $xml_string;
        $this->doc = @domxml_open_mem($xml_string, DOMXML_LOAD_PARSING,
                                      $this->errors);

        if (!$this->doc) {
            return false;
        }

        $this->xpath = $this->doc->xpath_new_context();

        return true;
    }

    function registerNamespace($prefix, $uri)
    {
        return xpath_register_ns($this->xpath, $prefix, $uri);
    }

    function &evalXPath($xpath, $node = null)
    {
        if ($node) {
            $result = @$this->xpath->xpath_eval($xpath, $node);
        } else {
            $result = @$this->xpath->xpath_eval($xpath);
        }

        if (!$result) {
            $n = array();
            return $n;
        }

        if (!$result->nodeset) {
            $n = array();
            return $n;
        }

        return $result->nodeset;
    }

    function content($node)
    {
        if ($node) {
            return $node->get_content();
        }
    }

    function attributes($node)
    {
        if ($node) {
            $arr = $node->attributes();
            $result = array();

            if ($arr) {
                foreach ($arr as $attrnode) {
                    $result[$attrnode->name] = $attrnode->value;
                }
            }

            return $result;
        }
    }
}

/**
 * This concrete implementation of Auth_Yadis_XMLParser implements
 * the appropriate API for the 'dom' extension which is typically
 * packaged with PHP 5.  This class will be used whenever the 'dom'
 * extension is detected.  See the Auth_Yadis_XMLParser class for
 * details on this class's methods.
 *
 * @package OpenID
 */
class Auth_Yadis_dom extends Auth_Yadis_XMLParser {
    function Auth_Yadis_dom()
    {
        $this->xml = null;
        $this->doc = null;
        $this->xpath = null;
        $this->errors = array();
    }

    function setXML($xml_string)
    {
        $this->xml = $xml_string;
        $this->doc = new DOMDocument;

        if (!$this->doc) {
            return false;
        }

        // libxml_disable_entity_loader (PHP 5 >= 5.2.11)
        if (function_exists('libxml_disable_entity_loader') && function_exists('libxml_use_internal_errors')) {
            // disable external entities and libxml errors
            $loader = libxml_disable_entity_loader(true);
            $errors = libxml_use_internal_errors(true);
            $parse_result = @$this->doc->loadXML($xml_string);
            libxml_disable_entity_loader($loader);
            libxml_use_internal_errors($errors);
        } else {
            $parse_result = @$this->doc->loadXML($xml_string);
        }

        if (!$parse_result) {
            return false;
        }

        if (isset($this->doc->doctype)) {
            return false;
        }

        $this->xpath = new DOMXPath($this->doc);

        if ($this->xpath) {
            return true;
        } else {
            return false;
        }
    }

    function registerNamespace($prefix, $uri)
    {
        return $this->xpath->registerNamespace($prefix, $uri);
    }

    function &evalXPath($xpath, $node = null)
    {
        if ($node) {
            $result = @$this->xpath->query($xpath, $node);
        } else {
            $result = @$this->xpath->query($xpath);
        }

        $n = array();

        if (!$result) {
            return $n;
        }

        for ($i = 0; $i < $result->length; $i++) {
            $n[] = $result->item($i);
        }

        return $n;
    }

    function content($node)
    {
        if ($node) {
            return $node->textContent;
        }
    }

    function attributes($node)
    {
        if ($node) {
            $arr = $node->attributes;
            $result = array();

            if ($arr) {
                for ($i = 0; $i < $arr->length; $i++) {
                    $node = $arr->item($i);
                    $result[$node->nodeName] = $node->nodeValue;
                }
            }

            return $result;
        }
    }
}

global $__Auth_Yadis_defaultParser;
$__Auth_Yadis_defaultParser = null;

/**
 * Set a default parser to override the extension-driven selection of
 * available parser classes.  This is helpful in a test environment or
 * one in which multiple parsers can be used but one is more
 * desirable.
 *
 * @param Auth_Yadis_XMLParser $parser An instance of a
 * Auth_Yadis_XMLParser subclass.
 */
function Auth_Yadis_setDefaultParser($parser)
{
    global $__Auth_Yadis_defaultParser;
    $__Auth_Yadis_defaultParser = $parser;
}

function Auth_Yadis_getSupportedExtensions()
{
    return array('dom'    => 'Auth_Yadis_dom',
                 'domxml' => 'Auth_Yadis_domxml');
}

/**
 * Returns an instance of a Auth_Yadis_XMLParser subclass based on
 * the availability of PHP extensions for XML parsing.  If
 * Auth_Yadis_setDefaultParser has been called, the parser used in
 * that call will be returned instead.
 */
function Auth_Yadis_getXMLParser()
{
    global $__Auth_Yadis_defaultParser;

    if (isset($__Auth_Yadis_defaultParser)) {
        return $__Auth_Yadis_defaultParser;
    }

    foreach(Auth_Yadis_getSupportedExtensions() as $extension => $classname)
    {
      if (extension_loaded($extension))
      {
        $p = new $classname();
        Auth_Yadis_setDefaultParser($p);
        return $p;
      }
    }

    return false;
}


code:
<?php

/**
 * This module contains the XRDS parsing code.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * Require the XPath implementation.
 */
require_once 'Auth/Yadis/XML.php';

/**
 * This match mode means a given service must match ALL filters passed
 * to the Auth_Yadis_XRDS::services() call.
 */
define('SERVICES_YADIS_MATCH_ALL', 101);

/**
 * This match mode means a given service must match ANY filters (at
 * least one) passed to the Auth_Yadis_XRDS::services() call.
 */
define('SERVICES_YADIS_MATCH_ANY', 102);

/**
 * The priority value used for service elements with no priority
 * specified.
 */
define('SERVICES_YADIS_MAX_PRIORITY', pow(2, 30));

/**
 * XRD XML namespace
 */
define('Auth_Yadis_XMLNS_XRD_2_0', 'xri://$xrd*($v*2.0)');

/**
 * XRDS XML namespace
 */
define('Auth_Yadis_XMLNS_XRDS', 'xri://$xrds');

function Auth_Yadis_getNSMap()
{
    return array('xrds' => Auth_Yadis_XMLNS_XRDS,
                 'xrd' => Auth_Yadis_XMLNS_XRD_2_0);
}

/**
 * @access private
 */
function Auth_Yadis_array_scramble($arr)
{
    $result = array();

    while (count($arr)) {
        $index = array_rand($arr, 1);
        $result[] = $arr[$index];
        unset($arr[$index]);
    }

    return $result;
}

/**
 * This class represents a <Service> element in an XRDS document.
 * Objects of this type are returned by
 * Auth_Yadis_XRDS::services() and
 * Auth_Yadis_Yadis::services().  Each object corresponds directly
 * to a <Service> element in the XRDS and supplies a
 * getElements($name) method which you should use to inspect the
 * element's contents.  See {@link Auth_Yadis_Yadis} for more
 * information on the role this class plays in Yadis discovery.
 *
 * @package OpenID
 */
class Auth_Yadis_Service {

    /**
     * Creates an empty service object.
     */
    function Auth_Yadis_Service()
    {
        $this->element = null;
        $this->parser = null;
    }

    /**
     * Return the URIs in the "Type" elements, if any, of this Service
     * element.
     *
     * @return array $type_uris An array of Type URI strings.
     */
    function getTypes()
    {
        $t = array();
        foreach ($this->getElements('xrd:Type') as $elem) {
            $c = $this->parser->content($elem);
            if ($c) {
                $t[] = $c;
            }
        }
        return $t;
    }

    function matchTypes($type_uris)
    {
        $result = array();

        foreach ($this->getTypes() as $typ) {
            if (in_array($typ, $type_uris)) {
                $result[] = $typ;
            }
        }

        return $result;
    }

    /**
     * Return the URIs in the "URI" elements, if any, of this Service
     * element.  The URIs are returned sorted in priority order.
     *
     * @return array $uris An array of URI strings.
     */
    function getURIs()
    {
        $uris = array();
        $last = array();

        foreach ($this->getElements('xrd:URI') as $elem) {
            $uri_string = $this->parser->content($elem);
            $attrs = $this->parser->attributes($elem);
            if ($attrs &&
                array_key_exists('priority', $attrs)) {
                $priority = intval($attrs['priority']);
                if (!array_key_exists($priority, $uris)) {
                    $uris[$priority] = array();
                }

                $uris[$priority][] = $uri_string;
            } else {
                $last[] = $uri_string;
            }
        }

        $keys = array_keys($uris);
        sort($keys);

        // Rebuild array of URIs.
        $result = array();
        foreach ($keys as $k) {
            $new_uris = Auth_Yadis_array_scramble($uris[$k]);
            $result = array_merge($result, $new_uris);
        }

        $result = array_merge($result,
                              Auth_Yadis_array_scramble($last));

        return $result;
    }

    /**
     * Returns the "priority" attribute value of this <Service>
     * element, if the attribute is present.  Returns null if not.
     *
     * @return mixed $result Null or integer, depending on whether
     * this Service element has a 'priority' attribute.
     */
    function getPriority()
    {
        $attributes = $this->parser->attributes($this->element);

        if (array_key_exists('priority', $attributes)) {
            return intval($attributes['priority']);
        }

        return null;
    }

    /**
     * Used to get XML elements from this object's <Service> element.
     *
     * This is what you should use to get all custom information out
     * of this element. This is used by service filter functions to
     * determine whether a service element contains specific tags,
     * etc.  NOTE: this only considers elements which are direct
     * children of the <Service> element for this object.
     *
     * @param string $name The name of the element to look for
     * @return array $list An array of elements with the specified
     * name which are direct children of the <Service> element.  The
     * nodes returned by this function can be passed to $this->parser
     * methods (see {@link Auth_Yadis_XMLParser}).
     */
    function getElements($name)
    {
        return $this->parser->evalXPath($name, $this->element);
    }
}

/*
 * Return the expiration date of this XRD element, or None if no
 * expiration was specified.
 *
 * @param $default The value to use as the expiration if no expiration
 * was specified in the XRD.
 */
function Auth_Yadis_getXRDExpiration($xrd_element, $default=null)
{
    $expires_element = $xrd_element->$parser->evalXPath('/xrd:Expires');
    if ($expires_element === null) {
        return $default;
    } else {
        $expires_string = $expires_element->text;

        // Will raise ValueError if the string is not the expected
        // format
        $t = strptime($expires_string, "%Y-%m-%dT%H:%M:%SZ");

        if ($t === false) {
            return false;
        }

        // [int $hour [, int $minute [, int $second [,
        //  int $month [, int $day [, int $year ]]]]]]
        return mktime($t['tm_hour'], $t['tm_min'], $t['tm_sec'],
                      $t['tm_mon'], $t['tm_day'], $t['tm_year']);
    }
}

/**
 * This class performs parsing of XRDS documents.
 *
 * You should not instantiate this class directly; rather, call
 * parseXRDS statically:
 *
 * <pre>  $xrds = Auth_Yadis_XRDS::parseXRDS($xml_string);</pre>
 *
 * If the XRDS can be parsed and is valid, an instance of
 * Auth_Yadis_XRDS will be returned.  Otherwise, null will be
 * returned.  This class is used by the Auth_Yadis_Yadis::discover
 * method.
 *
 * @package OpenID
 */
class Auth_Yadis_XRDS {

    /**
     * Instantiate a Auth_Yadis_XRDS object.  Requires an XPath
     * instance which has been used to parse a valid XRDS document.
     */
    function Auth_Yadis_XRDS($xmlParser, $xrdNodes)
    {
        $this->parser = $xmlParser;
        $this->xrdNode = $xrdNodes[count($xrdNodes) - 1];
        $this->allXrdNodes = $xrdNodes;
        $this->serviceList = array();
        $this->_parse();
    }

    /**
     * Parse an XML string (XRDS document) and return either a
     * Auth_Yadis_XRDS object or null, depending on whether the
     * XRDS XML is valid.
     *
     * @param string $xml_string An XRDS XML string.
     * @return mixed $xrds An instance of Auth_Yadis_XRDS or null,
     * depending on the validity of $xml_string
     */
    static function parseXRDS($xml_string, $extra_ns_map = null)
    {
        $_null = null;

        if (!$xml_string) {
            return $_null;
        }

        $parser = Auth_Yadis_getXMLParser();

        $ns_map = Auth_Yadis_getNSMap();

        if ($extra_ns_map && is_array($extra_ns_map)) {
            $ns_map = array_merge($ns_map, $extra_ns_map);
        }

        if (!($parser && $parser->init($xml_string, $ns_map))) {
            return $_null;
        }

        // Try to get root element.
        $root = $parser->evalXPath('/xrds:XRDS[1]');
        if (!$root) {
            return $_null;
        }

        if (is_array($root)) {
            $root = $root[0];
        }

        $attrs = $parser->attributes($root);

        if (array_key_exists('xmlns:xrd', $attrs) &&
            $attrs['xmlns:xrd'] != Auth_Yadis_XMLNS_XRDS) {
            return $_null;
        } else if (array_key_exists('xmlns', $attrs) &&
                   preg_match('/xri/', $attrs['xmlns']) &&
                   $attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_2_0) {
            return $_null;
        }

        // Get the last XRD node.
        $xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');

        if (!$xrd_nodes) {
            return $_null;
        }

        $xrds = new Auth_Yadis_XRDS($parser, $xrd_nodes);
        return $xrds;
    }

    /**
     * @access private
     */
    function _addService($priority, $service)
    {
        $priority = intval($priority);

        if (!array_key_exists($priority, $this->serviceList)) {
            $this->serviceList[$priority] = array();
        }

        $this->serviceList[$priority][] = $service;
    }

    /**
     * Creates the service list using nodes from the XRDS XML
     * document.
     *
     * @access private
     */
    function _parse()
    {
        $this->serviceList = array();

        $services = $this->parser->evalXPath('xrd:Service', $this->xrdNode);

        foreach ($services as $node) {
            $s = new Auth_Yadis_Service();
            $s->element = $node;
            $s->parser = $this->parser;

            $priority = $s->getPriority();

            if ($priority === null) {
                $priority = SERVICES_YADIS_MAX_PRIORITY;
            }

            $this->_addService($priority, $s);
        }
    }

    /**
     * Returns a list of service objects which correspond to <Service>
     * elements in the XRDS XML document for this object.
     *
     * Optionally, an array of filter callbacks may be given to limit
     * the list of returned service objects.  Furthermore, the default
     * mode is to return all service objects which match ANY of the
     * specified filters, but $filter_mode may be
     * SERVICES_YADIS_MATCH_ALL if you want to be sure that the
     * returned services match all the given filters.  See {@link
     * Auth_Yadis_Yadis} for detailed usage information on filter
     * functions.
     *
     * @param mixed $filters An array of callbacks to filter the
     * returned services, or null if all services are to be returned.
     * @param integer $filter_mode SERVICES_YADIS_MATCH_ALL or
     * SERVICES_YADIS_MATCH_ANY, depending on whether the returned
     * services should match ALL or ANY of the specified filters,
     * respectively.
     * @return mixed $services An array of {@link
     * Auth_Yadis_Service} objects if $filter_mode is a valid
     * mode; null if $filter_mode is an invalid mode (i.e., not
     * SERVICES_YADIS_MATCH_ANY or SERVICES_YADIS_MATCH_ALL).
     */
    function services($filters = null,
                      $filter_mode = SERVICES_YADIS_MATCH_ANY)
    {

        $pri_keys = array_keys($this->serviceList);
        sort($pri_keys, SORT_NUMERIC);

        // If no filters are specified, return the entire service
        // list, ordered by priority.
        if (!$filters ||
            (!is_array($filters))) {

            $result = array();
            foreach ($pri_keys as $pri) {
                $result = array_merge($result, $this->serviceList[$pri]);
            }

            return $result;
        }

        // If a bad filter mode is specified, return null.
        if (!in_array($filter_mode, array(SERVICES_YADIS_MATCH_ANY,
                                          SERVICES_YADIS_MATCH_ALL))) {
            return null;
        }

        // Otherwise, use the callbacks in the filter list to
        // determine which services are returned.
        $filtered = array();

        foreach ($pri_keys as $priority_value) {
            $service_obj_list = $this->serviceList[$priority_value];

            foreach ($service_obj_list as $service) {

                $matches = 0;

                foreach ($filters as $filter) {

                    if (call_user_func_array($filter, array($service))) {
                        $matches++;

                        if ($filter_mode == SERVICES_YADIS_MATCH_ANY) {
                            $pri = $service->getPriority();
                            if ($pri === null) {
                                $pri = SERVICES_YADIS_MAX_PRIORITY;
                            }

                            if (!array_key_exists($pri, $filtered)) {
                                $filtered[$pri] = array();
                            }

                            $filtered[$pri][] = $service;
                            break;
                        }
                    }
                }

                if (($filter_mode == SERVICES_YADIS_MATCH_ALL) &&
                    ($matches == count($filters))) {

                    $pri = $service->getPriority();
                    if ($pri === null) {
                        $pri = SERVICES_YADIS_MAX_PRIORITY;
                    }

                    if (!array_key_exists($pri, $filtered)) {
                        $filtered[$pri] = array();
                    }
                    $filtered[$pri][] = $service;
                }
            }
        }

        $pri_keys = array_keys($filtered);
        sort($pri_keys, SORT_NUMERIC);

        $result = array();
        foreach ($pri_keys as $pri) {
            $result = array_merge($result, $filtered[$pri]);
        }

        return $result;
    }
}


code:
<?php

/**
 * Routines for XRI resolution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

require_once 'Auth/Yadis/Misc.php';
require_once 'Auth/Yadis/Yadis.php';
require_once 'Auth/OpenID.php';

function Auth_Yadis_getDefaultProxy()
{
    return 'http://xri.net/';
}

function Auth_Yadis_getXRIAuthorities()
{
    return array('!', '=', '@', '+', '$', '(');
}

function Auth_Yadis_getEscapeRE()
{
    $parts = array();
    foreach (array_merge(Auth_Yadis_getUCSChars(),
                         Auth_Yadis_getIPrivateChars()) as $pair) {
        list($m, $n) = $pair;
        $parts[] = sprintf("%s-%s", chr($m), chr($n));
    }

    return sprintf('/[%s]/', implode('', $parts));
}

function Auth_Yadis_getXrefRE()
{
    return '/\((.*?)\)/';
}

function Auth_Yadis_identifierScheme($identifier)
{
    if (Auth_Yadis_startswith($identifier, 'xri://') ||
        ($identifier &&
          in_array($identifier[0], Auth_Yadis_getXRIAuthorities()))) {
        return "XRI";
    } else {
        return "URI";
    }
}

function Auth_Yadis_toIRINormal($xri)
{
    if (!Auth_Yadis_startswith($xri, 'xri://')) {
        $xri = 'xri://' . $xri;
    }

    return Auth_Yadis_escapeForIRI($xri);
}

function _escape_xref($xref_match)
{
    $xref = $xref_match[0];
    $xref = str_replace('/', '%2F', $xref);
    $xref = str_replace('?', '%3F', $xref);
    $xref = str_replace('#', '%23', $xref);
    return $xref;
}

function Auth_Yadis_escapeForIRI($xri)
{
    $xri = str_replace('%', '%25', $xri);
    $xri = preg_replace_callback(Auth_Yadis_getXrefRE(),
                                 '_escape_xref', $xri);
    return $xri;
}

function Auth_Yadis_toURINormal($xri)
{
    return Auth_Yadis_iriToURI(Auth_Yadis_toIRINormal($xri));
}

function Auth_Yadis_iriToURI($iri)
{
    if (1) {
        return $iri;
    } else {
        // According to RFC 3987, section 3.1, "Mapping of IRIs to URIs"
        return preg_replace_callback(Auth_Yadis_getEscapeRE(),
                                     'Auth_Yadis_pct_escape_unicode', $iri);
    }
}

function Auth_Yadis_XRIAppendArgs($url, $args)
{
    // Append some arguments to an HTTP query.  Yes, this is just like
    // OpenID's appendArgs, but with special seasoning for XRI
    // queries.

    if (count($args) == 0) {
        return $url;
    }

    // Non-empty array; if it is an array of arrays, use multisort;
    // otherwise use sort.
    if (array_key_exists(0, $args) &&
        is_array($args[0])) {
        // Do nothing here.
    } else {
        $keys = array_keys($args);
        sort($keys);
        $new_args = array();
        foreach ($keys as $key) {
            $new_args[] = array($key, $args[$key]);
        }
        $args = $new_args;
    }

    // According to XRI Resolution section "QXRI query parameters":
    //
    // "If the original QXRI had a null query component (only a
    //  leading question mark), or a query component consisting of
    //  only question marks, one additional leading question mark MUST
    //  be added when adding any XRI resolution parameters."
    if (strpos(rtrim($url, '?'), '?') !== false) {
        $sep = '&';
    } else {
        $sep = '?';
    }

    return $url . $sep . Auth_OpenID::httpBuildQuery($args);
}

function Auth_Yadis_providerIsAuthoritative($providerID, $canonicalID)
{
    $lastbang = strrpos($canonicalID, '!');
    $p = substr($canonicalID, 0, $lastbang);
    return $p == $providerID;
}

function Auth_Yadis_rootAuthority($xri)
{
    // Return the root authority for an XRI.

    $root = null;

    if (Auth_Yadis_startswith($xri, 'xri://')) {
        $xri = substr($xri, 6);
    }

    $authority = explode('/', $xri, 2);
    $authority = $authority[0];
    if ($authority[0] == '(') {
        // Cross-reference.
        // XXX: This is incorrect if someone nests cross-references so
        //   there is another close-paren in there.  Hopefully nobody
        //   does that before we have a real xriparse function.
        //   Hopefully nobody does that *ever*.
        $root = substr($authority, 0, strpos($authority, ')') + 1);
    } else if (in_array($authority[0], Auth_Yadis_getXRIAuthorities())) {
        // Other XRI reference.
        $root = $authority[0];
    } else {
        // IRI reference.
        $_segments = explode("!", $authority);
        $segments = array();
        foreach ($_segments as $s) {
            $segments = array_merge($segments, explode("*", $s));
        }
        $root = $segments[0];
    }

    return Auth_Yadis_XRI($root);
}

function Auth_Yadis_XRI($xri)
{
    if (!Auth_Yadis_startswith($xri, 'xri://')) {
        $xri = 'xri://' . $xri;
    }
    return $xri;
}

function Auth_Yadis_getCanonicalID($iname, $xrds)
{
    // Returns false or a canonical ID value.

    // Now nodes are in reverse order.
    $xrd_list = array_reverse($xrds->allXrdNodes);
    $parser = $xrds->parser;
    $node = $xrd_list[0];

    $canonicalID_nodes = $parser->evalXPath('xrd:CanonicalID', $node);

    if (!$canonicalID_nodes) {
        return false;
    }

    $canonicalID = $canonicalID_nodes[0];
    $canonicalID = Auth_Yadis_XRI($parser->content($canonicalID));

    $childID = $canonicalID;

    for ($i = 1; $i < count($xrd_list); $i++) {
        $xrd = $xrd_list[$i];

        $parent_sought = substr($childID, 0, strrpos($childID, '!'));
        $parentCID = $parser->evalXPath('xrd:CanonicalID', $xrd);
        if (!$parentCID) {
            return false;
        }
        $parentCID = Auth_Yadis_XRI($parser->content($parentCID[0]));

        if (strcasecmp($parent_sought, $parentCID)) {
            // raise XRDSFraud.
            return false;
        }

        $childID = $parent_sought;
    }

    $root = Auth_Yadis_rootAuthority($iname);
    if (!Auth_Yadis_providerIsAuthoritative($root, $childID)) {
        // raise XRDSFraud.
        return false;
    }

    return $canonicalID;
}


code:
<?php

/**
 * Code for using a proxy XRI resolver.
 */

require_once 'Auth/Yadis/XRDS.php';
require_once 'Auth/Yadis/XRI.php';

class Auth_Yadis_ProxyResolver {
    function Auth_Yadis_ProxyResolver($fetcher, $proxy_url = null)
    {
        $this->fetcher = $fetcher;
        $this->proxy_url = $proxy_url;
        if (!$this->proxy_url) {
            $this->proxy_url = Auth_Yadis_getDefaultProxy();
        }
    }

    function queryURL($xri, $service_type = null)
    {
        // trim off the xri:// prefix
        $qxri = substr(Auth_Yadis_toURINormal($xri), 6);
        $hxri = $this->proxy_url . $qxri;
        $args = array(
                      '_xrd_r' => 'application/xrds+xml'
                      );

        if ($service_type) {
            $args['_xrd_t'] = $service_type;
        } else {
            // Don't perform service endpoint selection.
            $args['_xrd_r'] .= ';sep=false';
        }

        $query = Auth_Yadis_XRIAppendArgs($hxri, $args);
        return $query;
    }

    function query($xri, $service_types, $filters = array())
    {
        $services = array();
        $canonicalID = null;
        foreach ($service_types as $service_type) {
            $url = $this->queryURL($xri, $service_type);
            $response = $this->fetcher->get($url);
            if ($response->status != 200 and $response->status != 206) {
                continue;
            }
            $xrds = Auth_Yadis_XRDS::parseXRDS($response->body);
            if (!$xrds) {
                continue;
            }
            $canonicalID = Auth_Yadis_getCanonicalID($xri,
                                                         $xrds);

            if ($canonicalID === false) {
                return null;
            }

            $some_services = $xrds->services($filters);
            $services = array_merge($services, $some_services);
            // TODO:
            //  * If we do get hits for multiple service_types, we're
            //    almost certainly going to have duplicated service
            //    entries and broken priority ordering.
        }
        return array($canonicalID, $services);
    }
}


code:
<?php

/**
 * The core PHP Yadis implementation.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * Need both fetcher types so we can use the right one based on the
 * presence or absence of CURL.
 */
require_once "Auth/Yadis/PlainHTTPFetcher.php";
require_once "Auth/Yadis/ParanoidHTTPFetcher.php";

/**
 * Need this for parsing HTML (looking for META tags).
 */
require_once "Auth/Yadis/ParseHTML.php";

/**
 * Need this to parse the XRDS document during Yadis discovery.
 */
require_once "Auth/Yadis/XRDS.php";

/**
 * XRDS (yadis) content type
 */
define('Auth_Yadis_CONTENT_TYPE', 'application/xrds+xml');

/**
 * Yadis header
 */
define('Auth_Yadis_HEADER_NAME', 'X-XRDS-Location');

/**
 * Contains the result of performing Yadis discovery on a URI.
 *
 * @package OpenID
 */
class Auth_Yadis_DiscoveryResult {

    // The URI that was passed to the fetcher
    var $request_uri = null;

    // The result of following redirects from the request_uri
    var $normalized_uri = null;

    // The URI from which the response text was returned (set to
    // None if there was no XRDS document found)
    var $xrds_uri = null;

    var $xrds = null;

    // The content-type returned with the response_text
    var $content_type = null;

    // The document returned from the xrds_uri
    var $response_text = null;

    // Did the discovery fail miserably?
    var $failed = false;

    function Auth_Yadis_DiscoveryResult($request_uri)
    {
        // Initialize the state of the object
        // sets all attributes to None except the request_uri
        $this->request_uri = $request_uri;
    }

    function fail()
    {
        $this->failed = true;
    }

    function isFailure()
    {
        return $this->failed;
    }

    /**
     * Returns the list of service objects as described by the XRDS
     * document, if this yadis object represents a successful Yadis
     * discovery.
     *
     * @return array $services An array of {@link Auth_Yadis_Service}
     * objects
     */
    function services()
    {
        if ($this->xrds) {
            return $this->xrds->services();
        }

        return null;
    }

    function usedYadisLocation()
    {
        // Was the Yadis protocol's indirection used?
        return ($this->xrds_uri && $this->normalized_uri != $this->xrds_uri);
    }

    function isXRDS()
    {
        // Is the response text supposed to be an XRDS document?
        return ($this->usedYadisLocation() ||
                $this->content_type == Auth_Yadis_CONTENT_TYPE);
    }
}

/**
 *
 * Perform the Yadis protocol on the input URL and return an iterable
 * of resulting endpoint objects.
 *
 * input_url: The URL on which to perform the Yadis protocol
 *
 * @return: The normalized identity URL and an iterable of endpoint
 * objects generated by the filter function.
 *
 * xrds_parse_func: a callback which will take (uri, xrds_text) and
 * return an array of service endpoint objects or null.  Usually
 * array('Auth_OpenID_ServiceEndpoint', 'fromXRDS').
 *
 * discover_func: if not null, a callback which should take (uri) and
 * return an Auth_Yadis_Yadis object or null.
 */
function Auth_Yadis_getServiceEndpoints($input_url, $xrds_parse_func,
                                        $discover_func=null, $fetcher=null)
{
    if ($discover_func === null) {
        $discover_function = array('Auth_Yadis_Yadis', 'discover');
    }

    $yadis_result = call_user_func_array($discover_func,
                                         array($input_url, $fetcher));

    if ($yadis_result === null) {
        return array($input_url, array());
    }

    $endpoints = call_user_func_array($xrds_parse_func,
                      array($yadis_result->normalized_uri,
                            $yadis_result->response_text));

    if ($endpoints === null) {
        $endpoints = array();
    }

    return array($yadis_result->normalized_uri, $endpoints);
}

/**
 * This is the core of the PHP Yadis library.  This is the only class
 * a user needs to use to perform Yadis discovery.  This class
 * performs the discovery AND stores the result of the discovery.
 *
 * First, require this library into your program source:
 *
 *
  require_once "Auth/Yadis/Yadis.php";

 *
 * To perform Yadis discovery, first call the "discover" method
 * statically with a URI parameter:
 *
 *
  $http_response = array();
 *  $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
 *  $yadis_object = Auth_Yadis_Yadis::discover($uri,
 *                                    $http_response, $fetcher);

 *
 * If the discovery succeeds, $yadis_object will be an instance of
 * {@link Auth_Yadis_Yadis}.  If not, it will be null.  The XRDS
 * document found during discovery should have service descriptions,
 * which can be accessed by calling
 *
 *
  $service_list = $yadis_object->services();

 *
 * which returns an array of objects which describe each service.
 * These objects are instances of Auth_Yadis_Service.  Each object
 * describes exactly one whole Service element, complete with all of
 * its Types and URIs (no expansion is performed).  The common use
 * case for using the service objects returned by services() is to
 * write one or more filter functions and pass those to services():
 *
 *
  $service_list = $yadis_object->services(
 *                               array("filterByURI",
 *                                     "filterByExtension"));

 *
 * The filter functions (whose names appear in the array passed to
 * services()) take the following form:
 *
 *
  function myFilter($service) {
 *       // Query $service object here.  Return true if the service
 *       // matches your query; false if not.
 *  }

 *
 * This is an example of a filter which uses a regular expression to
 * match the content of URI tags (note that the Auth_Yadis_Service
 * class provides a getURIs() method which you should use instead of
 * this contrived example):
 *
 *

 *  function URIMatcher($service) {
 *      foreach ($service->getElements('xrd:URI') as $uri) {
 *          if (preg_match("/some_pattern/",
 *                         $service->parser->content($uri))) {
 *              return true;
 *          }
 *      }
 *      return false;
 *  }

 *
 * The filter functions you pass will be called for each service
 * object to determine which ones match the criteria your filters
 * specify.  The default behavior is that if a given service object
 * matches ANY of the filters specified in the services() call, it
 * will be returned.  You can specify that a given service object will
 * be returned ONLY if it matches ALL specified filters by changing
 * the match mode of services():
 *
 *
  $yadis_object->services(array("filter1", "filter2"),
 *                          SERVICES_YADIS_MATCH_ALL);

 *
 * See {@link SERVICES_YADIS_MATCH_ALL} and {@link
 * SERVICES_YADIS_MATCH_ANY}.
 *
 * Services described in an XRDS should have a library which you'll
 * probably be using.  Those libraries are responsible for defining
 * filters that can be used with the "services()" call.  If you need
 * to write your own filter, see the documentation for {@link
 * Auth_Yadis_Service}.
 *
 * @package OpenID
 */
class Auth_Yadis_Yadis {

    /**
     * Returns an HTTP fetcher object.  If the CURL extension is
     * present, an instance of {@link Auth_Yadis_ParanoidHTTPFetcher}
     * is returned.  If not, an instance of
     * {@link Auth_Yadis_PlainHTTPFetcher} is returned.
     *
     * If Auth_Yadis_CURL_OVERRIDE is defined, this method will always
     * return a {@link Auth_Yadis_PlainHTTPFetcher}.
     */
    static function getHTTPFetcher($timeout = 20)
    {
        if (Auth_Yadis_Yadis::curlPresent() &&
            (!defined('Auth_Yadis_CURL_OVERRIDE'))) {
            $fetcher = new Auth_Yadis_ParanoidHTTPFetcher($timeout);
        } else {
            $fetcher = new Auth_Yadis_PlainHTTPFetcher($timeout);
        }
        return $fetcher;
    }

    static function curlPresent()
    {
        return function_exists('curl_init');
    }

    /**
     * @access private
     */
   static function _getHeader($header_list, $names)
    {
        foreach ($header_list as $name => $value) {
            foreach ($names as $n) {
                if (strtolower($name) == strtolower($n)) {
                    return $value;
                }
            }
        }

        return null;
    }

    /**
     * @access private
     */
    static function _getContentType($content_type_header)
    {
        if ($content_type_header) {
            $parts = explode(";", $content_type_header);
            return strtolower($parts[0]);
        }
    }

    /**
     * This should be called statically and will build a Yadis
     * instance if the discovery process succeeds.  This implements
     * Yadis discovery as specified in the Yadis specification.
     *
     * @param string $uri The URI on which to perform Yadis discovery.
     *
     * @param array $http_response An array reference where the HTTP
     * response object will be stored (see {@link
     * Auth_Yadis_HTTPResponse}.
     *
     * @param Auth_Yadis_HTTPFetcher $fetcher An instance of a
     * Auth_Yadis_HTTPFetcher subclass.
     *
     * @param array $extra_ns_map An array which maps namespace names
     * to namespace URIs to be used when parsing the Yadis XRDS
     * document.
     *
     * @param integer $timeout An optional fetcher timeout, in seconds.
     *
     * @return mixed $obj Either null or an instance of
     * Auth_Yadis_Yadis, depending on whether the discovery
     * succeeded.
     */
    static function discover($uri, $fetcher,
                      $extra_ns_map = null, $timeout = 20)
    {
        $result = new Auth_Yadis_DiscoveryResult($uri);

        $request_uri = $uri;
        $headers = array("Accept: " . Auth_Yadis_CONTENT_TYPE .
                         ', text/html; q=0.3, application/xhtml+xml; q=0.5');

        if ($fetcher === null) {
            $fetcher = Auth_Yadis_Yadis::getHTTPFetcher($timeout);
        }

        $response = $fetcher->get($uri, $headers);

        if (!$response || ($response->status != 200 and
                           $response->status != 206)) {
            $result->fail();
            return $result;
        }

        $result->normalized_uri = $response->final_url;
        $result->content_type = Auth_Yadis_Yadis::_getHeader(
                                       $response->headers,
                                       array('content-type'));

        if ($result->content_type &&
            (Auth_Yadis_Yadis::_getContentType($result->content_type) ==
             Auth_Yadis_CONTENT_TYPE)) {
            $result->xrds_uri = $result->normalized_uri;
        } else {
            $yadis_location = Auth_Yadis_Yadis::_getHeader(
                                                 $response->headers,
                                                 array(Auth_Yadis_HEADER_NAME));

            if (!$yadis_location) {
                $parser = new Auth_Yadis_ParseHTML();
                $yadis_location = $parser->getHTTPEquiv($response->body);
            }

            if ($yadis_location) {
                $result->xrds_uri = $yadis_location;

                $response = $fetcher->get($yadis_location);

                if ((!$response) || ($response->status != 200 and
                                     $response->status != 206)) {
                    $result->fail();
                    return $result;
                }

                $result->content_type = Auth_Yadis_Yadis::_getHeader(
                                                         $response->headers,
                                                         array('content-type'));
            }
        }

        $result->response_text = $response->body;
        return $result;
    }
}


code:
* API Changes
  * AX::FetchResponse::fromSuccessResponse - return null when AX
    response arguments are absent
  * Alter AX fromOpenIDRequest() to take Auth_OpenID_AuthRequest
    object instead of Auth_OpenID_Message object so that it matches
    its counterpart methods in SREG and PAPE extensions.
  * PAPE (Provider Authentication Policy Extension) module
      * Updated extension for specification draft 2
      * Auth_OpenID_PAPE_Request::fromSuccessResponse returns None if
        PAPE response arguments were not signed
  * Added functions to generate request/response HTML forms with
    auto-submission javascript
      * Consumer (relying party) API:
        Auth_OpenID_AuthRequest::htmlMarkup
      * Server API: Auth_OpenID_OpenIDResponse::toHTML

* New Features
  * Added examples/discover.php, an OpenID service discovery tool
  * Add optional form_tag_attrs argument to
    Auth_OpenID_ServerResponse::toFormMarkup for setting arbitrary
    FORM element attributes
  * Fetchers now only read/request first megabyte of response

* Bug Fixes
  * NOT NULL constraints were added to SQLStore tables where
    appropriate
  * Yadis discovery now properly falls back to HTML-based discovery if
    it fails to get an XRDS document
  * Auth_OpenID_Decoder now behaves correctly when given a protocol
    message with an invalid OpenID namespace or a missing OpenID mode
  * Auth_OpenID_OpenIDResponse::toFormMarkup: Use return_to from the
    request, not the response fields (Not all responses (i.e. cancel,
    setup_needed) include a return_to field.)
  * normalize return_to URL before performing return_to verification
  * Auth_OpenID_Consumer::_verifyDiscoveryResults: fall back to OpenID
    1.0 type if 1.1 endpoint cannot be found
  * Auth_Yadis_ParanoidHTTPFetcher now works correctly with both array
    and non-array CURL versions
  * Clarified licensing language in all source files
  * OpenID 1 association requests no longer explicitly set
    no-encryption session type
  * Auth_OpenID_ServiceEndpoint::getDisplayIdentifier no longer
    includes a fragment, if present, in display identifiers
  * check_authentication requests: copy entire response, not just
    signed fields.  Fixes missing namespace in check_authentication
    requests
  * Yadis discovery now includes application/xhtml+xml and qualities
    in the Accept header
  * Normalize URLs correctly with URINorm.php
  * Auth_OpenID_MySQLStore: Use ENGINE instead of TYPE when creating
    tables


code:
What's New in PHP OpenID 2.0
============================

This library implements both the OpenID 1 and OpenID 2 protocols.  The
API changes in this version of the library are minimal and mostly
backwards-compatible with current RP and Server implementations.  If
you're already using this library for OpenID 1, only a few small
changes (see Summary below) will be needed once you upgrade.

The big news here is compatibility with version 2.0 of the OpenID
protocol.  Highlights include:

 * Simple Registration support in a new module Auth/OpenID/SReg.php.
   (Those previously using
   Auth_OpenID_SuccessResponse::extensionResponse() are advised to
   look here and at the example consumer and server for detailed usage
   information.)
 * OpenID provider-driven identifier selection.
 * "Negotiators" allow you to define which association types to use.
 * Improved examples/detect.php script (bugs fixed)
 * Improved layout of example consumer (see examples/consumer)
 * An improved HTML parser implementation
 * Library is now immune to being included inside functions and
   methods
 * Fixes to avoid multibyte overloading problems

If you've written your own custom store or code that interacts
directly with it, you'll need to review the change notes for
Auth_OpenID_Interface in Auth/OpenID/Interface.php.

Upgrading from earlier versions of this library
-----------------------------------------------

One of the additions to the OpenID protocol was a specified nonce
format for one-way nonces.  As a result, the nonce table in the
SQL-driven stores has changed.  You'll need to run the Python script
contrib/upgrade-store-1.1-to-2.0 to upgrade your store, or you'll
encounter errors about the wrong number of columns in the oid_nonces
table.  To run the script, you'll need a python module supporting your
database type: pysqlite2, psycopg, or MySQLdb.

If you cannot run the Python script, you can re-create your store by
dropping the tables in the store and calling createTables() on the
store object.

Consumers should now pass the consumer return_to URL to
Auth_OpenID_Consumer::complete() to defend against return_to URL
tampering.  This has REPLACED the old parameter, $query.  $query is
now a second optional parameter.  It is STRONGLY RECOMMENDED that you
never override $query, since the OpenID library uses its own logic to
sidestep PHP's broken request-processing code.

Summary of API Changes
----------------------

 - Auth_OpenID::fixArgs is now no longer necessary, and
Auth_OpenID_Consumer::complete and Auth_OpenID_Server::decodeRequest
no longer take query argument arrays.  *You should no longer pass any
parameters to these methods.*

 - Auth_OpenID_SuccessResponse::extensionResponse() is no longer the
preferred way to extract extension response parameters from the OpenID
response.  Instead, see the Auth/OpenID/SReg.php module and the
example consumer and server for detailed usage information on
constructing Simple Registration requests and inspecting responses.
extensionResponse() is still valid, but now takes a second parameter
(bool) indicating whether extension args should be signed.

 - The Auth_OpenID_Server's response answer() method now takes
additional parameters to support provider-driven identifier selection.
See the example server and the documentation for
Auth_OpenID_CheckIDRequest::answer.

 - Auth_OpenID_Consumer::complete() now takes two args:

   - $return_to, a required string that is the return URL passed to
     Auth_OpenID_AuthRequest::redirectURL()

   - $query, an optional array (or null if absent) denoting the query
     parameters of the OpenID response.  If null, the response data
     will be extracted from the PHP request environment.  Library
     users SHOULD NOT ever pass anything for $query unless they're
     testing the library.

path: vendor/openid/php-openid/NEWS


code:
PHP OpenID
----------

This is the PHP OpenID library by JanRain, Inc.  You can visit our
website for more information about this package and other OpenID
implementations and tools:

  http://www.openidenabled.com/

GETTING STARTED
===============

First, run the 'examples/detect.php' script either from the command
line or via the web.  It will generate a report of any system
configuration changes necessary to run the library.

INSTALLATION
============

You will need PHP 4.3.0 or greater to use this library.  We have
tested the library Linux on PHP 4.3.0, 4.4.1, 5.0.5, and 5.1.1.  We
have tested the library on Windows XP on PHP 4.4.4.

Follow these steps:

1. Install dependencies.

   - Enable either the GMP extension or Bcmath extension. (GMP is
     STRONGLY recommended because it's MUCH faster!)  This is
     required.

   - Enable the CURL extension.

   - If you plan to use SQLite, PostgreSQL, or MySQL to store OpenID
     data, you'll need PEAR MDB2.  You can install this by running this
     as root:

     # pear install MDB2

     You'll also need to install and enable the appropriate PHP
     database extension.  Alternatively, you can store OpenID data on
     the filesystem instead of using a relational database.  Nothing
     special is required for using the filesystem method.

   - Install either the DOM or domxml PHP XML processing extension,
     but not both (they are incompatible).

2. Copy the Auth/ directory into your PHP include path.

TESTING YOUR SETUP
==================

You can use the example code to test your setup.  To run the example
consumer or server, follow the instructions in the examples/README
file.

USING THE API
=============

The best way to get started using the API is to take a look at the
example consumer and server in the examples/ directory.  See the
examples/README file for more details.

TROUBLESHOOTING
===============

* If you're unable to use an OpenID URL with the library, you may want
to try using the discover tool (examples/discover.php).  This tool
will perform OpenID discovery on the identifier and give a list of
discovered OpenID services and their types.

* On some systems, PHP basedir restrictions prevent web servers from
opening a source of randomness, such as /dev/urandom.  If your PHP
OpenID library has trouble getting a satisfactory source of
randomness, check your Apache and PHP configurations to be sure that
the randomness source is in the list of allowed paths for the
"open_basedir" option.

* In some cases, bugs in the GMP math library will result in signature
validation errors when using this library.  Since GMP is preferred
over bcmath (for performance), you will have to define
Auth_OpenID_BUGGY_GMP in your application *before* importing any of
the library code:

  define('Auth_OpenID_BUGGY_GMP', true);

* Not all PHP installations support SSL.  You can find out if yours
supports SSL by reading the "HTTP Fetching" section of the output of
"examples/detect.php."  If your installation does not support SSL,
then https:// identity URLs and server URLs will not be supported by
the library.  An attempt to use such an identity URL will be
equivalent to using an invalid OpenID.  To enable SSL support,
recompile PHP with OpenSSL support or install the appropriate OpenSSL
module for your platform.  If you are using CURL, CURL will need to be
built with OpenSSL support.

GETTING HELP
============

If you have any questions, recommendations, or patches, please tell
us!  Subscribe to our OpenID development discussion list at

  http://openid.net/developers/dev-mailing-lists/

DOCUMENTATION
=============

You can view the HTML library documentation in the doc/ directory.

This package's documentation is in PhpDoc format.  To generate the
documentation, install phpdoc and run the admin/makedoc.sh script.
Phpdoc lives at:

  http://www.phpdoc.org/

CONTRIBUTING
============

If you have a bugfix or feature you'd like to contribute, don't
hesitate to send it to us.  Post your patch to the development list at

  http://openid.net/developers/dev-mailing-lists/

For more detailed information on how to contribute, see

  http://openidenabled.com/contribute/

To run the test suite included with this package, install PHPUnit 1.x
and run

  php admin/texttest.php

PHPUnit 1.x can be found at

  http://pear.phpunit.de/get/

path: vendor/openid/php-openid/README


code:
Development Environment Setup
=============================

Janrain note: You'll need to run these commands to generate
documentation for this project:

  apt-get install php4-pear
  pear install PhpDocumentor


code:
GitHub is the new home for php-openid library development.

This library was originally written by JanRain and managed using the darcs RCS.  This file is home to notes regarding the migration from darcs to git, and the move from openidenabled.com to github.com.

Contact:
Brian Ellin
brian@janrain.com