some cleaning, removed config.html for admin
[moodle.git] / blog / class.HttpClient.php
1 <?php
3 /* Version 0.9, 6th April 2003 - Simon Willison ( http://simon.incutio.com/ )
4    Manual: http://scripts.incutio.com/httpclient/
5 */
7 class HttpClient {
8     // Request vars
9     var $host;
10     var $port;
11     var $path;
12     var $method;
13     var $postdata = '';
14     var $cookies = array();
15     var $referer;
16     var $accept = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
17     var $accept_encoding = 'gzip';
18     var $accept_language = 'en-us';
19     var $user_agent = 'Incutio HttpClient v0.9';
20     // Options
21     var $timeout = 20;
22     var $use_gzip = true;
23     var $persist_cookies = true;  // If true, received cookies are placed in the $this->cookies array ready for the next request
24                                   // Note: This currently ignores the cookie path (and time) completely. Time is not important, 
25                                   //       but path could possibly lead to security problems.
26     var $persist_referers = true; // For each request, sends path of last request as referer
27     var $debug = false;
28     var $handle_redirects = true; // Auaomtically redirect if Location or URI header is found
29     var $max_redirects = 5;
30     var $headers_only = false;    // If true, stops receiving once headers have been read.
31     // Basic authorization variables
32     var $username;
33     var $password;
34     // Response vars
35     var $status;
36     var $headers = array();
37     var $content = '';
38     var $errormsg;
39     // Tracker variables
40     var $redirect_count = 0;
41     var $cookie_host = '';
42     function HttpClient($host, $port=80) {
43         $this->host = $host;
44         $this->port = $port;
45     }
46     function get($path, $data = false) {
47         $this->path = $path;
48         $this->method = 'GET';
49         if ($data) {
50             $this->path .= '?'. $this->buildQueryString($data);
51         }
52         return $this->doRequest();
53     }
54     function post($path, $data) {
55         $this->path = $path;
56         $this->method = 'POST';
57         $this->postdata = $this->buildQueryString($data);
58         return $this->doRequest();
59     }
60     function buildQueryString($data) {
61         $querystring = '';
62         if (is_array($data)) {
63             // Change data in to postable data
64             foreach ($data as $key => $val) {
65                 if (is_array($val)) {
66                     foreach ($val as $val2) {
67                         $querystring .= urlencode($key) .'='. urlencode($val2) .'&';
68                     }
69                 } else {
70                     $querystring .= urlencode($key) .'='. urlencode($val) .'&';
71                 }
72             }
73             $querystring = substr($querystring, 0, -1); // Eliminate unnecessary &
74         } else {
75             $querystring = $data;
76         }
77         return $querystring;
78     }
79     function doRequest() {
80         // Performs the actual HTTP request, returning true or false depending on outcome
81         if (!$fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout)) {
82             // Set error message
83             switch($errno) {
84                 case -3:
85                     $this->errormsg = 'Socket creation failed (-3)';
86                 case -4:
87                     $this->errormsg = 'DNS lookup failure (-4)';
88                 case -5:
89                     $this->errormsg = 'Connection refused or timed out (-5)';
90                 default:
91                     $this->errormsg = 'Connection failed ('. $errno .')';
92                 $this->errormsg .= ' '. $errstr;
93                 $this->debug($this->errormsg);
94             }
95             return false;
96         }
97         socket_set_timeout($fp, $this->timeout);
98         $request = $this->buildRequest();
99         $this->debug('Request', $request);
100         fwrite($fp, $request);
101         // Reset all the variables that should not persist between requests
102         $this->headers = array();
103         $this->content = '';
104         $this->errormsg = '';
105         // Set a couple of flags
106         $inHeaders = true;
107         $atStart = true;
108         // Now start reading back the response
109         while (!feof($fp)) {
110             $line = fgets($fp, 4096);
111             if ($atStart) {
112                 // Deal with first line of returned data
113                 $atStart = false;
114                 if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m)) {
115                     $this->errormsg = 'Status code line invalid: '. htmlentities($line);
116                     $this->debug($this->errormsg);
117                     return false;
118                 }
119                 $http_version = $m[1]; // not used
120                 $this->status = $m[2];
121                 $status_string = $m[3]; // not used
122                 $this->debug(trim($line));
123                 continue;
124             }
125             if ($inHeaders) {
126                 if (trim($line) == '') {
127                     $inHeaders = false;
128                     $this->debug('Received Headers', $this->headers);
129                     if ($this->headers_only) {
130                         break; // Skip the rest of the input
131                     }
132                     continue;
133                 }
134                 if (!preg_match('/([^:]+):\\s*(.*)/', $line, $m)) {
135                     // Skip to the next header
136                     continue;
137                 }
138                 $key = strtolower(trim($m[1]));
139                 $val = trim($m[2]);
140                 // Deal with the possibility of multiple headers of same name
141                 if (isset($this->headers[$key])) {
142                     if (is_array($this->headers[$key])) {
143                         $this->headers[$key][] = $val;
144                     } else {
145                         $this->headers[$key] = array($this->headers[$key], $val);
146                     }
147                 } else {
148                     $this->headers[$key] = $val;
149                 }
150                 continue;
151             }
152             // We're not in the headers, so append the line to the contents
153             $this->content .= $line;
154         }
155         fclose($fp);
156         // If data is compressed, uncompress it
157         if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] == 'gzip') {
158             $this->debug('Content is gzip encoded, unzipping it');
159             $this->content = substr($this->content, 10); // See http://www.php.net/manual/en/function.gzencode.php
160             $this->content = gzinflate($this->content);
161         }
162         // If $persist_cookies, deal with any cookies
163         if ($this->persist_cookies && isset($this->headers['set-cookie']) && $this->host == $this->cookie_host) {
164             $cookies = $this->headers['set-cookie'];
165             if (!is_array($cookies)) {
166                 $cookies = array($cookies);
167             }
168             foreach ($cookies as $cookie) {
169                 if (preg_match('/([^=]+)=([^;]+);/', $cookie, $m)) {
170                     $this->cookies[$m[1]] = $m[2];
171                 }
172             }
173             // Record domain of cookies for security reasons
174             $this->cookie_host = $this->host;
175         }
176         // If $persist_referers, set the referer ready for the next request
177         if ($this->persist_referers) {
178             $this->debug('Persisting referer: '. $this->getRequestURL());
179             $this->referer = $this->getRequestURL();
180         }
181         // Finally, if handle_redirects and a redirect is sent, do that
182         if ($this->handle_redirects) {
183             if (++$this->redirect_count >= $this->max_redirects) {
184                 $this->errormsg = 'Number of redirects exceeded maximum ('. $this->max_redirects .')';
185                 $this->debug($this->errormsg);
186                 $this->redirect_count = 0;
187                 return false;
188             }
189             $location = isset($this->headers['location']) ? $this->headers['location'] : '';
190             $uri = isset($this->headers['uri']) ? $this->headers['uri'] : '';
191             if ($location || $uri) {
192                 $url = parse_url($location.$uri);
193                 // This will FAIL if redirect is to a different site
194                 return $this->get($url['path']);
195             }
196         }
197         return true;
198     }
199     function buildRequest() {
200         $headers = array();
201         $headers[] = "{$this->method} {$this->path} HTTP/1.0"; // Using 1.1 leads to all manner of problems, such as "chunked" encoding
202         $headers[] = 'Host: '. $this->host;
203         $headers[] = 'User-Agent: '. $this->user_agent;
204         $headers[] = 'Accept: '. $this->accept;
205         if ($this->use_gzip) {
206             $headers[] = 'Accept-encoding: '. $this->accept_encoding;
207         }
208         $headers[] = 'Accept-language: '. $this->accept_language;
209         if ($this->referer) {
210             $headers[] = 'Referer: '. $this->referer;
211         }
212         // Cookies
213         if ($this->cookies) {
214             $cookie = 'Cookie: ';
215             foreach ($this->cookies as $key => $value) {
216                 $cookie .= "$key=$value; ";
217             }
218             $headers[] = $cookie;
219         }
220         // Basic authentication
221         if ($this->username && $this->password) {
222             $headers[] = 'Authorization: BASIC '. base64_encode($this->username .':'. $this->password);
223         }
224         // If this is a POST, set the content type and length
225         if ($this->postdata) {
226             $headers[] = 'Content-Type: application/x-www-form-urlencoded';
227             $headers[] = 'Content-Length: '. strlen($this->postdata);
228         }
229         $request = implode("\r\n", $headers) ."\r\n\r\n". $this->postdata;
230         return $request;
231     }
232     function getStatus() {
233         return $this->status;
234     }
235     function getContent() {
236         return $this->content;
237     }
238     function getHeaders() {
239         return $this->headers;
240     }
241     function getHeader($header) {
242         $header = strtolower($header);
243         if (isset($this->headers[$header])) {
244             return $this->headers[$header];
245         } else {
246             return false;
247         }
248     }
249     function getError() {
250         return $this->errormsg;
251     }
252     function getCookies() {
253         return $this->cookies;
254     }
255     function getRequestURL() {
256         $url = 'http://'. $this->host;
257         if ($this->port != 80) {
258             $url .= ':'. $this->port;
259         }            
260         $url .= $this->path;
261         return $url;
262     }
263     // Setter methods
264     function setUserAgent($string) {
265         $this->user_agent = $string;
266     }
267     function setAuthorization($username, $password) {
268         $this->username = $username;
269         $this->password = $password;
270     }
271     function setCookies($array) {
272         $this->cookies = $array;
273     }
274     // Option setting methods
275     function useGzip($boolean) {
276         $this->use_gzip = $boolean;
277     }
278     function setPersistCookies($boolean) {
279         $this->persist_cookies = $boolean;
280     }
281     function setPersistReferers($boolean) {
282         $this->persist_referers = $boolean;
283     }
284     function setHandleRedirects($boolean) {
285         $this->handle_redirects = $boolean;
286     }
287     function setMaxRedirects($num) {
288         $this->max_redirects = $num;
289     }
290     function setHeadersOnly($boolean) {
291         $this->headers_only = $boolean;
292     }
293     function setDebug($boolean) {
294         $this->debug = $boolean;
295     }
296     // "Quick" static methods
297     function quickGet($url) {
298         $bits = parse_url($url);
299         $host = $bits['host'];
300         $port = isset($bits['port']) ? $bits['port'] : 80;
301         $path = isset($bits['path']) ? $bits['path'] : '/';
302         if (isset($bits['query'])) {
303             $path .= '?'. $bits['query'];
304         }
305         $client = new HttpClient($host, $port);
306         if (!$client->get($path)) {
307             return false;
308         } else {
309             return $client->getContent();
310         }
311     }
312     function quickPost($url, $data) {
313         $bits = parse_url($url);
314         $host = $bits['host'];
315         $port = isset($bits['port']) ? $bits['port'] : 80;
316         $path = isset($bits['path']) ? $bits['path'] : '/';
317         $client = new HttpClient($host, $port);
318         if (!$client->post($path, $data)) {
319             return false;
320         } else {
321             return $client->getContent();
322         }
323     }
324     function debug($msg, $object = false) {
325         if ($this->debug) {
326             print '<div style="border: 1px solid red; padding: 0.5em; margin: 0.5em;"><strong>HttpClient Debug:</strong> '.$msg;
327             if ($object) {
328                 ob_start();
329                 print_r($object);
330                 $content = htmlentities(ob_get_contents());
331                 ob_end_clean();
332                 print '<pre>'. $content .'</pre>';
333             }
334             print '</div>';
335         }
336     }   
338 ?>