* @license http://opensource.org/licenses/bsd-license.php BSD
* @category Horde
* @package Horde_Http_Client
- *
- * @TODO - add support for http://pecl.php.net/package/pecl_http ?
*/
/**
class Horde_Http_Client
{
/**
- * URI to make our next request to
- * @var string
- */
- protected $_uri = null;
-
- /**
- * Request headers
- * @var array
- */
- protected $_headers = array();
-
- /**
- * Proxy server
- * @var string
- */
- protected $_proxyServer = null;
-
- /**
- * Proxy username
- * @var string
- */
- protected $_proxyUser = null;
-
- /**
- * Proxy password
- * @var string
+ * HTTP Adapter to use for transport
+ * @var Horde_Http_Client_Adapter
*/
- protected $_proxyPass = null;
+ protected $_adapter;
/**
- * HTTP timeout
- * @var fload
+ * The current HTTP request
+ * @var Horde_Http_Client_Request
*/
- protected $_timeout = 5;
+ protected $_request;
/**
- * The most recent HTTP request
- *
- * An array with these values:
- * 'uri'
- * 'method'
- * 'headers'
- * 'data'
- *
- * @var array
+ * The previous HTTP request
+ * @var Horde_Http_Client_Request
*/
protected $_lastRequest;
*
* @param array $args Any Http_Client settings to initialize in the
* constructor. Available settings are:
- * uri
- * headers
- * proxyServer
- * proxyUser
- * proxyPass
+ * adapter
+ * adapter.proxyServer
+ * adapter.proxyUser
+ * adapter.proxyPass
+ * adapter.timeout
+ * request
+ * request.uri
+ * request.headers
+ * request.method
+ * request.data
*/
public function __construct($args = array())
{
- if (!ini_get('allow_url_fopen')) {
- throw new Horde_Http_Client_Exception('allow_url_fopen must be enabled');
- }
-
- foreach ($args as $key => $val) {
- $this->$key = $val;
+ // Set or create adapter object
+ if (isset($args['adapter'])) {
+ $this->_adapter = $args['adapter'];
+ unset($args['adapter']);
+ } else {
+ $this->_adapter = $this->_createBestAvailableAdapter();
}
- }
- /**
- * Set one or more headers
- *
- * @param mixed $headers A hash of header + value pairs, or a single header name
- * @param string $value A header value
- */
- public function setHeaders($headers, $value = null)
- {
- if (!is_array($headers)) {
- $headers = array($headers => $value);
+ // Set or create request object
+ if (isset($args['request'])) {
+ $this->_request = $args['request'];
+ unset($args['request']);
+ } else {
+ $this->_request = new Horde_Http_Client_Request();
}
- foreach ($headers as $header => $value) {
- $this->_headers[$header] = $value;
+ foreach ($args as $key => $val) {
+ list($object, $objectkey) = explode('.', $key, 2);
+ $this->$object->$objectkey = $val;
}
}
/**
- * Get the current value of $header
- *
- * @param string $header Header name to get
- * @return string $header's current value
- */
- public function getHeader($header)
- {
- return isset($this->_headers[$header]) ? $this->_headers[$header] : null;
- }
-
- /**
* Send a GET request
*
* @return Horde_Http_Client_Response
*/
public function request($method, $uri = null, $data = null, $headers = array())
{
- if (is_null($uri)) {
- $uri = $this->uri;
+ if ($method !== null) {
+ $this->request->method = $method;
}
-
- if (is_array($data)) {
- $data = http_build_query($data, '', '&');
+ if ($uri !== null) {
+ $this->request->uri = $uri;
}
-
- $headers = array_merge($this->_headers, $headers);
-
- // Store the last request for ease of debugging.
- $this->_lastRequest = array(
- 'uri' => $uri,
- 'method' => $method,
- 'headers' => $headers,
- 'data' => $data,
- );
-
- $opts = array('http' => array());
- // Proxy settings - check first, so we can include the correct headers
- if ($this->proxyServer) {
- $opts['http']['proxy'] = 'tcp://' . $this->proxyServer;
- $opts['http']['request_fulluri'] = true;
- if ($this->proxyUser && $this->proxyPass) {
- $headers['Proxy-Authorization'] = 'Basic ' . base64_encode($this->proxyUser . ':' . $this->proxyPass);
- }
+ if ($data !== null) {
+ $this->request->data = $data;
}
-
- // Concatenate the headers
- $hdr = array();
- foreach ($headers as $header => $value) {
- $hdr[] = $header . ': ' . $value;
+ if (count($headers)) {
+ $this->request->setHeaders($headers);
}
- // Stream context config.
- $opts['http']['method'] = $method;
- $opts['http']['header'] = implode("\n", $hdr);
- $opts['http']['content'] = $data;
- $opts['http']['timeout'] = $this->_timeout;
-
- $context = stream_context_create($opts);
- $stream = @fopen($uri, 'rb', false, $context);
- if (!$stream) {
- throw new Horde_Http_Client_Exception('Problem with ' . $uri . ': ', error_get_last());
- }
-
- $meta = stream_get_meta_data($stream);
- $headers = isset($meta['wrapper_data']) ? $meta['wrapper_data'] : array();
-
- $this->_lastResponse = new Horde_Http_Client_Response($uri, $stream, $headers);
+ $this->_lastRequest = $this->_request;
+ $this->_lastResponse = $this->_adapter->send($this->_lastRequest);
return $this->_lastResponse;
}
*/
public function __set($name, $value)
{
- switch ($name) {
- case 'headers':
- $this->setHeaders($value);
- break;
- }
-
$this->{'_' . $name} = $value;
}
+ /**
+ * Find the best available adapter
+ *
+ * @return Horde_Http_Client_Adapter
+ */
+ public function _createBestAvailableAdapter()
+ {
+ /*if (class_exists('HttpRequest', false)) {
+ return new Horde_Http_Client_Adapter_Peclhttp();
+ } else*/if (extension_loaded('curl')) {
+ return new Horde_Http_Client_Adapter_Curl();
+ } elseif (ini_get('allow_url_fopen')) {
+ return new Horde_Http_Client_Adapter_Fopen();
+ } else {
+ throw new Horde_Http_Client_Exception('No HTTP adapters are available. You must install pecl_http, curl, or enable allow_url_fopen.');
+ }
+ }
}
--- /dev/null
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+class Horde_Http_Client_Adapter_Base
+{
+ /**
+ * Proxy server
+ * @var string
+ */
+ protected $_proxyServer = null;
+
+ /**
+ * Proxy username
+ * @var string
+ */
+ protected $_proxyUser = null;
+
+ /**
+ * Proxy password
+ * @var string
+ */
+ protected $_proxyPass = null;
+
+ /**
+ * HTTP timeout
+ * @var float
+ */
+ protected $_timeout = 5;
+
+ /**
+ * Constructor
+ */
+ public function __construct($args = array())
+ {
+ foreach ($args as $key => $value) {
+ $this->$key = $value;
+ }
+ }
+
+ /**
+ * Get an adapter parameter
+ *
+ * @param string $name The parameter to get.
+ * @return mixed Parameter value.
+ */
+ public function __get($name)
+ {
+ return isset($this->{'_' . $name}) ? $this->{'_' . $name} : null;
+ }
+
+ /**
+ * Set an adapter parameter
+ *
+ * @param string $name The parameter to set.
+ * @param mixed $value Parameter value.
+ */
+ public function __set($name, $value)
+ {
+ $this->{'_' . $name} = $value;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+class Horde_Http_Client_Adapter_Curl extends Horde_Http_Client_Adapter_Base
+{
+ public function __construct()
+ {
+ if (!extension_loaded('curl')) {
+ throw new Horde_Http_Client_Exception('The curl extension is not installed. See http://php.net/curl.installation');
+ }
+ }
+
+ /**
+ * Send an HTTP request
+ *
+ * @param Horde_Http_Client_Request HTTP Request object
+ *
+ * @return Horde_Http_Client_Response
+ */
+ public function send($request)
+ {
+ $body = tmpfile();
+ $headers = tmpfile();
+
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_URL, $request->uri);
+ curl_setopt($curl, CURLOPT_FILE, $body);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $request->data);
+ curl_setopt($curl, CURLOPT_WRITEHEADER, $headers);
+
+ $result = curl_exec($curl);
+
+ rewind($body);
+ rewind($headers);
+
+ return new Horde_Http_Client_Response($request->uri, $body, stream_get_contents($headers));
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+class Horde_Http_Client_Adapter_Fopen extends Horde_Http_Client_Adapter_Base
+{
+ public function __construct()
+ {
+ if (!ini_get('allow_url_fopen')) {
+ throw new Horde_Http_Client_Exception('allow_url_fopen must be enabled');
+ }
+ }
+
+ /**
+ * Send an HTTP request
+ *
+ * @param Horde_Http_Client_Request HTTP Request object
+ *
+ * @return Horde_Http_Client_Response
+ */
+ public function send($request)
+ {
+ $method = $request->method;
+ $uri = $request->uri;
+ $headers = $request->headers;
+ $data = $request->data;
+ if (is_array($data)) {
+ $data = http_build_query($data, '', '&');
+ }
+
+ $opts = array('http' => array());
+
+ // Proxy settings - check first, so we can include the correct headers
+ if ($this->proxyServer) {
+ $opts['http']['proxy'] = 'tcp://' . $this->proxyServer;
+ $opts['http']['request_fulluri'] = true;
+ if ($this->proxyUser && $this->proxyPass) {
+ $headers['Proxy-Authorization'] = 'Basic ' . base64_encode($this->proxyUser . ':' . $this->proxyPass);
+ }
+ }
+
+ // Concatenate the headers
+ $hdr = array();
+ foreach ($headers as $header => $value) {
+ $hdr[] = $header . ': ' . $value;
+ }
+
+ // Stream context config.
+ $opts['http']['method'] = $method;
+ $opts['http']['header'] = implode("\n", $hdr);
+ $opts['http']['content'] = $data;
+ $opts['http']['timeout'] = $this->timeout;
+
+ $context = stream_context_create($opts);
+ $stream = @fopen($uri, 'rb', false, $context);
+ if (!$stream) {
+ throw new Horde_Http_Client_Exception('Problem with ' . $uri . ': ', error_get_last());
+ }
+
+ $meta = stream_get_meta_data($stream);
+ $headers = isset($meta['wrapper_data']) ? $meta['wrapper_data'] : array();
+
+ return new Horde_Http_Client_Response($uri, $stream, $headers);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+class Horde_Http_Client_Adapter_Peclhttp extends Horde_Http_Client_Adapter_Base
+{
+ public static $methods = array(
+ 'GET' => HTTP_METH_GET,
+ 'HEAD' => HTTP_METH_HEAD,
+ 'POST' => HTTP_METH_POST,
+ 'PUT' => HTTP_METH_PUT,
+ 'DELETE' => HTTP_METH_DELETE,
+ );
+
+ public function __construct()
+ {
+ if (!class_exists('HttpRequest', false)) {
+ throw new Horde_Http_Client_Exception('The pecl_http extension is not installed. See http://php.net/http.install');
+ }
+ }
+
+ /**
+ * Send an HTTP request
+ *
+ * @param Horde_Http_Client_Request HTTP Request object
+ *
+ * @return Horde_Http_Client_Response
+ */
+ public function send($request)
+ {
+ $httpRequest = new HttpRequest($request->uri, self::$methods[$request->method]);
+ $httpRequest->setHeaders($request->headers);
+
+ $data = $request->data;
+ if (is_array($data)) {
+ $httpRequest->setPostFields($data);
+ } else {
+ $httpRequest->setRawPostData($dat);
+ }
+
+ try {
+ $httpResponse = $httpRequest->send();
+ } catch (HttpException $e) {
+ throw new Horde_Http_Client_Exception($e->getMessage(), $e->getCode(), $e);
+ }
+
+ /*@TODO build Horde_Http_Client_Response from $httpResponse */
+ return $httpResponse;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Http_Client
+ */
+class Horde_Http_Client_Request
+{
+ /**
+ * URI
+ * @var string
+ */
+ protected $_uri;
+
+ /**
+ * Request method
+ * @var string
+ */
+ protected $_method = 'GET';
+
+ /**
+ * Request headers
+ * @var array
+ */
+ protected $_headers = array();
+
+ /**
+ * Request data. Can be an array of form data that will be encoded
+ * automatically, or a raw string
+ * @var mixed
+ */
+ protected $_data;
+
+ /**
+ * Constructor
+ */
+ public function __construct($args = array())
+ {
+ foreach ($args as $key => $value) {
+ $this->$key = $value;
+ }
+ }
+
+ /**
+ * Get a request parameter
+ *
+ * @param string $name The parameter to get.
+ * @return mixed Parameter value.
+ */
+ public function __get($name)
+ {
+ return isset($this->{'_' . $name}) ? $this->{'_' . $name} : null;
+ }
+
+ /**
+ * Set a request parameter
+ *
+ * @param string $name The parameter to set.
+ * @param mixed $value Parameter value.
+ */
+ public function __set($name, $value)
+ {
+ switch ($name) {
+ case 'headers':
+ $this->setHeaders($value);
+ break;
+ }
+
+ $this->{'_' . $name} = $value;
+ }
+
+ /**
+ * Set one or more headers
+ *
+ * @param mixed $headers A hash of header + value pairs, or a single header name
+ * @param string $value A header value
+ */
+ public function setHeaders($headers, $value = null)
+ {
+ if (!is_array($headers)) {
+ $headers = array($headers => $value);
+ }
+
+ foreach ($headers as $header => $value) {
+ $this->_headers[$header] = $value;
+ }
+ }
+
+ /**
+ * Get the current value of $header
+ *
+ * @param string $header Header name to get
+ * @return string $header's current value
+ */
+ public function getHeader($header)
+ {
+ return isset($this->_headers[$header]) ? $this->_headers[$header] : null;
+ }
+}
*/
protected function _parseHeaders($headers)
{
+ if (!is_array($headers)) {
+ $headers = explode("\n", $headers);
+ }
+
$lastHeader = null;
foreach ($headers as $headerLine) {
// stream_get_meta returns all headers generated while processing a
<dir name="Horde">
<dir name="Http">
<dir name="Client">
+ <dir name="Adapter">
+ <file name="Base.php" role="php" />
+ <file name="Curl.php" role="php" />
+ <file name="Fopen.php" role="php" />
+ <file name="Peclhttp.php" role="php" />
+ </dir>
<file name="Exception.php" role="php" />
<file name="Mock.php" role="php" />
+ <file name="Request.php" role="php" />
<file name="Response.php" role="php" />
</dir> <!-- /lib/Horde/Http/Client -->
<file name="Client.php" role="php" />
</dependencies>
<phprelease>
<filelist>
+ <install name="lib/Horde/Http/Client/Adapter/Base.php" as="Horde/Http/Client/Adapter/Base.php" />
+ <install name="lib/Horde/Http/Client/Adapter/Curl.php" as="Horde/Http/Client/Adapter/Curl.php" />
+ <install name="lib/Horde/Http/Client/Adapter/Fopen.php" as="Horde/Http/Client/Adapter/Fopen.php" />
+ <install name="lib/Horde/Http/Client/Adapter/Peclhttp.php" as="Horde/Http/Client/Adapter/Peclhttp.php" />
<install name="lib/Horde/Http/Client/Exception.php" as="Horde/Http/Client/Exception.php" />
<install name="lib/Horde/Http/Client/Mock.php" as="Horde/Http/Client/Mock.php" />
+ <install name="lib/Horde/Http/Client/Request.php" as="Horde/Http/Client/Request.php" />
<install name="lib/Horde/Http/Client/Response.php" as="Horde/Http/Client/Response.php" />
<install name="lib/Horde/Http/Client.php" as="Horde/Http/Client.php" />
</filelist>