New file |
0,0 → 1,313 |
<?php |
|
/** |
* The core PHP Yadis implementation. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package Yadis |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
|
/** |
* Need both fetcher types so we can use the right one based on the |
* presence or absence of CURL. |
*/ |
require_once "Services/Yadis/PlainHTTPFetcher.php"; |
require_once "Services/Yadis/ParanoidHTTPFetcher.php"; |
|
/** |
* Need this for parsing HTML (looking for META tags). |
*/ |
require_once "Services/Yadis/ParseHTML.php"; |
|
/** |
* Need this to parse the XRDS document during Yadis discovery. |
*/ |
require_once "Services/Yadis/XRDS.php"; |
|
/** |
* 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: |
* |
* <pre> require_once "Services/Yadis/Yadis.php";</pre> |
* |
* To perform Yadis discovery, first call the "discover" method |
* statically with a URI parameter: |
* |
* <pre> $http_response = array(); |
* $fetcher = Services_Yadis_Yadis::getHTTPFetcher(); |
* $yadis_object = Services_Yadis_Yadis::discover($uri, |
* $http_response, $fetcher);</pre> |
* |
* If the discovery succeeds, $yadis_object will be an instance of |
* {@link Services_Yadis_Yadis}. If not, it will be null. The XRDS |
* document found during discovery should have service descriptions, |
* which can be accessed by calling |
* |
* <pre> $service_list = $yadis_object->services();</pre> |
* |
* which returns an array of objects which describe each service. |
* These objects are instances of Services_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(): |
* |
* <pre> $service_list = $yadis_object->services( |
* array("filterByURI", |
* "filterByExtension"));</pre> |
* |
* The filter functions (whose names appear in the array passed to |
* services()) take the following form: |
* |
* <pre> function myFilter(&$service) { |
* // Query $service object here. Return true if the service |
* // matches your query; false if not. |
* }</pre> |
* |
* This is an example of a filter which uses a regular expression to |
* match the content of URI tags (note that the Services_Yadis_Service |
* class provides a getURIs() method which you should use instead of |
* this contrived example): |
* |
* <pre> |
* function URIMatcher(&$service) { |
* foreach ($service->getElements('xrd:URI') as $uri) { |
* if (preg_match("/some_pattern/", |
* $service->parser->content($uri))) { |
* return true; |
* } |
* } |
* return false; |
* }</pre> |
* |
* 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(): |
* |
* <pre> $yadis_object->services(array("filter1", "filter2"), |
* SERVICES_YADIS_MATCH_ALL);</pre> |
* |
* 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 |
* Services_Yadis_Service}. |
* |
* @package Yadis |
*/ |
class Services_Yadis_Yadis { |
|
/** |
* Returns an HTTP fetcher object. If the CURL extension is |
* present, an instance of {@link Services_Yadis_ParanoidHTTPFetcher} |
* is returned. If not, an instance of |
* {@link Services_Yadis_PlainHTTPFetcher} is returned. |
*/ |
function getHTTPFetcher($timeout = 20) |
{ |
if (Services_Yadis_Yadis::curlPresent()) { |
$fetcher = new Services_Yadis_ParanoidHTTPFetcher($timeout); |
} else { |
$fetcher = new Services_Yadis_PlainHTTPFetcher($timeout); |
} |
return $fetcher; |
} |
|
function curlPresent() |
{ |
return function_exists('curl_init'); |
} |
|
/** |
* @access private |
*/ |
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 |
*/ |
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 |
* Services_Yadis_HTTPResponse}. |
* |
* @param Services_Yadis_HTTPFetcher $fetcher An instance of a |
* Services_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 |
* Services_Yadis_Yadis, depending on whether the discovery |
* succeeded. |
*/ |
function discover($uri, &$http_response, &$fetcher, |
$extra_ns_map = null, $timeout = 20) |
{ |
if (!$uri) { |
return null; |
} |
|
$request_uri = $uri; |
$headers = array("Accept: application/xrds+xml"); |
|
if (!$fetcher) { |
$fetcher = Services_Yadis_Yadis::getHTTPFetcher($timeout); |
} |
|
$response = $fetcher->get($uri, $headers); |
$http_response = $response; |
|
if (!$response) { |
return null; |
} |
|
if ($response->status != 200) { |
return null; |
} |
|
$xrds_uri = $response->final_url; |
$uri = $response->final_url; |
$body = $response->body; |
|
$xrds_header_uri = Services_Yadis_Yadis::_getHeader( |
$response->headers, |
array('x-xrds-location', |
'x-yadis-location')); |
|
$content_type = Services_Yadis_Yadis::_getHeader($response->headers, |
array('content-type')); |
|
if ($xrds_header_uri) { |
$xrds_uri = $xrds_header_uri; |
$response = $fetcher->get($xrds_uri); |
$http_response = $response; |
if (!$response) { |
return null; |
} else { |
$body = $response->body; |
$headers = $response->headers; |
$content_type = Services_Yadis_Yadis::_getHeader($headers, |
array('content-type')); |
} |
} |
|
if (Services_Yadis_Yadis::_getContentType($content_type) != |
'application/xrds+xml') { |
// Treat the body as HTML and look for a META tag. |
$parser = new Services_Yadis_ParseHTML(); |
$new_uri = $parser->getHTTPEquiv($body); |
$xrds_uri = null; |
if ($new_uri) { |
$response = $fetcher->get($new_uri); |
if ($response->status != 200) { |
return null; |
} |
$http_response = $response; |
$body = $response->body; |
$xrds_uri = $new_uri; |
$content_type = Services_Yadis_Yadis::_getHeader( |
$response->headers, |
array('content-type')); |
} |
} |
|
$xrds = Services_Yadis_XRDS::parseXRDS($body, $extra_ns_map); |
|
if ($xrds !== null) { |
$y = new Services_Yadis_Yadis(); |
|
$y->request_uri = $request_uri; |
$y->xrds = $xrds; |
$y->uri = $uri; |
$y->xrds_uri = $xrds_uri; |
$y->body = $body; |
$y->content_type = $content_type; |
|
return $y; |
} else { |
return null; |
} |
} |
|
/** |
* Instantiates an empty Services_Yadis_Yadis object. This |
* constructor should not be used by any user of the library. |
* This constructor results in a completely useless object which |
* must be populated with valid discovery information. Instead of |
* using this constructor, call |
* Services_Yadis_Yadis::discover($uri). |
*/ |
function Services_Yadis_Yadis() |
{ |
$this->request_uri = null; |
$this->uri = null; |
$this->xrds = null; |
$this->xrds_uri = null; |
$this->body = null; |
$this->content_type = null; |
} |
|
/** |
* 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 Services_Yadis_Service} |
* objects |
*/ |
function services() |
{ |
if ($this->xrds) { |
return $this->xrds->services(); |
} |
|
return null; |
} |
} |
|
?> |