1 : <?php
2 :
3 :
4 :
5 :
6 :
7 :
8 :
9 :
10 :
11 :
12 :
13 :
14 :
15 :
16 :
17 :
18 :
19 :
20 :
21 : class Requests {
22 :
23 :
24 :
25 :
26 :
27 : const POST = 'POST';
28 :
29 :
30 :
31 :
32 :
33 :
34 : const PUT = 'PUT';
35 :
36 :
37 :
38 :
39 :
40 :
41 : const GET = 'GET';
42 :
43 :
44 :
45 :
46 :
47 :
48 : const HEAD = 'HEAD';
49 :
50 :
51 :
52 :
53 :
54 :
55 : const DELETE = 'DELETE';
56 :
57 :
58 :
59 :
60 :
61 :
62 : const VERSION = '1.6-dev';
63 :
64 :
65 :
66 :
67 :
68 :
69 : protected static $transports = array();
70 :
71 :
72 :
73 :
74 :
75 :
76 :
77 :
78 : public static $transport = null;
79 :
80 :
81 :
82 :
83 :
84 :
85 : private function __construct() {}
86 :
87 :
88 :
89 :
90 :
91 :
92 :
93 :
94 :
95 :
96 :
97 :
98 :
99 : public static function autoloader($class) {
100 :
101 : if (strpos($class, 'Requests') !== 0) {
102 : return;
103 : }
104 :
105 : $file = str_replace('_', '/', $class);
106 : if (file_exists(dirname(__FILE__) . '/' . $file . '.php')) {
107 : require_once(dirname(__FILE__) . '/' . $file . '.php');
108 : }
109 : }
110 :
111 :
112 :
113 :
114 :
115 :
116 : public static function register_autoloader() {
117 : spl_autoload_register(array('Requests', 'autoloader'));
118 : }
119 :
120 :
121 :
122 :
123 :
124 :
125 : public static function add_transport($transport) {
126 0 : if (empty(self::$transports)) {
127 0 : self::$transports = array(
128 0 : 'Requests_Transport_cURL',
129 0 : 'Requests_Transport_fsockopen',
130 0 : );
131 0 : }
132 :
133 0 : self::$transports = array_merge(self::$transports, array($transport));
134 0 : }
135 :
136 :
137 :
138 :
139 :
140 :
141 :
142 : protected static function get_transport() {
143 :
144 :
145 : if (!is_null(self::$transport)) {
146 : return new self::$transport();
147 : }
148 :
149 :
150 1 : if (empty(self::$transports)) {
151 1 : self::$transports = array(
152 1 : 'Requests_Transport_cURL',
153 1 : 'Requests_Transport_fsockopen',
154 1 : );
155 1 : }
156 :
157 :
158 1 : foreach (self::$transports as $class) {
159 1 : if (!class_exists($class))
160 1 : continue;
161 :
162 1 : $result = call_user_func(array($class, 'test'));
163 1 : if ($result) {
164 1 : self::$transport = $class;
165 1 : break;
166 : }
167 1 : }
168 1 : if (self::$transport === null) {
169 0 : throw new Requests_Exception('No working transports found', 'notransport', self::$transports);
170 : }
171 :
172 1 : return new self::$transport();
173 : }
174 :
175 :
176 :
177 :
178 :
179 :
180 :
181 :
182 :
183 :
184 :
185 : public static function get($url, $headers = array(), $options = array()) {
186 120 : return self::request($url, $headers, null, self::GET, $options);
187 : }
188 :
189 :
190 :
191 :
192 : public static function head($url, $headers = array(), $options = array()) {
193 2 : return self::request($url, $headers, null, self::HEAD, $options);
194 : }
195 :
196 :
197 :
198 :
199 : public static function delete($url, $headers = array(), $options = array()) {
200 2 : return self::request($url, $headers, null, self::DELETE, $options);
201 : }
202 :
203 :
204 :
205 :
206 :
207 :
208 :
209 :
210 :
211 :
212 :
213 :
214 :
215 : public static function post($url, $headers = array(), $data = array(), $options = array()) {
216 6 : return self::request($url, $headers, $data, self::POST, $options);
217 : }
218 :
219 :
220 :
221 : public static function put($url, $headers = array(), $data = array(), $options = array()) {
222 6 : return self::request($url, $headers, $data, self::PUT, $options);
223 : }
224 :
225 :
226 :
227 :
228 :
229 :
230 :
231 :
232 :
233 :
234 :
235 :
236 :
237 :
238 :
239 :
240 :
241 :
242 :
243 :
244 :
245 :
246 :
247 :
248 :
249 :
250 :
251 :
252 :
253 :
254 :
255 :
256 :
257 :
258 :
259 :
260 :
261 :
262 :
263 :
264 :
265 :
266 : public static function request($url, $headers = array(), $data = array(), $type = self::GET, $options = array()) {
267 143 : if (!preg_match('/^http(s)?:\/\//i', $url)) {
268 1 : throw new Requests_Exception('Only HTTP requests are handled.', 'nonhttp', $url);
269 : }
270 : $defaults = array(
271 142 : 'timeout' => 10,
272 142 : 'useragent' => 'php-requests/' . self::VERSION,
273 142 : 'redirected' => 0,
274 142 : 'redirects' => 10,
275 142 : 'follow_redirects' => true,
276 142 : 'blocking' => true,
277 142 : 'type' => $type,
278 142 : 'filename' => false,
279 142 : 'auth' => false,
280 142 : 'idn' => true,
281 142 : 'hooks' => null,
282 142 : 'transport' => null,
283 142 : );
284 142 : $options = array_merge($defaults, $options);
285 :
286 142 : if (empty($options['hooks'])) {
287 142 : $options['hooks'] = new Requests_Hooks();
288 142 : }
289 :
290 :
291 142 : if (is_array($options['auth'])) {
292 2 : $options['auth'] = new Requests_Auth_Basic($options['auth']);
293 2 : }
294 142 : if ($options['auth'] !== false) {
295 4 : $options['auth']->register($options['hooks']);
296 4 : }
297 :
298 142 : $options['hooks']->dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options));
299 :
300 142 : if ($options['idn'] !== false) {
301 142 : $iri = new Requests_IRI($url);
302 142 : $iri->host = Requests_IDNAEncoder::encode($iri->ihost);
303 142 : $url = $iri->uri;
304 142 : }
305 :
306 142 : if (!empty($options['transport'])) {
307 141 : $transport = $options['transport'];
308 :
309 141 : if (is_string($options['transport'])) {
310 130 : $transport = new $transport();
311 130 : }
312 141 : }
313 : else {
314 1 : $transport = self::get_transport();
315 : }
316 142 : $response = $transport->request($url, $headers, $data, $options);
317 :
318 140 : $options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options));
319 :
320 140 : return self::parse_response($response, $url, $headers, $data, $options);
321 : }
322 :
323 :
324 :
325 :
326 :
327 :
328 :
329 :
330 :
331 :
332 :
333 :
334 :
335 :
336 :
337 : protected static function parse_response($headers, $url, $req_headers, $req_data, $options) {
338 140 : $return = new Requests_Response();
339 140 : if (!$options['blocking']) {
340 2 : return $return;
341 : }
342 :
343 138 : $return->url = $url;
344 :
345 138 : if (!$options['filename']) {
346 136 : if (strpos($headers, "\r\n\r\n") === false) {
347 :
348 1 : throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator');
349 : }
350 :
351 135 : $headers = explode("\r\n\r\n", $headers, 2);
352 135 : $return->body = array_pop($headers);
353 135 : $headers = $headers[0];
354 135 : }
355 : else {
356 2 : $return->body = '';
357 : }
358 :
359 137 : $headers = str_replace("\r\n", "\n", $headers);
360 :
361 137 : $headers = preg_replace('/\n[ \t]/', ' ', $headers);
362 137 : $headers = explode("\n", $headers);
363 137 : preg_match('#^HTTP/1\.\d[ \t]+(\d+)#i', array_shift($headers), $matches);
364 137 : if (empty($matches)) {
365 2 : throw new Requests_Exception('Response could not be parsed', 'noversion', $headers);
366 : }
367 135 : $return->status_code = (int) $matches[1];
368 135 : if ($return->status_code >= 200 && $return->status_code < 300) {
369 66 : $return->success = true;
370 66 : }
371 :
372 135 : foreach ($headers as $header) {
373 135 : list($key, $value) = explode(':', $header, 2);
374 135 : $value = trim($value);
375 135 : preg_replace('#(\s+)#i', ' ', $value);
376 135 : $return->headers[$key] = $value;
377 135 : }
378 135 : if (isset($return->headers['transfer-encoding'])) {
379 5 : $return->body = self::decode_chunked($return->body);
380 5 : unset($return->headers['transfer-encoding']);
381 5 : }
382 135 : if (isset($return->headers['content-encoding'])) {
383 2 : $return->body = self::decompress($return->body);
384 2 : }
385 :
386 :
387 135 : if (isset($return->headers['connection'])) {
388 133 : unset($return->headers['connection']);
389 133 : }
390 :
391 135 : if ((in_array($return->status_code, array(300, 301, 302, 303, 307)) || $return->status_code > 307 && $return->status_code < 400) && $options['follow_redirects'] === true) {
392 7 : if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) {
393 6 : if ($return->status_code === 303) {
394 0 : $options['type'] = Requests::GET;
395 0 : }
396 6 : $options['redirected']++;
397 6 : $location = $return->headers['location'];
398 6 : $redirected = self::request($location, $req_headers, $req_data, false, $options);
399 4 : $redirected->history[] = $return;
400 4 : return $redirected;
401 : }
402 3 : elseif ($options['redirected'] >= $options['redirects']) {
403 2 : throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return);
404 : }
405 1 : }
406 :
407 133 : $return->redirects = $options['redirected'];
408 :
409 133 : $options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options));
410 133 : return $return;
411 : }
412 :
413 :
414 :
415 :
416 :
417 :
418 :
419 :
420 : protected static function decode_chunked($data) {
421 5 : if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($data))) {
422 1 : return $data;
423 : }
424 :
425 4 : $decoded = '';
426 4 : $encoded = $data;
427 :
428 4 : while (true) {
429 4 : $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
430 4 : if (!$is_chunked) {
431 :
432 1 : return $data;
433 : }
434 :
435 4 : $length = hexdec(trim($matches[1]));
436 4 : if ($length === 0) {
437 :
438 1 : return $decoded;
439 : }
440 :
441 4 : $chunk_length = strlen($matches[0]);
442 4 : $decoded .= $part = substr($encoded, $chunk_length, $length);
443 4 : $encoded = substr($encoded, $chunk_length + $length + 2);
444 :
445 4 : if (trim($encoded) === '0' || empty($encoded)) {
446 2 : return $decoded;
447 : }
448 4 : }
449 :
450 :
451 :
452 : }
453 :
454 :
455 :
456 :
457 :
458 :
459 :
460 :
461 : public static function flattern($array) {
462 130 : $return = array();
463 130 : foreach ($array as $key => $value) {
464 8 : $return[] = "$key: $value";
465 130 : }
466 130 : return $return;
467 : }
468 :
469 :
470 :
471 :
472 :
473 :
474 :
475 :
476 :
477 :
478 :
479 : protected static function decompress($data) {
480 2 : if (substr($data, 0, 2) !== "\x1f\x8b") {
481 :
482 1 : return $data;
483 : }
484 :
485 1 : if (function_exists('gzdecode') && ($decoded = gzdecode($data)) !== false) {
486 0 : return $decoded;
487 : }
488 1 : elseif (function_exists('gzinflate') && ($decoded = @gzinflate($data)) !== false) {
489 0 : return $decoded;
490 : }
491 1 : elseif (($decoded = self::compatible_gzinflate($data)) !== false) {
492 1 : return $decoded;
493 : }
494 0 : elseif (function_exists('gzuncompress') && ($decoded = @gzuncompress($data)) !== false) {
495 0 : return $decoded;
496 : }
497 :
498 0 : return $data;
499 : }
500 :
501 :
502 :
503 :
504 :
505 :
506 :
507 :
508 :
509 :
510 :
511 :
512 :
513 :
514 : protected static function compatible_gzinflate($gzData) {
515 1 : if ( substr($gzData, 0, 3) == "\x1f\x8b\x08" ) {
516 1 : $i = 10;
517 1 : $flg = ord( substr($gzData, 3, 1) );
518 1 : if ( $flg > 0 ) {
519 0 : if ( $flg & 4 ) {
520 0 : list($xlen) = unpack('v', substr($gzData, $i, 2) );
521 0 : $i = $i + 2 + $xlen;
522 0 : }
523 0 : if ( $flg & 8 )
524 0 : $i = strpos($gzData, "\0", $i) + 1;
525 0 : if ( $flg & 16 )
526 0 : $i = strpos($gzData, "\0", $i) + 1;
527 0 : if ( $flg & 2 )
528 0 : $i = $i + 2;
529 0 : }
530 1 : return gzinflate( substr($gzData, $i, -8) );
531 : } else {
532 0 : return false;
533 : }
534 : }
|