Subversion Repositories Applications.annuaire

Rev

Rev 42 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
42 aurelien 1
<?php
2
 
3
/**
4
 * The core PHP Yadis implementation.
5
 *
6
 * PHP versions 4 and 5
7
 *
8
 * LICENSE: See the COPYING file included in this distribution.
9
 *
10
 * @package Yadis
11
 * @author JanRain, Inc. <openid@janrain.com>
12
 * @copyright 2005 Janrain, Inc.
13
 * @license http://www.gnu.org/copyleft/lesser.html LGPL
14
 */
15
 
16
/**
17
 * Need both fetcher types so we can use the right one based on the
18
 * presence or absence of CURL.
19
 */
20
require_once "Services/Yadis/PlainHTTPFetcher.php";
21
require_once "Services/Yadis/ParanoidHTTPFetcher.php";
22
 
23
/**
24
 * Need this for parsing HTML (looking for META tags).
25
 */
26
require_once "Services/Yadis/ParseHTML.php";
27
 
28
/**
29
 * Need this to parse the XRDS document during Yadis discovery.
30
 */
31
require_once "Services/Yadis/XRDS.php";
32
 
33
/**
34
 * This is the core of the PHP Yadis library.  This is the only class
35
 * a user needs to use to perform Yadis discovery.  This class
36
 * performs the discovery AND stores the result of the discovery.
37
 *
38
 * First, require this library into your program source:
39
 *
40
 * <pre>  require_once "Services/Yadis/Yadis.php";</pre>
41
 *
42
 * To perform Yadis discovery, first call the "discover" method
43
 * statically with a URI parameter:
44
 *
45
 * <pre>  $http_response = array();
46
 *  $fetcher = Services_Yadis_Yadis::getHTTPFetcher();
47
 *  $yadis_object = Services_Yadis_Yadis::discover($uri,
48
 *                                    $http_response, $fetcher);</pre>
49
 *
50
 * If the discovery succeeds, $yadis_object will be an instance of
51
 * {@link Services_Yadis_Yadis}.  If not, it will be null.  The XRDS
52
 * document found during discovery should have service descriptions,
53
 * which can be accessed by calling
54
 *
55
 * <pre>  $service_list = $yadis_object->services();</pre>
56
 *
57
 * which returns an array of objects which describe each service.
58
 * These objects are instances of Services_Yadis_Service.  Each object
59
 * describes exactly one whole Service element, complete with all of
60
 * its Types and URIs (no expansion is performed).  The common use
61
 * case for using the service objects returned by services() is to
62
 * write one or more filter functions and pass those to services():
63
 *
64
 * <pre>  $service_list = $yadis_object->services(
65
 *                               array("filterByURI",
66
 *                                     "filterByExtension"));</pre>
67
 *
68
 * The filter functions (whose names appear in the array passed to
69
 * services()) take the following form:
70
 *
71
 * <pre>  function myFilter(&$service) {
72
 *       // Query $service object here.  Return true if the service
73
 *       // matches your query; false if not.
74
 *  }</pre>
75
 *
76
 * This is an example of a filter which uses a regular expression to
77
 * match the content of URI tags (note that the Services_Yadis_Service
78
 * class provides a getURIs() method which you should use instead of
79
 * this contrived example):
80
 *
81
 * <pre>
82
 *  function URIMatcher(&$service) {
83
 *      foreach ($service->getElements('xrd:URI') as $uri) {
84
 *          if (preg_match("/some_pattern/",
85
 *                         $service->parser->content($uri))) {
86
 *              return true;
87
 *          }
88
 *      }
89
 *      return false;
90
 *  }</pre>
91
 *
92
 * The filter functions you pass will be called for each service
93
 * object to determine which ones match the criteria your filters
94
 * specify.  The default behavior is that if a given service object
95
 * matches ANY of the filters specified in the services() call, it
96
 * will be returned.  You can specify that a given service object will
97
 * be returned ONLY if it matches ALL specified filters by changing
98
 * the match mode of services():
99
 *
100
 * <pre>  $yadis_object->services(array("filter1", "filter2"),
101
 *                          SERVICES_YADIS_MATCH_ALL);</pre>
102
 *
103
 * See {@link SERVICES_YADIS_MATCH_ALL} and {@link
104
 * SERVICES_YADIS_MATCH_ANY}.
105
 *
106
 * Services described in an XRDS should have a library which you'll
107
 * probably be using.  Those libraries are responsible for defining
108
 * filters that can be used with the "services()" call.  If you need
109
 * to write your own filter, see the documentation for {@link
110
 * Services_Yadis_Service}.
111
 *
112
 * @package Yadis
113
 */
114
class Services_Yadis_Yadis {
115
 
116
    /**
117
     * Returns an HTTP fetcher object.  If the CURL extension is
118
     * present, an instance of {@link Services_Yadis_ParanoidHTTPFetcher}
119
     * is returned.  If not, an instance of
120
     * {@link Services_Yadis_PlainHTTPFetcher} is returned.
121
     */
122
    function getHTTPFetcher($timeout = 20)
123
    {
124
        if (Services_Yadis_Yadis::curlPresent()) {
125
            $fetcher = new Services_Yadis_ParanoidHTTPFetcher($timeout);
126
        } else {
127
            $fetcher = new Services_Yadis_PlainHTTPFetcher($timeout);
128
        }
129
        return $fetcher;
130
    }
131
 
132
    function curlPresent()
133
    {
134
        return function_exists('curl_init');
135
    }
136
 
137
    /**
138
     * @access private
139
     */
140
    function _getHeader($header_list, $names)
141
    {
142
        foreach ($header_list as $name => $value) {
143
            foreach ($names as $n) {
144
                if (strtolower($name) == strtolower($n)) {
145
                    return $value;
146
                }
147
            }
148
        }
149
 
150
        return null;
151
    }
152
 
153
    /**
154
     * @access private
155
     */
156
    function _getContentType($content_type_header)
157
    {
158
        if ($content_type_header) {
159
            $parts = explode(";", $content_type_header);
160
            return strtolower($parts[0]);
161
        }
162
    }
163
 
164
    /**
165
     * This should be called statically and will build a Yadis
166
     * instance if the discovery process succeeds.  This implements
167
     * Yadis discovery as specified in the Yadis specification.
168
     *
169
     * @param string $uri The URI on which to perform Yadis discovery.
170
     *
171
     * @param array $http_response An array reference where the HTTP
172
     * response object will be stored (see {@link
173
     * Services_Yadis_HTTPResponse}.
174
     *
175
     * @param Services_Yadis_HTTPFetcher $fetcher An instance of a
176
     * Services_Yadis_HTTPFetcher subclass.
177
     *
178
     * @param array $extra_ns_map An array which maps namespace names
179
     * to namespace URIs to be used when parsing the Yadis XRDS
180
     * document.
181
     *
182
     * @param integer $timeout An optional fetcher timeout, in seconds.
183
     *
184
     * @return mixed $obj Either null or an instance of
185
     * Services_Yadis_Yadis, depending on whether the discovery
186
     * succeeded.
187
     */
188
    function discover($uri, &$http_response, &$fetcher,
189
                      $extra_ns_map = null, $timeout = 20)
190
    {
191
        if (!$uri) {
192
            return null;
193
        }
194
 
195
        $request_uri = $uri;
196
        $headers = array("Accept: application/xrds+xml");
197
 
198
        if (!$fetcher) {
199
            $fetcher = Services_Yadis_Yadis::getHTTPFetcher($timeout);
200
        }
201
 
202
        $response = $fetcher->get($uri, $headers);
203
        $http_response = $response;
204
 
205
        if (!$response) {
206
            return null;
207
        }
208
 
209
        if ($response->status != 200) {
210
          return null;
211
        }
212
 
213
        $xrds_uri = $response->final_url;
214
        $uri = $response->final_url;
215
        $body = $response->body;
216
 
217
        $xrds_header_uri = Services_Yadis_Yadis::_getHeader(
218
                                                    $response->headers,
219
                                                    array('x-xrds-location',
220
                                                          'x-yadis-location'));
221
 
222
        $content_type = Services_Yadis_Yadis::_getHeader($response->headers,
223
                                                         array('content-type'));
224
 
225
        if ($xrds_header_uri) {
226
            $xrds_uri = $xrds_header_uri;
227
            $response = $fetcher->get($xrds_uri);
228
            $http_response = $response;
229
            if (!$response) {
230
                return null;
231
            } else {
232
                $body = $response->body;
233
                $headers = $response->headers;
234
                $content_type = Services_Yadis_Yadis::_getHeader($headers,
235
                                                       array('content-type'));
236
            }
237
        }
238
 
239
        if (Services_Yadis_Yadis::_getContentType($content_type) !=
240
            'application/xrds+xml') {
241
            // Treat the body as HTML and look for a META tag.
242
            $parser = new Services_Yadis_ParseHTML();
243
            $new_uri = $parser->getHTTPEquiv($body);
244
            $xrds_uri = null;
245
            if ($new_uri) {
246
                $response = $fetcher->get($new_uri);
247
                if ($response->status != 200) {
248
                  return null;
249
                }
250
                $http_response = $response;
251
                $body = $response->body;
252
                $xrds_uri = $new_uri;
253
                $content_type = Services_Yadis_Yadis::_getHeader(
254
                                                         $response->headers,
255
                                                         array('content-type'));
256
            }
257
        }
258
 
259
        $xrds = Services_Yadis_XRDS::parseXRDS($body, $extra_ns_map);
260
 
261
        if ($xrds !== null) {
262
            $y = new Services_Yadis_Yadis();
263
 
264
            $y->request_uri = $request_uri;
265
            $y->xrds = $xrds;
266
            $y->uri = $uri;
267
            $y->xrds_uri = $xrds_uri;
268
            $y->body = $body;
269
            $y->content_type = $content_type;
270
 
271
            return $y;
272
        } else {
273
            return null;
274
        }
275
    }
276
 
277
    /**
278
     * Instantiates an empty Services_Yadis_Yadis object.  This
279
     * constructor should not be used by any user of the library.
280
     * This constructor results in a completely useless object which
281
     * must be populated with valid discovery information.  Instead of
282
     * using this constructor, call
283
     * Services_Yadis_Yadis::discover($uri).
284
     */
285
    function Services_Yadis_Yadis()
286
    {
287
        $this->request_uri = null;
288
        $this->uri = null;
289
        $this->xrds = null;
290
        $this->xrds_uri = null;
291
        $this->body = null;
292
        $this->content_type = null;
293
    }
294
 
295
    /**
296
     * Returns the list of service objects as described by the XRDS
297
     * document, if this yadis object represents a successful Yadis
298
     * discovery.
299
     *
300
     * @return array $services An array of {@link Services_Yadis_Service}
301
     * objects
302
     */
303
    function services()
304
    {
305
        if ($this->xrds) {
306
            return $this->xrds->services();
307
        }
308
 
309
        return null;
310
    }
311
}
312
 
313
?>