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

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
@ -37,7 +37,7 @@
* @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: Request2.php 308735 2011-02-27 20:31:28Z avb $ * @version SVN: $Id: Request2.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
*/ */
@ -57,7 +57,9 @@ require_once 'HTTP/Request2/Exception.php';
* @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
* @link http://tools.ietf.org/html/rfc2616#section-5 * @link http://tools.ietf.org/html/rfc2616#section-5
*/ */
class HTTP_Request2 implements SplSubject class HTTP_Request2 implements SplSubject
@ -156,6 +158,7 @@ class HTTP_Request2 implements SplSubject
'proxy_user' => '', 'proxy_user' => '',
'proxy_password' => '', 'proxy_password' => '',
'proxy_auth_scheme' => self::AUTH_BASIC, 'proxy_auth_scheme' => self::AUTH_BASIC,
'proxy_type' => 'http',
'ssl_verify_peer' => true, 'ssl_verify_peer' => true,
'ssl_verify_host' => true, 'ssl_verify_host' => true,
@ -217,12 +220,13 @@ class HTTP_Request2 implements SplSubject
* *
* Also sets a default value for User-Agent header. * Also sets a default value for User-Agent header.
* *
* @param string|Net_Url2 Request URL * @param string|Net_Url2 $url Request URL
* @param string Request method * @param string $method Request method
* @param array Configuration for this Request instance * @param array $config Configuration for this Request instance
*/ */
public function __construct($url = null, $method = self::METHOD_GET, array $config = array()) public function __construct(
{ $url = null, $method = self::METHOD_GET, array $config = array()
) {
$this->setConfig($config); $this->setConfig($config);
if (!empty($url)) { if (!empty($url)) {
$this->setUrl($url); $this->setUrl($url);
@ -230,9 +234,10 @@ class HTTP_Request2 implements SplSubject
if (!empty($method)) { if (!empty($method)) {
$this->setMethod($method); $this->setMethod($method);
} }
$this->setHeader('user-agent', 'HTTP_Request2/2.0.0RC1 ' . $this->setHeader(
'(http://pear.php.net/package/http_request2) ' . 'user-agent', 'HTTP_Request2/2.1.1 ' .
'PHP/' . phpversion()); '(http://pear.php.net/package/http_request2) PHP/' . phpversion()
);
} }
/** /**
@ -242,7 +247,8 @@ class HTTP_Request2 implements SplSubject
* and converted to auth data. If the URL does not have a path component, * and converted to auth data. If the URL does not have a path component,
* that will be set to '/'. * that will be set to '/'.
* *
* @param string|Net_URL2 Request URL * @param string|Net_URL2 $url Request URL
*
* @return HTTP_Request2 * @return HTTP_Request2
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
*/ */
@ -287,7 +293,8 @@ class HTTP_Request2 implements SplSubject
/** /**
* Sets the request method * Sets the request method
* *
* @param string * @param string $method one of the methods defined in RFC 2616
*
* @return HTTP_Request2 * @return HTTP_Request2
* @throws HTTP_Request2_LogicException if the method name is invalid * @throws HTTP_Request2_LogicException if the method name is invalid
*/ */
@ -331,11 +338,14 @@ class HTTP_Request2 implements SplSubject
* <li> 'store_body' - Whether to store response body in response object. * <li> 'store_body' - Whether to store response body in response object.
* Set to false if receiving a huge response and * Set to false if receiving a huge response and
* using an Observer to save it (boolean)</li> * using an Observer to save it (boolean)</li>
* <li> 'proxy_type' - Proxy type, 'http' or 'socks5' (string)</li>
* <li> 'proxy_host' - Proxy server host (string)</li> * <li> 'proxy_host' - Proxy server host (string)</li>
* <li> 'proxy_port' - Proxy server port (integer)</li> * <li> 'proxy_port' - Proxy server port (integer)</li>
* <li> 'proxy_user' - Proxy auth username (string)</li> * <li> 'proxy_user' - Proxy auth username (string)</li>
* <li> 'proxy_password' - Proxy auth password (string)</li> * <li> 'proxy_password' - Proxy auth password (string)</li>
* <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li> * <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li>
* <li> 'proxy' - Shorthand for proxy_* parameters, proxy given as URL,
* e.g. 'socks5://localhost:1080/' (string)</li>
* <li> 'ssl_verify_peer' - Whether to verify peer's SSL certificate (bool)</li> * <li> 'ssl_verify_peer' - Whether to verify peer's SSL certificate (bool)</li>
* <li> 'ssl_verify_host' - Whether to check that Common Name in SSL * <li> 'ssl_verify_host' - Whether to check that Common Name in SSL
* certificate matches host name (bool)</li> * certificate matches host name (bool)</li>
@ -357,9 +367,10 @@ class HTTP_Request2 implements SplSubject
* browsers) (boolean)</li> * browsers) (boolean)</li>
* </ul> * </ul>
* *
* @param string|array configuration parameter name or array * @param string|array $nameOrConfig configuration parameter name or array
* ('parameter name' => 'parameter value') * ('parameter name' => 'parameter value')
* @param mixed parameter value if $nameOrConfig is not an array * @param mixed $value parameter value if $nameOrConfig is not an array
*
* @return HTTP_Request2 * @return HTTP_Request2
* @throws HTTP_Request2_LogicException If the parameter is unknown * @throws HTTP_Request2_LogicException If the parameter is unknown
*/ */
@ -370,6 +381,16 @@ class HTTP_Request2 implements SplSubject
$this->setConfig($name, $value); $this->setConfig($name, $value);
} }
} elseif ('proxy' == $nameOrConfig) {
$url = new Net_URL2($value);
$this->setConfig(array(
'proxy_type' => $url->getScheme(),
'proxy_host' => $url->getHost(),
'proxy_port' => $url->getPort(),
'proxy_user' => rawurldecode($url->getUser()),
'proxy_password' => rawurldecode($url->getPassword())
));
} else { } else {
if (!array_key_exists($nameOrConfig, $this->config)) { if (!array_key_exists($nameOrConfig, $this->config)) {
throw new HTTP_Request2_LogicException( throw new HTTP_Request2_LogicException(
@ -386,7 +407,8 @@ class HTTP_Request2 implements SplSubject
/** /**
* Returns the value(s) of the configuration parameter(s) * Returns the value(s) of the configuration parameter(s)
* *
* @param string parameter name * @param string $name parameter name
*
* @return mixed value of $name parameter, array of all configuration * @return mixed value of $name parameter, array of all configuration
* parameters if $name is not given * parameters if $name is not given
* @throws HTTP_Request2_LogicException If the parameter is unknown * @throws HTTP_Request2_LogicException If the parameter is unknown
@ -407,9 +429,10 @@ class HTTP_Request2 implements SplSubject
/** /**
* Sets the autentification data * Sets the autentification data
* *
* @param string user name * @param string $user user name
* @param string password * @param string $password password
* @param string authentication scheme * @param string $scheme authentication scheme
*
* @return HTTP_Request2 * @return HTTP_Request2
*/ */
public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC) public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC)
@ -458,12 +481,13 @@ class HTTP_Request2 implements SplSubject
* $req->setHeader('FOO'); // removes 'Foo' header from request * $req->setHeader('FOO'); // removes 'Foo' header from request
* </code> * </code>
* *
* @param string|array header name, header string ('Header: value') * @param string|array $name header name, header string ('Header: value')
* or an array of headers * or an array of headers
* @param string|array|null header value if $name is not an array, * @param string|array|null $value header value if $name is not an array,
* header will be removed if value is null * header will be removed if value is null
* @param bool whether to replace previous header with the * @param bool $replace whether to replace previous header with the
* same name or append to its value * same name or append to its value
*
* @return HTTP_Request2 * @return HTTP_Request2
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
*/ */
@ -534,8 +558,9 @@ class HTTP_Request2 implements SplSubject
* parameters, 'expires' and 'secure' will be set to null and false, * parameters, 'expires' and 'secure' will be set to null and false,
* respectively. If you need further control, use CookieJar's methods. * respectively. If you need further control, use CookieJar's methods.
* *
* @param string cookie name * @param string $name cookie name
* @param string cookie value * @param string $value cookie value
*
* @return HTTP_Request2 * @return HTTP_Request2
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
* @see setCookieJar() * @see setCookieJar()
@ -543,8 +568,9 @@ class HTTP_Request2 implements SplSubject
public function addCookie($name, $value) public function addCookie($name, $value)
{ {
if (!empty($this->cookieJar)) { if (!empty($this->cookieJar)) {
$this->cookieJar->store(array('name' => $name, 'value' => $value), $this->cookieJar->store(
$this->url); array('name' => $name, 'value' => $value), $this->url
);
} else { } else {
$cookie = $name . '=' . $value; $cookie = $name . '=' . $value;
@ -567,10 +593,12 @@ class HTTP_Request2 implements SplSubject
* If you provide file pointer rather than file name, it should support * If you provide file pointer rather than file name, it should support
* fstat() and rewind() operations. * fstat() and rewind() operations.
* *
* @param string|resource|HTTP_Request2_MultipartBody Either a string * @param string|resource|HTTP_Request2_MultipartBody $body Either a
* with the body or filename containing body or pointer to * string with the body or filename containing body or
* an open file or object with multipart body data * pointer to an open file or object with multipart body data
* @param bool Whether first parameter is a filename * @param bool $isFilename Whether
* first parameter is a filename
*
* @return HTTP_Request2 * @return HTTP_Request2
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
*/ */
@ -601,8 +629,8 @@ class HTTP_Request2 implements SplSubject
*/ */
public function getBody() public function getBody()
{ {
if (self::METHOD_POST == $this->method && if (self::METHOD_POST == $this->method
(!empty($this->postParams) || !empty($this->uploads)) && (!empty($this->postParams) || !empty($this->uploads))
) { ) {
if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) { if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) {
$body = http_build_query($this->postParams, '', '&'); $body = http_build_query($this->postParams, '', '&');
@ -634,17 +662,18 @@ class HTTP_Request2 implements SplSubject
* If you provide file pointers rather than file names, they should support * If you provide file pointers rather than file names, they should support
* fstat() and rewind() operations. * fstat() and rewind() operations.
* *
* @param string name of file-upload field * @param string $fieldName name of file-upload field
* @param string|resource|array full name of local file, pointer to * @param string|resource|array $filename full name of local file,
* open file or an array of files * pointer to open file or an array of files
* @param string filename to send in the request * @param string $sendFilename filename to send in the request
* @param string content-type of file being uploaded * @param string $contentType content-type of file being uploaded
*
* @return HTTP_Request2 * @return HTTP_Request2
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
*/ */
public function addUpload($fieldName, $filename, $sendFilename = null, public function addUpload(
$contentType = null) $fieldName, $filename, $sendFilename = null, $contentType = null
{ ) {
if (!is_array($filename)) { if (!is_array($filename)) {
$fileData = $this->fopenWrapper($filename, empty($contentType)); $fileData = $this->fopenWrapper($filename, empty($contentType));
$this->uploads[$fieldName] = array( $this->uploads[$fieldName] = array(
@ -671,8 +700,8 @@ class HTTP_Request2 implements SplSubject
'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types 'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types
); );
} }
if (empty($this->headers['content-type']) || if (empty($this->headers['content-type'])
'application/x-www-form-urlencoded' == $this->headers['content-type'] || 'application/x-www-form-urlencoded' == $this->headers['content-type']
) { ) {
$this->setHeader('content-type', 'multipart/form-data'); $this->setHeader('content-type', 'multipart/form-data');
} }
@ -683,8 +712,9 @@ class HTTP_Request2 implements SplSubject
/** /**
* Adds POST parameter(s) to the request. * Adds POST parameter(s) to the request.
* *
* @param string|array parameter name or array ('name' => 'value') * @param string|array $name parameter name or array ('name' => 'value')
* @param mixed parameter value (can be an array) * @param mixed $value parameter value (can be an array)
*
* @return HTTP_Request2 * @return HTTP_Request2
*/ */
public function addPostParameter($name, $value = null) public function addPostParameter($name, $value = null)
@ -706,7 +736,7 @@ class HTTP_Request2 implements SplSubject
/** /**
* Attaches a new observer * Attaches a new observer
* *
* @param SplObserver * @param SplObserver $observer any object implementing SplObserver
*/ */
public function attach(SplObserver $observer) public function attach(SplObserver $observer)
{ {
@ -721,7 +751,7 @@ class HTTP_Request2 implements SplSubject
/** /**
* Detaches an existing observer * Detaches an existing observer
* *
* @param SplObserver * @param SplObserver $observer any object implementing SplObserver
*/ */
public function detach(SplObserver $observer) public function detach(SplObserver $observer)
{ {
@ -749,8 +779,8 @@ class HTTP_Request2 implements SplSubject
* Adapters should use this method to set the current state of the request * Adapters should use this method to set the current state of the request
* and notify the observers. * and notify the observers.
* *
* @param string event name * @param string $name event name
* @param mixed event data * @param mixed $data event data
*/ */
public function setLastEvent($name, $data = null) public function setLastEvent($name, $data = null)
{ {
@ -807,7 +837,8 @@ class HTTP_Request2 implements SplSubject
* </code> * </code>
* will work. * will work.
* *
* @param string|HTTP_Request2_Adapter * @param string|HTTP_Request2_Adapter $adapter Adapter to use
*
* @return HTTP_Request2 * @return HTTP_Request2
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
*/ */
@ -818,7 +849,9 @@ class HTTP_Request2 implements SplSubject
if (false === strpos($adapter, '_')) { if (false === strpos($adapter, '_')) {
$adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter); $adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter);
} }
if (preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)) { if (!class_exists($adapter, false)
&& preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)
) {
include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php'; include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php';
} }
if (!class_exists($adapter, false)) { if (!class_exists($adapter, false)) {
@ -848,8 +881,11 @@ class HTTP_Request2 implements SplSubject
* responses. Cookies from jar will be automatically added to the request * responses. Cookies from jar will be automatically added to the request
* headers based on request URL. * headers based on request URL.
* *
* @param HTTP_Request2_CookieJar|bool Existing CookieJar object, true to * @param HTTP_Request2_CookieJar|bool $jar Existing CookieJar object, true to
* create a new one, false to remove * create a new one, false to remove
*
* @return HTTP_Request2
* @throws HTTP_Request2_LogicException
*/ */
public function setCookieJar($jar = true) public function setCookieJar($jar = true)
{ {
@ -899,7 +935,7 @@ class HTTP_Request2 implements SplSubject
throw new HTTP_Request2_LogicException( throw new HTTP_Request2_LogicException(
'HTTP_Request2 needs an absolute HTTP(S) request URL, ' 'HTTP_Request2 needs an absolute HTTP(S) request URL, '
. ($this->url instanceof Net_URL2 . ($this->url instanceof Net_URL2
? 'none' : "'" . $this->url->__toString() . "'") ? "'" . $this->url->__toString() . "'" : 'none')
. ' given', . ' given',
HTTP_Request2_Exception::INVALID_ARGUMENT HTTP_Request2_Exception::INVALID_ARGUMENT
); );
@ -916,7 +952,7 @@ class HTTP_Request2 implements SplSubject
// strlen() and substr(); see bug #1781, bug #10605 // strlen() and substr(); see bug #1781, bug #10605
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 {
@ -940,9 +976,11 @@ class HTTP_Request2 implements SplSubject
/** /**
* Wrapper around fopen()/fstat() used by setBody() and addUpload() * Wrapper around fopen()/fstat() used by setBody() and addUpload()
* *
* @param string|resource file name or pointer to open file * @param string|resource $file file name or pointer to open file
* @param bool whether to try autodetecting MIME type of file, * @param bool $detectType whether to try autodetecting MIME
* will only work if $file is a filename, not pointer * type of file, will only work if $file is a
* filename, not pointer
*
* @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type) * @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type)
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
*/ */
@ -960,16 +998,12 @@ class HTTP_Request2 implements SplSubject
'size' => 0 'size' => 0
); );
if (is_string($file)) { if (is_string($file)) {
$track = @ini_set('track_errors', 1);
if (!($fileData['fp'] = @fopen($file, 'rb'))) { if (!($fileData['fp'] = @fopen($file, 'rb'))) {
$e = new HTTP_Request2_LogicException( $error = error_get_last();
$php_errormsg, HTTP_Request2_Exception::READ_ERROR throw new HTTP_Request2_LogicException(
$error['message'], HTTP_Request2_Exception::READ_ERROR
); );
} }
@ini_set('track_errors', $track);
if (isset($e)) {
throw $e;
}
if ($detectType) { if ($detectType) {
$fileData['type'] = self::detectMimeType($file); $fileData['type'] = self::detectMimeType($file);
} }
@ -991,7 +1025,8 @@ class HTTP_Request2 implements SplSubject
* deprecated mime_content_type() function in the other case. If neither * deprecated mime_content_type() function in the other case. If neither
* works, default 'application/octet-stream' MIME type is returned * works, default 'application/octet-stream' MIME type is returned
* *
* @param string filename * @param string $filename file name
*
* @return string file MIME type * @return string file MIME type
*/ */
protected static function detectMimeType($filename) protected static function detectMimeType($filename)

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
@ -37,7 +37,7 @@
* @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
*/ */
@ -56,7 +56,9 @@ require_once 'HTTP/Request2/Response.php';
* @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
{ {
@ -100,7 +102,8 @@ abstract class 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 * @return HTTP_Request2_Response
* @throws HTTP_Request2_Exception * @throws HTTP_Request2_Exception
*/ */
@ -109,9 +112,9 @@ abstract class HTTP_Request2_Adapter
/** /**
* 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)
{ {
@ -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
@ -37,7 +37,7 @@
* @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
*/ */
@ -52,7 +52,9 @@ require_once 'HTTP/Request2/Adapter.php';
* @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
{ {
@ -153,7 +155,8 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
/** /**
* 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)
@ -173,7 +176,8 @@ 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 * @return HTTP_Request2_Response
* @throws HTTP_Request2_Exception * @throws HTTP_Request2_Exception
*/ */
@ -315,8 +319,10 @@ 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);
@ -325,6 +331,20 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
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"
);
}
}
} }
// set authentication data // set authentication data
@ -391,8 +411,8 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
* 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)
{ {
@ -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();
@ -424,9 +444,10 @@ 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)
@ -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 '';
} }
@ -457,8 +478,9 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
/** /**
* 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 * @return integer number of bytes saved
* @see HTTP_Request2_Response::parseHeaderLine() * @see HTTP_Request2_Response::parseHeaderLine()
*/ */
@ -467,8 +489,8 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
// 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)
@ -535,9 +557,11 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
/** /**
* 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 * @return integer number of bytes saved
* @throws HTTP_Request2_MessageException
* @see HTTP_Request2_Response::appendBody() * @see HTTP_Request2_Response::appendBody()
*/ */
protected function callbackWriteBody($ch, $string) protected function callbackWriteBody($ch, $string)

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
@ -37,7 +37,7 @@
* @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
*/ */
@ -66,7 +66,9 @@ require_once 'HTTP/Request2/Adapter.php';
* @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
{ {
@ -79,19 +81,33 @@ class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
/** /**
* 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
* will be considered. If matching response is not found or the queue is
* empty then default empty response with status 400 will be returned,
* if an Exception object was added to the queue it will be thrown. * if an Exception object was added to the queue it will be thrown.
* *
* @param HTTP_Request2 * @param HTTP_Request2 $request HTTP request message
*
* @return HTTP_Request2_Response * @return HTTP_Request2_Response
* @throws Exception * @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) {
if (!$v[1] || $requestUrl == $v[1]) {
$response = $v[0];
array_splice($this->responses, $k, 1);
break;
}
}
if (!$response) {
return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");
} elseif ($response instanceof HTTP_Request2_Response) {
return $response; return $response;
} else { } else {
// rethrow the exception // rethrow the exception
$class = get_class($response); $class = get_class($response);
@ -99,19 +115,19 @@ class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
$code = $response->getCode(); $code = $response->getCode();
throw new $class($message, $code); throw new $class($message, $code);
} }
} else {
return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");
}
} }
/** /**
* 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
* @param string $url A request URL this response should be valid for
* (see {@link http://pear.php.net/bugs/bug.php?id=19276})
*
* @throws HTTP_Request2_Exception * @throws HTTP_Request2_Exception
*/ */
public function addResponse($response) public function addResponse($response, $url = null)
{ {
if (is_string($response)) { if (is_string($response)) {
$response = self::createResponseFromString($response); $response = self::createResponseFromString($response);
@ -122,13 +138,14 @@ 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 * @return HTTP_Request2_Response
* @throws HTTP_Request2_Exception * @throws HTTP_Request2_Exception
*/ */
@ -150,7 +167,8 @@ class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
/** /**
* 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 * @return HTTP_Request2_Response
* @throws HTTP_Request2_Exception * @throws 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
@ -37,15 +37,16 @@
* @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: Socket.php 309921 2011-04-03 16:43:02Z avb $ * @version SVN: $Id: Socket.php 324953 2012-04-08 07:24:12Z avb $
* @link http://pear.php.net/package/HTTP_Request2 * @link http://pear.php.net/package/HTTP_Request2
*/ */
/** /** Base class for HTTP_Request2 adapters */
* Base class for HTTP_Request2 adapters
*/
require_once 'HTTP/Request2/Adapter.php'; require_once 'HTTP/Request2/Adapter.php';
/** Socket wrapper class */
require_once 'HTTP/Request2/SocketWrapper.php';
/** /**
* Socket-based adapter for HTTP_Request2 * Socket-based adapter for HTTP_Request2
* *
@ -55,7 +56,9 @@ require_once 'HTTP/Request2/Adapter.php';
* @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_Socket extends HTTP_Request2_Adapter class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
{ {
@ -92,7 +95,7 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
/** /**
* Connected socket * Connected socket
* @var resource * @var HTTP_Request2_SocketWrapper
* @see connect() * @see connect()
*/ */
protected $socket; protected $socket;
@ -109,12 +112,6 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
*/ */
protected $proxyChallenge; protected $proxyChallenge;
/**
* Sum of start time and global timeout, exception will be thrown if request continues past this time
* @var integer
*/
protected $deadline = null;
/** /**
* Remaining length of the current chunk, when reading chunked response * Remaining length of the current chunk, when reading chunked response
* @var integer * @var integer
@ -135,7 +132,8 @@ class HTTP_Request2_Adapter_Socket 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 * @return HTTP_Request2_Response
* @throws HTTP_Request2_Exception * @throws HTTP_Request2_Exception
*/ */
@ -143,31 +141,14 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
{ {
$this->request = $request; $this->request = $request;
// Use global request timeout if given, see feature requests #5735, #8964
if ($timeout = $request->getConfig('timeout')) {
$this->deadline = time() + $timeout;
} else {
$this->deadline = null;
}
try { try {
$keepAlive = $this->connect(); $keepAlive = $this->connect();
$headers = $this->prepareHeaders(); $headers = $this->prepareHeaders();
if (false === @fwrite($this->socket, $headers, strlen($headers))) { $this->socket->write($headers);
throw new HTTP_Request2_MessageException('Error writing request');
}
// provide request headers to the observer, see request #7633 // provide request headers to the observer, see request #7633
$this->request->setLastEvent('sentHeaders', $headers); $this->request->setLastEvent('sentHeaders', $headers);
$this->writeBody(); $this->writeBody();
if ($this->deadline && time() > $this->deadline) {
throw new HTTP_Request2_MessageException(
'Request timed out after ' .
$request->getConfig('timeout') . ' second(s)',
HTTP_Request2_Exception::TIMEOUT
);
}
$response = $this->readResponse(); $response = $this->readResponse();
if ($jar = $request->getCookieJar()) { if ($jar = $request->getCookieJar()) {
@ -226,21 +207,29 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$reqPort = $secure? 443: 80; $reqPort = $secure? 443: 80;
} }
if ($host = $this->request->getConfig('proxy_host')) { $httpProxy = $socksProxy = false;
if (!($host = $this->request->getConfig('proxy_host'))) {
$host = $reqHost;
$port = $reqPort;
} else {
if (!($port = $this->request->getConfig('proxy_port'))) { if (!($port = $this->request->getConfig('proxy_port'))) {
throw new HTTP_Request2_LogicException( throw new HTTP_Request2_LogicException(
'Proxy port not provided', 'Proxy port not provided',
HTTP_Request2_Exception::MISSING_VALUE HTTP_Request2_Exception::MISSING_VALUE
); );
} }
$proxy = true; if ('http' == ($type = $this->request->getConfig('proxy_type'))) {
$httpProxy = true;
} elseif ('socks5' == $type) {
$socksProxy = true;
} else { } else {
$host = $reqHost; throw new HTTP_Request2_NotImplementedException(
$port = $reqPort; "Proxy type '{$type}' is not supported"
$proxy = false; );
}
} }
if ($tunnel && !$proxy) { if ($tunnel && !$httpProxy) {
throw new HTTP_Request2_LogicException( throw new HTTP_Request2_LogicException(
"Trying to perform CONNECT request without proxy", "Trying to perform CONNECT request without proxy",
HTTP_Request2_Exception::MISSING_VALUE HTTP_Request2_Exception::MISSING_VALUE
@ -255,8 +244,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
// RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
// connection token to a proxy server... // connection token to a proxy server...
if ($proxy && !$secure && if ($httpProxy && !$secure && !empty($headers['connection'])
!empty($headers['connection']) && 'Keep-Alive' == $headers['connection'] && 'Keep-Alive' == $headers['connection']
) { ) {
$this->request->setHeader('connection'); $this->request->setHeader('connection');
} }
@ -265,7 +254,6 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
empty($headers['connection'])) || empty($headers['connection'])) ||
(!empty($headers['connection']) && (!empty($headers['connection']) &&
'Keep-Alive' == $headers['connection']); 'Keep-Alive' == $headers['connection']);
$host = ((!$secure || $proxy)? 'tcp://': 'ssl://') . $host;
$options = array(); $options = array();
if ($secure || $tunnel) { if ($secure || $tunnel) {
@ -283,56 +271,62 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
ksort($options); ksort($options);
} }
// Use global request timeout if given, see feature requests #5735, #8964
if ($timeout = $this->request->getConfig('timeout')) {
$deadline = time() + $timeout;
} else {
$deadline = null;
}
// Changing SSL context options after connection is established does *not* // Changing SSL context options after connection is established does *not*
// work, we need a new connection if options change // work, we need a new connection if options change
$remote = $host . ':' . $port; $remote = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://')
$socketKey = $remote . (($secure && $proxy)? "->{$reqHost}:{$reqPort}": '') . . $host . ':' . $port;
(empty($options)? '': ':' . serialize($options)); $socketKey = $remote . (
($secure && $httpProxy || $socksProxy)
? "->{$reqHost}:{$reqPort}" : ''
) . (empty($options)? '': ':' . serialize($options));
unset($this->socket); unset($this->socket);
// We use persistent connections and have a connected socket? // We use persistent connections and have a connected socket?
// Ensure that the socket is still connected, see bug #16149 // Ensure that the socket is still connected, see bug #16149
if ($keepAlive && !empty(self::$sockets[$socketKey]) && if ($keepAlive && !empty(self::$sockets[$socketKey])
!feof(self::$sockets[$socketKey]) && !self::$sockets[$socketKey]->eof()
) { ) {
$this->socket =& self::$sockets[$socketKey]; $this->socket =& self::$sockets[$socketKey];
} elseif ($secure && $proxy && !$tunnel) { } else {
$this->establishTunnel(); if ($socksProxy) {
$this->request->setLastEvent( require_once 'HTTP/Request2/SOCKS5.php';
'connect', "ssl://{$reqHost}:{$reqPort} via {$host}:{$port}"
$this->socket = new HTTP_Request2_SOCKS5(
$remote, $this->request->getConfig('connect_timeout'),
$options, $this->request->getConfig('proxy_user'),
$this->request->getConfig('proxy_password')
); );
self::$sockets[$socketKey] =& $this->socket; // handle request timeouts ASAP
$this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
$this->socket->connect($reqHost, $reqPort);
if (!$secure) {
$conninfo = "tcp://{$reqHost}:{$reqPort} via {$remote}";
} else {
$this->socket->enableCrypto();
$conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
}
} elseif ($secure && $httpProxy && !$tunnel) {
$this->establishTunnel();
$conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
} else { } else {
// Set SSL context options if doing HTTPS request or creating a tunnel $this->socket = new HTTP_Request2_SocketWrapper(
$context = stream_context_create(); $remote, $this->request->getConfig('connect_timeout'), $options
foreach ($options as $name => $value) {
if (!stream_context_set_option($context, 'ssl', $name, $value)) {
throw new HTTP_Request2_LogicException(
"Error setting SSL context option '{$name}'"
); );
} }
} $this->request->setLastEvent('connect', empty($conninfo)? $remote: $conninfo);
$track = @ini_set('track_errors', 1);
$this->socket = @stream_socket_client(
$remote, $errno, $errstr,
$this->request->getConfig('connect_timeout'),
STREAM_CLIENT_CONNECT, $context
);
if (!$this->socket) {
$e = new HTTP_Request2_ConnectionException(
"Unable to connect to {$remote}. Error: "
. (empty($errstr)? $php_errormsg: $errstr), 0, $errno
);
}
@ini_set('track_errors', $track);
if (isset($e)) {
throw $e;
}
$this->request->setLastEvent('connect', $remote);
self::$sockets[$socketKey] =& $this->socket; self::$sockets[$socketKey] =& $this->socket;
} }
$this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
return $keepAlive; return $keepAlive;
} }
@ -351,8 +345,7 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$donor = new self; $donor = new self;
$connect = new HTTP_Request2( $connect = new HTTP_Request2(
$this->request->getUrl(), HTTP_Request2::METHOD_CONNECT, $this->request->getUrl(), HTTP_Request2::METHOD_CONNECT,
array_merge($this->request->getConfig(), array_merge($this->request->getConfig(), array('adapter' => $donor))
array('adapter' => $donor))
); );
$response = $connect->send(); $response = $connect->send();
// Need any successful (2XX) response // Need any successful (2XX) response
@ -363,37 +356,23 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
); );
} }
$this->socket = $donor->socket; $this->socket = $donor->socket;
$this->socket->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'
);
} }
/** /**
* Checks whether current connection may be reused or should be closed * Checks whether current connection may be reused or should be closed
* *
* @param boolean whether connection could be persistent * @param boolean $requestKeepAlive whether connection could
* in the first place * be persistent in the first place
* @param HTTP_Request2_Response response object to check * @param HTTP_Request2_Response $response response object to check
*
* @return boolean * @return boolean
*/ */
protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response) protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response)
{ {
// Do not close socket on successful CONNECT request // Do not close socket on successful CONNECT request
if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() && if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
200 <= $response->getStatus() && 300 > $response->getStatus() && 200 <= $response->getStatus() && 300 > $response->getStatus()
) { ) {
return true; return true;
} }
@ -414,8 +393,7 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
*/ */
protected function disconnect() protected function disconnect()
{ {
if (is_resource($this->socket)) { if (!empty($this->socket)) {
fclose($this->socket);
$this->socket = null; $this->socket = null;
$this->request->setLastEvent('disconnect'); $this->request->setLastEvent('disconnect');
} }
@ -428,14 +406,15 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
* is attempted, also if number of redirects performed already is equal to * is attempted, also if number of redirects performed already is equal to
* 'max_redirects' configuration parameter. * 'max_redirects' configuration parameter.
* *
* @param HTTP_Request2 Original request * @param HTTP_Request2 $request Original request
* @param HTTP_Request2_Response Response containing redirect * @param HTTP_Request2_Response $response Response containing redirect
*
* @return HTTP_Request2_Response Response from a new location * @return HTTP_Request2_Response Response from a new location
* @throws HTTP_Request2_Exception * @throws HTTP_Request2_Exception
*/ */
protected function handleRedirect(HTTP_Request2 $request, protected function handleRedirect(
HTTP_Request2_Response $response) HTTP_Request2 $request, HTTP_Request2_Response $response
{ ) {
if (is_null($this->redirectCountdown)) { if (is_null($this->redirectCountdown)) {
$this->redirectCountdown = $request->getConfig('max_redirects'); $this->redirectCountdown = $request->getConfig('max_redirects');
} }
@ -468,7 +447,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
} }
$redirect = clone $request; $redirect = clone $request;
$redirect->setUrl($redirectUrl); $redirect->setUrl($redirectUrl);
if (303 == $response->getStatus() || (!$request->getConfig('strict_redirects') if (303 == $response->getStatus()
|| (!$request->getConfig('strict_redirects')
&& in_array($response->getStatus(), array(301, 302))) && in_array($response->getStatus(), array(301, 302)))
) { ) {
$redirect->setMethod(HTTP_Request2::METHOD_GET); $redirect->setMethod(HTTP_Request2::METHOD_GET);
@ -494,7 +474,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
* *
* The method stores challenge values in $challenges static property * The method stores challenge values in $challenges static property
* *
* @param HTTP_Request2_Response response to check * @param HTTP_Request2_Response $response response to check
*
* @return boolean whether another request should be performed * @return boolean whether another request should be performed
* @throws HTTP_Request2_Exception in case of unsupported challenge parameters * @throws HTTP_Request2_Exception in case of unsupported challenge parameters
*/ */
@ -512,8 +493,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$scheme = $url->getScheme(); $scheme = $url->getScheme();
$host = $scheme . '://' . $url->getHost(); $host = $scheme . '://' . $url->getHost();
if ($port = $url->getPort()) { if ($port = $url->getPort()) {
if ((0 == strcasecmp($scheme, 'http') && 80 != $port) || if ((0 == strcasecmp($scheme, 'http') && 80 != $port)
(0 == strcasecmp($scheme, 'https') && 443 != $port) || (0 == strcasecmp($scheme, 'https') && 443 != $port)
) { ) {
$host .= ':' . $port; $host .= ':' . $port;
} }
@ -534,8 +515,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$ret = true; $ret = true;
foreach ($prefixes as $prefix) { foreach ($prefixes as $prefix) {
if (!empty(self::$challenges[$prefix]) && if (!empty(self::$challenges[$prefix])
(empty($challenge['stale']) || strcasecmp('true', $challenge['stale'])) && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
) { ) {
// probably credentials are invalid // probably credentials are invalid
$ret = false; $ret = false;
@ -558,7 +539,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
* *
* The method stores challenge values in $challenges static property * The method stores challenge values in $challenges static property
* *
* @param HTTP_Request2_Response response to check * @param HTTP_Request2_Response $response response to check
*
* @return boolean whether another request should be performed * @return boolean whether another request should be performed
* @throws HTTP_Request2_Exception in case of unsupported challenge parameters * @throws HTTP_Request2_Exception in case of unsupported challenge parameters
*/ */
@ -574,8 +556,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$key = 'proxy://' . $this->request->getConfig('proxy_host') . $key = 'proxy://' . $this->request->getConfig('proxy_host') .
':' . $this->request->getConfig('proxy_port'); ':' . $this->request->getConfig('proxy_port');
if (!empty(self::$challenges[$key]) && if (!empty(self::$challenges[$key])
(empty($challenge['stale']) || strcasecmp('true', $challenge['stale'])) && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
) { ) {
$ret = false; $ret = false;
} else { } else {
@ -608,7 +590,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
* quoted-string handling, unfortunately that means failure to authorize * quoted-string handling, unfortunately that means failure to authorize
* sometimes * sometimes
* *
* @param string value of WWW-Authenticate or Proxy-Authenticate header * @param string $headerValue value of WWW-Authenticate or Proxy-Authenticate header
*
* @return mixed associative array with challenge parameters, false if * @return mixed associative array with challenge parameters, false if
* no challenge is present in header value * no challenge is present in header value
* @throws HTTP_Request2_NotImplementedException in case of unsupported challenge parameters * @throws HTTP_Request2_NotImplementedException in case of unsupported challenge parameters
@ -637,8 +620,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
} }
} }
// we only support qop=auth // we only support qop=auth
if (!empty($paramsAry['qop']) && if (!empty($paramsAry['qop'])
!in_array('auth', array_map('trim', explode(',', $paramsAry['qop']))) && !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))
) { ) {
throw new HTTP_Request2_NotImplementedException( throw new HTTP_Request2_NotImplementedException(
"Only 'auth' qop is currently supported in digest authentication, " . "Only 'auth' qop is currently supported in digest authentication, " .
@ -659,8 +642,9 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
/** /**
* Parses [Proxy-]Authentication-Info header value and updates challenge * Parses [Proxy-]Authentication-Info header value and updates challenge
* *
* @param array challenge to update * @param array &$challenge challenge to update
* @param string value of [Proxy-]Authentication-Info header * @param string $headerValue value of [Proxy-]Authentication-Info header
*
* @todo validate server rspauth response * @todo validate server rspauth response
*/ */
protected function updateChallenge(&$challenge, $headerValue) protected function updateChallenge(&$challenge, $headerValue)
@ -687,17 +671,18 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
/** /**
* Creates a value for [Proxy-]Authorization header when using digest authentication * Creates a value for [Proxy-]Authorization header when using digest authentication
* *
* @param string user name * @param string $user user name
* @param string password * @param string $password password
* @param string request URL * @param string $url request URL
* @param array digest challenge parameters * @param array &$challenge digest challenge parameters
*
* @return string value of [Proxy-]Authorization request header * @return string value of [Proxy-]Authorization request header
* @link http://tools.ietf.org/html/rfc2617#section-3.2.2 * @link http://tools.ietf.org/html/rfc2617#section-3.2.2
*/ */
protected function createDigestResponse($user, $password, $url, &$challenge) protected function createDigestResponse($user, $password, $url, &$challenge)
{ {
if (false !== ($q = strpos($url, '?')) && if (false !== ($q = strpos($url, '?'))
$this->request->getConfig('digest_compat_ie') && $this->request->getConfig('digest_compat_ie')
) { ) {
$url = substr($url, 0, $q); $url = substr($url, 0, $q);
} }
@ -713,8 +698,10 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$challenge['nc'] = 1; $challenge['nc'] = 1;
} }
$nc = sprintf('%08x', $challenge['nc']++); $nc = sprintf('%08x', $challenge['nc']++);
$digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' . $digest = md5(
$challenge['cnonce'] . ':auth:' . $a2); $a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .
$challenge['cnonce'] . ':auth:' . $a2
);
} }
return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' . return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' .
'realm="' . $challenge['realm'] . '", ' . 'realm="' . $challenge['realm'] . '", ' .
@ -732,9 +719,10 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
/** /**
* Adds 'Authorization' header (if needed) to request headers array * Adds 'Authorization' header (if needed) to request headers array
* *
* @param array request headers * @param array &$headers request headers
* @param string request host (needed for digest authentication) * @param string $requestHost request host (needed for digest authentication)
* @param string request URL (needed for digest authentication) * @param string $requestUrl request URL (needed for digest authentication)
*
* @throws HTTP_Request2_NotImplementedException * @throws HTTP_Request2_NotImplementedException
*/ */
protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl) protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl)
@ -744,8 +732,9 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
} }
switch ($auth['scheme']) { switch ($auth['scheme']) {
case HTTP_Request2::AUTH_BASIC: case HTTP_Request2::AUTH_BASIC:
$headers['authorization'] = $headers['authorization'] = 'Basic ' . base64_encode(
'Basic ' . base64_encode($auth['user'] . ':' . $auth['password']); $auth['user'] . ':' . $auth['password']
);
break; break;
case HTTP_Request2::AUTH_DIGEST: case HTTP_Request2::AUTH_DIGEST:
@ -776,16 +765,17 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
/** /**
* Adds 'Proxy-Authorization' header (if needed) to request headers array * Adds 'Proxy-Authorization' header (if needed) to request headers array
* *
* @param array request headers * @param array &$headers request headers
* @param string request URL (needed for digest authentication) * @param string $requestUrl request URL (needed for digest authentication)
*
* @throws HTTP_Request2_NotImplementedException * @throws HTTP_Request2_NotImplementedException
*/ */
protected function addProxyAuthorizationHeader(&$headers, $requestUrl) protected function addProxyAuthorizationHeader(&$headers, $requestUrl)
{ {
if (!$this->request->getConfig('proxy_host') || if (!$this->request->getConfig('proxy_host')
!($user = $this->request->getConfig('proxy_user')) || || !($user = $this->request->getConfig('proxy_user'))
(0 == strcasecmp('https', $this->request->getUrl()->getScheme()) && || (0 == strcasecmp('https', $this->request->getUrl()->getScheme())
HTTP_Request2::METHOD_CONNECT != $this->request->getMethod()) && HTTP_Request2::METHOD_CONNECT != $this->request->getMethod())
) { ) {
return; return;
} }
@ -793,8 +783,9 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$password = $this->request->getConfig('proxy_password'); $password = $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:
$headers['proxy-authorization'] = $headers['proxy-authorization'] = 'Basic ' . base64_encode(
'Basic ' . base64_encode($user . ':' . $password); $user . ':' . $password
);
break; break;
case HTTP_Request2::AUTH_DIGEST: case HTTP_Request2::AUTH_DIGEST:
@ -845,8 +836,9 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$requestUrl = $host; $requestUrl = $host;
} else { } else {
if (!$this->request->getConfig('proxy_host') || if (!$this->request->getConfig('proxy_host')
0 == strcasecmp($url->getScheme(), 'https') || 'http' != $this->request->getConfig('proxy_type')
|| 0 == strcasecmp($url->getScheme(), 'https')
) { ) {
$requestUrl = ''; $requestUrl = '';
} else { } else {
@ -857,8 +849,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query); $requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query);
} }
if ('1.1' == $this->request->getConfig('protocol_version') && if ('1.1' == $this->request->getConfig('protocol_version')
extension_loaded('zlib') && !isset($headers['accept-encoding']) && extension_loaded('zlib') && !isset($headers['accept-encoding'])
) { ) {
$headers['accept-encoding'] = 'gzip, deflate'; $headers['accept-encoding'] = 'gzip, deflate';
} }
@ -888,8 +880,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
*/ */
protected function writeBody() protected function writeBody()
{ {
if (in_array($this->request->getMethod(), self::$bodyDisallowed) || if (in_array($this->request->getMethod(), self::$bodyDisallowed)
0 == $this->contentLength || 0 == $this->contentLength
) { ) {
return; return;
} }
@ -904,9 +896,7 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
} else { } else {
$str = $this->requestBody->read($bufferSize); $str = $this->requestBody->read($bufferSize);
} }
if (false === @fwrite($this->socket, $str, strlen($str))) { $this->socket->write($str);
throw new HTTP_Request2_MessageException('Error writing request');
}
// Provide the length of written string to the observer, request #7630 // Provide the length of written string to the observer, request #7630
$this->request->setLastEvent('sentBodyPart', strlen($str)); $this->request->setLastEvent('sentBodyPart', strlen($str));
$position += strlen($str); $position += strlen($str);
@ -926,10 +916,10 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
do { do {
$response = new HTTP_Request2_Response( $response = new HTTP_Request2_Response(
$this->readLine($bufferSize), true, $this->request->getUrl() $this->socket->readLine($bufferSize), true, $this->request->getUrl()
); );
do { do {
$headerLine = $this->readLine($bufferSize); $headerLine = $this->socket->readLine($bufferSize);
$response->parseHeaderLine($headerLine); $response->parseHeaderLine($headerLine);
} while ('' != $headerLine); } while ('' != $headerLine);
} while (in_array($response->getStatus(), array(100, 101))); } while (in_array($response->getStatus(), array(100, 101)));
@ -937,10 +927,10 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$this->request->setLastEvent('receivedHeaders', $response); $this->request->setLastEvent('receivedHeaders', $response);
// No body possible in such responses // No body possible in such responses
if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod() || if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
(HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() && || (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
200 <= $response->getStatus() && 300 > $response->getStatus()) || && 200 <= $response->getStatus() && 300 > $response->getStatus())
in_array($response->getStatus(), array(204, 304)) || in_array($response->getStatus(), array(204, 304))
) { ) {
return $response; return $response;
} }
@ -956,16 +946,16 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$toRead = ($chunked || null === $length)? null: $length; $toRead = ($chunked || null === $length)? null: $length;
$this->chunkLength = 0; $this->chunkLength = 0;
while (!feof($this->socket) && (is_null($toRead) || 0 < $toRead)) { while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) {
if ($chunked) { if ($chunked) {
$data = $this->readChunked($bufferSize); $data = $this->readChunked($bufferSize);
} elseif (is_null($toRead)) { } elseif (is_null($toRead)) {
$data = $this->fread($bufferSize); $data = $this->socket->read($bufferSize);
} else { } else {
$data = $this->fread(min($toRead, $bufferSize)); $data = $this->socket->read(min($toRead, $bufferSize));
$toRead -= strlen($data); $toRead -= strlen($data);
} }
if ('' == $data && (!$this->chunkLength || feof($this->socket))) { if ('' == $data && (!$this->chunkLength || $this->socket->eof())) {
break; break;
} }
@ -987,69 +977,11 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
return $response; return $response;
} }
/**
* 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 buffer size to use for reading
* @return Available data up to the newline (not including newline)
* @throws HTTP_Request2_MessageException In case of timeout
*/
protected 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);
$info = stream_get_meta_data($this->socket);
if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {
$reason = $this->deadline
? 'after ' . $this->request->getConfig('timeout') . ' second(s)'
: 'due to default_socket_timeout php.ini setting';
throw new HTTP_Request2_MessageException(
"Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT
);
}
if (substr($line, -1) == "\n") {
return rtrim($line, "\r\n");
}
}
return $line;
}
/**
* Wrapper around fread(), handles global request timeout
*
* @param int Reads up to this number of bytes
* @return Data read from socket
* @throws HTTP_Request2_MessageException In case of timeout
*/
protected function fread($length)
{
if ($this->deadline) {
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
}
$data = fread($this->socket, $length);
$info = stream_get_meta_data($this->socket);
if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {
$reason = $this->deadline
? 'after ' . $this->request->getConfig('timeout') . ' second(s)'
: 'due to default_socket_timeout php.ini setting';
throw new HTTP_Request2_MessageException(
"Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT
);
}
return $data;
}
/** /**
* Reads a part of response body encoded with chunked Transfer-Encoding * Reads a part of response body encoded with chunked Transfer-Encoding
* *
* @param int buffer size to use for reading * @param int $bufferSize buffer size to use for reading
*
* @return string * @return string
* @throws HTTP_Request2_MessageException * @throws HTTP_Request2_MessageException
*/ */
@ -1057,7 +989,7 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
{ {
// at start of the next chunk? // at start of the next chunk?
if (0 == $this->chunkLength) { if (0 == $this->chunkLength) {
$line = $this->readLine($bufferSize); $line = $this->socket->readLine($bufferSize);
if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) { if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {
throw new HTTP_Request2_MessageException( throw new HTTP_Request2_MessageException(
"Cannot decode chunked response, invalid chunk length '{$line}'", "Cannot decode chunked response, invalid chunk length '{$line}'",
@ -1067,15 +999,15 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
$this->chunkLength = hexdec($matches[1]); $this->chunkLength = hexdec($matches[1]);
// Chunk with zero length indicates the end // Chunk with zero length indicates the end
if (0 == $this->chunkLength) { if (0 == $this->chunkLength) {
$this->readLine($bufferSize); $this->socket->readLine($bufferSize);
return ''; return '';
} }
} }
} }
$data = $this->fread(min($this->chunkLength, $bufferSize)); $data = $this->socket->read(min($this->chunkLength, $bufferSize));
$this->chunkLength -= strlen($data); $this->chunkLength -= strlen($data);
if (0 == $this->chunkLength) { if (0 == $this->chunkLength) {
$this->readLine($bufferSize); // Trailing CRLF $this->socket->readLine($bufferSize); // Trailing CRLF
} }
return $data; return $data;
} }

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
@ -37,7 +37,7 @@
* @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
*/ */
@ -50,7 +50,9 @@ require_once 'HTTP/Request2.php';
* @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: @package_version@ * @version Release: @package_version@
* @link http://pear.php.net/package/HTTP_Request2
*/ */
class HTTP_Request2_CookieJar implements Serializable class HTTP_Request2_CookieJar implements Serializable
{ {
@ -92,11 +94,14 @@ class HTTP_Request2_CookieJar implements Serializable
/** /**
* 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,
* see {@link usePublicSuffixList()}
*/ */
public function __construct($serializeSessionCookies = false, $usePublicSuffixList = true) public function __construct(
{ $serializeSessionCookies = false, $usePublicSuffixList = true
) {
$this->serializeSessionCookies($serializeSessionCookies); $this->serializeSessionCookies($serializeSessionCookies);
$this->usePublicSuffixList($usePublicSuffixList); $this->usePublicSuffixList($usePublicSuffixList);
} }
@ -129,8 +134,10 @@ class HTTP_Request2_CookieJar implements Serializable
* '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()}
* @param Net_URL2 $setter URL of the document that sent Set-Cookie header
*
* @return array Updated cookie array * @return array Updated cookie array
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
* @throws HTTP_Request2_MessageException * @throws HTTP_Request2_MessageException
@ -206,8 +213,10 @@ class HTTP_Request2_CookieJar implements Serializable
/** /**
* 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()}
* @param Net_URL2 $setter URL of the document that sent Set-Cookie header
*
* @throws HTTP_Request2_Exception * @throws HTTP_Request2_Exception
*/ */
public function store(array $cookie, Net_URL2 $setter = null) public function store(array $cookie, Net_URL2 $setter = null)
@ -233,9 +242,9 @@ 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)
{ {
@ -252,9 +261,10 @@ class HTTP_Request2_CookieJar implements Serializable
* - 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)
{ {
@ -312,7 +322,7 @@ class HTTP_Request2_CookieJar implements Serializable
/** /**
* 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)
{ {
@ -336,7 +346,8 @@ class HTTP_Request2_CookieJar implements Serializable
* 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)
@ -348,6 +359,7 @@ class HTTP_Request2_CookieJar implements Serializable
* 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()
@ -370,7 +382,8 @@ 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)
@ -400,8 +413,9 @@ class HTTP_Request2_CookieJar implements Serializable
* 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)
@ -432,7 +446,8 @@ class HTTP_Request2_CookieJar implements Serializable
* 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 * @return string|bool registered domain, will return false if $domain is
* either invalid or a TLD itself * either invalid or a TLD itself
*/ */
@ -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';
} }
@ -469,8 +486,9 @@ class HTTP_Request2_CookieJar implements Serializable
/** /**
* 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)

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
@ -37,7 +37,7 @@
* @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
*/ */
@ -51,7 +51,10 @@ require_once 'PEAR/Exception.php';
* *
* @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
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132 * @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
@ -85,9 +88,9 @@ class HTTP_Request2_Exception extends PEAR_Exception
/** /**
* 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)
{ {
@ -115,9 +118,14 @@ class HTTP_Request2_Exception extends PEAR_Exception
* *
* @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
@ -131,9 +139,14 @@ class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception {}
* *
* @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
@ -143,9 +156,14 @@ class HTTP_Request2_LogicException extends HTTP_Request2_Exception {}
* *
* @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
@ -154,7 +172,12 @@ class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception {}
* *
* @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
@ -37,7 +37,7 @@
* @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
*/ */
@ -50,7 +50,9 @@
* @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
* @link http://tools.ietf.org/html/rfc1867 * @link http://tools.ietf.org/html/rfc1867
*/ */
class HTTP_Request2_MultipartBody class HTTP_Request2_MultipartBody
@ -99,9 +101,11 @@ class HTTP_Request2_MultipartBody
/** /**
* 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)
{ {
@ -160,7 +164,8 @@ class HTTP_Request2_MultipartBody
/** /**
* 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)
@ -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);
@ -246,9 +251,10 @@ 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)

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,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
@ -37,7 +37,7 @@
* @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,11 +66,12 @@ 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>
* @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
* @link http://tools.ietf.org/html/rfc2616#section-6 * @link http://tools.ietf.org/html/rfc2616#section-6
*/ */
class HTTP_Request2_Response class HTTP_Request2_Response
@ -203,12 +204,32 @@ class HTTP_Request2_Response
); );
/**
* Returns the default reason phrase for the given code or all reason phrases
*
* @param int $code Response code
*
* @return string|array|null Default reason phrase for $code if $code is given
* (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 * Constructor, parses the response status line
* *
* @param string Response status line (e.g. "HTTP/1.1 200 OK") * @param string $statusLine Response status line (e.g. "HTTP/1.1 200 OK")
* @param bool Whether body is still encoded by Content-Encoding * @param bool $bodyEncoded Whether body is still encoded by Content-Encoding
* @param string Effective URL of the response * @param string $effectiveUrl Effective URL of the response
*
* @throws HTTP_Request2_MessageException if status line is invalid according to spec * @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)
@ -221,11 +242,7 @@ class HTTP_Request2_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;
} }
@ -238,14 +255,14 @@ class HTTP_Request2_Response
* 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 {
@ -289,7 +306,8 @@ 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)
@ -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));
@ -338,7 +356,8 @@ class HTTP_Request2_Response
/** /**
* 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)
{ {
@ -360,6 +379,7 @@ class HTTP_Request2_Response
/** /**
* Returns the status code * Returns the status code
*
* @return integer * @return integer
*/ */
public function getStatus() public function getStatus()
@ -369,6 +389,7 @@ class HTTP_Request2_Response
/** /**
* Returns the reason phrase * Returns the reason phrase
*
* @return string * @return string
*/ */
public function getReasonPhrase() public function getReasonPhrase()
@ -378,6 +399,7 @@ class HTTP_Request2_Response
/** /**
* 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()
@ -389,7 +411,8 @@ class HTTP_Request2_Response
/** /**
* 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 * @return string|array Value of $headerName header (null if header is
* not present), array of all response headers if * not present), array of all response headers if
* $headerName is null * $headerName is null
@ -422,15 +445,15 @@ class HTTP_Request2_Response
*/ */
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 {
@ -471,7 +494,8 @@ class HTTP_Request2_Response
* 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 * @return string decoded data
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
* @throws HTTP_Request2_MessageException * @throws HTTP_Request2_MessageException
@ -606,7 +630,8 @@ class HTTP_Request2_Response
/** /**
* 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 * @return string decoded data
* @throws HTTP_Request2_LogicException * @throws HTTP_Request2_LogicException
*/ */

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];
}
}
?>

210
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,
ini_get('arg_separator.input'));
$this->setOption(self::OPTION_SEPARATOR_OUTPUT,
ini_get('arg_separator.output'));
if (is_array($options)) {
foreach ($options as $optionName => $value) { foreach ($options as $optionName => $value) {
$this->setOption($optionName, $value); if (array_key_exists($optionName, $this->_options)) {
$this->_options[$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,6 +803,7 @@ 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. // This is only necessary in PHP < 5.3.
$encoded = str_replace('%7E', '~', $encoded); $encoded = str_replace('%7E', '~', $encoded);
return $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