Removed 'base_path' from AkInstaller->setInstalledVersion because Ak:make_dir can...
[akelos.git] / vendor / domit / php_http_client_generic.php
blobb34f6d036d01a17b8640f02a0431391a31f87574
1 <?php
2 /**
3 * PHP HTTP Tools is a library for working with the http protocol
4 * php_http_client_generic represents a basic http client
5 * @package php-http-tools
6 * @version 0.2-pre
7 * @copyright (C) 2004 John Heinstein. All rights reserved
8 * @license http://www.gnu.org/copyleft/lesser.html LGPL License
9 * @author John Heinstein <johnkarl@nbnet.nb.ca>
10 * @link http://www.engageinteractive.com/php_http_tools/ PHP HTTP Tools Home Page
11 * PHP HTTP Tools are Free Software
12 **/
14 if (!defined('PHP_HTTP_TOOLS_INCLUDE_PATH')) {
15 define('PHP_HTTP_TOOLS_INCLUDE_PATH', (dirname(__FILE__) . "/"));
18 /** end-of-line character sequence as defined in HTTP spec */
19 define ('CRLF', "\r\n");
20 /** carriage return character */
21 define ('CR', "\r");
22 /** line feed character */
23 define ('LF', "\n");
25 //http read states for client
26 /** beginning read state */
27 define('HTTP_READ_STATE_BEGIN', 1);
28 /** state when reading headers */
29 define('HTTP_READ_STATE_HEADERS', 2);
30 /** state when reading body of message */
31 define('HTTP_READ_STATE_BODY', 3);
33 require_once(PHP_HTTP_TOOLS_INCLUDE_PATH . 'php_http_exceptions.php');
35 /**
37 * An HTTP Request class
39 * @package php-http-tools
40 * @author John Heinstein <johnkarl@nbnet.nb.ca>
42 class php_http_request {
43 /** @var object A reference to the headers object */
44 var $headers = null;
45 /** @var string The requested method, e.g. GET, POST, HEAD */
46 var $requestMethod = 'POST';
47 /** @var string The requested path */
48 var $requestPath = '';
49 /** @var string The requested protocol */
50 var $protocol = 'HTTP';
51 /** @var string The version of the requested protocol */
52 var $protocolVersion= '1.1';
54 /**
55 * Returns the headers object
56 * @return object The headers object
58 function &getHeaders() {
59 return $this->headers;
60 } //getHeaders
62 /**
63 * Sets the header to the specified value
64 * @param string The header name
65 * @param string The header value
66 * @param boolean True if multiple headers with the same name are allowed
68 function setHeader($name, $value, $allowMultipleHeaders = false) {
69 $this->headers->setHeader($name, $value, $allowMultipleHeaders);
70 } //setHeader
72 /**
73 * Default method for setting headers; meant to be overridden in subclasses
75 function setHeaders() {
76 //you will want to override this method
77 $this->setHeader('User-Agent', 'PHP-HTTP-Client(Generic)/0.1');
78 $this->setHeader('Connection', 'Close');
79 } //setHeaders
81 /**
82 * Sets the request method, e.g., GET
83 * @param string The name of the request method
84 * @return boolean True if the version number is valid
86 function setRequestMethod($method) {
87 $method = strtoupper($method);
89 switch ($method) {
90 case 'POST':
91 case 'GET':
92 case 'HEAD':
93 case 'PUT':
94 $this->requestMethod = $method;
95 return true;
96 break;
99 return false;
100 } //setRequestMethod
103 * Sets the request path, e.g., http://www.engageinteractive.com/domit/test.xml
104 * @param string The request path
106 function setRequestPath($path) {
107 $this->requestPath = $path;
108 } //setRequestPath
111 * Sets the version number of the protocol
112 * @param string The version number
113 * @return boolean True if the version number is valid
115 function setProtocolVersion($version) {
116 if (($version == '1.0') || ($version == '1.1')) {
117 $this->protocolVersion = $version;
118 return true;
121 return false;
122 } //setProtocolVersion
125 * Specifies a user name and password for basic authentication
126 * @param string The user name
127 * @param string The password
129 function setAuthorization($user, $password) {
130 $encodedChallengeResponse = 'Basic ' . base64_encode($this->user . ':' . $this->password);
131 $this->setHeader('Authorization', $encodedChallengeResponse);
132 } //setAuthorization
133 } //php_http_request
136 class php_http_client_generic extends php_http_request {
137 /** @var object A reference to the connection object */
138 var $connection;
139 /** @var string True if response headers are to be generated as an object */
140 var $responseHeadersAsObject = false;
141 /** @var object The http response */
142 var $response = null;
143 /** @var string A list of event names that can be fired by the client */
144 var $events = array('onRequest' => null, 'onRead' => null,
145 'onResponse' => null, 'onResponseHeaders' => null,
146 'onResponseBody' => null);
149 * HTTP Client constructor
150 * @param string The client connection host name, with or without its protocol prefix
151 * @param string The client connection path, not including the host name
152 * @param int The port to establish the client connection on
153 * @param int The timeout value for the client connection
155 function php_http_client_generic($host = '', $path = '/', $port = 80, $timeout = 0) {
156 $this->connection =& new php_http_connection($host, $path, $port, $timeout);
157 $this->headers =& new php_http_headers();
158 $this->requestPath = $path;
159 $this->response =& new php_http_response();
160 $this->setHeaders();
161 } //php_http_client_generic
164 * Specifies that the response headers array should be generated
165 * @param boolean True if the response headers array should be built
167 function generateResponseHeadersAsObject($responseHeadersAsObject) {
168 $this->responseHeadersAsObject = $responseHeadersAsObject;
170 if ($responseHeadersAsObject) {
171 $this->response->headers =& new php_http_headers();
173 } //generateResponseHeadersAsObject
176 * Fires an http event that has been registered
177 * @param string The name of the event, e.g., onRead
178 * @param string The data to be passed to the event
180 function fireEvent($target, $data) {
181 if ($this->events[$target] != null) {
182 call_user_func($this->events[$target], $data);
184 } //fireEvent
187 * Sets which http events are to be fired
188 * @param string The http event option to be set
189 * @param string True if the event is to be fired
190 * @param object A reference to a custom handler for the http event data
192 function setHTTPEvent($option, $truthVal, $customHandler = null) {
193 if ($customHandler != null) {
194 $handler =& $customHandler;
196 else {
197 $handler = array(&$this, 'defaultHTTPEventHandler');
200 switch($option) {
201 case 'onRequest':
202 case 'onRead':
203 case 'onResponse':
204 case 'onResponseHeaders':
205 case 'onResponseBody':
206 $truthVal ? ($this->events[$option] =& $handler) : ($this->events[$option] = null);
207 break;
209 } //setHTTPEvent
212 * Evaluates whether the specified http event option is active
213 * @param string The http event option to evaluate
214 * @return boolean True if the specified option is active
216 function getHTTPEvent($option) {
217 switch($option) {
218 case 'onRequest':
219 case 'onRead':
220 case 'onResponse':
221 case 'onResponseHeaders':
222 case 'onResponseBody':
223 return ($this->events[$option] != null);
224 break;
226 } //getHTTPEvent
229 * The default http event handler; fired if no custom handler has been registered
230 * @param string The event data
232 function defaultHTTPEventHandler($data) {
233 $this->printHTML($data);
234 } //defaultHTTPEventHandler
237 * Prints the data to the browser as preformatted, htmlentified output
238 * @param string The data to be printed
240 function printHTML($html) {
241 print('<pre>' . htmlentities($html) . '</pre>');
242 } //printHTML
245 * Establishes a client connection
247 function connect() {
248 if (!$this->headers->headerExists('Host')) {
249 $this->setHeader('Host', $this->connection->host);
252 return $this->connection->connect();
253 } //connect
256 * Disconnects the current client connection if one exists
258 function disconnect() {
259 return $this->connection->disconnect();
260 } //disconnect
263 * Evaluated whether the current client is connected
264 * @return boolean True if a connection exists
266 function isConnected() {
267 return $this->connection->isOpen();
268 } //isConnected
271 * Performs an HTTP GET
272 * @param string The target url
274 function &get($url) {
275 $this->setRequestMethod('GET');
276 $this->setRequestPath($url);
278 $this->get_custom($url);
280 $this->connect();
282 $result = $this->send('');
284 return $result;
285 } //get
288 * Handler for customizing the HTTP GET call
289 * @param string The target url
291 function get_custom($url) {
292 //do nothing; meant to be overridden
293 } //get_custom
296 * Performs an HTTP POST
297 * @param string The posted data
299 function &post($data) {
300 $this->setRequestMethod('POST');
301 $this->setHeader('Content-Type', 'text/html');
302 $this->post_custom($data);
304 $this->connect();
306 return $this->send($data);
307 } //post
310 * Handler for customizing the HTTP POST call
311 * @param string The post data
313 function post_custom($data) {
314 //do nothing; meant to be overridden
315 } //post_custom
318 * Performs an HTTP HEAD
319 * @param string The target url
321 function &head($url) {
322 $this->setRequestMethod('HEAD');
323 $this->head_custom($url);
325 $this->connect();
327 return $this->send('');
328 } //head
331 * Handler for customizing the HTTP HEAD call
332 * @param string The target url
334 function head_custom($url) {
335 //do nothing; meant to be overridden
336 } //head_custom
339 * Sends data through the client connection
340 * @return string The body of the http response
342 function &send($message) {
343 $conn =& $this->connection;
345 if ($conn->isOpen()) {
346 //build header info
347 $request = $this->requestMethod . ' ' . $this->requestPath . ' ' . $this->protocol .
348 '/' . $this->protocolVersion . CRLF;
349 $request .= $this->headers->toString() . CRLF;
350 $request .= $message;
352 //init variables
353 $response = $headers = $body = '';
354 $readState = HTTP_READ_STATE_BEGIN;
356 $this->fireEvent('onRequest', $request);
358 //send request
359 $connResource =& $conn->connection;
360 fputs ($connResource, $request);
362 //read response
363 while (!feof($connResource)) {
364 $data = fgets($connResource, 4096);
365 $this->fireEvent('onRead', $data);
367 switch ($readState) {
368 case HTTP_READ_STATE_BEGIN:
369 $this->response->statusLine = $data;
370 $readState = HTTP_READ_STATE_HEADERS;
371 break;
373 case HTTP_READ_STATE_HEADERS:
374 if (trim($data) == '') { //end of headers is signalled by a blank line
375 $readState = HTTP_READ_STATE_BODY;
377 else {
378 if ($this->responseHeadersAsObject) {
379 $this->response->setUnformattedHeader($data);
381 else {
382 $this->response->headers .= $data;
385 break;
387 case HTTP_READ_STATE_BODY:
388 $this->response->message .= $data;
389 break;
393 $this->normalizeResponseIfChunked();
395 $headerString = is_object($this->response->headers) ?
396 $this->response->headers->toString() : $this->response->headers;
398 $this->fireEvent('onResponseHeaders', $headerString);
399 $this->fireEvent('onResponseBody', $this->response->message);
401 $this->fireEvent('onResponse', $this->response->headers . $this->response->message);
403 return $this->response;
405 else {
406 HTTPExceptions::raiseException(HTTP_SOCKET_CONNECTION_ERR, ('HTTP Transport Error - Unable to establish connection to host ' .
407 $conn->host));
409 } //send
412 * Determines if response data is transfer encoding chunked, then decodes
414 function normalizeResponseIfChunked() {
415 if (($this->protocolVersion = '1.1') && (!$this->response->isResponseChunkDecoded)) {
416 if ($this->responseHeadersAsObject) {
417 if ($this->response->headers->headerExists('Transfer-Encoding') &&
418 ($this->response->headers->getHeader('Transfer-Encoding') == 'chunked')) {
419 $this->response->message = $this->decodeChunkedData($this->response->getResponse());
420 $this->response->isResponseChunkDecoded = true;
423 else {
424 if ((strpos($this->response->headers, 'Transfer-Encoding') !== false) &&
425 (strpos($this->response->headers, 'chunked') !== false)){
426 $this->response->message = $this->decodeChunkedData($this->response->getResponse());
427 $this->response->isResponseChunkDecoded = true;
431 } //normalizeResponseIfChunked
434 * Decodes data if transfer encoding chunked
435 * @param string The encoded data
436 * @return string The decoded data
438 function decodeChunkedData($data) {
439 $chunkStart = $chunkEnd = strpos($data, CRLF) + 2;
440 $chunkLengthInHex = substr($data, 0, $chunkEnd);
441 $chunkLength = hexdec(trim($chunkLengthInHex));
443 $decodedData = '';
445 while ($chunkLength > 0) {
446 $chunkEnd = strpos($data, CRLF, ($chunkStart + $chunkLength));
448 if (!$chunkEnd) {
449 //if the trailing CRLF is missing, return all the remaining data
450 $decodedData .= substr($data, $chunkStart);
451 break;
454 $decodedData .= substr($data, $chunkStart, ($chunkEnd - $chunkStart));
455 $chunkStart = $chunkEnd + 2;
456 $chunkEnd = strpos($data, CRLF, $chunkStart) + 2;
458 if (!$chunkEnd) break;
460 $chunkLengthInHex = substr($data, $chunkStart, ($chunkEnd - $chunkStart));
461 $chunkLength = hexdec(trim($chunkLengthInHex));
462 $chunkStart = $chunkEnd;
465 return $decodedData;
466 } //decodeChunkedData
467 } //php_http_client_generic
471 * An HTTP Connection class
473 * @package php-http-tools
474 * @author John Heinstein <johnkarl@nbnet.nb.ca>
476 class php_http_connection {
477 /** @var object A reference to the current connection */
478 var $connection = null;
479 /** @var string The host of the connection */
480 var $host;
481 /** @var string The path of the connection */
482 var $path;
483 /** @var int The port of the connection */
484 var $port;
485 /** @var int The timeout value for the connection */
486 var $timeout;
487 /** @var int The error number of the connection */
488 var $errorNumber = 0;
489 /** @var string The error string of the connection */
490 var $errorString = '';
493 * HTTP Connection constructor
494 * @param string The connection host name, with or without its protocol prefix
495 * @param string The connection path, not including the host name
496 * @param int The port to establish the client connection on
497 * @param int The timeout value for the client connection
499 function php_http_connection($host = '', $path = '/', $port = 80, $timeout = 0) {
500 $this->host = $this->formatHost($host);
501 $this->path = $this->formatPath($path);
502 $this->port = $port;
503 $this->timeout = $timeout;
504 } //php_http_connection
507 * Formats a host string by stripping off the http:// prefix
508 * @param string The host name
509 * @return string The formatted host name
511 function formatHost($hostString) {
512 $hasProtocol = (substr(strtoupper($hostString), 0, 7) == 'HTTP://');
514 if ($hasProtocol) {
515 $hostString = substr($hostString, 7);
518 return $hostString;
519 } //formatHost
522 * Formats a path string
523 * @param string The path
524 * @return string The formatted path
526 function formatPath($pathString) {
527 if (($pathString == '') || ($pathString == null)) {
528 $pathString = '/';
531 return $pathString;
532 } //formatPath
535 * Establishes a socket connection
536 * @return boolean True if the connection was successful
538 function connect() {
539 if ($this->timeout == 0) {
540 $this->connection = @fsockopen($this->host, $this->port, $errorNumber, $errorString);
542 else {
543 $this->connection = @fsockopen($this->host, $this->port, $errorNumber, $errorString, $this->timeout);
546 $this->errorNumber = $errorNumber;
547 $this->errorString = $errorString;
549 return is_resource($this->connection);
550 } //connect
553 * Determines whether the connection is still open
554 * @return boolean True if the connection is still open
556 function isOpen() {
557 return (is_resource($this->connection) && (!feof($this->connection)));
558 } //isOpen
561 * Disconnects the current connection
562 * @return boolean True if the connection has been disconnected
564 function disconnect() {
565 fclose($this->connection);
566 $this->connection = null;
567 return true;
568 } //disconnect
569 } //php_http_connection
572 * An HTTP Headers class
574 * @package php-http-tools
575 * @author John Heinstein <johnkarl@nbnet.nb.ca>
577 class php_http_headers {
578 /** @var object An array of headers */
579 var $headers;
582 * HTTP Headers constructor
584 function php_http_headers() {
585 $this->headers = array();
586 } //php_http_headers
589 * Returns the specified header value
590 * @param string The header name
591 * @return mixed The header value, or an array of header values
593 function &getHeader($name) {
594 if ($this->headerExists($name)) {
595 return $this->headers[$name];
598 return false;
599 } //getHeader
602 * Sets the named header to the specified value
603 * @param string The header name
604 * @param string The header value
605 * @param boolean True if multiple headers with the same name are allowed
607 function setHeader($name, $value, $allowMultipleHeaders = false) {
608 if ($allowMultipleHeaders) {
609 if (isset($this->headers[$name])) {
610 if (is_array($this->headers[$name])) {
611 $this->headers[$name][count($this->headers)] = $value;
613 else {
614 $tempVal = $this->headers[$name];
615 $this->headers[$name] = array($tempVal, $value);
618 else {
619 $this->headers[$name] = array();
620 $this->headers[$name][0] = $value;
623 else {
624 $this->headers[$name] = $value;
626 } //setHeader
629 * Determines whether the specified header exists
630 * @param string The header name
631 * @return boolean True if the specified header exists
633 function headerExists($name) {
634 return isset($this->headers[$name]);
635 } //headerExists
638 * Removes the specified header
639 * @param string The header name
640 * @return boolean True if the specified header has been removed
642 function removeHeader($name) {
643 if ($this->headerExists($name)) {
644 unset($this->headers[$name]);
645 return true;
648 return false;
649 } //removeHeader
652 * Returns a reference to the headers array
653 * @return array The headers array
655 function getHeaders() {
656 return $this->headers;
657 } //getHeaders
660 * Returns a list of existing headers names
661 * @return array A list of existing header names
663 function getHeaderList() {
664 return array_keys($this->headers);
665 } //getHeaderList
668 * Returns a string representation of the headers array
669 * @return string A string representation of the headers array
671 function toString() {
672 $retString = '';
674 foreach ($this->headers as $key => $value) {
675 if (is_array($value)) {
676 foreach ($value as $key2 => $value2) {
677 $retString .= $key . ': ' . $value2 . CRLF;
680 else {
681 $retString .= $key . ': ' . $value . CRLF;
685 return $retString;
686 } //toString
687 } //php_http_headers
690 * An HTTP Response class
692 * @package php-http-tools
693 * @author John Heinstein <johnkarl@nbnet.nb.ca>
695 class php_http_response {
696 /** @var string Response number */
697 var $statusLine = '';
698 /** @var mixed Response headers, either as object or string */
699 var $headers = '';
700 /** @var string Response message */
701 var $message = '';
702 /** @var boolean True if the chunked transfer-encoding of the response has been decoded */
703 var $isResponseChunkDecoded = false;
706 * Returns a reference to the headers array
707 * @return array The headers array
709 function getResponse() {
710 return $this->message;
711 } //getResponse
714 * Returns the response status line
715 * @return string The response status line
717 function getStatusLine() {
718 return $this->statusLine;
719 } //getStatusLine
722 * Returns the response status code
723 * @return int The response status code
725 function getStatusCode() {
726 $statusArray = split(' ', $this->statusLine);
728 if (count($statusArray > 1)) {
729 return intval($statusArray[1], 10);
732 return -1;
733 } //getStatusCode
736 * Returns a reference to the headers array
737 * @return array The headers array
739 function &getHeaders() {
740 return $this->headers;
741 } //getHeaders
744 * Converts a header string into a key value pair and sets header
746 function setUnformattedHeader($headerString) {
747 $colonIndex = strpos($headerString, ':');
749 if ($colonIndex !== false) {
750 $key = trim(substr($headerString, 0, $colonIndex));
751 $value = trim(substr($headerString, ($colonIndex + 1)));
752 $this->headers->setHeader($key, $value, true);
754 } //setUnformattedHeader
755 } //php_http_response