Quick Search:

View

Revision:

Diff

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