]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Irc/extlib/phergie/Phergie/Plugin/Http.php
Added Phergie PHP IRC library
[quix0rs-gnu-social.git] / plugins / Irc / extlib / phergie / Phergie / Plugin / Http.php
1 <?php
2 /**
3  * Phergie 
4  *
5  * PHP version 5
6  *
7  * LICENSE
8  *
9  * This source file is subject to the new BSD license that is bundled
10  * with this package in the file LICENSE.
11  * It is also available through the world-wide-web at this URL:
12  * http://phergie.org/license
13  *
14  * @category  Phergie 
15  * @package   Phergie_Plugin_Http
16  * @author    Phergie Development Team <team@phergie.org>
17  * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
18  * @license   http://phergie.org/license New BSD License
19  * @link      http://pear.phergie.org/package/Phergie_Plugin_Http
20  */
21
22 /**
23  * Provides an HTTP client for plugins to use in contacting web services or 
24  * retrieving feeds or web pages.
25  *
26  * @category Phergie 
27  * @package  Phergie_Plugin_Http
28  * @author   Phergie Development Team <team@phergie.org>
29  * @license  http://phergie.org/license New BSD License
30  * @link     http://pear.phergie.org/package/Phergie_Plugin_Http
31  * @uses     extension simplexml optional
32  * @uses     extension json optional
33  */
34 class Phergie_Plugin_Http extends Phergie_Plugin_Abstract
35 {
36     /**
37      * Response to the last executed HTTP request
38      *
39      * @var Phergie_Plugin_Http_Response
40      */
41     protected $response;
42
43     /**
44      * Mapping of content types to handlers for them
45      *
46      * @var array
47      */
48     protected $handlers;
49     
50     /**
51      * Initializes the handler lookup table.
52      *
53      * @return void
54      */
55     public function onLoad()
56     {
57         $this->handlers = array(
58             '(?:application|text)/xml(?:;.*)?' => 'simplexml_load_string',
59             '(?:(?:application|text)/(?:x-)?json)|text/javascript.*' => 'json_decode',
60         );
61
62         if (is_array($this->config['http.handlers'])) {
63             $this->handlers = array_merge(
64                 $this->handlers,
65                 $this->config['http.handlers']
66             );
67         }
68     }
69
70     /**
71      * Sets a handler callback for a content type, which is called when a 
72      * response of that content type is received to perform any needed 
73      * transformations on the response body content before storing it in the 
74      * response object. Note that the calling plugin is responsible for 
75      * indicating any dependencies related to specified handler callbacks.
76      *
77      * @param string   $type     PCRE regular expression (without delimiters) that
78      *        matches one or more MIME types
79      * @param callback $callback Callback to execute when a response of a content
80      *        type matched by $type is encountered
81      *
82      * @return Phergie_Plugin_Http Provides a fluent interface
83      */
84     public function setHandler($type, $callback)
85     {
86         if (!is_callable($callback)) {
87             throw new Phergie_Plugin_Exception(
88                 'Invalid callback specified',
89                 Phergie_Plugin_Exception::ERR_FATAL_ERROR
90             );
91         }
92
93         $this->handlers[$type] = $callback;
94
95         return $this;
96     }
97
98     /**
99      * Supporting method that parses the status line of an HTTP response 
100      * message.
101      *
102      * @param string $status Status line
103      *
104      * @return array Associative array containing the HTTP version, response 
105      *         code, and response description
106      */
107     protected function parseStatusLine($status)
108     {
109         $parts = explode(' ', $status, 3);
110         $parsed = array(
111             'version' => str_replace('HTTP/', '', $parts[0]),
112             'code' => $parts[1],
113             'message' => rtrim($parts[2])
114         );
115         return $parsed;
116     }
117
118     /**
119      * Supporting method that acts as an error handler to intercept HTTP 
120      * responses resulting in PHP-level errors.
121      *
122      * @param int    $errno   Level of the error raised
123      * @param string $errstr  Error message
124      * @param string $errfile Name of the file in which the error was raised
125      * @param string $errline Line number on which the error was raised
126      *
127      * @return bool Always returns TRUE to allow normal execution to 
128      *         continue once this method terminates
129      */
130     protected function handleError($errno, $errstr, $errfile, $errline)
131     {
132         if ($httperr = strstr($errstr, 'HTTP/')) {
133             $parts = $this->parseStatusLine($httperr); 
134             $this->response
135                 ->setCode($parts['code'])
136                 ->setMessage($parts['message']);
137         }
138
139         return true;
140     }
141
142     /**
143      * Supporting method that executes a request and handles the response.
144      *
145      * @param string $url     URL to request
146      * @param array  $context Associative array of stream context parameters 
147      *
148      * @return Phergie_Plugin_Http_Response Object representing the response 
149      *         resulting from the request
150      */
151     public function request($url, array $context)
152     {
153         $this->response = new Phergie_Plugin_Http_Response;
154
155         $url = (string) $url;
156         $context = stream_context_create(array('http' => $context));
157
158         set_error_handler(array($this, 'handleError'), E_WARNING);
159         $stream = fopen($url, 'r', false, $context);
160         if ($stream) {
161             $meta = stream_get_meta_data($stream);
162             $status = $this->parseStatusLine($meta['wrapper_data'][0]);
163             $code = $status['code'];
164             $message = $status['message'];
165             $headers = array();
166             foreach (array_slice($meta['wrapper_data'], 1) as $header) {
167                 list($name, $value) = explode(': ', $header, 2);
168                 $headers[$name] = $value;
169             }
170             unset($meta['wrapper_data']);
171
172             $this->response
173                 ->setCode($code)
174                 ->setMessage($message)
175                 ->setHeaders($headers)
176                 ->setMeta($meta);
177  
178             $body = stream_get_contents($stream);
179             $type = $this->response->getHeaders('content-type');
180             foreach ($this->handlers as $expr => $handler) {
181                 if (preg_match('#^' . $expr . '$#i', $type)) {
182                     $body = call_user_func($handler, $body);
183                 }
184             }
185
186             $this->response->setContent($body);
187         }
188         restore_error_handler();
189
190         return $this->response;
191     }
192
193     /**
194      * Performs a GET request.
195      *
196      * @param string $url     URL for the request
197      * @param array  $query   Optional associative array of parameters
198      *        constituting the URL query string if $url has none
199      * @param array  $context Optional associative array of additional stream
200      *        context parameters
201      *
202      * @return Phergie_Plugin_Http_Response Received response data
203      */
204     public function get($url, array $query = array(), array $context = array())
205     {
206         if (!empty($query)) {
207             $url .= '?' . http_build_query($query);
208         }
209
210         $context['method'] = 'GET';
211
212         return $this->request($url, $context);
213     }
214
215     /**
216      * Performs a HEAD request.
217      *
218      * @param string $url     URL for the request
219      * @param array  $query   Optional associative array of parameters
220      *        constituting the URL query string if $url has none
221      * @param array  $context Optional associative array of additional stream 
222      *        context parameters
223      *
224      * @return Phergie_Plugin_Http_Response Received response data
225      */
226     public function head($url, array $query = array(), array $context = array())
227     {
228         if (!empty($query)) {
229             $url .= '?' . http_build_query($query);
230         }
231
232         $context['method'] = 'HEAD';
233
234         return $this->request($url, $context);
235     }
236
237     /**
238      * Performs a POST request.
239      *
240      * @param string $url     URL for the request
241      * @param array  $query   Optional associative array of parameters 
242      *        constituting the URL query string if $url has none
243      * @param array  $post    Optional associative array of parameters 
244      *        constituting the POST request body if it is using the 
245      *        traditional URL-encoded format
246      * @param array  $context Optional associative array of additional stream 
247      *        context parameters
248      *
249      * @return Phergie_Plugin_Http_Response Received response data
250      */
251     public function post($url, array $query = array(), array $post = array(), array $context = array())
252     {
253         if (!empty($params)) {
254             $url .= '?' . http_build_query($query);
255         }
256
257         $context['method'] = 'POST';
258
259         if (!empty($post) 
260             && (!empty($context['header'])
261             xor stripos($context['header'], 'Content-Type'))
262         ) {
263             if (!empty($context['header'])) {
264                 $context['header'] .= "\r\n";
265             } else {
266                 $context['header'] = '';
267             }
268             $context['header'] .= 
269                 'Content-Type: application/x-www-form-urlencoded';
270             $context['content'] = http_build_query($post);
271         }
272
273         return $this->request($url, $context);
274     }
275 }