* @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: * *
  require_once "Services/Yadis/Yadis.php";
* * To perform Yadis discovery, first call the "discover" method * statically with a URI parameter: * *
  $http_response = array();
 *  $fetcher = Services_Yadis_Yadis::getHTTPFetcher();
 *  $yadis_object = Services_Yadis_Yadis::discover($uri,
 *                                    $http_response, $fetcher);
* * 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 * *
  $service_list = $yadis_object->services();
* * 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(): * *
  $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 Services_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 * 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; } } ?>