Quick Search:

View

Revision:

Diff

Diff from 1 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/osCommerce/trunk/oscommerce/includes/classes/http_client.php

Annotated File View

hpdl
1
1 <?php
2 /*
3   $Id: http_client.php,v 1.1 2002/11/01 02:26:03 hpdl Exp $
4
5   osCommerce, Open Source E-Commerce Solutions
6   http://www.oscommerce.com
7
8   Copyright (c) 2002 osCommerce
9
10   Released under the GNU General Public License
11
12   Copyright 2001 Leo West <west_leo@yahoo-REMOVE-.com> Net_HTTP_Client v0.6
13
14   Minimal Example:
15
16   $http = new httpClient();
17   $http->Connect("somehost", 80) or die("Connect problem");
18   $status = $http->Get("/index.html");
19   if ($status != 200) {
20     die("Problem : " . $http->getStatusMessage());
21   } else {
22     echo $http->getBody();
23   }
24   $http->Disconnect();
25
26   Persistent Example:
27
28   $http = new httpClient("dir.yahoo.com", 80);
29   $http->addHeader("Host", "dir.yahoo.com");
30   $http->addHeader("Connection", "keep-alive");
31
32   if ($http->Get("/Reference/Libraries/") == 200) $page1 = $http->getBody();
33   if ($http->Get("/News_and_Media/") == 200 ) $page2 = $http->getBody();
34   $http->disconnect();
35 */
36
37   class httpClient {
38     var $url; // array containg server URL, similar to parseurl() returned array
39     var $reply; // response code
40     var $replyString; // full response
41     var $protocolVersion = '1.1';
42     var $requestHeaders, $requestBody;
43     var $socket = false;
44 // proxy stuff
45     var $useProxy = false;
46     var $proxyHost, $proxyPort;
47
48 /**
49  * httpClient constructor
50  * Note: when host and port are defined, the connection is immediate
51  * @seeAlso connect
52  **/
53     function httpClient($host = '', $port = '') {
54       if (tep_not_null($host)) {
55         $this->connect($host, $port);
56       }
57     }
58
59 /**
60  * turn on proxy support
61  * @param proxyHost proxy host address eg "proxy.mycorp.com"
62  * @param proxyPort proxy port usually 80 or 8080
63  **/
64     function setProxy($proxyHost, $proxyPort) {
65       $this->useProxy = true;
66       $this->proxyHost = $proxyHost;
67       $this->proxyPort = $proxyPort;
68     }
69
70 /**
71  * setProtocolVersion
72  * define the HTTP protocol version to use
73  * @param version string the version number with one decimal: "0.9", "1.0", "1.1"
74  * when using 1.1, you MUST set the mandatory headers "Host"
75  * @return boolean false if the version number is bad, true if ok
76  **/
77     function setProtocolVersion($version) {
78       if ( ($version > 0) && ($version <= 1.1) ) {
79         $this->protocolVersion = $version;
80         return true;
81       } else {
82         return false;
83       }
84     }
85
86 /**
87  * set a username and password to access a protected resource
88  * Only "Basic" authentication scheme is supported yet
89  * @param username string - identifier
90  * @param password string - clear password
91  **/
92     function setCredentials($username, $password) {
93       $this->addHeader('Authorization', 'Basic ' . base64_encode($username . ':' . $password));
94      }
95
96 /**
97  * define a set of HTTP headers to be sent to the server
98  * header names are lowercased to avoid duplicated headers
99  * @param headers hash array containing the headers as headerName => headerValue pairs
100  **/
101     function setHeaders($headers) {
102       if (is_array($headers)) {
103         reset($headers);
104         while (list($name, $value) = each($headers)) {
105           $this->requestHeaders[$name] = $value;
106         }
107       }
108     }
109
110 /**
111  * addHeader
112  * set a unique request header
113  * @param headerName the header name
114  * @param headerValue the header value, ( unencoded)
115  **/
116     function addHeader($headerName, $headerValue) {
117       $this->requestHeaders[$headerName] = $headerValue;
118     }
119
120 /**
121  * removeHeader
122  * unset a request header
123  * @param headerName the header name
124  **/
125     function removeHeader($headerName) {
126       unset($this->requestHeaders[$headerName]);
127     }
128
129 /**
130  * Connect
131  * open the connection to the server
132  * @param host string server address (or IP)
133  * @param port string server listening port - defaults to 80
134  * @return boolean false is connection failed, true otherwise
135  **/
136     function Connect($host, $port = '') {
137       $this->url['scheme'] = 'http';
138       $this->url['host'] = $host;
139       if (tep_not_null($port)) $this->url['port'] = $port;
140
141       return true;
142     }
143
144 /**
145  * Disconnect
146  * close the connection to the  server
147  **/
148     function Disconnect() {
149       if ($this->socket) fclose($this->socket);
150     }
151
152 /**
153  * head
154  * issue a HEAD request
155  * @param uri string URI of the document
156  * @return string response status code (200 if ok)
157  * @seeAlso getHeaders()
158  **/
159     function Head($uri) {
160       $this->responseHeaders = $this->responseBody = '';
161
162       $uri = $this->makeUri($uri);
163
164       if ($this->sendCommand('HEAD ' . $uri . ' HTTP/' . $this->protocolVersion)) {
165         $this->processReply();
166       }
167
168       return $this->reply;
169     }
170
171 /**
172  * get
173  * issue a GET http request
174  * @param uri URI (path on server) or full URL of the document
175  * @return string response status code (200 if ok)
176  * @seeAlso getHeaders(), getBody()
177  **/
178     function Get($url) {
179       $this->responseHeaders = $this->responseBody = '';
180
181       $uri = $this->makeUri($url);
182
183       if ($this->sendCommand('GET ' . $uri . ' HTTP/' . $this->protocolVersion)) {
184         $this->processReply();
185       }
186
187       return $this->reply;
188     }
189
190 /**
191  * Post
192  * issue a POST http request
193  * @param uri string URI of the document
194  * @param query_params array parameters to send in the form "parameter name" => value
195  * @return string response status code (200 if ok)
196  * @example 
197  * $params = array( "login" => "tiger", "password" => "secret" );
198  * $http->post( "/login.php", $params );
199  **/
200     function Post($uri, $query_params = '') {
201       $uri = $this->makeUri($uri);
202
203       if (is_array($query_params)) {
204         $postArray = array();
205         reset($query_params);
206         while (list($k, $v) = each($query_params)) {
207           $postArray[] = urlencode($k) . '=' . urlencode($v);
208         }
209
210         $this->requestBody = implode('&', $postArray);
211       }
212
213 // set the content type for post parameters
214       $this->addHeader('Content-Type', 'application/x-www-form-urlencoded');
215
216       if ($this->sendCommand('POST ' . $uri . ' HTTP/' . $this->protocolVersion)) {
217         $this->processReply();
218       }
219
220       $this->removeHeader('Content-Type');
221       $this->removeHeader('Content-Length');
222       $this->requestBody = '';
223
224       return $this->reply;
225     }
226
227 /**
228  * Put
229  * Send a PUT request
230  * PUT is the method to sending a file on the server. it is *not* widely supported
231  * @param uri the location of the file on the server. dont forget the heading "/"
232  * @param filecontent the content of the file. binary content accepted
233  * @return string response status code 201 (Created) if ok
234  * @see RFC2518 "HTTP Extensions for Distributed Authoring WEBDAV"
235  **/
236     function Put($uri, $filecontent) {
237       $uri = $this->makeUri($uri);
238       $this->requestBody = $filecontent;
239
240       if ($this->sendCommand('PUT ' . $uri . ' HTTP/' . $this->protocolVersion)) {
241         $this->processReply();
242       }
243
244       return $this->reply;
245     }
246
247 /**
248  * getHeaders
249  * return the response headers
250  * to be called after a Get() or Head() call
251  * @return array headers received from server in the form headername => value
252  * @seeAlso get, head
253  **/
254     function getHeaders() {
255       return $this->responseHeaders;
256     }
257
258 /**
259  * getHeader
260  * return the response header "headername"
261  * @param headername the name of the header
262  * @return header value or NULL if no such header is defined
263  **/
264     function getHeader($headername) {
265       return $this->responseHeaders[$headername];
266     }
267
268 /**
269  * getBody
270  * return the response body
271  * invoke it after a Get() call for instance, to retrieve the response
272  * @return string body content
273  * @seeAlso get, head
274  **/
275     function getBody() {
276       return $this->responseBody;
277     }
278
279 /**
280  * getStatus return the server response's status code
281  * @return string a status code
282  * code are divided in classes (where x is a digit)
283  *  - 20x : request processed OK
284  *  - 30x : document moved
285  *  - 40x : client error ( bad url, document not found, etc...)
286  *  - 50x : server error 
287  * @see RFC2616 "Hypertext Transfer Protocol -- HTTP/1.1"
288  **/
289     function getStatus() {
290       return $this->reply;
291     }
292
293 /** 
294  * getStatusMessage return the full response status, of the form "CODE Message"
295  * eg. "404 Document not found"
296  * @return string the message 
297  **/
298     function getStatusMessage() {
299       return $this->replyString;
300     }
301
302 /**
303  * @scope only protected or private methods below
304  **/
305
306 /** 
307  * send a request
308  * data sent are in order
309  * a) the command
310  * b) the request headers if they are defined
311  * c) the request body if defined
312  * @return string the server repsonse status code
313  **/
314     function sendCommand($command) {
315       $this->responseHeaders = array();
316       $this->responseBody = '';
317
318 // connect if necessary
319       if ( ($this->socket == false) || (feof($this->socket)) ) {
320         if ($this->useProxy) {
321           $host = $this->proxyHost;
322           $port = $this->proxyPort;
323         } else {
324           $host = $this->url['host'];
325           $port = $this->url['port'];
326         }
327
328         if (!tep_not_null($port)) $port = 80;
329
330         if (!$this->socket = fsockopen($host, $port, $this->reply, $this->replyString)) {
331           return false;
332         }
333
334         if (tep_not_null($this->requestBody)) {
335           $this->addHeader('Content-Length', strlen($this->requestBody));
336         }
337
338         $this->request = $command;
339         $cmd = $command . "\r\n";
340         if (is_array($this->requestHeaders)) {
341           reset($this->requestHeaders);
342           while (list($k, $v) = each($this->requestHeaders)) {
343             $cmd .= $k . ': ' . $v . "\r\n";
344           }
345         }
346
347         if (tep_not_null($this->requestBody)) {
348           $cmd .= "\r\n" . $this->requestBody;
349         }
350
351 // unset body (in case of successive requests)
352         $this->requestBody = '';
353
354         fputs($this->socket, $cmd . "\r\n");
355
356         return true;
357       }
358     }
359
360     function processReply() {
361       $this->replyString = trim(fgets($this->socket, 1024));
362
363       if (preg_match('|^HTTP/\S+ (\d+) |i', $this->replyString, $a )) {
364         $this->reply = $a[1];
365       } else {
366         $this->reply = 'Bad Response';
367       }
368
369 //get response headers and body
370       $this->responseHeaders = $this->processHeader();
371       $this->responseBody = $this->processBody();
372
373       return $this->reply;
374     }
375
376 /**
377  * processHeader() reads header lines from socket until the line equals $lastLine
378  * @scope protected
379  * @return array of headers with header names as keys and header content as values
380  **/
381     function processHeader($lastLine = "\r\n") {
382       $headers = array();
383       $finished = false;
384
385       while ( (!$finished) && (!feof($this->socket)) ) {
386         $str = fgets($this->socket, 1024);
387         $finished = ($str == $lastLine);
388         if (!$finished) {
389           list($hdr, $value) = split(': ', $str, 2);
390 // nasty workaround broken multiple same headers (eg. Set-Cookie headers) @FIXME 
391           if (isset($headers[$hdr])) {
392             $headers[$hdr] .= '; ' . trim($value);
393           } else {
394             $headers[$hdr] = trim($value);
395           }
396         }
397       }
398
399       return $headers;
400     }
401
402 /**
403  * processBody() reads the body from the socket
404  * the body is the "real" content of the reply
405  * @return string body content 
406  * @scope private
407  **/
408     function processBody() {
409       $data = '';
410       $counter = 0;
411
412       do {
413         $status = socket_get_status($this->socket);
414         if ($status['eof'] == 1) {
415           break;
416         }
417
418         if ($status['unread_bytes'] > 0) {
419           $buffer = fread($this->socket, $status['unread_bytes']);
420           $counter = 0;
421         } else {
422           $buffer = fread($this->socket, 128);
423           $counter++;
424           usleep(2);
425         }
426
427         $data .= $buffer;
428       } while ( ($status['unread_bytes'] > 0) || ($counter++ < 10) );
429
430       return $data;
431     }
432
433 /**
434  * Calculate and return the URI to be sent ( proxy purpose )
435  * @param the local URI
436  * @return URI to be used in the HTTP request
437  * @scope private
438  **/
439     function makeUri($uri) {
440       $a = parse_url($uri);
441
442       if ( (isset($a['scheme'])) && (isset($a['host'])) ) {
443         $this->url = $a;
444       } else {
445         unset($this->url['query']);
446         unset($this->url['fragment']);
447         $this->url = array_merge($this->url, $a);
448       }
449
450       if ($this->useProxy) {
451         $requesturi = 'http://' . $this->url['host'] . (empty($this->url['port']) ? '' : ':' . $this->url['port']) . $this->url['path'] . (empty($this->url['query']) ? '' : '?' . $this->url['query']);
452       } else {
453         $requesturi = $this->url['path'] . (empty($this->url['query']) ? '' : '?' . $this->url['query']);
454       }
455
456       return $requesturi;
457     }
458   }
459 ?>
    \ No newline at end of file