]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Irc/extlib/phergie/Phergie/Plugin/Http.php
Documentation + filename uniqueness in File class
[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(?:;.*)?'
59                 => 'simplexml_load_string',
60             '(?:(?:application|text)/(?:x-)?json)|text/javascript.*'
61                 => 'json_decode',
62         );
63
64         if (is_array($this->config['http.handlers'])) {
65             $this->handlers = array_merge(
66                 $this->handlers,
67                 $this->config['http.handlers']
68             );
69         }
70     }
71
72     /**
73      * Sets a handler callback for a content type, which is called when a
74      * response of that content type is received to perform any needed
75      * transformations on the response body content before storing it in the
76      * response object. Note that the calling plugin is responsible for
77      * indicating any dependencies related to specified handler callbacks.
78      *
79      * @param string   $type     PCRE regular expression (without delimiters) that
80      *        matches one or more MIME types
81      * @param callback $callback Callback to execute when a response of a content
82      *        type matched by $type is encountered
83      *
84      * @return Phergie_Plugin_Http Provides a fluent interface
85      */
86     public function setHandler($type, $callback)
87     {
88         if (!is_callable($callback)) {
89             throw new Phergie_Plugin_Exception(
90                 'Invalid callback specified',
91                 Phergie_Plugin_Exception::ERR_FATAL_ERROR
92             );
93         }
94
95         $this->handlers[$type] = $callback;
96
97         return $this;
98     }
99
100     /**
101      * Supporting method that parses the status line of an HTTP response
102      * message.
103      *
104      * @param string $status Status line
105      *
106      * @return array Associative array containing the HTTP version, response
107      *         code, and response description
108      */
109     protected function parseStatusLine($status)
110     {
111         $parts = explode(' ', $status, 3);
112         $parsed = array(
113             'version' => str_replace('HTTP/', '', $parts[0]),
114             'code' => $parts[1],
115             'message' => rtrim($parts[2])
116         );
117         return $parsed;
118     }
119
120     /**
121      * Supporting method that acts as an error handler to intercept HTTP
122      * responses resulting in PHP-level errors.
123      *
124      * @param int    $errno   Level of the error raised
125      * @param string $errstr  Error message
126      * @param string $errfile Name of the file in which the error was raised
127      * @param string $errline Line number on which the error was raised
128      *
129      * @return bool Always returns TRUE to allow normal execution to
130      *         continue once this method terminates
131      */
132     public function handleError($errno, $errstr, $errfile, $errline)
133     {
134         if ($httperr = strstr($errstr, 'HTTP/')) {
135             $parts = $this->parseStatusLine($httperr);
136             $this->response
137                 ->setCode($parts['code'])
138                 ->setMessage($parts['message']);
139         }
140
141         return true;
142     }
143
144     /**
145      * Supporting method that executes a request and handles the response.
146      *
147      * @param string $url     URL to request
148      * @param array  $context Associative array of stream context parameters
149      *
150      * @return Phergie_Plugin_Http_Response Object representing the response
151      *         resulting from the request
152      */
153     public function request($url, array $context)
154     {
155         $this->response = new Phergie_Plugin_Http_Response;
156
157         $url = (string) $url;
158         $context = stream_context_create(array('http' => $context));
159
160         set_error_handler(array($this, 'handleError'), E_WARNING);
161         $stream = fopen($url, 'r', false, $context);
162         if ($stream) {
163             $meta = stream_get_meta_data($stream);
164             $status = $this->parseStatusLine($meta['wrapper_data'][0]);
165             $code = $status['code'];
166             $message = $status['message'];
167             $headers = array();
168             foreach (array_slice($meta['wrapper_data'], 1) as $header) {
169                 if (!strpos($header, ':')) {
170                     continue;
171                 }
172                 list($name, $value) = explode(': ', $header, 2);
173                 $headers[$name] = $value;
174             }
175             unset($meta['wrapper_data']);
176
177             $this->response
178                 ->setCode($code)
179                 ->setMessage($message)
180                 ->setHeaders($headers)
181                 ->setMeta($meta);
182
183             $body = stream_get_contents($stream);
184             $type = $this->response->getHeaders('content-type');
185             foreach ($this->handlers as $expr => $handler) {
186                 if (preg_match('#^' . $expr . '$#i', $type)) {
187                     $handled = call_user_func($handler, $body);
188                     if (!empty($handled)) {
189                         $body = $handled;
190                     }
191                 }
192             }
193
194             $this->response->setContent($body);
195         }
196         restore_error_handler();
197
198         return $this->response;
199     }
200
201     /**
202      * Performs a GET request.
203      *
204      * @param string $url     URL for the request
205      * @param array  $query   Optional associative array of parameters
206      *        constituting the URL query string if $url has none
207      * @param array  $context Optional associative array of additional stream
208      *        context parameters
209      *
210      * @return Phergie_Plugin_Http_Response Received response data
211      */
212     public function get($url, array $query = array(), array $context = array())
213     {
214         if (!empty($query)) {
215             $url .= '?' . http_build_query($query);
216         }
217
218         $context['method'] = 'GET';
219
220         return $this->request($url, $context);
221     }
222
223     /**
224      * Performs a HEAD request.
225      *
226      * @param string $url     URL for the request
227      * @param array  $query   Optional associative array of parameters
228      *        constituting the URL query string if $url has none
229      * @param array  $context Optional associative array of additional stream
230      *        context parameters
231      *
232      * @return Phergie_Plugin_Http_Response Received response data
233      */
234     public function head($url, array $query = array(), array $context = array())
235     {
236         if (!empty($query)) {
237             $url .= '?' . http_build_query($query);
238         }
239
240         $context['method'] = 'HEAD';
241
242         return $this->request($url, $context);
243     }
244
245     /**
246      * Performs a POST request.
247      *
248      * @param string $url     URL for the request
249      * @param array  $query   Optional associative array of parameters
250      *        constituting the URL query string if $url has none
251      * @param array  $post    Optional associative array of parameters
252      *        constituting the POST request body if it is using the
253      *        traditional URL-encoded format
254      * @param array  $context Optional associative array of additional stream
255      *        context parameters
256      *
257      * @return Phergie_Plugin_Http_Response Received response data
258      */
259     public function post($url, array $query = array(),
260         array $post = array(), array $context = array()
261     ) {
262         if (!empty($query)) {
263             $url .= '?' . http_build_query($query);
264         }
265
266         $context['method'] = 'POST';
267
268         if (!empty($post)
269             && (!empty($context['header'])
270             xor stripos($context['header'], 'Content-Type'))
271         ) {
272             if (!empty($context['header'])) {
273                 $context['header'] .= "\r\n";
274             } else {
275                 $context['header'] = '';
276             }
277             $context['header'] .=
278                 'Content-Type: application/x-www-form-urlencoded';
279             $context['content'] = http_build_query($post);
280         }
281
282         return $this->request($url, $context);
283     }
284 }