Updating external libraries for net access

This commit is contained in:
Mikael Nordfeldth 2013-10-05 14:29:02 +02:00
parent ce37edc1b0
commit c51086b302
16 changed files with 7223 additions and 2240 deletions

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2008-2011, Alexey Borzov <avb@php.net> * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -33,12 +33,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: Adapter.php 308322 2011-02-14 13:58:03Z avb $ * @version SVN: $Id: Adapter.php 324415 2012-03-21 10:50:50Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
/** /**
@ -53,66 +53,69 @@ require_once 'HTTP/Request2/Response.php';
* data, all actual work of sending the request to the remote server and * data, all actual work of sending the request to the remote server and
* receiving its response is performed by adapters. * receiving its response is performed by adapters.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @version Release: 2.0.0RC1 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
*/ */
abstract class HTTP_Request2_Adapter abstract class HTTP_Request2_Adapter
{ {
/** /**
* A list of methods that MUST NOT have a request body, per RFC 2616 * A list of methods that MUST NOT have a request body, per RFC 2616
* @var array * @var array
*/ */
protected static $bodyDisallowed = array('TRACE'); protected static $bodyDisallowed = array('TRACE');
/** /**
* Methods having defined semantics for request body * Methods having defined semantics for request body
* *
* Content-Length header (indicating that the body follows, section 4.3 of * Content-Length header (indicating that the body follows, section 4.3 of
* RFC 2616) will be sent for these methods even if no body was added * RFC 2616) will be sent for these methods even if no body was added
* *
* @var array * @var array
* @link http://pear.php.net/bugs/bug.php?id=12900 * @link http://pear.php.net/bugs/bug.php?id=12900
* @link http://pear.php.net/bugs/bug.php?id=14740 * @link http://pear.php.net/bugs/bug.php?id=14740
*/ */
protected static $bodyRequired = array('POST', 'PUT'); protected static $bodyRequired = array('POST', 'PUT');
/** /**
* Request being sent * Request being sent
* @var HTTP_Request2 * @var HTTP_Request2
*/ */
protected $request; protected $request;
/** /**
* Request body * Request body
* @var string|resource|HTTP_Request2_MultipartBody * @var string|resource|HTTP_Request2_MultipartBody
* @see HTTP_Request2::getBody() * @see HTTP_Request2::getBody()
*/ */
protected $requestBody; protected $requestBody;
/** /**
* Length of the request body * Length of the request body
* @var integer * @var integer
*/ */
protected $contentLength; protected $contentLength;
/** /**
* Sends request to the remote server and returns its response * Sends request to the remote server and returns its response
* *
* @param HTTP_Request2 * @param HTTP_Request2 $request HTTP request message
* @return HTTP_Request2_Response *
* @throws HTTP_Request2_Exception * @return HTTP_Request2_Response
*/ * @throws HTTP_Request2_Exception
*/
abstract public function sendRequest(HTTP_Request2 $request); abstract public function sendRequest(HTTP_Request2 $request);
/** /**
* Calculates length of the request body, adds proper headers * Calculates length of the request body, adds proper headers
* *
* @param array associative array of request headers, this method will * @param array &$headers associative array of request headers, this method
* add proper 'Content-Length' and 'Content-Type' headers * will add proper 'Content-Length' and 'Content-Type'
* to this array (or remove them if not needed) * headers to this array (or remove them if not needed)
*/ */
protected function calculateRequestLength(&$headers) protected function calculateRequestLength(&$headers)
{ {
$this->requestBody = $this->request->getBody(); $this->requestBody = $this->request->getBody();
@ -130,8 +133,8 @@ abstract class HTTP_Request2_Adapter
$this->requestBody->rewind(); $this->requestBody->rewind();
} }
if (in_array($this->request->getMethod(), self::$bodyDisallowed) || if (in_array($this->request->getMethod(), self::$bodyDisallowed)
0 == $this->contentLength || 0 == $this->contentLength
) { ) {
// No body: send a Content-Length header nonetheless (request #12900), // No body: send a Content-Length header nonetheless (request #12900),
// but do that only for methods that require a body (bug #14740) // but do that only for methods that require a body (bug #14740)

View File

@ -6,7 +6,7 @@
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2008-2011, Alexey Borzov <avb@php.net> * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -33,12 +33,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: Curl.php 310800 2011-05-06 07:29:56Z avb $ * @version SVN: $Id: Curl.php 324746 2012-04-03 15:09:16Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
/** /**
@ -49,17 +49,19 @@ require_once 'HTTP/Request2/Adapter.php';
/** /**
* Adapter for HTTP_Request2 wrapping around cURL extension * Adapter for HTTP_Request2 wrapping around cURL extension
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @version Release: 2.0.0RC1 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
{ {
/** /**
* Mapping of header names to cURL options * Mapping of header names to cURL options
* @var array * @var array
*/ */
protected static $headerMap = array( protected static $headerMap = array(
'accept-encoding' => CURLOPT_ENCODING, 'accept-encoding' => CURLOPT_ENCODING,
'cookie' => CURLOPT_COOKIE, 'cookie' => CURLOPT_COOKIE,
@ -67,22 +69,22 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
'user-agent' => CURLOPT_USERAGENT 'user-agent' => CURLOPT_USERAGENT
); );
/** /**
* Mapping of SSL context options to cURL options * Mapping of SSL context options to cURL options
* @var array * @var array
*/ */
protected static $sslContextMap = array( protected static $sslContextMap = array(
'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER, 'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER,
'ssl_cafile' => CURLOPT_CAINFO, 'ssl_cafile' => CURLOPT_CAINFO,
'ssl_capath' => CURLOPT_CAPATH, 'ssl_capath' => CURLOPT_CAPATH,
'ssl_local_cert' => CURLOPT_SSLCERT, 'ssl_local_cert' => CURLOPT_SSLCERT,
'ssl_passphrase' => CURLOPT_SSLCERTPASSWD 'ssl_passphrase' => CURLOPT_SSLCERTPASSWD
); );
/** /**
* Mapping of CURLE_* constants to Exception subclasses and error codes * Mapping of CURLE_* constants to Exception subclasses and error codes
* @var array * @var array
*/ */
protected static $errorMap = array( protected static $errorMap = array(
CURLE_UNSUPPORTED_PROTOCOL => array('HTTP_Request2_MessageException', CURLE_UNSUPPORTED_PROTOCOL => array('HTTP_Request2_MessageException',
HTTP_Request2_Exception::NON_HTTP_REDIRECT), HTTP_Request2_Exception::NON_HTTP_REDIRECT),
@ -119,43 +121,44 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
CURLE_BAD_CONTENT_ENCODING => array('HTTP_Request2_MessageException'), CURLE_BAD_CONTENT_ENCODING => array('HTTP_Request2_MessageException'),
); );
/** /**
* Response being received * Response being received
* @var HTTP_Request2_Response * @var HTTP_Request2_Response
*/ */
protected $response; protected $response;
/** /**
* Whether 'sentHeaders' event was sent to observers * Whether 'sentHeaders' event was sent to observers
* @var boolean * @var boolean
*/ */
protected $eventSentHeaders = false; protected $eventSentHeaders = false;
/** /**
* Whether 'receivedHeaders' event was sent to observers * Whether 'receivedHeaders' event was sent to observers
* @var boolean * @var boolean
*/ */
protected $eventReceivedHeaders = false; protected $eventReceivedHeaders = false;
/** /**
* Position within request body * Position within request body
* @var integer * @var integer
* @see callbackReadBody() * @see callbackReadBody()
*/ */
protected $position = 0; protected $position = 0;
/** /**
* Information about last transfer, as returned by curl_getinfo() * Information about last transfer, as returned by curl_getinfo()
* @var array * @var array
*/ */
protected $lastInfo; protected $lastInfo;
/** /**
* Creates a subclass of HTTP_Request2_Exception from curl error data * Creates a subclass of HTTP_Request2_Exception from curl error data
* *
* @param resource curl handle * @param resource $ch curl handle
* @return HTTP_Request2_Exception *
*/ * @return HTTP_Request2_Exception
*/
protected static function wrapCurlError($ch) protected static function wrapCurlError($ch)
{ {
$nativeCode = curl_errno($ch); $nativeCode = curl_errno($ch);
@ -170,13 +173,14 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
} }
} }
/** /**
* Sends request to the remote server and returns its response * Sends request to the remote server and returns its response
* *
* @param HTTP_Request2 * @param HTTP_Request2 $request HTTP request message
* @return HTTP_Request2_Response *
* @throws HTTP_Request2_Exception * @return HTTP_Request2_Response
*/ * @throws HTTP_Request2_Exception
*/
public function sendRequest(HTTP_Request2 $request) public function sendRequest(HTTP_Request2 $request)
{ {
if (!extension_loaded('curl')) { if (!extension_loaded('curl')) {
@ -219,22 +223,22 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
return $response; return $response;
} }
/** /**
* Returns information about last transfer * Returns information about last transfer
* *
* @return array associative array as returned by curl_getinfo() * @return array associative array as returned by curl_getinfo()
*/ */
public function getInfo() public function getInfo()
{ {
return $this->lastInfo; return $this->lastInfo;
} }
/** /**
* Creates a new cURL handle and populates it with data from the request * Creates a new cURL handle and populates it with data from the request
* *
* @return resource a cURL handle, as created by curl_init() * @return resource a cURL handle, as created by curl_init()
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
*/ */
protected function createCurlHandle() protected function createCurlHandle()
{ {
$ch = curl_init(); $ch = curl_init();
@ -281,29 +285,29 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
// set HTTP version // set HTTP version
switch ($this->request->getConfig('protocol_version')) { switch ($this->request->getConfig('protocol_version')) {
case '1.0': case '1.0':
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
break; break;
case '1.1': case '1.1':
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
} }
// set request method // set request method
switch ($this->request->getMethod()) { switch ($this->request->getMethod()) {
case HTTP_Request2::METHOD_GET: case HTTP_Request2::METHOD_GET:
curl_setopt($ch, CURLOPT_HTTPGET, true); curl_setopt($ch, CURLOPT_HTTPGET, true);
break; break;
case HTTP_Request2::METHOD_POST: case HTTP_Request2::METHOD_POST:
curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POST, true);
break; break;
case HTTP_Request2::METHOD_HEAD: case HTTP_Request2::METHOD_HEAD:
curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_NOBODY, true);
break; break;
case HTTP_Request2::METHOD_PUT: case HTTP_Request2::METHOD_PUT:
curl_setopt($ch, CURLOPT_UPLOAD, true); curl_setopt($ch, CURLOPT_UPLOAD, true);
break; break;
default: default:
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod()); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());
} }
// set proxy, if needed // set proxy, if needed
@ -315,14 +319,30 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
} }
curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port); curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);
if ($user = $this->request->getConfig('proxy_user')) { if ($user = $this->request->getConfig('proxy_user')) {
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $user . ':' . curl_setopt(
$this->request->getConfig('proxy_password')); $ch, CURLOPT_PROXYUSERPWD,
$user . ':' . $this->request->getConfig('proxy_password')
);
switch ($this->request->getConfig('proxy_auth_scheme')) { switch ($this->request->getConfig('proxy_auth_scheme')) {
case HTTP_Request2::AUTH_BASIC: case HTTP_Request2::AUTH_BASIC:
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
break; break;
case HTTP_Request2::AUTH_DIGEST: case HTTP_Request2::AUTH_DIGEST:
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
}
}
if ($type = $this->request->getConfig('proxy_type')) {
switch ($type) {
case 'http':
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
break;
case 'socks5':
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
break;
default:
throw new HTTP_Request2_NotImplementedException(
"Proxy type '{$type}' is not supported"
);
} }
} }
} }
@ -331,11 +351,11 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
if ($auth = $this->request->getAuth()) { if ($auth = $this->request->getAuth()) {
curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']); curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
switch ($auth['scheme']) { switch ($auth['scheme']) {
case HTTP_Request2::AUTH_BASIC: case HTTP_Request2::AUTH_BASIC:
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
break; break;
case HTTP_Request2::AUTH_DIGEST: case HTTP_Request2::AUTH_DIGEST:
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
} }
} }
@ -384,16 +404,16 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
return $ch; return $ch;
} }
/** /**
* Workaround for PHP bug #47204 that prevents rewinding request body * Workaround for PHP bug #47204 that prevents rewinding request body
* *
* The workaround consists of reading the entire request body into memory * The workaround consists of reading the entire request body into memory
* and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large
* file uploads, use Socket adapter instead. * file uploads, use Socket adapter instead.
* *
* @param resource cURL handle * @param resource $ch cURL handle
* @param array Request headers * @param array &$headers Request headers
*/ */
protected function workaroundPhpBug47204($ch, &$headers) protected function workaroundPhpBug47204($ch, &$headers)
{ {
// no redirects, no digest auth -> probably no rewind needed // no redirects, no digest auth -> probably no rewind needed
@ -403,8 +423,8 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
) { ) {
curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody')); curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));
// rewind may be needed, read the whole body into memory
} else { } else {
// rewind may be needed, read the whole body into memory
if ($this->requestBody instanceof HTTP_Request2_MultipartBody) { if ($this->requestBody instanceof HTTP_Request2_MultipartBody) {
$this->requestBody = $this->requestBody->__toString(); $this->requestBody = $this->requestBody->__toString();
@ -421,14 +441,15 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
} }
} }
/** /**
* Callback function called by cURL for reading the request body * Callback function called by cURL for reading the request body
* *
* @param resource cURL handle * @param resource $ch cURL handle
* @param resource file descriptor (not used) * @param resource $fd file descriptor (not used)
* @param integer maximum length of data to return * @param integer $length maximum length of data to return
* @return string part of the request body, up to $length bytes *
*/ * @return string part of the request body, up to $length bytes
*/
protected function callbackReadBody($ch, $fd, $length) protected function callbackReadBody($ch, $fd, $length)
{ {
if (!$this->eventSentHeaders) { if (!$this->eventSentHeaders) {
@ -437,8 +458,8 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
); );
$this->eventSentHeaders = true; $this->eventSentHeaders = true;
} }
if (in_array($this->request->getMethod(), self::$bodyDisallowed) || if (in_array($this->request->getMethod(), self::$bodyDisallowed)
0 == $this->contentLength || $this->position >= $this->contentLength || 0 == $this->contentLength || $this->position >= $this->contentLength
) { ) {
return ''; return '';
} }
@ -454,21 +475,22 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
return $string; return $string;
} }
/** /**
* Callback function called by cURL for saving the response headers * Callback function called by cURL for saving the response headers
* *
* @param resource cURL handle * @param resource $ch cURL handle
* @param string response header (with trailing CRLF) * @param string $string response header (with trailing CRLF)
* @return integer number of bytes saved *
* @see HTTP_Request2_Response::parseHeaderLine() * @return integer number of bytes saved
*/ * @see HTTP_Request2_Response::parseHeaderLine()
*/
protected function callbackWriteHeader($ch, $string) protected function callbackWriteHeader($ch, $string)
{ {
// we may receive a second set of headers if doing e.g. digest auth // we may receive a second set of headers if doing e.g. digest auth
if ($this->eventReceivedHeaders || !$this->eventSentHeaders) { if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {
// don't bother with 100-Continue responses (bug #15785) // don't bother with 100-Continue responses (bug #15785)
if (!$this->eventSentHeaders || if (!$this->eventSentHeaders
$this->response->getStatus() >= 200 || $this->response->getStatus() >= 200
) { ) {
$this->request->setLastEvent( $this->request->setLastEvent(
'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT) 'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
@ -532,14 +554,16 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
return strlen($string); return strlen($string);
} }
/** /**
* Callback function called by cURL for saving the response body * Callback function called by cURL for saving the response body
* *
* @param resource cURL handle (not used) * @param resource $ch cURL handle (not used)
* @param string part of the response body * @param string $string part of the response body
* @return integer number of bytes saved *
* @see HTTP_Request2_Response::appendBody() * @return integer number of bytes saved
*/ * @throws HTTP_Request2_MessageException
* @see HTTP_Request2_Response::appendBody()
*/
protected function callbackWriteBody($ch, $string) protected function callbackWriteBody($ch, $string)
{ {
// cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if // cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if

View File

@ -6,7 +6,7 @@
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2008-2011, Alexey Borzov <avb@php.net> * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -33,12 +33,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: Mock.php 308322 2011-02-14 13:58:03Z avb $ * @version SVN: $Id: Mock.php 324937 2012-04-07 10:05:57Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
/** /**
@ -63,55 +63,71 @@ require_once 'HTTP/Request2/Adapter.php';
* $response = $req->send(); * $response = $req->send();
* </code> * </code>
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @version Release: 2.0.0RC1 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
{ {
/** /**
* A queue of responses to be returned by sendRequest() * A queue of responses to be returned by sendRequest()
* @var array * @var array
*/ */
protected $responses = array(); protected $responses = array();
/** /**
* Returns the next response from the queue built by addResponse() * Returns the next response from the queue built by addResponse()
* *
* If the queue is empty it will return default empty response with status 400, * Only responses without explicit URLs or with URLs equal to request URL
* if an Exception object was added to the queue it will be thrown. * will be considered. If matching response is not found or the queue is
* * empty then default empty response with status 400 will be returned,
* @param HTTP_Request2 * if an Exception object was added to the queue it will be thrown.
* @return HTTP_Request2_Response *
* @throws Exception * @param HTTP_Request2 $request HTTP request message
*/ *
* @return HTTP_Request2_Response
* @throws Exception
*/
public function sendRequest(HTTP_Request2 $request) public function sendRequest(HTTP_Request2 $request)
{ {
if (count($this->responses) > 0) { $requestUrl = (string)$request->getUrl();
$response = array_shift($this->responses); $response = null;
if ($response instanceof HTTP_Request2_Response) { foreach ($this->responses as $k => $v) {
return $response; if (!$v[1] || $requestUrl == $v[1]) {
} else { $response = $v[0];
// rethrow the exception array_splice($this->responses, $k, 1);
$class = get_class($response); break;
$message = $response->getMessage();
$code = $response->getCode();
throw new $class($message, $code);
} }
} else { }
if (!$response) {
return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n"); return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");
} elseif ($response instanceof HTTP_Request2_Response) {
return $response;
} else {
// rethrow the exception
$class = get_class($response);
$message = $response->getMessage();
$code = $response->getCode();
throw new $class($message, $code);
} }
} }
/** /**
* Adds response to the queue * Adds response to the queue
* *
* @param mixed either a string, a pointer to an open file, * @param mixed $response either a string, a pointer to an open file,
* an instance of HTTP_Request2_Response or Exception * an instance of HTTP_Request2_Response or Exception
* @throws HTTP_Request2_Exception * @param string $url A request URL this response should be valid for
*/ * (see {@link http://pear.php.net/bugs/bug.php?id=19276})
public function addResponse($response) *
* @throws HTTP_Request2_Exception
*/
public function addResponse($response, $url = null)
{ {
if (is_string($response)) { if (is_string($response)) {
$response = self::createResponseFromString($response); $response = self::createResponseFromString($response);
@ -122,16 +138,17 @@ class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
) { ) {
throw new HTTP_Request2_Exception('Parameter is not a valid response'); throw new HTTP_Request2_Exception('Parameter is not a valid response');
} }
$this->responses[] = $response; $this->responses[] = array($response, $url);
} }
/** /**
* Creates a new HTTP_Request2_Response object from a string * Creates a new HTTP_Request2_Response object from a string
* *
* @param string * @param string $str string containing HTTP response message
* @return HTTP_Request2_Response *
* @throws HTTP_Request2_Exception * @return HTTP_Request2_Response
*/ * @throws HTTP_Request2_Exception
*/
public static function createResponseFromString($str) public static function createResponseFromString($str)
{ {
$parts = preg_split('!(\r?\n){2}!m', $str, 2); $parts = preg_split('!(\r?\n){2}!m', $str, 2);
@ -147,13 +164,14 @@ class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
return $response; return $response;
} }
/** /**
* Creates a new HTTP_Request2_Response object from a file * Creates a new HTTP_Request2_Response object from a file
* *
* @param resource file pointer returned by fopen() * @param resource $fp file pointer returned by fopen()
* @return HTTP_Request2_Response *
* @throws HTTP_Request2_Exception * @return HTTP_Request2_Response
*/ * @throws HTTP_Request2_Exception
*/
public static function createResponseFromFile($fp) public static function createResponseFromFile($fp)
{ {
$response = new HTTP_Request2_Response(fgets($fp)); $response = new HTTP_Request2_Response(fgets($fp));

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2008-2011, Alexey Borzov <avb@php.net> * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -33,12 +33,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: CookieJar.php 308629 2011-02-24 17:34:24Z avb $ * @version SVN: $Id: CookieJar.php 324415 2012-03-21 10:50:50Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
/** Class representing a HTTP request message */ /** Class representing a HTTP request message */
@ -47,65 +47,70 @@ require_once 'HTTP/Request2.php';
/** /**
* Stores cookies and passes them between HTTP requests * Stores cookies and passes them between HTTP requests
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @version Release: @package_version@ * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: @package_version@
* @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_CookieJar implements Serializable class HTTP_Request2_CookieJar implements Serializable
{ {
/** /**
* Array of stored cookies * Array of stored cookies
* *
* The array is indexed by domain, path and cookie name * The array is indexed by domain, path and cookie name
* .example.com * .example.com
* / * /
* some_cookie => cookie data * some_cookie => cookie data
* /subdir * /subdir
* other_cookie => cookie data * other_cookie => cookie data
* .example.org * .example.org
* ... * ...
* *
* @var array * @var array
*/ */
protected $cookies = array(); protected $cookies = array();
/** /**
* Whether session cookies should be serialized when serializing the jar * Whether session cookies should be serialized when serializing the jar
* @var bool * @var bool
*/ */
protected $serializeSession = false; protected $serializeSession = false;
/** /**
* Whether Public Suffix List should be used for domain matching * Whether Public Suffix List should be used for domain matching
* @var bool * @var bool
*/ */
protected $useList = true; protected $useList = true;
/** /**
* Array with Public Suffix List data * Array with Public Suffix List data
* @var array * @var array
* @link http://publicsuffix.org/ * @link http://publicsuffix.org/
*/ */
protected static $psl = array(); protected static $psl = array();
/** /**
* Class constructor, sets various options * Class constructor, sets various options
* *
* @param bool Controls serializing session cookies, see {@link serializeSessionCookies()} * @param bool $serializeSessionCookies Controls serializing session cookies,
* @param bool Controls using Public Suffix List, see {@link usePublicSuffixList()} * see {@link serializeSessionCookies()}
*/ * @param bool $usePublicSuffixList Controls using Public Suffix List,
public function __construct($serializeSessionCookies = false, $usePublicSuffixList = true) * see {@link usePublicSuffixList()}
{ */
public function __construct(
$serializeSessionCookies = false, $usePublicSuffixList = true
) {
$this->serializeSessionCookies($serializeSessionCookies); $this->serializeSessionCookies($serializeSessionCookies);
$this->usePublicSuffixList($usePublicSuffixList); $this->usePublicSuffixList($usePublicSuffixList);
} }
/** /**
* Returns current time formatted in ISO-8601 at UTC timezone * Returns current time formatted in ISO-8601 at UTC timezone
* *
* @return string * @return string
*/ */
protected function now() protected function now()
{ {
$dt = new DateTime(); $dt = new DateTime();
@ -113,28 +118,30 @@ class HTTP_Request2_CookieJar implements Serializable
return $dt->format(DateTime::ISO8601); return $dt->format(DateTime::ISO8601);
} }
/** /**
* Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields * Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields
* *
* The checks are as follows: * The checks are as follows:
* - cookie array should contain 'name' and 'value' fields; * - cookie array should contain 'name' and 'value' fields;
* - name and value should not contain disallowed symbols; * - name and value should not contain disallowed symbols;
* - 'expires' should be either empty parseable by DateTime; * - 'expires' should be either empty parseable by DateTime;
* - 'domain' and 'path' should be either not empty or an URL where * - 'domain' and 'path' should be either not empty or an URL where
* cookie was set should be provided. * cookie was set should be provided.
* - if $setter is provided, then document at that URL should be allowed * - if $setter is provided, then document at that URL should be allowed
* to set a cookie for that 'domain'. If $setter is not provided, * to set a cookie for that 'domain'. If $setter is not provided,
* then no domain checks will be made. * then no domain checks will be made.
* *
* 'expires' field will be converted to ISO8601 format from COOKIE format, * 'expires' field will be converted to ISO8601 format from COOKIE format,
* 'domain' and 'path' will be set from setter URL if empty. * 'domain' and 'path' will be set from setter URL if empty.
* *
* @param array cookie data, as returned by {@link HTTP_Request2_Response::getCookies()} * @param array $cookie cookie data, as returned by
* @param Net_URL2 URL of the document that sent Set-Cookie header * {@link HTTP_Request2_Response::getCookies()}
* @return array Updated cookie array * @param Net_URL2 $setter URL of the document that sent Set-Cookie header
* @throws HTTP_Request2_LogicException *
* @throws HTTP_Request2_MessageException * @return array Updated cookie array
*/ * @throws HTTP_Request2_LogicException
* @throws HTTP_Request2_MessageException
*/
protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null) protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null)
{ {
if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) { if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) {
@ -203,13 +210,15 @@ class HTTP_Request2_CookieJar implements Serializable
return $cookie; return $cookie;
} }
/** /**
* Stores a cookie in the jar * Stores a cookie in the jar
* *
* @param array cookie data, as returned by {@link HTTP_Request2_Response::getCookies()} * @param array $cookie cookie data, as returned by
* @param Net_URL2 URL of the document that sent Set-Cookie header * {@link HTTP_Request2_Response::getCookies()}
* @throws HTTP_Request2_Exception * @param Net_URL2 $setter URL of the document that sent Set-Cookie header
*/ *
* @throws HTTP_Request2_Exception
*/
public function store(array $cookie, Net_URL2 $setter = null) public function store(array $cookie, Net_URL2 $setter = null)
{ {
$cookie = $this->checkAndUpdateFields($cookie, $setter); $cookie = $this->checkAndUpdateFields($cookie, $setter);
@ -230,13 +239,13 @@ class HTTP_Request2_CookieJar implements Serializable
} }
} }
/** /**
* Adds cookies set in HTTP response to the jar * Adds cookies set in HTTP response to the jar
* *
* @param HTTP_Request2_Response response * @param HTTP_Request2_Response $response HTTP response message
* @param Net_URL2 original request URL, needed for setting * @param Net_URL2 $setter original request URL, needed for
* default domain/path * setting default domain/path
*/ */
public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter) public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter)
{ {
foreach ($response->getCookies() as $cookie) { foreach ($response->getCookies() as $cookie) {
@ -244,18 +253,19 @@ class HTTP_Request2_CookieJar implements Serializable
} }
} }
/** /**
* Returns all cookies matching a given request URL * Returns all cookies matching a given request URL
* *
* The following checks are made: * The following checks are made:
* - cookie domain should match request host * - cookie domain should match request host
* - cookie path should be a prefix for request path * - cookie path should be a prefix for request path
* - 'secure' cookies will only be sent for HTTPS requests * - 'secure' cookies will only be sent for HTTPS requests
* *
* @param Net_URL2 * @param Net_URL2 $url Request url
* @param bool Whether to return cookies as string for "Cookie: " header * @param bool $asString Whether to return cookies as string for "Cookie: " header
* @return array *
*/ * @return array|string Matching cookies
*/
public function getMatching(Net_URL2 $url, $asString = false) public function getMatching(Net_URL2 $url, $asString = false)
{ {
$host = $url->getHost(); $host = $url->getHost();
@ -291,11 +301,11 @@ class HTTP_Request2_CookieJar implements Serializable
} }
} }
/** /**
* Returns all cookies stored in a jar * Returns all cookies stored in a jar
* *
* @return array * @return array
*/ */
public function getAll() public function getAll()
{ {
$cookies = array(); $cookies = array();
@ -309,47 +319,49 @@ class HTTP_Request2_CookieJar implements Serializable
return $cookies; return $cookies;
} }
/** /**
* Sets whether session cookies should be serialized when serializing the jar * Sets whether session cookies should be serialized when serializing the jar
* *
* @param boolean * @param boolean $serialize serialize?
*/ */
public function serializeSessionCookies($serialize) public function serializeSessionCookies($serialize)
{ {
$this->serializeSession = (bool)$serialize; $this->serializeSession = (bool)$serialize;
} }
/** /**
* Sets whether Public Suffix List should be used for restricting cookie-setting * Sets whether Public Suffix List should be used for restricting cookie-setting
* *
* Without PSL {@link domainMatch()} will only prevent setting cookies for * Without PSL {@link domainMatch()} will only prevent setting cookies for
* top-level domains like '.com' or '.org'. However, it will not prevent * top-level domains like '.com' or '.org'. However, it will not prevent
* setting a cookie for '.co.uk' even though only third-level registrations * setting a cookie for '.co.uk' even though only third-level registrations
* are possible in .uk domain. * are possible in .uk domain.
* *
* With the List it is possible to find the highest level at which a domain * With the List it is possible to find the highest level at which a domain
* may be registered for a particular top-level domain and consequently * may be registered for a particular top-level domain and consequently
* prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by * prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by
* Firefox, Chrome and Opera browsers to restrict cookie setting. * Firefox, Chrome and Opera browsers to restrict cookie setting.
* *
* Note that PSL is licensed differently to HTTP_Request2 package (refer to * Note that PSL is licensed differently to HTTP_Request2 package (refer to
* the license information in public-suffix-list.php), so you can disable * the license information in public-suffix-list.php), so you can disable
* its use if this is an issue for you. * its use if this is an issue for you.
* *
* @param boolean * @param boolean $useList use the list?
* @link http://publicsuffix.org/learn/ *
*/ * @link http://publicsuffix.org/learn/
*/
public function usePublicSuffixList($useList) public function usePublicSuffixList($useList)
{ {
$this->useList = (bool)$useList; $this->useList = (bool)$useList;
} }
/** /**
* Returns string representation of object * Returns string representation of object
* *
* @return string * @return string
* @see Serializable::serialize() *
*/ * @see Serializable::serialize()
*/
public function serialize() public function serialize()
{ {
$cookies = $this->getAll(); $cookies = $this->getAll();
@ -367,12 +379,13 @@ class HTTP_Request2_CookieJar implements Serializable
)); ));
} }
/** /**
* Constructs the object from serialized string * Constructs the object from serialized string
* *
* @param string string representation * @param string $serialized string representation
* @see Serializable::unserialize() *
*/ * @see Serializable::unserialize()
*/
public function unserialize($serialized) public function unserialize($serialized)
{ {
$data = unserialize($serialized); $data = unserialize($serialized);
@ -393,17 +406,18 @@ class HTTP_Request2_CookieJar implements Serializable
} }
} }
/** /**
* Checks whether a cookie domain matches a request host. * Checks whether a cookie domain matches a request host.
* *
* The method is used by {@link store()} to check for whether a document * The method is used by {@link store()} to check for whether a document
* at given URL can set a cookie with a given domain attribute and by * at given URL can set a cookie with a given domain attribute and by
* {@link getMatching()} to find cookies matching the request URL. * {@link getMatching()} to find cookies matching the request URL.
* *
* @param string request host * @param string $requestHost request host
* @param string cookie domain * @param string $cookieDomain cookie domain
* @return bool match success *
*/ * @return bool match success
*/
public function domainMatch($requestHost, $cookieDomain) public function domainMatch($requestHost, $cookieDomain)
{ {
if ($requestHost == $cookieDomain) { if ($requestHost == $cookieDomain) {
@ -425,17 +439,18 @@ class HTTP_Request2_CookieJar implements Serializable
return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain; return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain;
} }
/** /**
* Removes subdomains to get the registered domain (the first after top-level) * Removes subdomains to get the registered domain (the first after top-level)
* *
* The method will check Public Suffix List to find out where top-level * The method will check Public Suffix List to find out where top-level
* domain ends and registered domain starts. It will remove domain parts * domain ends and registered domain starts. It will remove domain parts
* to the left of registered one. * to the left of registered one.
* *
* @param string domain name * @param string $domain domain name
* @return string|bool registered domain, will return false if $domain is *
* either invalid or a TLD itself * @return string|bool registered domain, will return false if $domain is
*/ * either invalid or a TLD itself
*/
public static function getRegisteredDomain($domain) public static function getRegisteredDomain($domain)
{ {
$domainParts = explode('.', ltrim($domain, '.')); $domainParts = explode('.', ltrim($domain, '.'));
@ -444,8 +459,10 @@ class HTTP_Request2_CookieJar implements Serializable
if (empty(self::$psl)) { if (empty(self::$psl)) {
$path = '@data_dir@' . DIRECTORY_SEPARATOR . 'HTTP_Request2'; $path = '@data_dir@' . DIRECTORY_SEPARATOR . 'HTTP_Request2';
if (0 === strpos($path, '@' . 'data_dir@')) { if (0 === strpos($path, '@' . 'data_dir@')) {
$path = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' $path = realpath(
. DIRECTORY_SEPARATOR . 'data'); dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'
. DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data'
);
} }
self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php'; self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php';
} }
@ -466,13 +483,14 @@ class HTTP_Request2_CookieJar implements Serializable
return $result; return $result;
} }
/** /**
* Recursive helper method for {@link getRegisteredDomain()} * Recursive helper method for {@link getRegisteredDomain()}
* *
* @param array remaining domain parts * @param array $domainParts remaining domain parts
* @param mixed node in {@link HTTP_Request2_CookieJar::$psl} to check * @param mixed $listNode node in {@link HTTP_Request2_CookieJar::$psl} to check
* @return string|null concatenated domain parts, null in case of error *
*/ * @return string|null concatenated domain parts, null in case of error
*/
protected static function checkDomainsList(array $domainParts, $listNode) protected static function checkDomainsList(array $domainParts, $listNode)
{ {
$sub = array_pop($domainParts); $sub = array_pop($domainParts);
@ -480,7 +498,7 @@ class HTTP_Request2_CookieJar implements Serializable
if (!is_array($listNode) || is_null($sub) if (!is_array($listNode) || is_null($sub)
|| array_key_exists('!' . $sub, $listNode) || array_key_exists('!' . $sub, $listNode)
) { ) {
return $sub; return $sub;
} elseif (array_key_exists($sub, $listNode)) { } elseif (array_key_exists($sub, $listNode)) {

View File

@ -6,7 +6,7 @@
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2008-2011, Alexey Borzov <avb@php.net> * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -33,12 +33,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: Exception.php 308629 2011-02-24 17:34:24Z avb $ * @version SVN: $Id: Exception.php 324415 2012-03-21 10:50:50Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
/** /**
@ -49,10 +49,13 @@ require_once 'PEAR/Exception.php';
/** /**
* Base exception class for HTTP_Request2 package * Base exception class for HTTP_Request2 package
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @version Release: 2.0.0RC1 * @author Alexey Borzov <avb@php.net>
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132
*/ */
class HTTP_Request2_Exception extends PEAR_Exception class HTTP_Request2_Exception extends PEAR_Exception
{ {
@ -76,34 +79,34 @@ class HTTP_Request2_Exception extends PEAR_Exception
/** Redirect to a protocol other than http(s):// */ /** Redirect to a protocol other than http(s):// */
const NON_HTTP_REDIRECT = 50; const NON_HTTP_REDIRECT = 50;
/** /**
* Native error code * Native error code
* @var int * @var int
*/ */
private $_nativeCode; private $_nativeCode;
/** /**
* Constructor, can set package error code and native error code * Constructor, can set package error code and native error code
* *
* @param string exception message * @param string $message exception message
* @param int package error code, one of class constants * @param int $code package error code, one of class constants
* @param int error code from underlying PHP extension * @param int $nativeCode error code from underlying PHP extension
*/ */
public function __construct($message = null, $code = null, $nativeCode = null) public function __construct($message = null, $code = null, $nativeCode = null)
{ {
parent::__construct($message, $code); parent::__construct($message, $code);
$this->_nativeCode = $nativeCode; $this->_nativeCode = $nativeCode;
} }
/** /**
* Returns error code produced by underlying PHP extension * Returns error code produced by underlying PHP extension
* *
* For Socket Adapter this may contain error number returned by * For Socket Adapter this may contain error number returned by
* stream_socket_client(), for Curl Adapter this will contain error number * stream_socket_client(), for Curl Adapter this will contain error number
* returned by curl_errno() * returned by curl_errno()
* *
* @return integer * @return integer
*/ */
public function getNativeCode() public function getNativeCode()
{ {
return $this->_nativeCode; return $this->_nativeCode;
@ -113,11 +116,16 @@ class HTTP_Request2_Exception extends PEAR_Exception
/** /**
* Exception thrown in case of missing features * Exception thrown in case of missing features
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @version Release: 2.0.0RC1 * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception {} class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception
{
}
/** /**
* Exception that represents error in the program logic * Exception that represents error in the program logic
@ -129,11 +137,16 @@ class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception {}
* *
* The exception will usually contain a package error code. * The exception will usually contain a package error code.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @version Release: 2.0.0RC1 * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_LogicException extends HTTP_Request2_Exception {} class HTTP_Request2_LogicException extends HTTP_Request2_Exception
{
}
/** /**
* Exception thrown when connection to a web or proxy server fails * Exception thrown when connection to a web or proxy server fails
@ -141,20 +154,30 @@ class HTTP_Request2_LogicException extends HTTP_Request2_Exception {}
* The exception will not contain a package error code, but will contain * The exception will not contain a package error code, but will contain
* native error code, as returned by stream_socket_client() or curl_errno(). * native error code, as returned by stream_socket_client() or curl_errno().
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @version Release: 2.0.0RC1 * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception {} class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception
{
}
/** /**
* Exception thrown when sending or receiving HTTP message fails * Exception thrown when sending or receiving HTTP message fails
* *
* The exception may contain both package error code and native error code. * The exception may contain both package error code and native error code.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @version Release: 2.0.0RC1 * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_MessageException extends HTTP_Request2_Exception {} class HTTP_Request2_MessageException extends HTTP_Request2_Exception
{
}
?> ?>

View File

@ -6,7 +6,7 @@
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2008-2011, Alexey Borzov <avb@php.net> * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -33,12 +33,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: MultipartBody.php 308322 2011-02-14 13:58:03Z avb $ * @version SVN: $Id: MultipartBody.php 324415 2012-03-21 10:50:50Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
/** /**
@ -47,62 +47,66 @@
* The class helps to reduce memory consumption by streaming large file uploads * The class helps to reduce memory consumption by streaming large file uploads
* from disk, it also allows monitoring of upload progress (see request #7630) * from disk, it also allows monitoring of upload progress (see request #7630)
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @version Release: 2.0.0RC1 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @link http://tools.ietf.org/html/rfc1867 * @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
* @link http://tools.ietf.org/html/rfc1867
*/ */
class HTTP_Request2_MultipartBody class HTTP_Request2_MultipartBody
{ {
/** /**
* MIME boundary * MIME boundary
* @var string * @var string
*/ */
private $_boundary; private $_boundary;
/** /**
* Form parameters added via {@link HTTP_Request2::addPostParameter()} * Form parameters added via {@link HTTP_Request2::addPostParameter()}
* @var array * @var array
*/ */
private $_params = array(); private $_params = array();
/** /**
* File uploads added via {@link HTTP_Request2::addUpload()} * File uploads added via {@link HTTP_Request2::addUpload()}
* @var array * @var array
*/ */
private $_uploads = array(); private $_uploads = array();
/** /**
* Header for parts with parameters * Header for parts with parameters
* @var string * @var string
*/ */
private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n"; private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n";
/** /**
* Header for parts with uploads * Header for parts with uploads
* @var string * @var string
*/ */
private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n"; private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n";
/** /**
* Current position in parameter and upload arrays * Current position in parameter and upload arrays
* *
* First number is index of "current" part, second number is position within * First number is index of "current" part, second number is position within
* "current" part * "current" part
* *
* @var array * @var array
*/ */
private $_pos = array(0, 0); private $_pos = array(0, 0);
/** /**
* Constructor. Sets the arrays with POST data. * Constructor. Sets the arrays with POST data.
* *
* @param array values of form fields set via {@link HTTP_Request2::addPostParameter()} * @param array $params values of form fields set via
* @param array file uploads set via {@link HTTP_Request2::addUpload()} * {@link HTTP_Request2::addPostParameter()}
* @param bool whether to append brackets to array variable names * @param array $uploads file uploads set via
*/ * {@link HTTP_Request2::addUpload()}
* @param bool $useBrackets whether to append brackets to array variable names
*/
public function __construct(array $params, array $uploads, $useBrackets = true) public function __construct(array $params, array $uploads, $useBrackets = true)
{ {
$this->_params = self::_flattenArray('', $params, $useBrackets); $this->_params = self::_flattenArray('', $params, $useBrackets);
@ -123,11 +127,11 @@ class HTTP_Request2_MultipartBody
} }
} }
/** /**
* Returns the length of the body to use in Content-Length header * Returns the length of the body to use in Content-Length header
* *
* @return integer * @return integer
*/ */
public function getLength() public function getLength()
{ {
$boundaryLength = strlen($this->getBoundary()); $boundaryLength = strlen($this->getBoundary());
@ -144,11 +148,11 @@ class HTTP_Request2_MultipartBody
return $length; return $length;
} }
/** /**
* Returns the boundary to use in Content-Type header * Returns the boundary to use in Content-Type header
* *
* @return string * @return string
*/ */
public function getBoundary() public function getBoundary()
{ {
if (empty($this->_boundary)) { if (empty($this->_boundary)) {
@ -157,12 +161,13 @@ class HTTP_Request2_MultipartBody
return $this->_boundary; return $this->_boundary;
} }
/** /**
* Returns next chunk of request body * Returns next chunk of request body
* *
* @param integer Amount of bytes to read * @param integer $length Number of bytes to read
* @return string Up to $length bytes of data, empty string if at end *
*/ * @return string Up to $length bytes of data, empty string if at end
*/
public function read($length) public function read($length)
{ {
$ret = ''; $ret = '';
@ -172,18 +177,18 @@ class HTTP_Request2_MultipartBody
while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) { while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) {
$oldLength = $length; $oldLength = $length;
if ($this->_pos[0] < $paramCount) { if ($this->_pos[0] < $paramCount) {
$param = sprintf($this->_headerParam, $boundary, $param = sprintf(
$this->_params[$this->_pos[0]][0]) . $this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0]
$this->_params[$this->_pos[0]][1] . "\r\n"; ) . $this->_params[$this->_pos[0]][1] . "\r\n";
$ret .= substr($param, $this->_pos[1], $length); $ret .= substr($param, $this->_pos[1], $length);
$length -= min(strlen($param) - $this->_pos[1], $length); $length -= min(strlen($param) - $this->_pos[1], $length);
} elseif ($this->_pos[0] < $paramCount + $uploadCount) { } elseif ($this->_pos[0] < $paramCount + $uploadCount) {
$pos = $this->_pos[0] - $paramCount; $pos = $this->_pos[0] - $paramCount;
$header = sprintf($this->_headerUpload, $boundary, $header = sprintf(
$this->_uploads[$pos]['name'], $this->_headerUpload, $boundary, $this->_uploads[$pos]['name'],
$this->_uploads[$pos]['filename'], $this->_uploads[$pos]['filename'], $this->_uploads[$pos]['type']
$this->_uploads[$pos]['type']); );
if ($this->_pos[1] < strlen($header)) { if ($this->_pos[1] < strlen($header)) {
$ret .= substr($header, $this->_pos[1], $length); $ret .= substr($header, $this->_pos[1], $length);
$length -= min(strlen($header) - $this->_pos[1], $length); $length -= min(strlen($header) - $this->_pos[1], $length);
@ -214,11 +219,11 @@ class HTTP_Request2_MultipartBody
return $ret; return $ret;
} }
/** /**
* Sets the current position to the start of the body * Sets the current position to the start of the body
* *
* This allows reusing the same body in another request * This allows reusing the same body in another request
*/ */
public function rewind() public function rewind()
{ {
$this->_pos = array(0, 0); $this->_pos = array(0, 0);
@ -227,14 +232,14 @@ class HTTP_Request2_MultipartBody
} }
} }
/** /**
* Returns the body as string * Returns the body as string
* *
* Note that it reads all file uploads into memory so it is a good idea not * Note that it reads all file uploads into memory so it is a good idea not
* to use this method with large file uploads and rely on read() instead. * to use this method with large file uploads and rely on read() instead.
* *
* @return string * @return string
*/ */
public function __toString() public function __toString()
{ {
$this->rewind(); $this->rewind();
@ -242,15 +247,16 @@ class HTTP_Request2_MultipartBody
} }
/** /**
* Helper function to change the (probably multidimensional) associative array * Helper function to change the (probably multidimensional) associative array
* into the simple one. * into the simple one.
* *
* @param string name for item * @param string $name name for item
* @param mixed item's values * @param mixed $values item's values
* @param bool whether to append [] to array variables' names * @param bool $useBrackets whether to append [] to array variables' names
* @return array array with the following items: array('item name', 'item value'); *
*/ * @return array array with the following items: array('item name', 'item value');
*/
private static function _flattenArray($name, $values, $useBrackets) private static function _flattenArray($name, $values, $useBrackets)
{ {
if (!is_array($values)) { if (!is_array($values)) {

View File

@ -6,7 +6,7 @@
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2008-2011, Alexey Borzov <avb@php.net> * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -38,7 +38,7 @@
* @author David Jean Louis <izi@php.net> * @author David Jean Louis <izi@php.net>
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: Log.php 308680 2011-02-25 17:40:17Z avb $ * @version SVN: $Id: Log.php 324415 2012-03-21 10:50:50Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
@ -87,7 +87,7 @@ require_once 'HTTP/Request2/Exception.php';
* @author David Jean Louis <izi@php.net> * @author David Jean Louis <izi@php.net>
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.0.0RC1 * @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_Observer_Log implements SplObserver class HTTP_Request2_Observer_Log implements SplObserver
@ -171,10 +171,10 @@ class HTTP_Request2_Observer_Log implements SplObserver
$this->log('> ' . $event['data'] . ' byte(s) sent'); $this->log('> ' . $event['data'] . ' byte(s) sent');
break; break;
case 'receivedHeaders': case 'receivedHeaders':
$this->log(sprintf('< HTTP/%s %s %s', $this->log(sprintf(
$event['data']->getVersion(), '< HTTP/%s %s %s', $event['data']->getVersion(),
$event['data']->getStatus(), $event['data']->getStatus(), $event['data']->getReasonPhrase()
$event['data']->getReasonPhrase())); ));
$headers = $event['data']->getHeader(); $headers = $event['data']->getHeader();
foreach ($headers as $key => $val) { foreach ($headers as $key => $val) {
$this->log('< ' . $key . ': ' . $val); $this->log('< ' . $key . ': ' . $val);

View File

@ -6,19 +6,19 @@
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2008-2011, Alexey Borzov <avb@php.net> * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * The names of the authors may not be used to endorse or promote products * * The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
@ -33,12 +33,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @category HTTP * @category HTTP
* @package HTTP_Request2 * @package HTTP_Request2
* @author Alexey Borzov <avb@php.net> * @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: Response.php 309921 2011-04-03 16:43:02Z avb $ * @version SVN: $Id: Response.php 324936 2012-04-07 07:49:03Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
/** /**
@ -66,84 +66,85 @@ require_once 'HTTP/Request2/Exception.php';
* var_dump($response->getHeader(), $response->getCookies(), $response->getBody()); * var_dump($response->getHeader(), $response->getCookies(), $response->getBody());
* </code> * </code>
* *
* * @category HTTP
* @category HTTP * @package HTTP_Request2
* @package HTTP_Request2 * @author Alexey Borzov <avb@php.net>
* @author Alexey Borzov <avb@php.net> * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.0.0RC1 * @version Release: 2.1.1
* @link http://tools.ietf.org/html/rfc2616#section-6 * @link http://pear.php.net/package/HTTP_Request2
* @link http://tools.ietf.org/html/rfc2616#section-6
*/ */
class HTTP_Request2_Response class HTTP_Request2_Response
{ {
/** /**
* HTTP protocol version (e.g. 1.0, 1.1) * HTTP protocol version (e.g. 1.0, 1.1)
* @var string * @var string
*/ */
protected $version; protected $version;
/** /**
* Status code * Status code
* @var integer * @var integer
* @link http://tools.ietf.org/html/rfc2616#section-6.1.1 * @link http://tools.ietf.org/html/rfc2616#section-6.1.1
*/ */
protected $code; protected $code;
/** /**
* Reason phrase * Reason phrase
* @var string * @var string
* @link http://tools.ietf.org/html/rfc2616#section-6.1.1 * @link http://tools.ietf.org/html/rfc2616#section-6.1.1
*/ */
protected $reasonPhrase; protected $reasonPhrase;
/** /**
* Effective URL (may be different from original request URL in case of redirects) * Effective URL (may be different from original request URL in case of redirects)
* @var string * @var string
*/ */
protected $effectiveUrl; protected $effectiveUrl;
/** /**
* Associative array of response headers * Associative array of response headers
* @var array * @var array
*/ */
protected $headers = array(); protected $headers = array();
/** /**
* Cookies set in the response * Cookies set in the response
* @var array * @var array
*/ */
protected $cookies = array(); protected $cookies = array();
/** /**
* Name of last header processed by parseHederLine() * Name of last header processed by parseHederLine()
* *
* Used to handle the headers that span multiple lines * Used to handle the headers that span multiple lines
* *
* @var string * @var string
*/ */
protected $lastHeader = null; protected $lastHeader = null;
/** /**
* Response body * Response body
* @var string * @var string
*/ */
protected $body = ''; protected $body = '';
/** /**
* Whether the body is still encoded by Content-Encoding * Whether the body is still encoded by Content-Encoding
* *
* cURL provides the decoded body to the callback; if we are reading from * cURL provides the decoded body to the callback; if we are reading from
* socket the body is still gzipped / deflated * socket the body is still gzipped / deflated
* *
* @var bool * @var bool
*/ */
protected $bodyEncoded; protected $bodyEncoded;
/** /**
* Associative array of HTTP status code / reason phrase. * Associative array of HTTP status code / reason phrase.
* *
* @var array * @var array
* @link http://tools.ietf.org/html/rfc2616#section-10 * @link http://tools.ietf.org/html/rfc2616#section-10
*/ */
protected static $phrases = array( protected static $phrases = array(
// 1xx: Informational - Request received, continuing process // 1xx: Informational - Request received, continuing process
@ -203,14 +204,34 @@ class HTTP_Request2_Response
); );
/** /**
* Constructor, parses the response status line * Returns the default reason phrase for the given code or all reason phrases
* *
* @param string Response status line (e.g. "HTTP/1.1 200 OK") * @param int $code Response code
* @param bool Whether body is still encoded by Content-Encoding *
* @param string Effective URL of the response * @return string|array|null Default reason phrase for $code if $code is given
* @throws HTTP_Request2_MessageException if status line is invalid according to spec * (null if no phrase is available), array of all
*/ * reason phrases if $code is null
* @link http://pear.php.net/bugs/18716
*/
public static function getDefaultReasonPhrase($code = null)
{
if (null === $code) {
return self::$phrases;
} else {
return isset(self::$phrases[$code]) ? self::$phrases[$code] : null;
}
}
/**
* Constructor, parses the response status line
*
* @param string $statusLine Response status line (e.g. "HTTP/1.1 200 OK")
* @param bool $bodyEncoded Whether body is still encoded by Content-Encoding
* @param string $effectiveUrl Effective URL of the response
*
* @throws HTTP_Request2_MessageException if status line is invalid according to spec
*/
public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null) public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null)
{ {
if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) { if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) {
@ -219,33 +240,29 @@ class HTTP_Request2_Response
HTTP_Request2_Exception::MALFORMED_RESPONSE HTTP_Request2_Exception::MALFORMED_RESPONSE
); );
} }
$this->version = $m[1]; $this->version = $m[1];
$this->code = intval($m[2]); $this->code = intval($m[2]);
if (!empty($m[3])) { $this->reasonPhrase = !empty($m[3]) ? trim($m[3]) : self::getDefaultReasonPhrase($this->code);
$this->reasonPhrase = trim($m[3]);
} elseif (!empty(self::$phrases[$this->code])) {
$this->reasonPhrase = self::$phrases[$this->code];
}
$this->bodyEncoded = (bool)$bodyEncoded; $this->bodyEncoded = (bool)$bodyEncoded;
$this->effectiveUrl = (string)$effectiveUrl; $this->effectiveUrl = (string)$effectiveUrl;
} }
/** /**
* Parses the line from HTTP response filling $headers array * Parses the line from HTTP response filling $headers array
* *
* The method should be called after reading the line from socket or receiving * The method should be called after reading the line from socket or receiving
* it into cURL callback. Passing an empty string here indicates the end of * it into cURL callback. Passing an empty string here indicates the end of
* response headers and triggers additional processing, so be sure to pass an * response headers and triggers additional processing, so be sure to pass an
* empty string in the end. * empty string in the end.
* *
* @param string Line from HTTP response * @param string $headerLine Line from HTTP response
*/ */
public function parseHeaderLine($headerLine) public function parseHeaderLine($headerLine)
{ {
$headerLine = trim($headerLine, "\r\n"); $headerLine = trim($headerLine, "\r\n");
// empty string signals the end of headers, process the received ones
if ('' == $headerLine) { if ('' == $headerLine) {
// empty string signals the end of headers, process the received ones
if (!empty($this->headers['set-cookie'])) { if (!empty($this->headers['set-cookie'])) {
$cookies = is_array($this->headers['set-cookie'])? $cookies = is_array($this->headers['set-cookie'])?
$this->headers['set-cookie']: $this->headers['set-cookie']:
@ -261,8 +278,8 @@ class HTTP_Request2_Response
} }
} }
// string of the form header-name: header value
} elseif (preg_match('!^([^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+):(.+)$!', $headerLine, $m)) { } elseif (preg_match('!^([^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+):(.+)$!', $headerLine, $m)) {
// string of the form header-name: header value
$name = strtolower($m[1]); $name = strtolower($m[1]);
$value = trim($m[2]); $value = trim($m[2]);
if (empty($this->headers[$name])) { if (empty($this->headers[$name])) {
@ -275,8 +292,8 @@ class HTTP_Request2_Response
} }
$this->lastHeader = $name; $this->lastHeader = $name;
// continuation of a previous header
} elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) { } elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {
// continuation of a previous header
if (!is_array($this->headers[$this->lastHeader])) { if (!is_array($this->headers[$this->lastHeader])) {
$this->headers[$this->lastHeader] .= ' ' . trim($m[1]); $this->headers[$this->lastHeader] .= ' ' . trim($m[1]);
} else { } else {
@ -286,12 +303,13 @@ class HTTP_Request2_Response
} }
} }
/** /**
* Parses a Set-Cookie header to fill $cookies array * Parses a Set-Cookie header to fill $cookies array
* *
* @param string value of Set-Cookie header * @param string $cookieString value of Set-Cookie header
* @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html *
*/ * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
*/
protected function parseCookie($cookieString) protected function parseCookie($cookieString)
{ {
$cookie = array( $cookie = array(
@ -301,14 +319,14 @@ class HTTP_Request2_Response
'secure' => false 'secure' => false
); );
// Only a name=value pair
if (!strpos($cookieString, ';')) { if (!strpos($cookieString, ';')) {
// Only a name=value pair
$pos = strpos($cookieString, '='); $pos = strpos($cookieString, '=');
$cookie['name'] = trim(substr($cookieString, 0, $pos)); $cookie['name'] = trim(substr($cookieString, 0, $pos));
$cookie['value'] = trim(substr($cookieString, $pos + 1)); $cookie['value'] = trim(substr($cookieString, $pos + 1));
// Some optional parameters are supplied
} else { } else {
// Some optional parameters are supplied
$elements = explode(';', $cookieString); $elements = explode(';', $cookieString);
$pos = strpos($elements[0], '='); $pos = strpos($elements[0], '=');
$cookie['name'] = trim(substr($elements[0], 0, $pos)); $cookie['name'] = trim(substr($elements[0], 0, $pos));
@ -336,64 +354,69 @@ class HTTP_Request2_Response
$this->cookies[] = $cookie; $this->cookies[] = $cookie;
} }
/** /**
* Appends a string to the response body * Appends a string to the response body
* @param string *
*/ * @param string $bodyChunk part of response body
*/
public function appendBody($bodyChunk) public function appendBody($bodyChunk)
{ {
$this->body .= $bodyChunk; $this->body .= $bodyChunk;
} }
/** /**
* Returns the effective URL of the response * Returns the effective URL of the response
* *
* This may be different from the request URL if redirects were followed. * This may be different from the request URL if redirects were followed.
* *
* @return string * @return string
* @link http://pear.php.net/bugs/bug.php?id=18412 * @link http://pear.php.net/bugs/bug.php?id=18412
*/ */
public function getEffectiveUrl() public function getEffectiveUrl()
{ {
return $this->effectiveUrl; return $this->effectiveUrl;
} }
/** /**
* Returns the status code * Returns the status code
* @return integer *
*/ * @return integer
*/
public function getStatus() public function getStatus()
{ {
return $this->code; return $this->code;
} }
/** /**
* Returns the reason phrase * Returns the reason phrase
* @return string *
*/ * @return string
*/
public function getReasonPhrase() public function getReasonPhrase()
{ {
return $this->reasonPhrase; return $this->reasonPhrase;
} }
/** /**
* Whether response is a redirect that can be automatically handled by HTTP_Request2 * Whether response is a redirect that can be automatically handled by HTTP_Request2
* @return bool *
*/ * @return bool
*/
public function isRedirect() public function isRedirect()
{ {
return in_array($this->code, array(300, 301, 302, 303, 307)) return in_array($this->code, array(300, 301, 302, 303, 307))
&& isset($this->headers['location']); && isset($this->headers['location']);
} }
/** /**
* Returns either the named header or all response headers * Returns either the named header or all response headers
* *
* @param string Name of header to return * @param string $headerName Name of header to return
* @return string|array Value of $headerName header (null if header is *
* not present), array of all response headers if * @return string|array Value of $headerName header (null if header is
* $headerName is null * not present), array of all response headers if
*/ * $headerName is null
*/
public function getHeader($headerName = null) public function getHeader($headerName = null)
{ {
if (null === $headerName) { if (null === $headerName) {
@ -404,42 +427,42 @@ class HTTP_Request2_Response
} }
} }
/** /**
* Returns cookies set in response * Returns cookies set in response
* *
* @return array * @return array
*/ */
public function getCookies() public function getCookies()
{ {
return $this->cookies; return $this->cookies;
} }
/** /**
* Returns the body of the response * Returns the body of the response
* *
* @return string * @return string
* @throws HTTP_Request2_Exception if body cannot be decoded * @throws HTTP_Request2_Exception if body cannot be decoded
*/ */
public function getBody() public function getBody()
{ {
if (0 == strlen($this->body) || !$this->bodyEncoded || if (0 == strlen($this->body) || !$this->bodyEncoded
!in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate')) || !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))
) { ) {
return $this->body; return $this->body;
} else { } else {
if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) { if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
$oldEncoding = mb_internal_encoding(); $oldEncoding = mb_internal_encoding();
mb_internal_encoding('iso-8859-1'); mb_internal_encoding('8bit');
} }
try { try {
switch (strtolower($this->getHeader('content-encoding'))) { switch (strtolower($this->getHeader('content-encoding'))) {
case 'gzip': case 'gzip':
$decoded = self::decodeGzip($this->body); $decoded = self::decodeGzip($this->body);
break; break;
case 'deflate': case 'deflate':
$decoded = self::decodeDeflate($this->body); $decoded = self::decodeDeflate($this->body);
} }
} catch (Exception $e) { } catch (Exception $e) {
} }
@ -454,29 +477,30 @@ class HTTP_Request2_Response
} }
} }
/** /**
* Get the HTTP version of the response * Get the HTTP version of the response
* *
* @return string * @return string
*/ */
public function getVersion() public function getVersion()
{ {
return $this->version; return $this->version;
} }
/** /**
* Decodes the message-body encoded by gzip * Decodes the message-body encoded by gzip
* *
* The real decoding work is done by gzinflate() built-in function, this * The real decoding work is done by gzinflate() built-in function, this
* method only parses the header and checks data for compliance with * method only parses the header and checks data for compliance with
* RFC 1952 * RFC 1952
* *
* @param string gzip-encoded data * @param string $data gzip-encoded data
* @return string decoded data *
* @throws HTTP_Request2_LogicException * @return string decoded data
* @throws HTTP_Request2_MessageException * @throws HTTP_Request2_LogicException
* @link http://tools.ietf.org/html/rfc1952 * @throws HTTP_Request2_MessageException
*/ * @link http://tools.ietf.org/html/rfc1952
*/
public static function decodeGzip($data) public static function decodeGzip($data)
{ {
$length = strlen($data); $length = strlen($data);
@ -603,13 +627,14 @@ class HTTP_Request2_Response
return $unpacked; return $unpacked;
} }
/** /**
* Decodes the message-body encoded by deflate * Decodes the message-body encoded by deflate
* *
* @param string deflate-encoded data * @param string $data deflate-encoded data
* @return string decoded data *
* @throws HTTP_Request2_LogicException * @return string decoded data
*/ * @throws HTTP_Request2_LogicException
*/
public static function decodeDeflate($data) public static function decodeDeflate($data)
{ {
if (!function_exists('gzuncompress')) { if (!function_exists('gzuncompress')) {

View File

@ -0,0 +1,158 @@
<?php
/**
* SOCKS5 proxy connection class
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category HTTP
* @package HTTP_Request2
* @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: SOCKS5.php 324953 2012-04-08 07:24:12Z avb $
* @link http://pear.php.net/package/HTTP_Request2
*/
/** Socket wrapper class used by Socket Adapter */
require_once 'HTTP/Request2/SocketWrapper.php';
/**
* SOCKS5 proxy connection class (used by Socket Adapter)
*
* @category HTTP
* @package HTTP_Request2
* @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
* @link http://pear.php.net/bugs/bug.php?id=19332
* @link http://tools.ietf.org/html/rfc1928
*/
class HTTP_Request2_SOCKS5 extends HTTP_Request2_SocketWrapper
{
/**
* Constructor, tries to connect and authenticate to a SOCKS5 proxy
*
* @param string $address Proxy address, e.g. 'tcp://localhost:1080'
* @param int $timeout Connection timeout (seconds)
* @param array $sslOptions SSL context options
* @param string $username Proxy user name
* @param string $password Proxy password
*
* @throws HTTP_Request2_LogicException
* @throws HTTP_Request2_ConnectionException
* @throws HTTP_Request2_MessageException
*/
public function __construct(
$address, $timeout = 10, array $sslOptions = array(),
$username = null, $password = null
) {
parent::__construct($address, $timeout, $sslOptions);
if (strlen($username)) {
$request = pack('C4', 5, 2, 0, 2);
} else {
$request = pack('C3', 5, 1, 0);
}
$this->write($request);
$response = unpack('Cversion/Cmethod', $this->read(3));
if (5 != $response['version']) {
throw new HTTP_Request2_MessageException(
'Invalid version received from SOCKS5 proxy: ' . $response['version'],
HTTP_Request2_Exception::MALFORMED_RESPONSE
);
}
switch ($response['method']) {
case 2:
$this->performAuthentication($username, $password);
case 0:
break;
default:
throw new HTTP_Request2_ConnectionException(
"Connection rejected by proxy due to unsupported auth method"
);
}
}
/**
* Performs username/password authentication for SOCKS5
*
* @param string $username Proxy user name
* @param string $password Proxy password
*
* @throws HTTP_Request2_ConnectionException
* @throws HTTP_Request2_MessageException
* @link http://tools.ietf.org/html/rfc1929
*/
protected function performAuthentication($username, $password)
{
$request = pack('C2', 1, strlen($username)) . $username
. pack('C', strlen($password)) . $password;
$this->write($request);
$response = unpack('Cvn/Cstatus', $this->read(3));
if (1 != $response['vn'] || 0 != $response['status']) {
throw new HTTP_Request2_ConnectionException(
'Connection rejected by proxy due to invalid username and/or password'
);
}
}
/**
* Connects to a remote host via proxy
*
* @param string $remoteHost Remote host
* @param int $remotePort Remote port
*
* @throws HTTP_Request2_ConnectionException
* @throws HTTP_Request2_MessageException
*/
public function connect($remoteHost, $remotePort)
{
$request = pack('C5', 0x05, 0x01, 0x00, 0x03, strlen($remoteHost))
. $remoteHost . pack('n', $remotePort);
$this->write($request);
$response = unpack('Cversion/Creply/Creserved', $this->read(1024));
if (5 != $response['version'] || 0 != $response['reserved']) {
throw new HTTP_Request2_MessageException(
'Invalid response received from SOCKS5 proxy',
HTTP_Request2_Exception::MALFORMED_RESPONSE
);
} elseif (0 != $response['reply']) {
throw new HTTP_Request2_ConnectionException(
"Unable to connect to {$remoteHost}:{$remotePort} through SOCKS5 proxy",
0, $response['reply']
);
}
}
}
?>

View File

@ -0,0 +1,283 @@
<?php
/**
* Socket wrapper class used by Socket Adapter
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category HTTP
* @package HTTP_Request2
* @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version SVN: $Id: SocketWrapper.php 324935 2012-04-07 07:10:50Z avb $
* @link http://pear.php.net/package/HTTP_Request2
*/
/** Exception classes for HTTP_Request2 package */
require_once 'HTTP/Request2/Exception.php';
/**
* Socket wrapper class used by Socket Adapter
*
* Needed to properly handle connection errors, global timeout support and
* similar things. Loosely based on Net_Socket used by older HTTP_Request.
*
* @category HTTP
* @package HTTP_Request2
* @author Alexey Borzov <avb@php.net>
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 2.1.1
* @link http://pear.php.net/package/HTTP_Request2
* @link http://pear.php.net/bugs/bug.php?id=19332
* @link http://tools.ietf.org/html/rfc1928
*/
class HTTP_Request2_SocketWrapper
{
/**
* PHP warning messages raised during stream_socket_client() call
* @var array
*/
protected $connectionWarnings = array();
/**
* Connected socket
* @var resource
*/
protected $socket;
/**
* Sum of start time and global timeout, exception will be thrown if request continues past this time
* @var integer
*/
protected $deadline;
/**
* Global timeout value, mostly for exception messages
* @var integer
*/
protected $timeout;
/**
* Class constructor, tries to establish connection
*
* @param string $address Address for stream_socket_client() call,
* e.g. 'tcp://localhost:80'
* @param int $timeout Connection timeout (seconds)
* @param array $sslOptions SSL context options
*
* @throws HTTP_Request2_LogicException
* @throws HTTP_Request2_ConnectionException
*/
public function __construct($address, $timeout, array $sslOptions = array())
{
$context = stream_context_create();
foreach ($sslOptions as $name => $value) {
if (!stream_context_set_option($context, 'ssl', $name, $value)) {
throw new HTTP_Request2_LogicException(
"Error setting SSL context option '{$name}'"
);
}
}
set_error_handler(array($this, 'connectionWarningsHandler'));
$this->socket = stream_socket_client(
$address, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context
);
restore_error_handler();
if (!$this->socket) {
$error = $errstr ? $errstr : implode("\n", $this->connectionWarnings);
throw new HTTP_Request2_ConnectionException(
"Unable to connect to {$address}. Error: {$error}", 0, $errno
);
}
}
/**
* Destructor, disconnects socket
*/
public function __destruct()
{
fclose($this->socket);
}
/**
* Wrapper around fread(), handles global request timeout
*
* @param int $length Reads up to this number of bytes
*
* @return string Data read from socket
* @throws HTTP_Request2_MessageException In case of timeout
*/
public function read($length)
{
if ($this->deadline) {
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
}
$data = fread($this->socket, $length);
$this->checkTimeout();
return $data;
}
/**
* Reads until either the end of the socket or a newline, whichever comes first
*
* Strips the trailing newline from the returned data, handles global
* request timeout. Method idea borrowed from Net_Socket PEAR package.
*
* @param int $bufferSize buffer size to use for reading
*
* @return string Available data up to the newline (not including newline)
* @throws HTTP_Request2_MessageException In case of timeout
*/
public function readLine($bufferSize)
{
$line = '';
while (!feof($this->socket)) {
if ($this->deadline) {
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
}
$line .= @fgets($this->socket, $bufferSize);
$this->checkTimeout();
if (substr($line, -1) == "\n") {
return rtrim($line, "\r\n");
}
}
return $line;
}
/**
* Wrapper around fwrite(), handles global request timeout
*
* @param string $data String to be written
*
* @return int
* @throws HTTP_Request2_MessageException
*/
public function write($data)
{
if ($this->deadline) {
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
}
$written = fwrite($this->socket, $data);
$this->checkTimeout();
// http://www.php.net/manual/en/function.fwrite.php#96951
if ($written < strlen($data)) {
throw new HTTP_Request2_MessageException('Error writing request');
}
return $written;
}
/**
* Tests for end-of-file on a socket
*
* @return bool
*/
public function eof()
{
return feof($this->socket);
}
/**
* Sets request deadline
*
* @param int $deadline Exception will be thrown if request continues
* past this time
* @param int $timeout Original request timeout value, to use in
* Exception message
*/
public function setDeadline($deadline, $timeout)
{
$this->deadline = $deadline;
$this->timeout = $timeout;
}
/**
* Turns on encryption on a socket
*
* @throws HTTP_Request2_ConnectionException
*/
public function enableCrypto()
{
$modes = array(
STREAM_CRYPTO_METHOD_TLS_CLIENT,
STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
STREAM_CRYPTO_METHOD_SSLv2_CLIENT
);
foreach ($modes as $mode) {
if (stream_socket_enable_crypto($this->socket, true, $mode)) {
return;
}
}
throw new HTTP_Request2_ConnectionException(
'Failed to enable secure connection when connecting through proxy'
);
}
/**
* Throws an Exception if stream timed out
*
* @throws HTTP_Request2_MessageException
*/
protected function checkTimeout()
{
$info = stream_get_meta_data($this->socket);
if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {
$reason = $this->deadline
? "after {$this->timeout} second(s)"
: 'due to default_socket_timeout php.ini setting';
throw new HTTP_Request2_MessageException(
"Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT
);
}
}
/**
* Error handler to use during stream_socket_client() call
*
* One stream_socket_client() call may produce *multiple* PHP warnings
* (especially OpenSSL-related), we keep them in an array to later use for
* the message of HTTP_Request2_ConnectionException
*
* @param int $errno error level
* @param string $errstr error message
*
* @return bool
*/
protected function connectionWarningsHandler($errno, $errstr)
{
if ($errno & E_WARNING) {
array_unshift($this->connectionWarnings, $errstr);
}
return true;
}
}
?>

View File

@ -1,485 +0,0 @@
<?php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2004, Richard Heyes |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard at php net> |
// +-----------------------------------------------------------------------+
//
// $Id: URL.php,v 1.49 2007/06/28 14:43:07 davidc Exp $
//
// Net_URL Class
class Net_URL
{
var $options = array('encode_query_keys' => false);
/**
* Full url
* @var string
*/
var $url;
/**
* Protocol
* @var string
*/
var $protocol;
/**
* Username
* @var string
*/
var $username;
/**
* Password
* @var string
*/
var $password;
/**
* Host
* @var string
*/
var $host;
/**
* Port
* @var integer
*/
var $port;
/**
* Path
* @var string
*/
var $path;
/**
* Query string
* @var array
*/
var $querystring;
/**
* Anchor
* @var string
*/
var $anchor;
/**
* Whether to use []
* @var bool
*/
var $useBrackets;
/**
* PHP4 Constructor
*
* @see __construct()
*/
function Net_URL($url = null, $useBrackets = true)
{
$this->__construct($url, $useBrackets);
}
/**
* PHP5 Constructor
*
* Parses the given url and stores the various parts
* Defaults are used in certain cases
*
* @param string $url Optional URL
* @param bool $useBrackets Whether to use square brackets when
* multiple querystrings with the same name
* exist
*/
function __construct($url = null, $useBrackets = true)
{
$this->url = $url;
$this->useBrackets = $useBrackets;
$this->initialize();
}
function initialize()
{
$HTTP_SERVER_VARS = !empty($_SERVER) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
$this->user = '';
$this->pass = '';
$this->host = '';
$this->port = 80;
$this->path = '';
$this->querystring = array();
$this->anchor = '';
// Only use defaults if not an absolute URL given
if (!preg_match('/^[a-z0-9]+:\/\//i', $this->url)) {
$this->protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http');
/**
* Figure out host/port
*/
if (!empty($HTTP_SERVER_VARS['HTTP_HOST']) &&
preg_match('/^(.*)(:([0-9]+))?$/U', $HTTP_SERVER_VARS['HTTP_HOST'], $matches))
{
$host = $matches[1];
if (!empty($matches[3])) {
$port = $matches[3];
} else {
$port = $this->getStandardPort($this->protocol);
}
}
$this->user = '';
$this->pass = '';
$this->host = !empty($host) ? $host : (isset($HTTP_SERVER_VARS['SERVER_NAME']) ? $HTTP_SERVER_VARS['SERVER_NAME'] : 'localhost');
$this->port = !empty($port) ? $port : (isset($HTTP_SERVER_VARS['SERVER_PORT']) ? $HTTP_SERVER_VARS['SERVER_PORT'] : $this->getStandardPort($this->protocol));
$this->path = !empty($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : '/';
$this->querystring = isset($HTTP_SERVER_VARS['QUERY_STRING']) ? $this->_parseRawQuerystring($HTTP_SERVER_VARS['QUERY_STRING']) : null;
$this->anchor = '';
}
// Parse the url and store the various parts
if (!empty($this->url)) {
$urlinfo = parse_url($this->url);
// Default querystring
$this->querystring = array();
foreach ($urlinfo as $key => $value) {
switch ($key) {
case 'scheme':
$this->protocol = $value;
$this->port = $this->getStandardPort($value);
break;
case 'user':
case 'pass':
case 'host':
case 'port':
$this->$key = $value;
break;
case 'path':
if ($value{0} == '/') {
$this->path = $value;
} else {
$path = dirname($this->path) == DIRECTORY_SEPARATOR ? '' : dirname($this->path);
$this->path = sprintf('%s/%s', $path, $value);
}
break;
case 'query':
$this->querystring = $this->_parseRawQueryString($value);
break;
case 'fragment':
$this->anchor = $value;
break;
}
}
}
}
/**
* Returns full url
*
* @return string Full url
* @access public
*/
function getURL()
{
$querystring = $this->getQueryString();
$this->url = $this->protocol . '://'
. $this->user . (!empty($this->pass) ? ':' : '')
. $this->pass . (!empty($this->user) ? '@' : '')
. $this->host . ($this->port == $this->getStandardPort($this->protocol) ? '' : ':' . $this->port)
. $this->path
. (!empty($querystring) ? '?' . $querystring : '')
. (!empty($this->anchor) ? '#' . $this->anchor : '');
return $this->url;
}
/**
* Adds or updates a querystring item (URL parameter).
* Automatically encodes parameters with rawurlencode() if $preencoded
* is false.
* You can pass an array to $value, it gets mapped via [] in the URL if
* $this->useBrackets is activated.
*
* @param string $name Name of item
* @param string $value Value of item
* @param bool $preencoded Whether value is urlencoded or not, default = not
* @access public
*/
function addQueryString($name, $value, $preencoded = false)
{
if ($this->getOption('encode_query_keys')) {
$name = rawurlencode($name);
}
if ($preencoded) {
$this->querystring[$name] = $value;
} else {
$this->querystring[$name] = is_array($value) ? array_map('rawurlencode', $value): rawurlencode($value);
}
}
/**
* Removes a querystring item
*
* @param string $name Name of item
* @access public
*/
function removeQueryString($name)
{
if ($this->getOption('encode_query_keys')) {
$name = rawurlencode($name);
}
if (isset($this->querystring[$name])) {
unset($this->querystring[$name]);
}
}
/**
* Sets the querystring to literally what you supply
*
* @param string $querystring The querystring data. Should be of the format foo=bar&x=y etc
* @access public
*/
function addRawQueryString($querystring)
{
$this->querystring = $this->_parseRawQueryString($querystring);
}
/**
* Returns flat querystring
*
* @return string Querystring
* @access public
*/
function getQueryString()
{
if (!empty($this->querystring)) {
foreach ($this->querystring as $name => $value) {
// Encode var name
$name = rawurlencode($name);
if (is_array($value)) {
foreach ($value as $k => $v) {
$querystring[] = $this->useBrackets ? sprintf('%s[%s]=%s', $name, $k, $v) : ($name . '=' . $v);
}
} elseif (!is_null($value)) {
$querystring[] = $name . '=' . $value;
} else {
$querystring[] = $name;
}
}
$querystring = implode(ini_get('arg_separator.output'), $querystring);
} else {
$querystring = '';
}
return $querystring;
}
/**
* Parses raw querystring and returns an array of it
*
* @param string $querystring The querystring to parse
* @return array An array of the querystring data
* @access private
*/
function _parseRawQuerystring($querystring)
{
$parts = preg_split('/[' . preg_quote(ini_get('arg_separator.input'), '/') . ']/', $querystring, -1, PREG_SPLIT_NO_EMPTY);
$return = array();
foreach ($parts as $part) {
if (strpos($part, '=') !== false) {
$value = substr($part, strpos($part, '=') + 1);
$key = substr($part, 0, strpos($part, '='));
} else {
$value = null;
$key = $part;
}
if (!$this->getOption('encode_query_keys')) {
$key = rawurldecode($key);
}
if (preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $key, $matches)) {
$key = $matches[1];
$idx = $matches[2];
// Ensure is an array
if (empty($return[$key]) || !is_array($return[$key])) {
$return[$key] = array();
}
// Add data
if ($idx === '') {
$return[$key][] = $value;
} else {
$return[$key][$idx] = $value;
}
} elseif (!$this->useBrackets AND !empty($return[$key])) {
$return[$key] = (array)$return[$key];
$return[$key][] = $value;
} else {
$return[$key] = $value;
}
}
return $return;
}
/**
* Resolves //, ../ and ./ from a path and returns
* the result. Eg:
*
* /foo/bar/../boo.php => /foo/boo.php
* /foo/bar/../../boo.php => /boo.php
* /foo/bar/.././/boo.php => /foo/boo.php
*
* This method can also be called statically.
*
* @param string $path URL path to resolve
* @return string The result
*/
function resolvePath($path)
{
$path = explode('/', str_replace('//', '/', $path));
for ($i=0; $i<count($path); $i++) {
if ($path[$i] == '.') {
unset($path[$i]);
$path = array_values($path);
$i--;
} elseif ($path[$i] == '..' AND ($i > 1 OR ($i == 1 AND $path[0] != '') ) ) {
unset($path[$i]);
unset($path[$i-1]);
$path = array_values($path);
$i -= 2;
} elseif ($path[$i] == '..' AND $i == 1 AND $path[0] == '') {
unset($path[$i]);
$path = array_values($path);
$i--;
} else {
continue;
}
}
return implode('/', $path);
}
/**
* Returns the standard port number for a protocol
*
* @param string $scheme The protocol to lookup
* @return integer Port number or NULL if no scheme matches
*
* @author Philippe Jausions <Philippe.Jausions@11abacus.com>
*/
function getStandardPort($scheme)
{
switch (strtolower($scheme)) {
case 'http': return 80;
case 'https': return 443;
case 'ftp': return 21;
case 'imap': return 143;
case 'imaps': return 993;
case 'pop3': return 110;
case 'pop3s': return 995;
default: return null;
}
}
/**
* Forces the URL to a particular protocol
*
* @param string $protocol Protocol to force the URL to
* @param integer $port Optional port (standard port is used by default)
*/
function setProtocol($protocol, $port = null)
{
$this->protocol = $protocol;
$this->port = is_null($port) ? $this->getStandardPort($protocol) : $port;
}
/**
* Set an option
*
* This function set an option
* to be used thorough the script.
*
* @access public
* @param string $optionName The optionname to set
* @param string $value The value of this option.
*/
function setOption($optionName, $value)
{
if (!array_key_exists($optionName, $this->options)) {
return false;
}
$this->options[$optionName] = $value;
$this->initialize();
}
/**
* Get an option
*
* This function gets an option
* from the $this->options array
* and return it's value.
*
* @access public
* @param string $opionName The name of the option to retrieve
* @see $this->options
*/
function getOption($optionName)
{
if (!isset($this->options[$optionName])) {
return false;
}
return $this->options[$optionName];
}
}
?>

220
extlib/Net/URL2.php Normal file → Executable file
View File

@ -18,9 +18,9 @@
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in * notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution. * the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_LexerGenerator nor the names of its * * Neither the name of the Net_URL2 nor the names of its contributors may
* contributors may be used to endorse or promote products derived * be used to endorse or promote products derived from this software
* from this software without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
@ -36,10 +36,10 @@
* *
* @category Networking * @category Networking
* @package Net_URL2 * @package Net_URL2
* @author Christian Schmidt <chsc@peytz.dk> * @author Christian Schmidt <schmidt@php.net>
* @copyright 2007-2008 Peytz & Co. A/S * @copyright 2007-2009 Peytz & Co. A/S
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: URL2.php 286661 2009-08-02 12:50:54Z schmidt $ * @version CVS: $Id: URL2.php 309223 2011-03-14 14:26:32Z till $
* @link http://www.rfc-editor.org/rfc/rfc3986.txt * @link http://www.rfc-editor.org/rfc/rfc3986.txt
*/ */
@ -48,8 +48,8 @@
* *
* @category Networking * @category Networking
* @package Net_URL2 * @package Net_URL2
* @author Christian Schmidt <chsc@peytz.dk> * @author Christian Schmidt <schmidt@php.net>
* @copyright 2007-2008 Peytz & Co. ApS * @copyright 2007-2009 Peytz & Co. A/S
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version Release: @package_version@ * @version Release: @package_version@
* @link http://pear.php.net/package/Net_URL2 * @link http://pear.php.net/package/Net_URL2
@ -74,15 +74,13 @@ class Net_URL2
/** /**
* Query variable separators when parsing the query string. Every character * Query variable separators when parsing the query string. Every character
* is considered a separator. Default is specified by the * is considered a separator. Default is "&".
* arg_separator.input php.ini setting (this defaults to "&").
*/ */
const OPTION_SEPARATOR_INPUT = 'input_separator'; const OPTION_SEPARATOR_INPUT = 'input_separator';
/** /**
* Query variable separator used when generating the query string. Default * Query variable separator used when generating the query string. Default
* is specified by the arg_separator.output php.ini setting (this defaults * is "&".
* to "&").
*/ */
const OPTION_SEPARATOR_OUTPUT = 'output_separator'; const OPTION_SEPARATOR_OUTPUT = 'output_separator';
@ -93,8 +91,8 @@ class Net_URL2
self::OPTION_STRICT => true, self::OPTION_STRICT => true,
self::OPTION_USE_BRACKETS => true, self::OPTION_USE_BRACKETS => true,
self::OPTION_ENCODE_KEYS => true, self::OPTION_ENCODE_KEYS => true,
self::OPTION_SEPARATOR_INPUT => 'x&', self::OPTION_SEPARATOR_INPUT => '&',
self::OPTION_SEPARATOR_OUTPUT => 'x&', self::OPTION_SEPARATOR_OUTPUT => '&',
); );
/** /**
@ -113,7 +111,7 @@ class Net_URL2
private $_host = false; private $_host = false;
/** /**
* @var int|bool * @var string|bool
*/ */
private $_port = false; private $_port = false;
@ -137,41 +135,19 @@ class Net_URL2
* *
* @param string $url an absolute or relative URL * @param string $url an absolute or relative URL
* @param array $options an array of OPTION_xxx constants * @param array $options an array of OPTION_xxx constants
*
* @return $this
* @uses self::parseUrl()
*/ */
public function __construct($url, $options = null) public function __construct($url, array $options = array())
{ {
$this->setOption(self::OPTION_SEPARATOR_INPUT, foreach ($options as $optionName => $value) {
ini_get('arg_separator.input')); if (array_key_exists($optionName, $this->_options)) {
$this->setOption(self::OPTION_SEPARATOR_OUTPUT, $this->_options[$optionName] = $value;
ini_get('arg_separator.output'));
if (is_array($options)) {
foreach ($options as $optionName => $value) {
$this->setOption($optionName, $value);
} }
} }
if (preg_match('@^([a-z][a-z0-9.+-]*):@i', $url, $reg)) { $this->parseUrl($url);
$this->_scheme = $reg[1];
$url = substr($url, strlen($reg[0]));
}
if (preg_match('@^//([^/#?]+)@', $url, $reg)) {
$this->setAuthority($reg[1]);
$url = substr($url, strlen($reg[0]));
}
$i = strcspn($url, '?#');
$this->_path = substr($url, 0, $i);
$url = substr($url, $i);
if (preg_match('@^\?([^#]*)@', $url, $reg)) {
$this->_query = $reg[1];
$url = substr($url, strlen($reg[0]));
}
if ($url) {
$this->_fragment = substr($url, 1);
}
} }
/** /**
@ -232,12 +208,13 @@ class Net_URL2
* scheme specified, i.e. if this is a relative * scheme specified, i.e. if this is a relative
* URL * URL
* *
* @return void * @return $this
* @see getScheme() * @see getScheme()
*/ */
public function setScheme($scheme) public function setScheme($scheme)
{ {
$this->_scheme = $scheme; $this->_scheme = $scheme;
return $this;
} }
/** /**
@ -286,7 +263,7 @@ class Net_URL2
* @param string|bool $userinfo userinfo or username * @param string|bool $userinfo userinfo or username
* @param string|bool $password optional password, or false * @param string|bool $password optional password, or false
* *
* @return void * @return $this
*/ */
public function setUserinfo($userinfo, $password = false) public function setUserinfo($userinfo, $password = false)
{ {
@ -294,6 +271,7 @@ class Net_URL2
if ($password !== false) { if ($password !== false) {
$this->_userinfo .= ':' . $password; $this->_userinfo .= ':' . $password;
} }
return $this;
} }
/** /**
@ -313,18 +291,19 @@ class Net_URL2
* *
* @param string|bool $host a hostname, an IP address, or false * @param string|bool $host a hostname, an IP address, or false
* *
* @return void * @return $this
*/ */
public function setHost($host) public function setHost($host)
{ {
$this->_host = $host; $this->_host = $host;
return $this;
} }
/** /**
* Returns the port number, or false if there is no port number specified, * Returns the port number, or false if there is no port number specified,
* i.e. if the default port is to be used. * i.e. if the default port is to be used.
* *
* @return int|bool * @return string|bool
*/ */
public function getPort() public function getPort()
{ {
@ -335,13 +314,14 @@ class Net_URL2
* Sets the port number. Specify false if there is no port number specified, * Sets the port number. Specify false if there is no port number specified,
* i.e. if the default port is to be used. * i.e. if the default port is to be used.
* *
* @param int|bool $port a port number, or false * @param string|bool $port a port number, or false
* *
* @return void * @return $this
*/ */
public function setPort($port) public function setPort($port)
{ {
$this->_port = intval($port); $this->_port = $port;
return $this;
} }
/** /**
@ -379,7 +359,7 @@ class Net_URL2
* with userinfo prefixed and port number * with userinfo prefixed and port number
* appended, e.g. "foo:bar@example.org:81". * appended, e.g. "foo:bar@example.org:81".
* *
* @return void * @return $this
*/ */
public function setAuthority($authority) public function setAuthority($authority)
{ {
@ -393,9 +373,10 @@ class Net_URL2
$this->_host = $reg[3]; $this->_host = $reg[3];
if (isset($reg[5])) { if (isset($reg[5])) {
$this->_port = intval($reg[5]); $this->_port = $reg[5];
} }
} }
return $this;
} }
/** /**
@ -413,11 +394,12 @@ class Net_URL2
* *
* @param string $path a path * @param string $path a path
* *
* @return void * @return $this
*/ */
public function setPath($path) public function setPath($path)
{ {
$this->_path = $path; $this->_path = $path;
return $this;
} }
/** /**
@ -438,12 +420,13 @@ class Net_URL2
* *
* @param string|bool $query a query string, e.g. "foo=1&bar=2" * @param string|bool $query a query string, e.g. "foo=1&bar=2"
* *
* @return void * @return $this
* @see self::setQueryVariables() * @see self::setQueryVariables()
*/ */
public function setQuery($query) public function setQuery($query)
{ {
$this->_query = $query; $this->_query = $query;
return $this;
} }
/** /**
@ -462,11 +445,12 @@ class Net_URL2
* @param string|bool $fragment a fragment excluding the leading "#", or * @param string|bool $fragment a fragment excluding the leading "#", or
* false * false
* *
* @return void * @return $this
*/ */
public function setFragment($fragment) public function setFragment($fragment)
{ {
$this->_fragment = $fragment; $this->_fragment = $fragment;
return $this;
} }
/** /**
@ -532,33 +516,19 @@ class Net_URL2
* *
* @param array $array (name => value) array * @param array $array (name => value) array
* *
* @return void * @return $this
*/ */
public function setQueryVariables(array $array) public function setQueryVariables(array $array)
{ {
if (!$array) { if (!$array) {
$this->_query = false; $this->_query = false;
} else { } else {
foreach ($array as $name => $value) { $this->_query = $this->buildQuery(
if ($this->getOption(self::OPTION_ENCODE_KEYS)) { $array,
$name = self::urlencode($name); $this->getOption(self::OPTION_SEPARATOR_OUTPUT)
} );
if (is_array($value)) {
foreach ($value as $k => $v) {
$parts[] = $this->getOption(self::OPTION_USE_BRACKETS)
? sprintf('%s[%s]=%s', $name, $k, $v)
: ($name . '=' . $v);
}
} elseif (!is_null($value)) {
$parts[] = $name . '=' . self::urlencode($value);
} else {
$parts[] = $name;
}
}
$this->_query = implode($this->getOption(self::OPTION_SEPARATOR_OUTPUT),
$parts);
} }
return $this;
} }
/** /**
@ -567,13 +537,14 @@ class Net_URL2
* @param string $name variable name * @param string $name variable name
* @param mixed $value variable value * @param mixed $value variable value
* *
* @return array * @return $this
*/ */
public function setQueryVariable($name, $value) public function setQueryVariable($name, $value)
{ {
$array = $this->getQueryVariables(); $array = $this->getQueryVariables();
$array[$name] = $value; $array[$name] = $value;
$this->setQueryVariables($array); $this->setQueryVariables($array);
return $this;
} }
/** /**
@ -832,9 +803,10 @@ class Net_URL2
public static function urlencode($string) public static function urlencode($string)
{ {
$encoded = rawurlencode($string); $encoded = rawurlencode($string);
// This is only necessary in PHP < 5.3.
$encoded = str_replace('%7E', '~', $encoded); // This is only necessary in PHP < 5.3.
return $encoded; $encoded = str_replace('%7E', '~', $encoded);
return $encoded;
} }
/** /**
@ -854,7 +826,7 @@ class Net_URL2
$url = new self($_SERVER['PHP_SELF']); $url = new self($_SERVER['PHP_SELF']);
$url->_scheme = isset($_SERVER['HTTPS']) ? 'https' : 'http'; $url->_scheme = isset($_SERVER['HTTPS']) ? 'https' : 'http';
$url->_host = $_SERVER['SERVER_NAME']; $url->_host = $_SERVER['SERVER_NAME'];
$port = intval($_SERVER['SERVER_PORT']); $port = $_SERVER['SERVER_PORT'];
if ($url->_scheme == 'http' && $port != 80 || if ($url->_scheme == 'http' && $port != 80 ||
$url->_scheme == 'https' && $port != 443) { $url->_scheme == 'https' && $port != 443) {
@ -894,25 +866,6 @@ class Net_URL2
return $url; return $url;
} }
/**
* Sets the specified option.
*
* @param string $optionName a self::OPTION_ constant
* @param mixed $value option value
*
* @return void
* @see self::OPTION_STRICT
* @see self::OPTION_USE_BRACKETS
* @see self::OPTION_ENCODE_KEYS
*/
function setOption($optionName, $value)
{
if (!array_key_exists($optionName, $this->_options)) {
return false;
}
$this->_options[$optionName] = $value;
}
/** /**
* Returns the value of the specified option. * Returns the value of the specified option.
* *
@ -920,9 +873,70 @@ class Net_URL2
* *
* @return mixed * @return mixed
*/ */
function getOption($optionName) public function getOption($optionName)
{ {
return isset($this->_options[$optionName]) return isset($this->_options[$optionName])
? $this->_options[$optionName] : false; ? $this->_options[$optionName] : false;
} }
/**
* A simple version of http_build_query in userland. The encoded string is
* percentage encoded according to RFC 3986.
*
* @param array $data An array, which has to be converted into
* QUERY_STRING. Anything is possible.
* @param string $seperator See {@link self::OPTION_SEPARATOR_OUTPUT}
* @param string $key For stacked values (arrays in an array).
*
* @return string
*/
protected function buildQuery(array $data, $separator, $key = null)
{
$query = array();
foreach ($data as $name => $value) {
if ($this->getOption(self::OPTION_ENCODE_KEYS) === true) {
$name = rawurlencode($name);
}
if ($key !== null) {
if ($this->getOption(self::OPTION_USE_BRACKETS) === true) {
$name = $key . '[' . $name . ']';
} else {
$name = $key;
}
}
if (is_array($value)) {
$query[] = $this->buildQuery($value, $separator, $name);
} else {
$query[] = $name . '=' . rawurlencode($value);
}
}
return implode($separator, $query);
}
/**
* This method uses a funky regex to parse the url into the designated parts.
*
* @param string $url
*
* @return void
* @uses self::$_scheme, self::setAuthority(), self::$_path, self::$_query,
* self::$_fragment
* @see self::__construct()
*/
protected function parseUrl($url)
{
// The regular expression is copied verbatim from RFC 3986, appendix B.
// The expression does not validate the URL but matches any string.
preg_match('!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!',
$url,
$matches);
// "path" is always present (possibly as an empty string); the rest
// are optional.
$this->_scheme = !empty($matches[1]) ? $matches[2] : false;
$this->setAuthority(!empty($matches[3]) ? $matches[4] : false);
$this->_path = $matches[5];
$this->_query = !empty($matches[6]) ? $matches[7] : false;
$this->_fragment = !empty($matches[8]) ? $matches[9] : false;
}
} }

View File

@ -0,0 +1,98 @@
<?php
/**
* Helper file for downloading Public Suffix List and converting it to PHP array
*
* You can run this script to update PSL to the current version instead of
* waiting for a new release of HTTP_Request2.
*
* @version SVN: $Id: generate-list.php 308480 2011-02-19 11:27:13Z avb $
*/
/** URL to download Public Suffix List from */
define('LIST_URL', 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1');
/** Name of PHP file to write */
define('OUTPUT_FILE', dirname(__FILE__) . '/public-suffix-list.php');
require_once 'HTTP/Request2.php';
function buildSubdomain(&$node, $tldParts)
{
$part = trim(array_pop($tldParts));
if (!array_key_exists($part, $node)) {
$node[$part] = array();
}
if (0 < count($tldParts)) {
buildSubdomain($node[$part], $tldParts);
}
}
function writeNode($fp, $valueTree, $key = null, $indent = 0)
{
if (is_null($key)) {
fwrite($fp, "return ");
} else {
fwrite($fp, str_repeat(' ', $indent) . "'$key' => ");
}
if (0 == ($count = count($valueTree))) {
fwrite($fp, 'true');
} else {
fwrite($fp, "array(\n");
for ($keys = array_keys($valueTree), $i = 0; $i < $count; $i++) {
writeNode($fp, $valueTree[$keys[$i]], $keys[$i], $indent + 1);
if ($i + 1 != $count) {
fwrite($fp, ",\n");
} else {
fwrite($fp, "\n");
}
}
fwrite($fp, str_repeat(' ', $indent) . ")");
}
}
try {
$request = new HTTP_Request2(LIST_URL);
$response = $request->send();
if (200 != $response->getStatus()) {
throw new Exception("List download URL returned status: " .
$response->getStatus() . ' ' . $response->getReasonPhrase());
}
$list = $response->getBody();
if (false === strpos($list, 'The Original Code is the Public Suffix List.')) {
throw new Exception("List download URL does not contain expected phrase");
}
if (!($fp = @fopen(OUTPUT_FILE, 'wt'))) {
throw new Exception("Unable to open " . OUTPUT_FILE);
}
} catch (Exception $e) {
die($e->getMessage());
}
$tldTree = array();
$license = true;
fwrite($fp, "<?php\n");
foreach (array_filter(array_map('trim', explode("\n", $list))) as $line) {
if ('//' != substr($line, 0, 2)) {
buildSubdomain($tldTree, explode('.', $line));
} elseif ($license) {
fwrite($fp, $line . "\n");
if (0 === strpos($line, "// ***** END LICENSE BLOCK")) {
$license = false;
fwrite($fp, "\n");
}
}
}
writeNode($fp, $tldTree);
fwrite($fp, ";\n?>");
fclose($fp);
?>

File diff suppressed because it is too large Load Diff