diff --git a/extlib/HTTP/Request2.php b/extlib/HTTP/Request2.php index 60beeaf2ef..1a40df2213 100644 --- a/extlib/HTTP/Request2.php +++ b/extlib/HTTP/Request2.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,12 +33,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: Request2.php 308735 2011-02-27 20:31:28Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Request2.php 324936 2012-04-07 07:49:03Z avb $ + * @link http://pear.php.net/package/HTTP_Request2 */ /** @@ -54,19 +54,21 @@ require_once 'HTTP/Request2/Exception.php'; /** * Class representing a HTTP request message * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @version Release: 2.0.0RC1 - * @link http://tools.ietf.org/html/rfc2616#section-5 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 */ class HTTP_Request2 implements SplSubject { - /**#@+ - * Constants for HTTP request methods - * - * @link http://tools.ietf.org/html/rfc2616#section-5.1.1 - */ + /**#@+ + * Constants for HTTP request methods + * + * @link http://tools.ietf.org/html/rfc2616#section-5.1.1 + */ const METHOD_OPTIONS = 'OPTIONS'; const METHOD_GET = 'GET'; const METHOD_HEAD = 'HEAD'; @@ -75,73 +77,73 @@ class HTTP_Request2 implements SplSubject const METHOD_DELETE = 'DELETE'; const METHOD_TRACE = 'TRACE'; const METHOD_CONNECT = 'CONNECT'; - /**#@-*/ + /**#@-*/ - /**#@+ - * Constants for HTTP authentication schemes - * - * @link http://tools.ietf.org/html/rfc2617 - */ + /**#@+ + * Constants for HTTP authentication schemes + * + * @link http://tools.ietf.org/html/rfc2617 + */ const AUTH_BASIC = 'basic'; const AUTH_DIGEST = 'digest'; - /**#@-*/ + /**#@-*/ - /** - * Regular expression used to check for invalid symbols in RFC 2616 tokens - * @link http://pear.php.net/bugs/bug.php?id=15630 - */ + /** + * Regular expression used to check for invalid symbols in RFC 2616 tokens + * @link http://pear.php.net/bugs/bug.php?id=15630 + */ const REGEXP_INVALID_TOKEN = '![\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]!'; - /** - * Regular expression used to check for invalid symbols in cookie strings - * @link http://pear.php.net/bugs/bug.php?id=15630 - * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html - */ + /** + * Regular expression used to check for invalid symbols in cookie strings + * @link http://pear.php.net/bugs/bug.php?id=15630 + * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html + */ const REGEXP_INVALID_COOKIE = '/[\s,;]/'; - /** - * Fileinfo magic database resource - * @var resource - * @see detectMimeType() - */ + /** + * Fileinfo magic database resource + * @var resource + * @see detectMimeType() + */ private static $_fileinfoDb; - /** - * Observers attached to the request (instances of SplObserver) - * @var array - */ + /** + * Observers attached to the request (instances of SplObserver) + * @var array + */ protected $observers = array(); - /** - * Request URL - * @var Net_URL2 - */ + /** + * Request URL + * @var Net_URL2 + */ protected $url; - /** - * Request method - * @var string - */ + /** + * Request method + * @var string + */ protected $method = self::METHOD_GET; - /** - * Authentication data - * @var array - * @see getAuth() - */ + /** + * Authentication data + * @var array + * @see getAuth() + */ protected $auth; - /** - * Request headers - * @var array - */ + /** + * Request headers + * @var array + */ protected $headers = array(); - /** - * Configuration parameters - * @var array - * @see setConfig() - */ + /** + * Configuration parameters + * @var array + * @see setConfig() + */ protected $config = array( 'adapter' => 'HTTP_Request2_Adapter_Socket', 'connect_timeout' => 10, @@ -156,6 +158,7 @@ class HTTP_Request2 implements SplSubject 'proxy_user' => '', 'proxy_password' => '', 'proxy_auth_scheme' => self::AUTH_BASIC, + 'proxy_type' => 'http', 'ssl_verify_peer' => true, 'ssl_verify_host' => true, @@ -171,58 +174,59 @@ class HTTP_Request2 implements SplSubject 'strict_redirects' => false ); - /** - * Last event in request / response handling, intended for observers - * @var array - * @see getLastEvent() - */ + /** + * Last event in request / response handling, intended for observers + * @var array + * @see getLastEvent() + */ protected $lastEvent = array( 'name' => 'start', 'data' => null ); - /** - * Request body - * @var string|resource - * @see setBody() - */ + /** + * Request body + * @var string|resource + * @see setBody() + */ protected $body = ''; - /** - * Array of POST parameters - * @var array - */ + /** + * Array of POST parameters + * @var array + */ protected $postParams = array(); - /** - * Array of file uploads (for multipart/form-data POST requests) - * @var array - */ + /** + * Array of file uploads (for multipart/form-data POST requests) + * @var array + */ protected $uploads = array(); - /** - * Adapter used to perform actual HTTP request - * @var HTTP_Request2_Adapter - */ + /** + * Adapter used to perform actual HTTP request + * @var HTTP_Request2_Adapter + */ protected $adapter; - /** - * Cookie jar to persist cookies between requests - * @var HTTP_Request2_CookieJar - */ + /** + * Cookie jar to persist cookies between requests + * @var HTTP_Request2_CookieJar + */ protected $cookieJar = null; - /** - * Constructor. Can set request URL, method and configuration array. - * - * Also sets a default value for User-Agent header. - * - * @param string|Net_Url2 Request URL - * @param string Request method - * @param array Configuration for this Request instance - */ - public function __construct($url = null, $method = self::METHOD_GET, array $config = array()) - { + /** + * Constructor. Can set request URL, method and configuration array. + * + * Also sets a default value for User-Agent header. + * + * @param string|Net_Url2 $url Request URL + * @param string $method Request method + * @param array $config Configuration for this Request instance + */ + public function __construct( + $url = null, $method = self::METHOD_GET, array $config = array() + ) { $this->setConfig($config); if (!empty($url)) { $this->setUrl($url); @@ -230,22 +234,24 @@ class HTTP_Request2 implements SplSubject if (!empty($method)) { $this->setMethod($method); } - $this->setHeader('user-agent', 'HTTP_Request2/2.0.0RC1 ' . - '(http://pear.php.net/package/http_request2) ' . - 'PHP/' . phpversion()); + $this->setHeader( + 'user-agent', 'HTTP_Request2/2.1.1 ' . + '(http://pear.php.net/package/http_request2) PHP/' . phpversion() + ); } - /** - * Sets the URL for this request - * - * If the URL has userinfo part (username & password) these will be removed - * and converted to auth data. If the URL does not have a path component, - * that will be set to '/'. - * - * @param string|Net_URL2 Request URL - * @return HTTP_Request2 - * @throws HTTP_Request2_LogicException - */ + /** + * Sets the URL for this request + * + * If the URL has userinfo part (username & password) these will be removed + * and converted to auth data. If the URL does not have a path component, + * that will be set to '/'. + * + * @param string|Net_URL2 $url Request URL + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException + */ public function setUrl($url) { if (is_string($url)) { @@ -274,23 +280,24 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Returns the request URL - * - * @return Net_URL2 - */ + /** + * Returns the request URL + * + * @return Net_URL2 + */ public function getUrl() { return $this->url; } - /** - * Sets the request method - * - * @param string - * @return HTTP_Request2 - * @throws HTTP_Request2_LogicException if the method name is invalid - */ + /** + * Sets the request method + * + * @param string $method one of the methods defined in RFC 2616 + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException if the method name is invalid + */ public function setMethod($method) { // Method name should be a token: http://tools.ietf.org/html/rfc2616#section-5.1.1 @@ -305,64 +312,68 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Returns the request method - * - * @return string - */ + /** + * Returns the request method + * + * @return string + */ public function getMethod() { return $this->method; } - /** - * Sets the configuration parameter(s) - * - * The following parameters are available: - *
    - *
  • 'adapter' - adapter to use (string)
  • - *
  • 'connect_timeout' - Connection timeout in seconds (integer)
  • - *
  • 'timeout' - Total number of seconds a request can take. - * Use 0 for no limit, should be greater than - * 'connect_timeout' if set (integer)
  • - *
  • 'use_brackets' - Whether to append [] to array variable names (bool)
  • - *
  • 'protocol_version' - HTTP Version to use, '1.0' or '1.1' (string)
  • - *
  • 'buffer_size' - Buffer size to use for reading and writing (int)
  • - *
  • 'store_body' - Whether to store response body in response object. - * Set to false if receiving a huge response and - * using an Observer to save it (boolean)
  • - *
  • 'proxy_host' - Proxy server host (string)
  • - *
  • 'proxy_port' - Proxy server port (integer)
  • - *
  • 'proxy_user' - Proxy auth username (string)
  • - *
  • 'proxy_password' - Proxy auth password (string)
  • - *
  • 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)
  • - *
  • 'ssl_verify_peer' - Whether to verify peer's SSL certificate (bool)
  • - *
  • 'ssl_verify_host' - Whether to check that Common Name in SSL - * certificate matches host name (bool)
  • - *
  • 'ssl_cafile' - Cerificate Authority file to verify the peer - * with (use with 'ssl_verify_peer') (string)
  • - *
  • 'ssl_capath' - Directory holding multiple Certificate - * Authority files (string)
  • - *
  • 'ssl_local_cert' - Name of a file containing local cerificate (string)
  • - *
  • 'ssl_passphrase' - Passphrase with which local certificate - * was encoded (string)
  • - *
  • 'digest_compat_ie' - Whether to imitate behaviour of MSIE 5 and 6 - * in using URL without query string in digest - * authentication (boolean)
  • - *
  • 'follow_redirects' - Whether to automatically follow HTTP Redirects (boolean)
  • - *
  • 'max_redirects' - Maximum number of redirects to follow (integer)
  • - *
  • 'strict_redirects' - Whether to keep request method on redirects via status 301 and - * 302 (true, needed for compatibility with RFC 2616) - * or switch to GET (false, needed for compatibility with most - * browsers) (boolean)
  • - *
- * - * @param string|array configuration parameter name or array - * ('parameter name' => 'parameter value') - * @param mixed parameter value if $nameOrConfig is not an array - * @return HTTP_Request2 - * @throws HTTP_Request2_LogicException If the parameter is unknown - */ + /** + * Sets the configuration parameter(s) + * + * The following parameters are available: + *
    + *
  • 'adapter' - adapter to use (string)
  • + *
  • 'connect_timeout' - Connection timeout in seconds (integer)
  • + *
  • 'timeout' - Total number of seconds a request can take. + * Use 0 for no limit, should be greater than + * 'connect_timeout' if set (integer)
  • + *
  • 'use_brackets' - Whether to append [] to array variable names (bool)
  • + *
  • 'protocol_version' - HTTP Version to use, '1.0' or '1.1' (string)
  • + *
  • 'buffer_size' - Buffer size to use for reading and writing (int)
  • + *
  • 'store_body' - Whether to store response body in response object. + * Set to false if receiving a huge response and + * using an Observer to save it (boolean)
  • + *
  • 'proxy_type' - Proxy type, 'http' or 'socks5' (string)
  • + *
  • 'proxy_host' - Proxy server host (string)
  • + *
  • 'proxy_port' - Proxy server port (integer)
  • + *
  • 'proxy_user' - Proxy auth username (string)
  • + *
  • 'proxy_password' - Proxy auth password (string)
  • + *
  • 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)
  • + *
  • 'proxy' - Shorthand for proxy_* parameters, proxy given as URL, + * e.g. 'socks5://localhost:1080/' (string)
  • + *
  • 'ssl_verify_peer' - Whether to verify peer's SSL certificate (bool)
  • + *
  • 'ssl_verify_host' - Whether to check that Common Name in SSL + * certificate matches host name (bool)
  • + *
  • 'ssl_cafile' - Cerificate Authority file to verify the peer + * with (use with 'ssl_verify_peer') (string)
  • + *
  • 'ssl_capath' - Directory holding multiple Certificate + * Authority files (string)
  • + *
  • 'ssl_local_cert' - Name of a file containing local cerificate (string)
  • + *
  • 'ssl_passphrase' - Passphrase with which local certificate + * was encoded (string)
  • + *
  • 'digest_compat_ie' - Whether to imitate behaviour of MSIE 5 and 6 + * in using URL without query string in digest + * authentication (boolean)
  • + *
  • 'follow_redirects' - Whether to automatically follow HTTP Redirects (boolean)
  • + *
  • 'max_redirects' - Maximum number of redirects to follow (integer)
  • + *
  • 'strict_redirects' - Whether to keep request method on redirects via status 301 and + * 302 (true, needed for compatibility with RFC 2616) + * or switch to GET (false, needed for compatibility with most + * browsers) (boolean)
  • + *
+ * + * @param string|array $nameOrConfig configuration parameter name or array + * ('parameter name' => 'parameter value') + * @param mixed $value parameter value if $nameOrConfig is not an array + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException If the parameter is unknown + */ public function setConfig($nameOrConfig, $value = null) { if (is_array($nameOrConfig)) { @@ -370,6 +381,16 @@ class HTTP_Request2 implements SplSubject $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 { if (!array_key_exists($nameOrConfig, $this->config)) { throw new HTTP_Request2_LogicException( @@ -383,14 +404,15 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Returns the value(s) of the configuration parameter(s) - * - * @param string parameter name - * @return mixed value of $name parameter, array of all configuration - * parameters if $name is not given - * @throws HTTP_Request2_LogicException If the parameter is unknown - */ + /** + * Returns the value(s) of the configuration parameter(s) + * + * @param string $name parameter name + * + * @return mixed value of $name parameter, array of all configuration + * parameters if $name is not given + * @throws HTTP_Request2_LogicException If the parameter is unknown + */ public function getConfig($name = null) { if (null === $name) { @@ -404,14 +426,15 @@ class HTTP_Request2 implements SplSubject return $this->config[$name]; } - /** - * Sets the autentification data - * - * @param string user name - * @param string password - * @param string authentication scheme - * @return HTTP_Request2 - */ + /** + * Sets the autentification data + * + * @param string $user user name + * @param string $password password + * @param string $scheme authentication scheme + * + * @return HTTP_Request2 + */ public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC) { if (empty($user)) { @@ -427,46 +450,47 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Returns the authentication data - * - * The array has the keys 'user', 'password' and 'scheme', where 'scheme' - * is one of the HTTP_Request2::AUTH_* constants. - * - * @return array - */ + /** + * Returns the authentication data + * + * The array has the keys 'user', 'password' and 'scheme', where 'scheme' + * is one of the HTTP_Request2::AUTH_* constants. + * + * @return array + */ public function getAuth() { return $this->auth; } - /** - * Sets request header(s) - * - * The first parameter may be either a full header string 'header: value' or - * header name. In the former case $value parameter is ignored, in the latter - * the header's value will either be set to $value or the header will be - * removed if $value is null. The first parameter can also be an array of - * headers, in that case method will be called recursively. - * - * Note that headers are treated case insensitively as per RFC 2616. - * - * - * $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar' - * $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz' - * $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux' - * $req->setHeader('FOO'); // removes 'Foo' header from request - * - * - * @param string|array header name, header string ('Header: value') - * or an array of headers - * @param string|array|null header value if $name is not an array, - * header will be removed if value is null - * @param bool whether to replace previous header with the - * same name or append to its value - * @return HTTP_Request2 - * @throws HTTP_Request2_LogicException - */ + /** + * Sets request header(s) + * + * The first parameter may be either a full header string 'header: value' or + * header name. In the former case $value parameter is ignored, in the latter + * the header's value will either be set to $value or the header will be + * removed if $value is null. The first parameter can also be an array of + * headers, in that case method will be called recursively. + * + * Note that headers are treated case insensitively as per RFC 2616. + * + * + * $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar' + * $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz' + * $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux' + * $req->setHeader('FOO'); // removes 'Foo' header from request + * + * + * @param string|array $name header name, header string ('Header: value') + * or an array of headers + * @param string|array|null $value header value if $name is not an array, + * header will be removed if value is null + * @param bool $replace whether to replace previous header with the + * same name or append to its value + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException + */ public function setHeader($name, $value = null, $replace = true) { if (is_array($name)) { @@ -510,41 +534,43 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Returns the request headers - * - * The array is of the form ('header name' => 'header value'), header names - * are lowercased - * - * @return array - */ + /** + * Returns the request headers + * + * The array is of the form ('header name' => 'header value'), header names + * are lowercased + * + * @return array + */ public function getHeaders() { return $this->headers; } - /** - * Adds a cookie to the request - * - * If the request does not have a CookieJar object set, this method simply - * appends a cookie to "Cookie:" header. - * - * If a CookieJar object is available, the cookie is stored in that object. - * Data from request URL will be used for setting its 'domain' and 'path' - * parameters, 'expires' and 'secure' will be set to null and false, - * respectively. If you need further control, use CookieJar's methods. - * - * @param string cookie name - * @param string cookie value - * @return HTTP_Request2 - * @throws HTTP_Request2_LogicException - * @see setCookieJar() - */ + /** + * Adds a cookie to the request + * + * If the request does not have a CookieJar object set, this method simply + * appends a cookie to "Cookie:" header. + * + * If a CookieJar object is available, the cookie is stored in that object. + * Data from request URL will be used for setting its 'domain' and 'path' + * parameters, 'expires' and 'secure' will be set to null and false, + * respectively. If you need further control, use CookieJar's methods. + * + * @param string $name cookie name + * @param string $value cookie value + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException + * @see setCookieJar() + */ public function addCookie($name, $value) { if (!empty($this->cookieJar)) { - $this->cookieJar->store(array('name' => $name, 'value' => $value), - $this->url); + $this->cookieJar->store( + array('name' => $name, 'value' => $value), $this->url + ); } else { $cookie = $name . '=' . $value; @@ -561,19 +587,21 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Sets the request body - * - * If you provide file pointer rather than file name, it should support - * fstat() and rewind() operations. - * - * @param string|resource|HTTP_Request2_MultipartBody Either a string - * with the body or filename containing body or pointer to - * an open file or object with multipart body data - * @param bool Whether first parameter is a filename - * @return HTTP_Request2 - * @throws HTTP_Request2_LogicException - */ + /** + * Sets the request body + * + * If you provide file pointer rather than file name, it should support + * fstat() and rewind() operations. + * + * @param string|resource|HTTP_Request2_MultipartBody $body Either a + * string with the body or filename containing body or + * pointer to an open file or object with multipart body data + * @param bool $isFilename Whether + * first parameter is a filename + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException + */ public function setBody($body, $isFilename = false) { if (!$isFilename && !is_resource($body)) { @@ -594,15 +622,15 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Returns the request body - * - * @return string|resource|HTTP_Request2_MultipartBody - */ + /** + * Returns the request body + * + * @return string|resource|HTTP_Request2_MultipartBody + */ public function getBody() { - if (self::METHOD_POST == $this->method && - (!empty($this->postParams) || !empty($this->uploads)) + if (self::METHOD_POST == $this->method + && (!empty($this->postParams) || !empty($this->uploads)) ) { if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) { $body = http_build_query($this->postParams, '', '&'); @@ -622,29 +650,30 @@ class HTTP_Request2 implements SplSubject return $this->body; } - /** - * Adds a file to form-based file upload - * - * Used to emulate file upload via a HTML form. The method also sets - * Content-Type of HTTP request to 'multipart/form-data'. - * - * If you just want to send the contents of a file as the body of HTTP - * request you should use setBody() method. - * - * If you provide file pointers rather than file names, they should support - * fstat() and rewind() operations. - * - * @param string name of file-upload field - * @param string|resource|array full name of local file, pointer to - * open file or an array of files - * @param string filename to send in the request - * @param string content-type of file being uploaded - * @return HTTP_Request2 - * @throws HTTP_Request2_LogicException - */ - public function addUpload($fieldName, $filename, $sendFilename = null, - $contentType = null) - { + /** + * Adds a file to form-based file upload + * + * Used to emulate file upload via a HTML form. The method also sets + * Content-Type of HTTP request to 'multipart/form-data'. + * + * If you just want to send the contents of a file as the body of HTTP + * request you should use setBody() method. + * + * If you provide file pointers rather than file names, they should support + * fstat() and rewind() operations. + * + * @param string $fieldName name of file-upload field + * @param string|resource|array $filename full name of local file, + * pointer to open file or an array of files + * @param string $sendFilename filename to send in the request + * @param string $contentType content-type of file being uploaded + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException + */ + public function addUpload( + $fieldName, $filename, $sendFilename = null, $contentType = null + ) { if (!is_array($filename)) { $fileData = $this->fopenWrapper($filename, empty($contentType)); $this->uploads[$fieldName] = array( @@ -671,8 +700,8 @@ class HTTP_Request2 implements SplSubject 'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types ); } - if (empty($this->headers['content-type']) || - 'application/x-www-form-urlencoded' == $this->headers['content-type'] + if (empty($this->headers['content-type']) + || 'application/x-www-form-urlencoded' == $this->headers['content-type'] ) { $this->setHeader('content-type', 'multipart/form-data'); } @@ -680,13 +709,14 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Adds POST parameter(s) to the request. - * - * @param string|array parameter name or array ('name' => 'value') - * @param mixed parameter value (can be an array) - * @return HTTP_Request2 - */ + /** + * Adds POST parameter(s) to the request. + * + * @param string|array $name parameter name or array ('name' => 'value') + * @param mixed $value parameter value (can be an array) + * + * @return HTTP_Request2 + */ public function addPostParameter($name, $value = null) { if (!is_array($name)) { @@ -703,11 +733,11 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Attaches a new observer - * - * @param SplObserver - */ + /** + * Attaches a new observer + * + * @param SplObserver $observer any object implementing SplObserver + */ public function attach(SplObserver $observer) { foreach ($this->observers as $attached) { @@ -718,11 +748,11 @@ class HTTP_Request2 implements SplSubject $this->observers[] = $observer; } - /** - * Detaches an existing observer - * - * @param SplObserver - */ + /** + * Detaches an existing observer + * + * @param SplObserver $observer any object implementing SplObserver + */ public function detach(SplObserver $observer) { foreach ($this->observers as $key => $attached) { @@ -733,9 +763,9 @@ class HTTP_Request2 implements SplSubject } } - /** - * Notifies all observers - */ + /** + * Notifies all observers + */ public function notify() { foreach ($this->observers as $observer) { @@ -743,15 +773,15 @@ class HTTP_Request2 implements SplSubject } } - /** - * Sets the last event - * - * Adapters should use this method to set the current state of the request - * and notify the observers. - * - * @param string event name - * @param mixed event data - */ + /** + * Sets the last event + * + * Adapters should use this method to set the current state of the request + * and notify the observers. + * + * @param string $name event name + * @param mixed $data event data + */ public function setLastEvent($name, $data = null) { $this->lastEvent = array( @@ -761,56 +791,57 @@ class HTTP_Request2 implements SplSubject $this->notify(); } - /** - * Returns the last event - * - * Observers should use this method to access the last change in request. - * The following event names are possible: - *
    - *
  • 'connect' - after connection to remote server, - * data is the destination (string)
  • - *
  • 'disconnect' - after disconnection from server
  • - *
  • 'sentHeaders' - after sending the request headers, - * data is the headers sent (string)
  • - *
  • 'sentBodyPart' - after sending a part of the request body, - * data is the length of that part (int)
  • - *
  • 'sentBody' - after sending the whole request body, - * data is request body length (int)
  • - *
  • 'receivedHeaders' - after receiving the response headers, - * data is HTTP_Request2_Response object
  • - *
  • 'receivedBodyPart' - after receiving a part of the response - * body, data is that part (string)
  • - *
  • 'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still - * encoded by Content-Encoding
  • - *
  • 'receivedBody' - after receiving the complete response - * body, data is HTTP_Request2_Response object
  • - *
- * Different adapters may not send all the event types. Mock adapter does - * not send any events to the observers. - * - * @return array The array has two keys: 'name' and 'data' - */ + /** + * Returns the last event + * + * Observers should use this method to access the last change in request. + * The following event names are possible: + *
    + *
  • 'connect' - after connection to remote server, + * data is the destination (string)
  • + *
  • 'disconnect' - after disconnection from server
  • + *
  • 'sentHeaders' - after sending the request headers, + * data is the headers sent (string)
  • + *
  • 'sentBodyPart' - after sending a part of the request body, + * data is the length of that part (int)
  • + *
  • 'sentBody' - after sending the whole request body, + * data is request body length (int)
  • + *
  • 'receivedHeaders' - after receiving the response headers, + * data is HTTP_Request2_Response object
  • + *
  • 'receivedBodyPart' - after receiving a part of the response + * body, data is that part (string)
  • + *
  • 'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still + * encoded by Content-Encoding
  • + *
  • 'receivedBody' - after receiving the complete response + * body, data is HTTP_Request2_Response object
  • + *
+ * Different adapters may not send all the event types. Mock adapter does + * not send any events to the observers. + * + * @return array The array has two keys: 'name' and 'data' + */ public function getLastEvent() { return $this->lastEvent; } - /** - * Sets the adapter used to actually perform the request - * - * You can pass either an instance of a class implementing HTTP_Request2_Adapter - * or a class name. The method will only try to include a file if the class - * name starts with HTTP_Request2_Adapter_, it will also try to prepend this - * prefix to the class name if it doesn't contain any underscores, so that - * - * $request->setAdapter('curl'); - * - * will work. - * - * @param string|HTTP_Request2_Adapter - * @return HTTP_Request2 - * @throws HTTP_Request2_LogicException - */ + /** + * Sets the adapter used to actually perform the request + * + * You can pass either an instance of a class implementing HTTP_Request2_Adapter + * or a class name. The method will only try to include a file if the class + * name starts with HTTP_Request2_Adapter_, it will also try to prepend this + * prefix to the class name if it doesn't contain any underscores, so that + * + * $request->setAdapter('curl'); + * + * will work. + * + * @param string|HTTP_Request2_Adapter $adapter Adapter to use + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException + */ public function setAdapter($adapter) { if (is_string($adapter)) { @@ -818,7 +849,9 @@ class HTTP_Request2 implements SplSubject if (false === strpos($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'; } if (!class_exists($adapter, false)) { @@ -841,16 +874,19 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Sets the cookie jar - * - * A cookie jar is used to maintain cookies across HTTP requests and - * responses. Cookies from jar will be automatically added to the request - * headers based on request URL. - * - * @param HTTP_Request2_CookieJar|bool Existing CookieJar object, true to - * create a new one, false to remove - */ + /** + * Sets the cookie jar + * + * A cookie jar is used to maintain cookies across HTTP requests and + * responses. Cookies from jar will be automatically added to the request + * headers based on request URL. + * + * @param HTTP_Request2_CookieJar|bool $jar Existing CookieJar object, true to + * create a new one, false to remove + * + * @return HTTP_Request2 + * @throws HTTP_Request2_LogicException + */ public function setCookieJar($jar = true) { if (!class_exists('HTTP_Request2_CookieJar', false)) { @@ -873,22 +909,22 @@ class HTTP_Request2 implements SplSubject return $this; } - /** - * Returns current CookieJar object or null if none - * - * @return HTTP_Request2_CookieJar|null - */ + /** + * Returns current CookieJar object or null if none + * + * @return HTTP_Request2_CookieJar|null + */ public function getCookieJar() { return $this->cookieJar; } - /** - * Sends the request and returns the response - * - * @throws HTTP_Request2_Exception - * @return HTTP_Request2_Response - */ + /** + * Sends the request and returns the response + * + * @throws HTTP_Request2_Exception + * @return HTTP_Request2_Response + */ public function send() { // Sanity check for URL @@ -899,7 +935,7 @@ class HTTP_Request2 implements SplSubject throw new HTTP_Request2_LogicException( 'HTTP_Request2 needs an absolute HTTP(S) request URL, ' . ($this->url instanceof Net_URL2 - ? 'none' : "'" . $this->url->__toString() . "'") + ? "'" . $this->url->__toString() . "'" : 'none') . ' given', HTTP_Request2_Exception::INVALID_ARGUMENT ); @@ -916,7 +952,7 @@ class HTTP_Request2 implements SplSubject // strlen() and substr(); see bug #1781, bug #10605 if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) { $oldEncoding = mb_internal_encoding(); - mb_internal_encoding('iso-8859-1'); + mb_internal_encoding('8bit'); } try { @@ -937,15 +973,17 @@ class HTTP_Request2 implements SplSubject return $response; } - /** - * Wrapper around fopen()/fstat() used by setBody() and addUpload() - * - * @param string|resource file name or pointer to open file - * @param bool whether to try autodetecting MIME 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) - * @throws HTTP_Request2_LogicException - */ + /** + * Wrapper around fopen()/fstat() used by setBody() and addUpload() + * + * @param string|resource $file file name or pointer to open file + * @param bool $detectType whether to try autodetecting MIME + * 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) + * @throws HTTP_Request2_LogicException + */ protected function fopenWrapper($file, $detectType = false) { if (!is_string($file) && !is_resource($file)) { @@ -960,16 +998,12 @@ class HTTP_Request2 implements SplSubject 'size' => 0 ); if (is_string($file)) { - $track = @ini_set('track_errors', 1); if (!($fileData['fp'] = @fopen($file, 'rb'))) { - $e = new HTTP_Request2_LogicException( - $php_errormsg, HTTP_Request2_Exception::READ_ERROR + $error = error_get_last(); + throw new HTTP_Request2_LogicException( + $error['message'], HTTP_Request2_Exception::READ_ERROR ); } - @ini_set('track_errors', $track); - if (isset($e)) { - throw $e; - } if ($detectType) { $fileData['type'] = self::detectMimeType($file); } @@ -984,16 +1018,17 @@ class HTTP_Request2 implements SplSubject return $fileData; } - /** - * Tries to detect MIME type of a file - * - * The method will try to use fileinfo extension if it is available, - * deprecated mime_content_type() function in the other case. If neither - * works, default 'application/octet-stream' MIME type is returned - * - * @param string filename - * @return string file MIME type - */ + /** + * Tries to detect MIME type of a file + * + * The method will try to use fileinfo extension if it is available, + * deprecated mime_content_type() function in the other case. If neither + * works, default 'application/octet-stream' MIME type is returned + * + * @param string $filename file name + * + * @return string file MIME type + */ protected static function detectMimeType($filename) { // finfo extension from PECL available @@ -1012,4 +1047,4 @@ class HTTP_Request2 implements SplSubject return empty($info)? 'application/octet-stream': $info; } } -?> \ No newline at end of file +?> diff --git a/extlib/HTTP/Request2/Adapter.php b/extlib/HTTP/Request2/Adapter.php index 2cabbf897b..3ab7d38cc3 100644 --- a/extlib/HTTP/Request2/Adapter.php +++ b/extlib/HTTP/Request2/Adapter.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,12 +33,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: Adapter.php 308322 2011-02-14 13:58:03Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Adapter.php 324415 2012-03-21 10:50:50Z avb $ + * @link http://pear.php.net/package/HTTP_Request2 */ /** @@ -53,66 +53,69 @@ require_once 'HTTP/Request2/Response.php'; * data, all actual work of sending the request to the remote server and * receiving its response is performed by adapters. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @version Release: 2.0.0RC1 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 { - /** - * A list of methods that MUST NOT have a request body, per RFC 2616 - * @var array - */ + /** + * A list of methods that MUST NOT have a request body, per RFC 2616 + * @var array + */ protected static $bodyDisallowed = array('TRACE'); - /** - * Methods having defined semantics for request body - * - * Content-Length header (indicating that the body follows, section 4.3 of - * RFC 2616) will be sent for these methods even if no body was added - * - * @var array - * @link http://pear.php.net/bugs/bug.php?id=12900 - * @link http://pear.php.net/bugs/bug.php?id=14740 - */ + /** + * Methods having defined semantics for request body + * + * Content-Length header (indicating that the body follows, section 4.3 of + * RFC 2616) will be sent for these methods even if no body was added + * + * @var array + * @link http://pear.php.net/bugs/bug.php?id=12900 + * @link http://pear.php.net/bugs/bug.php?id=14740 + */ protected static $bodyRequired = array('POST', 'PUT'); - /** - * Request being sent - * @var HTTP_Request2 - */ + /** + * Request being sent + * @var HTTP_Request2 + */ protected $request; - /** - * Request body - * @var string|resource|HTTP_Request2_MultipartBody - * @see HTTP_Request2::getBody() - */ + /** + * Request body + * @var string|resource|HTTP_Request2_MultipartBody + * @see HTTP_Request2::getBody() + */ protected $requestBody; - /** - * Length of the request body - * @var integer - */ + /** + * Length of the request body + * @var integer + */ protected $contentLength; - /** - * Sends request to the remote server and returns its response - * - * @param HTTP_Request2 - * @return HTTP_Request2_Response - * @throws HTTP_Request2_Exception - */ + /** + * Sends request to the remote server and returns its response + * + * @param HTTP_Request2 $request HTTP request message + * + * @return HTTP_Request2_Response + * @throws HTTP_Request2_Exception + */ abstract public function sendRequest(HTTP_Request2 $request); - /** - * Calculates length of the request body, adds proper headers - * - * @param array associative array of request headers, this method will - * add proper 'Content-Length' and 'Content-Type' headers - * to this array (or remove them if not needed) - */ + /** + * Calculates length of the request body, adds proper headers + * + * @param array &$headers associative array of request headers, this method + * will add proper 'Content-Length' and 'Content-Type' + * headers to this array (or remove them if not needed) + */ protected function calculateRequestLength(&$headers) { $this->requestBody = $this->request->getBody(); @@ -130,8 +133,8 @@ abstract class HTTP_Request2_Adapter $this->requestBody->rewind(); } - if (in_array($this->request->getMethod(), self::$bodyDisallowed) || - 0 == $this->contentLength + if (in_array($this->request->getMethod(), self::$bodyDisallowed) + || 0 == $this->contentLength ) { // No body: send a Content-Length header nonetheless (request #12900), // but do that only for methods that require a body (bug #14740) diff --git a/extlib/HTTP/Request2/Adapter/Curl.php b/extlib/HTTP/Request2/Adapter/Curl.php index fecfbd7abc..c80c94584e 100644 --- a/extlib/HTTP/Request2/Adapter/Curl.php +++ b/extlib/HTTP/Request2/Adapter/Curl.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,12 +33,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: Curl.php 310800 2011-05-06 07:29:56Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Curl.php 324746 2012-04-03 15:09:16Z avb $ + * @link http://pear.php.net/package/HTTP_Request2 */ /** @@ -49,17 +49,19 @@ require_once 'HTTP/Request2/Adapter.php'; /** * Adapter for HTTP_Request2 wrapping around cURL extension * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @version Release: 2.0.0RC1 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 { - /** - * Mapping of header names to cURL options - * @var array - */ + /** + * Mapping of header names to cURL options + * @var array + */ protected static $headerMap = array( 'accept-encoding' => CURLOPT_ENCODING, 'cookie' => CURLOPT_COOKIE, @@ -67,22 +69,22 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter 'user-agent' => CURLOPT_USERAGENT ); - /** - * Mapping of SSL context options to cURL options - * @var array - */ + /** + * Mapping of SSL context options to cURL options + * @var array + */ protected static $sslContextMap = array( 'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER, 'ssl_cafile' => CURLOPT_CAINFO, 'ssl_capath' => CURLOPT_CAPATH, 'ssl_local_cert' => CURLOPT_SSLCERT, 'ssl_passphrase' => CURLOPT_SSLCERTPASSWD - ); + ); - /** - * Mapping of CURLE_* constants to Exception subclasses and error codes - * @var array - */ + /** + * Mapping of CURLE_* constants to Exception subclasses and error codes + * @var array + */ protected static $errorMap = array( CURLE_UNSUPPORTED_PROTOCOL => array('HTTP_Request2_MessageException', HTTP_Request2_Exception::NON_HTTP_REDIRECT), @@ -119,43 +121,44 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter CURLE_BAD_CONTENT_ENCODING => array('HTTP_Request2_MessageException'), ); - /** - * Response being received - * @var HTTP_Request2_Response - */ + /** + * Response being received + * @var HTTP_Request2_Response + */ protected $response; - /** - * Whether 'sentHeaders' event was sent to observers - * @var boolean - */ + /** + * Whether 'sentHeaders' event was sent to observers + * @var boolean + */ protected $eventSentHeaders = false; - /** - * Whether 'receivedHeaders' event was sent to observers - * @var boolean - */ + /** + * Whether 'receivedHeaders' event was sent to observers + * @var boolean + */ protected $eventReceivedHeaders = false; - /** - * Position within request body - * @var integer - * @see callbackReadBody() - */ + /** + * Position within request body + * @var integer + * @see callbackReadBody() + */ protected $position = 0; - /** - * Information about last transfer, as returned by curl_getinfo() - * @var array - */ + /** + * Information about last transfer, as returned by curl_getinfo() + * @var array + */ protected $lastInfo; - /** - * Creates a subclass of HTTP_Request2_Exception from curl error data - * - * @param resource curl handle - * @return HTTP_Request2_Exception - */ + /** + * Creates a subclass of HTTP_Request2_Exception from curl error data + * + * @param resource $ch curl handle + * + * @return HTTP_Request2_Exception + */ protected static function wrapCurlError($ch) { $nativeCode = curl_errno($ch); @@ -170,13 +173,14 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter } } - /** - * Sends request to the remote server and returns its response - * - * @param HTTP_Request2 - * @return HTTP_Request2_Response - * @throws HTTP_Request2_Exception - */ + /** + * Sends request to the remote server and returns its response + * + * @param HTTP_Request2 $request HTTP request message + * + * @return HTTP_Request2_Response + * @throws HTTP_Request2_Exception + */ public function sendRequest(HTTP_Request2 $request) { if (!extension_loaded('curl')) { @@ -219,22 +223,22 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter return $response; } - /** - * Returns information about last transfer - * - * @return array associative array as returned by curl_getinfo() - */ + /** + * Returns information about last transfer + * + * @return array associative array as returned by curl_getinfo() + */ public function getInfo() { return $this->lastInfo; } - /** - * Creates a new cURL handle and populates it with data from the request - * - * @return resource a cURL handle, as created by curl_init() - * @throws HTTP_Request2_LogicException - */ + /** + * Creates a new cURL handle and populates it with data from the request + * + * @return resource a cURL handle, as created by curl_init() + * @throws HTTP_Request2_LogicException + */ protected function createCurlHandle() { $ch = curl_init(); @@ -281,29 +285,29 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter // set HTTP version switch ($this->request->getConfig('protocol_version')) { - case '1.0': - curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); - break; - case '1.1': - curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + case '1.0': + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + break; + case '1.1': + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); } // set request method switch ($this->request->getMethod()) { - case HTTP_Request2::METHOD_GET: - curl_setopt($ch, CURLOPT_HTTPGET, true); - break; - case HTTP_Request2::METHOD_POST: - curl_setopt($ch, CURLOPT_POST, true); - break; - case HTTP_Request2::METHOD_HEAD: - curl_setopt($ch, CURLOPT_NOBODY, true); - break; - case HTTP_Request2::METHOD_PUT: - curl_setopt($ch, CURLOPT_UPLOAD, true); - break; - default: - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod()); + case HTTP_Request2::METHOD_GET: + curl_setopt($ch, CURLOPT_HTTPGET, true); + break; + case HTTP_Request2::METHOD_POST: + curl_setopt($ch, CURLOPT_POST, true); + break; + case HTTP_Request2::METHOD_HEAD: + curl_setopt($ch, CURLOPT_NOBODY, true); + break; + case HTTP_Request2::METHOD_PUT: + curl_setopt($ch, CURLOPT_UPLOAD, true); + break; + default: + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod()); } // set proxy, if needed @@ -315,14 +319,30 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter } curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port); if ($user = $this->request->getConfig('proxy_user')) { - curl_setopt($ch, CURLOPT_PROXYUSERPWD, $user . ':' . - $this->request->getConfig('proxy_password')); + curl_setopt( + $ch, CURLOPT_PROXYUSERPWD, + $user . ':' . $this->request->getConfig('proxy_password') + ); switch ($this->request->getConfig('proxy_auth_scheme')) { - case HTTP_Request2::AUTH_BASIC: - curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); - break; - case HTTP_Request2::AUTH_DIGEST: - curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); + case HTTP_Request2::AUTH_BASIC: + curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); + break; + case HTTP_Request2::AUTH_DIGEST: + curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); + } + } + if ($type = $this->request->getConfig('proxy_type')) { + switch ($type) { + case 'http': + curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + break; + case 'socks5': + curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); + break; + default: + throw new HTTP_Request2_NotImplementedException( + "Proxy type '{$type}' is not supported" + ); } } } @@ -331,11 +351,11 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter if ($auth = $this->request->getAuth()) { curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']); switch ($auth['scheme']) { - case HTTP_Request2::AUTH_BASIC: - curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - break; - case HTTP_Request2::AUTH_DIGEST: - curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); + case HTTP_Request2::AUTH_BASIC: + curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + break; + case HTTP_Request2::AUTH_DIGEST: + curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); } } @@ -384,16 +404,16 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter return $ch; } - /** - * Workaround for PHP bug #47204 that prevents rewinding request body - * - * The workaround consists of reading the entire request body into memory - * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large - * file uploads, use Socket adapter instead. - * - * @param resource cURL handle - * @param array Request headers - */ + /** + * Workaround for PHP bug #47204 that prevents rewinding request body + * + * The workaround consists of reading the entire request body into memory + * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large + * file uploads, use Socket adapter instead. + * + * @param resource $ch cURL handle + * @param array &$headers Request headers + */ protected function workaroundPhpBug47204($ch, &$headers) { // no redirects, no digest auth -> probably no rewind needed @@ -403,8 +423,8 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter ) { curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody')); - // rewind may be needed, read the whole body into memory } else { + // rewind may be needed, read the whole body into memory if ($this->requestBody instanceof HTTP_Request2_MultipartBody) { $this->requestBody = $this->requestBody->__toString(); @@ -421,14 +441,15 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter } } - /** - * Callback function called by cURL for reading the request body - * - * @param resource cURL handle - * @param resource file descriptor (not used) - * @param integer maximum length of data to return - * @return string part of the request body, up to $length bytes - */ + /** + * Callback function called by cURL for reading the request body + * + * @param resource $ch cURL handle + * @param resource $fd file descriptor (not used) + * @param integer $length maximum length of data to return + * + * @return string part of the request body, up to $length bytes + */ protected function callbackReadBody($ch, $fd, $length) { if (!$this->eventSentHeaders) { @@ -437,8 +458,8 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter ); $this->eventSentHeaders = true; } - if (in_array($this->request->getMethod(), self::$bodyDisallowed) || - 0 == $this->contentLength || $this->position >= $this->contentLength + if (in_array($this->request->getMethod(), self::$bodyDisallowed) + || 0 == $this->contentLength || $this->position >= $this->contentLength ) { return ''; } @@ -454,21 +475,22 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter return $string; } - /** - * Callback function called by cURL for saving the response headers - * - * @param resource cURL handle - * @param string response header (with trailing CRLF) - * @return integer number of bytes saved - * @see HTTP_Request2_Response::parseHeaderLine() - */ + /** + * Callback function called by cURL for saving the response headers + * + * @param resource $ch cURL handle + * @param string $string response header (with trailing CRLF) + * + * @return integer number of bytes saved + * @see HTTP_Request2_Response::parseHeaderLine() + */ protected function callbackWriteHeader($ch, $string) { // we may receive a second set of headers if doing e.g. digest auth if ($this->eventReceivedHeaders || !$this->eventSentHeaders) { // don't bother with 100-Continue responses (bug #15785) - if (!$this->eventSentHeaders || - $this->response->getStatus() >= 200 + if (!$this->eventSentHeaders + || $this->response->getStatus() >= 200 ) { $this->request->setLastEvent( 'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT) @@ -532,14 +554,16 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter return strlen($string); } - /** - * Callback function called by cURL for saving the response body - * - * @param resource cURL handle (not used) - * @param string part of the response body - * @return integer number of bytes saved - * @see HTTP_Request2_Response::appendBody() - */ + /** + * Callback function called by cURL for saving the response body + * + * @param resource $ch cURL handle (not used) + * @param string $string part of the response body + * + * @return integer number of bytes saved + * @throws HTTP_Request2_MessageException + * @see HTTP_Request2_Response::appendBody() + */ protected function callbackWriteBody($ch, $string) { // cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if diff --git a/extlib/HTTP/Request2/Adapter/Mock.php b/extlib/HTTP/Request2/Adapter/Mock.php index c99defb899..29d48dbb74 100644 --- a/extlib/HTTP/Request2/Adapter/Mock.php +++ b/extlib/HTTP/Request2/Adapter/Mock.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,12 +33,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: Mock.php 308322 2011-02-14 13:58:03Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Mock.php 324937 2012-04-07 10:05:57Z avb $ + * @link http://pear.php.net/package/HTTP_Request2 */ /** @@ -63,55 +63,71 @@ require_once 'HTTP/Request2/Adapter.php'; * $response = $req->send(); * * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @version Release: 2.0.0RC1 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 { - /** - * A queue of responses to be returned by sendRequest() - * @var array - */ + /** + * A queue of responses to be returned by sendRequest() + * @var array + */ protected $responses = array(); - /** - * Returns the next response from the queue built by addResponse() - * - * If the queue is empty it will return default empty response with status 400, - * if an Exception object was added to the queue it will be thrown. - * - * @param HTTP_Request2 - * @return HTTP_Request2_Response - * @throws Exception - */ + /** + * Returns the next response from the queue built by addResponse() + * + * 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. + * + * @param HTTP_Request2 $request HTTP request message + * + * @return HTTP_Request2_Response + * @throws Exception + */ public function sendRequest(HTTP_Request2 $request) { - if (count($this->responses) > 0) { - $response = array_shift($this->responses); - if ($response instanceof HTTP_Request2_Response) { - return $response; - } else { - // rethrow the exception - $class = get_class($response); - $message = $response->getMessage(); - $code = $response->getCode(); - throw new $class($message, $code); + $requestUrl = (string)$request->getUrl(); + $response = null; + foreach ($this->responses as $k => $v) { + if (!$v[1] || $requestUrl == $v[1]) { + $response = $v[0]; + array_splice($this->responses, $k, 1); + break; } - } else { + } + if (!$response) { return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n"); + + } elseif ($response instanceof HTTP_Request2_Response) { + return $response; + + } else { + // rethrow the exception + $class = get_class($response); + $message = $response->getMessage(); + $code = $response->getCode(); + throw new $class($message, $code); } } - /** - * Adds response to the queue - * - * @param mixed either a string, a pointer to an open file, - * an instance of HTTP_Request2_Response or Exception - * @throws HTTP_Request2_Exception - */ - public function addResponse($response) + /** + * Adds response to the queue + * + * @param mixed $response either a string, a pointer to an open file, + * 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 + */ + public function addResponse($response, $url = null) { if (is_string($response)) { $response = self::createResponseFromString($response); @@ -122,16 +138,17 @@ class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter ) { throw new HTTP_Request2_Exception('Parameter is not a valid response'); } - $this->responses[] = $response; + $this->responses[] = array($response, $url); } - /** - * Creates a new HTTP_Request2_Response object from a string - * - * @param string - * @return HTTP_Request2_Response - * @throws HTTP_Request2_Exception - */ + /** + * Creates a new HTTP_Request2_Response object from a string + * + * @param string $str string containing HTTP response message + * + * @return HTTP_Request2_Response + * @throws HTTP_Request2_Exception + */ public static function createResponseFromString($str) { $parts = preg_split('!(\r?\n){2}!m', $str, 2); @@ -147,13 +164,14 @@ class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter return $response; } - /** - * Creates a new HTTP_Request2_Response object from a file - * - * @param resource file pointer returned by fopen() - * @return HTTP_Request2_Response - * @throws HTTP_Request2_Exception - */ + /** + * Creates a new HTTP_Request2_Response object from a file + * + * @param resource $fp file pointer returned by fopen() + * + * @return HTTP_Request2_Response + * @throws HTTP_Request2_Exception + */ public static function createResponseFromFile($fp) { $response = new HTTP_Request2_Response(fgets($fp)); diff --git a/extlib/HTTP/Request2/Adapter/Socket.php b/extlib/HTTP/Request2/Adapter/Socket.php index 05cc4c715b..fb2940a2ee 100644 --- a/extlib/HTTP/Request2/Adapter/Socket.php +++ b/extlib/HTTP/Request2/Adapter/Socket.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,141 +33,122 @@ * 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 - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: Socket.php 309921 2011-04-03 16:43:02Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Socket.php 324953 2012-04-08 07:24:12Z avb $ + * @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'; +/** Socket wrapper class */ +require_once 'HTTP/Request2/SocketWrapper.php'; + /** * Socket-based adapter for HTTP_Request2 * * This adapter uses only PHP sockets and will work on almost any PHP * environment. Code is based on original HTTP_Request PEAR package. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @version Release: 2.0.0RC1 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 { - /** - * Regular expression for 'token' rule from RFC 2616 - */ + /** + * Regular expression for 'token' rule from RFC 2616 + */ const REGEXP_TOKEN = '[^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+'; - /** - * Regular expression for 'quoted-string' rule from RFC 2616 - */ + /** + * Regular expression for 'quoted-string' rule from RFC 2616 + */ const REGEXP_QUOTED_STRING = '"(?:\\\\.|[^\\\\"])*"'; - /** - * Connected sockets, needed for Keep-Alive support - * @var array - * @see connect() - */ + /** + * Connected sockets, needed for Keep-Alive support + * @var array + * @see connect() + */ protected static $sockets = array(); - /** - * Data for digest authentication scheme - * - * The keys for the array are URL prefixes. - * - * The values are associative arrays with data (realm, nonce, nonce-count, - * opaque...) needed for digest authentication. Stored here to prevent making - * duplicate requests to digest-protected resources after we have already - * received the challenge. - * - * @var array - */ + /** + * Data for digest authentication scheme + * + * The keys for the array are URL prefixes. + * + * The values are associative arrays with data (realm, nonce, nonce-count, + * opaque...) needed for digest authentication. Stored here to prevent making + * duplicate requests to digest-protected resources after we have already + * received the challenge. + * + * @var array + */ protected static $challenges = array(); - /** - * Connected socket - * @var resource - * @see connect() - */ + /** + * Connected socket + * @var HTTP_Request2_SocketWrapper + * @see connect() + */ protected $socket; - /** - * Challenge used for server digest authentication - * @var array - */ + /** + * Challenge used for server digest authentication + * @var array + */ protected $serverChallenge; - /** - * Challenge used for proxy digest authentication - * @var array - */ + /** + * Challenge used for proxy digest authentication + * @var array + */ 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 - * @var integer - * @see readChunked() - */ + /** + * Remaining length of the current chunk, when reading chunked response + * @var integer + * @see readChunked() + */ protected $chunkLength = 0; - /** - * Remaining amount of redirections to follow - * - * Starts at 'max_redirects' configuration parameter and is reduced on each - * subsequent redirect. An Exception will be thrown once it reaches zero. - * - * @var integer - */ + /** + * Remaining amount of redirections to follow + * + * Starts at 'max_redirects' configuration parameter and is reduced on each + * subsequent redirect. An Exception will be thrown once it reaches zero. + * + * @var integer + */ protected $redirectCountdown = null; - /** - * Sends request to the remote server and returns its response - * - * @param HTTP_Request2 - * @return HTTP_Request2_Response - * @throws HTTP_Request2_Exception - */ + /** + * Sends request to the remote server and returns its response + * + * @param HTTP_Request2 $request HTTP request message + * + * @return HTTP_Request2_Response + * @throws HTTP_Request2_Exception + */ public function sendRequest(HTTP_Request2 $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 { $keepAlive = $this->connect(); $headers = $this->prepareHeaders(); - if (false === @fwrite($this->socket, $headers, strlen($headers))) { - throw new HTTP_Request2_MessageException('Error writing request'); - } + $this->socket->write($headers); // provide request headers to the observer, see request #7633 $this->request->setLastEvent('sentHeaders', $headers); $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(); if ($jar = $request->getCookieJar()) { @@ -210,12 +191,12 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter } } - /** - * Connects to the remote server - * - * @return bool whether the connection can be persistent - * @throws HTTP_Request2_Exception - */ + /** + * Connects to the remote server + * + * @return bool whether the connection can be persistent + * @throws HTTP_Request2_Exception + */ protected function connect() { $secure = 0 == strcasecmp($this->request->getUrl()->getScheme(), 'https'); @@ -226,21 +207,29 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $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'))) { throw new HTTP_Request2_LogicException( 'Proxy port not provided', HTTP_Request2_Exception::MISSING_VALUE ); } - $proxy = true; - } else { - $host = $reqHost; - $port = $reqPort; - $proxy = false; + if ('http' == ($type = $this->request->getConfig('proxy_type'))) { + $httpProxy = true; + } elseif ('socks5' == $type) { + $socksProxy = true; + } else { + throw new HTTP_Request2_NotImplementedException( + "Proxy type '{$type}' is not supported" + ); + } } - if ($tunnel && !$proxy) { + if ($tunnel && !$httpProxy) { throw new HTTP_Request2_LogicException( "Trying to perform CONNECT request without proxy", 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 // connection token to a proxy server... - if ($proxy && !$secure && - !empty($headers['connection']) && 'Keep-Alive' == $headers['connection'] + if ($httpProxy && !$secure && !empty($headers['connection']) + && 'Keep-Alive' == $headers['connection'] ) { $this->request->setHeader('connection'); } @@ -265,7 +254,6 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter empty($headers['connection'])) || (!empty($headers['connection']) && 'Keep-Alive' == $headers['connection']); - $host = ((!$secure || $proxy)? 'tcp://': 'ssl://') . $host; $options = array(); if ($secure || $tunnel) { @@ -283,76 +271,81 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter 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* // work, we need a new connection if options change - $remote = $host . ':' . $port; - $socketKey = $remote . (($secure && $proxy)? "->{$reqHost}:{$reqPort}": '') . - (empty($options)? '': ':' . serialize($options)); + $remote = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://') + . $host . ':' . $port; + $socketKey = $remote . ( + ($secure && $httpProxy || $socksProxy) + ? "->{$reqHost}:{$reqPort}" : '' + ) . (empty($options)? '': ':' . serialize($options)); unset($this->socket); // We use persistent connections and have a connected socket? // Ensure that the socket is still connected, see bug #16149 - if ($keepAlive && !empty(self::$sockets[$socketKey]) && - !feof(self::$sockets[$socketKey]) + if ($keepAlive && !empty(self::$sockets[$socketKey]) + && !self::$sockets[$socketKey]->eof() ) { $this->socket =& self::$sockets[$socketKey]; - } elseif ($secure && $proxy && !$tunnel) { - $this->establishTunnel(); - $this->request->setLastEvent( - 'connect', "ssl://{$reqHost}:{$reqPort} via {$host}:{$port}" - ); - self::$sockets[$socketKey] =& $this->socket; - } else { - // Set SSL context options if doing HTTPS request or creating a tunnel - $context = stream_context_create(); - 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}'" - ); + if ($socksProxy) { + require_once 'HTTP/Request2/SOCKS5.php'; + + $this->socket = new HTTP_Request2_SOCKS5( + $remote, $this->request->getConfig('connect_timeout'), + $options, $this->request->getConfig('proxy_user'), + $this->request->getConfig('proxy_password') + ); + // 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}"; } - } - $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 + + } elseif ($secure && $httpProxy && !$tunnel) { + $this->establishTunnel(); + $conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}"; + + } else { + $this->socket = new HTTP_Request2_SocketWrapper( + $remote, $this->request->getConfig('connect_timeout'), $options ); } - @ini_set('track_errors', $track); - if (isset($e)) { - throw $e; - } - $this->request->setLastEvent('connect', $remote); + $this->request->setLastEvent('connect', empty($conninfo)? $remote: $conninfo); self::$sockets[$socketKey] =& $this->socket; } + $this->socket->setDeadline($deadline, $this->request->getConfig('timeout')); return $keepAlive; } - /** - * Establishes a tunnel to a secure remote server via HTTP CONNECT request - * - * This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP - * sees that we are connected to a proxy server (duh!) rather than the server - * that presents its certificate. - * - * @link http://tools.ietf.org/html/rfc2817#section-5.2 - * @throws HTTP_Request2_Exception - */ + /** + * Establishes a tunnel to a secure remote server via HTTP CONNECT request + * + * This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP + * sees that we are connected to a proxy server (duh!) rather than the server + * that presents its certificate. + * + * @link http://tools.ietf.org/html/rfc2817#section-5.2 + * @throws HTTP_Request2_Exception + */ protected function establishTunnel() { $donor = new self; $connect = new HTTP_Request2( $this->request->getUrl(), HTTP_Request2::METHOD_CONNECT, - array_merge($this->request->getConfig(), - array('adapter' => $donor)) + array_merge($this->request->getConfig(), array('adapter' => $donor)) ); $response = $connect->send(); // Need any successful (2XX) response @@ -363,37 +356,23 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter ); } $this->socket = $donor->socket; - - $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' - ); + $this->socket->enableCrypto(); } - /** - * Checks whether current connection may be reused or should be closed - * - * @param boolean whether connection could be persistent - * in the first place - * @param HTTP_Request2_Response response object to check - * @return boolean - */ + /** + * Checks whether current connection may be reused or should be closed + * + * @param boolean $requestKeepAlive whether connection could + * be persistent in the first place + * @param HTTP_Request2_Response $response response object to check + * + * @return boolean + */ protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response) { // Do not close socket on successful CONNECT request - if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() && - 200 <= $response->getStatus() && 300 > $response->getStatus() + if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() + && 200 <= $response->getStatus() && 300 > $response->getStatus() ) { return true; } @@ -409,40 +388,40 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter return $requestKeepAlive && $lengthKnown && $persistent; } - /** - * Disconnects from the remote server - */ + /** + * Disconnects from the remote server + */ protected function disconnect() { - if (is_resource($this->socket)) { - fclose($this->socket); + if (!empty($this->socket)) { $this->socket = null; $this->request->setLastEvent('disconnect'); } } - /** - * Handles HTTP redirection - * - * This method will throw an Exception if redirect to a non-HTTP(S) location - * is attempted, also if number of redirects performed already is equal to - * 'max_redirects' configuration parameter. - * - * @param HTTP_Request2 Original request - * @param HTTP_Request2_Response Response containing redirect - * @return HTTP_Request2_Response Response from a new location - * @throws HTTP_Request2_Exception - */ - protected function handleRedirect(HTTP_Request2 $request, - HTTP_Request2_Response $response) - { + /** + * Handles HTTP redirection + * + * This method will throw an Exception if redirect to a non-HTTP(S) location + * is attempted, also if number of redirects performed already is equal to + * 'max_redirects' configuration parameter. + * + * @param HTTP_Request2 $request Original request + * @param HTTP_Request2_Response $response Response containing redirect + * + * @return HTTP_Request2_Response Response from a new location + * @throws HTTP_Request2_Exception + */ + protected function handleRedirect( + HTTP_Request2 $request, HTTP_Request2_Response $response + ) { if (is_null($this->redirectCountdown)) { $this->redirectCountdown = $request->getConfig('max_redirects'); } if (0 == $this->redirectCountdown) { $this->redirectCountdown = null; // Copying cURL behaviour - throw new HTTP_Request2_MessageException ( + throw new HTTP_Request2_MessageException( 'Maximum (' . $request->getConfig('max_redirects') . ') redirects followed', HTTP_Request2_Exception::TOO_MANY_REDIRECTS ); @@ -468,8 +447,9 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter } $redirect = clone $request; $redirect->setUrl($redirectUrl); - if (303 == $response->getStatus() || (!$request->getConfig('strict_redirects') - && in_array($response->getStatus(), array(301, 302))) + if (303 == $response->getStatus() + || (!$request->getConfig('strict_redirects') + && in_array($response->getStatus(), array(301, 302))) ) { $redirect->setMethod(HTTP_Request2::METHOD_GET); $redirect->setBody(''); @@ -481,23 +461,24 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter return $this->sendRequest($redirect); } - /** - * Checks whether another request should be performed with server digest auth - * - * Several conditions should be satisfied for it to return true: - * - response status should be 401 - * - auth credentials should be set in the request object - * - response should contain WWW-Authenticate header with digest challenge - * - there is either no challenge stored for this URL or new challenge - * contains stale=true parameter (in other case we probably just failed - * due to invalid username / password) - * - * The method stores challenge values in $challenges static property - * - * @param HTTP_Request2_Response response to check - * @return boolean whether another request should be performed - * @throws HTTP_Request2_Exception in case of unsupported challenge parameters - */ + /** + * Checks whether another request should be performed with server digest auth + * + * Several conditions should be satisfied for it to return true: + * - response status should be 401 + * - auth credentials should be set in the request object + * - response should contain WWW-Authenticate header with digest challenge + * - there is either no challenge stored for this URL or new challenge + * contains stale=true parameter (in other case we probably just failed + * due to invalid username / password) + * + * The method stores challenge values in $challenges static property + * + * @param HTTP_Request2_Response $response response to check + * + * @return boolean whether another request should be performed + * @throws HTTP_Request2_Exception in case of unsupported challenge parameters + */ protected function shouldUseServerDigestAuth(HTTP_Request2_Response $response) { // no sense repeating a request if we don't have credentials @@ -512,8 +493,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $scheme = $url->getScheme(); $host = $scheme . '://' . $url->getHost(); if ($port = $url->getPort()) { - if ((0 == strcasecmp($scheme, 'http') && 80 != $port) || - (0 == strcasecmp($scheme, 'https') && 443 != $port) + if ((0 == strcasecmp($scheme, 'http') && 80 != $port) + || (0 == strcasecmp($scheme, 'https') && 443 != $port) ) { $host .= ':' . $port; } @@ -534,8 +515,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $ret = true; foreach ($prefixes as $prefix) { - if (!empty(self::$challenges[$prefix]) && - (empty($challenge['stale']) || strcasecmp('true', $challenge['stale'])) + if (!empty(self::$challenges[$prefix]) + && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale'])) ) { // probably credentials are invalid $ret = false; @@ -545,23 +526,24 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter return $ret; } - /** - * Checks whether another request should be performed with proxy digest auth - * - * Several conditions should be satisfied for it to return true: - * - response status should be 407 - * - proxy auth credentials should be set in the request object - * - response should contain Proxy-Authenticate header with digest challenge - * - there is either no challenge stored for this proxy or new challenge - * contains stale=true parameter (in other case we probably just failed - * due to invalid username / password) - * - * The method stores challenge values in $challenges static property - * - * @param HTTP_Request2_Response response to check - * @return boolean whether another request should be performed - * @throws HTTP_Request2_Exception in case of unsupported challenge parameters - */ + /** + * Checks whether another request should be performed with proxy digest auth + * + * Several conditions should be satisfied for it to return true: + * - response status should be 407 + * - proxy auth credentials should be set in the request object + * - response should contain Proxy-Authenticate header with digest challenge + * - there is either no challenge stored for this proxy or new challenge + * contains stale=true parameter (in other case we probably just failed + * due to invalid username / password) + * + * The method stores challenge values in $challenges static property + * + * @param HTTP_Request2_Response $response response to check + * + * @return boolean whether another request should be performed + * @throws HTTP_Request2_Exception in case of unsupported challenge parameters + */ protected function shouldUseProxyDigestAuth(HTTP_Request2_Response $response) { if (407 != $response->getStatus() || !$this->request->getConfig('proxy_user')) { @@ -574,8 +556,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $key = 'proxy://' . $this->request->getConfig('proxy_host') . ':' . $this->request->getConfig('proxy_port'); - if (!empty(self::$challenges[$key]) && - (empty($challenge['stale']) || strcasecmp('true', $challenge['stale'])) + if (!empty(self::$challenges[$key]) + && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale'])) ) { $ret = false; } else { @@ -585,34 +567,35 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter return $ret; } - /** - * Extracts digest method challenge from (WWW|Proxy)-Authenticate header value - * - * There is a problem with implementation of RFC 2617: several of the parameters - * are defined as quoted-string there and thus may contain backslash escaped - * double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as - * just value of quoted-string X without surrounding quotes, it doesn't speak - * about removing backslash escaping. - * - * Now realm parameter is user-defined and human-readable, strange things - * happen when it contains quotes: - * - Apache allows quotes in realm, but apparently uses realm value without - * backslashes for digest computation - * - Squid allows (manually escaped) quotes there, but it is impossible to - * authorize with either escaped or unescaped quotes used in digest, - * probably it can't parse the response (?) - * - Both IE and Firefox display realm value with backslashes in - * the password popup and apparently use the same value for digest - * - * HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in - * quoted-string handling, unfortunately that means failure to authorize - * sometimes - * - * @param string value of WWW-Authenticate or Proxy-Authenticate header - * @return mixed associative array with challenge parameters, false if - * no challenge is present in header value - * @throws HTTP_Request2_NotImplementedException in case of unsupported challenge parameters - */ + /** + * Extracts digest method challenge from (WWW|Proxy)-Authenticate header value + * + * There is a problem with implementation of RFC 2617: several of the parameters + * are defined as quoted-string there and thus may contain backslash escaped + * double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as + * just value of quoted-string X without surrounding quotes, it doesn't speak + * about removing backslash escaping. + * + * Now realm parameter is user-defined and human-readable, strange things + * happen when it contains quotes: + * - Apache allows quotes in realm, but apparently uses realm value without + * backslashes for digest computation + * - Squid allows (manually escaped) quotes there, but it is impossible to + * authorize with either escaped or unescaped quotes used in digest, + * probably it can't parse the response (?) + * - Both IE and Firefox display realm value with backslashes in + * the password popup and apparently use the same value for digest + * + * HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in + * quoted-string handling, unfortunately that means failure to authorize + * sometimes + * + * @param string $headerValue value of WWW-Authenticate or Proxy-Authenticate header + * + * @return mixed associative array with challenge parameters, false if + * no challenge is present in header value + * @throws HTTP_Request2_NotImplementedException in case of unsupported challenge parameters + */ protected function parseDigestChallenge($headerValue) { $authParam = '(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' . @@ -637,8 +620,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter } } // we only support qop=auth - if (!empty($paramsAry['qop']) && - !in_array('auth', array_map('trim', explode(',', $paramsAry['qop']))) + if (!empty($paramsAry['qop']) + && !in_array('auth', array_map('trim', explode(',', $paramsAry['qop']))) ) { throw new HTTP_Request2_NotImplementedException( "Only 'auth' qop is currently supported in digest authentication, " . @@ -656,13 +639,14 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter return $paramsAry; } - /** - * Parses [Proxy-]Authentication-Info header value and updates challenge - * - * @param array challenge to update - * @param string value of [Proxy-]Authentication-Info header - * @todo validate server rspauth response - */ + /** + * Parses [Proxy-]Authentication-Info header value and updates challenge + * + * @param array &$challenge challenge to update + * @param string $headerValue value of [Proxy-]Authentication-Info header + * + * @todo validate server rspauth response + */ protected function updateChallenge(&$challenge, $headerValue) { $authParam = '!(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' . @@ -684,20 +668,21 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter } } - /** - * Creates a value for [Proxy-]Authorization header when using digest authentication - * - * @param string user name - * @param string password - * @param string request URL - * @param array digest challenge parameters - * @return string value of [Proxy-]Authorization request header - * @link http://tools.ietf.org/html/rfc2617#section-3.2.2 - */ + /** + * Creates a value for [Proxy-]Authorization header when using digest authentication + * + * @param string $user user name + * @param string $password password + * @param string $url request URL + * @param array &$challenge digest challenge parameters + * + * @return string value of [Proxy-]Authorization request header + * @link http://tools.ietf.org/html/rfc2617#section-3.2.2 + */ protected function createDigestResponse($user, $password, $url, &$challenge) { - if (false !== ($q = strpos($url, '?')) && - $this->request->getConfig('digest_compat_ie') + if (false !== ($q = strpos($url, '?')) + && $this->request->getConfig('digest_compat_ie') ) { $url = substr($url, 0, $q); } @@ -713,8 +698,10 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $challenge['nc'] = 1; } $nc = sprintf('%08x', $challenge['nc']++); - $digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' . - $challenge['cnonce'] . ':auth:' . $a2); + $digest = md5( + $a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' . + $challenge['cnonce'] . ':auth:' . $a2 + ); } return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' . 'realm="' . $challenge['realm'] . '", ' . @@ -729,102 +716,106 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter ''); } - /** - * Adds 'Authorization' header (if needed) to request headers array - * - * @param array request headers - * @param string request host (needed for digest authentication) - * @param string request URL (needed for digest authentication) - * @throws HTTP_Request2_NotImplementedException - */ + /** + * Adds 'Authorization' header (if needed) to request headers array + * + * @param array &$headers request headers + * @param string $requestHost request host (needed for digest authentication) + * @param string $requestUrl request URL (needed for digest authentication) + * + * @throws HTTP_Request2_NotImplementedException + */ protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl) { if (!($auth = $this->request->getAuth())) { return; } switch ($auth['scheme']) { - case HTTP_Request2::AUTH_BASIC: - $headers['authorization'] = - 'Basic ' . base64_encode($auth['user'] . ':' . $auth['password']); - break; + case HTTP_Request2::AUTH_BASIC: + $headers['authorization'] = 'Basic ' . base64_encode( + $auth['user'] . ':' . $auth['password'] + ); + break; - case HTTP_Request2::AUTH_DIGEST: - unset($this->serverChallenge); - $fullUrl = ('/' == $requestUrl[0])? - $this->request->getUrl()->getScheme() . '://' . - $requestHost . $requestUrl: - $requestUrl; - foreach (array_keys(self::$challenges) as $key) { - if ($key == substr($fullUrl, 0, strlen($key))) { - $headers['authorization'] = $this->createDigestResponse( - $auth['user'], $auth['password'], - $requestUrl, self::$challenges[$key] - ); - $this->serverChallenge =& self::$challenges[$key]; - break; - } + case HTTP_Request2::AUTH_DIGEST: + unset($this->serverChallenge); + $fullUrl = ('/' == $requestUrl[0])? + $this->request->getUrl()->getScheme() . '://' . + $requestHost . $requestUrl: + $requestUrl; + foreach (array_keys(self::$challenges) as $key) { + if ($key == substr($fullUrl, 0, strlen($key))) { + $headers['authorization'] = $this->createDigestResponse( + $auth['user'], $auth['password'], + $requestUrl, self::$challenges[$key] + ); + $this->serverChallenge =& self::$challenges[$key]; + break; } - break; + } + break; - default: - throw new HTTP_Request2_NotImplementedException( - "Unknown HTTP authentication scheme '{$auth['scheme']}'" - ); + default: + throw new HTTP_Request2_NotImplementedException( + "Unknown HTTP authentication scheme '{$auth['scheme']}'" + ); } } - /** - * Adds 'Proxy-Authorization' header (if needed) to request headers array - * - * @param array request headers - * @param string request URL (needed for digest authentication) - * @throws HTTP_Request2_NotImplementedException - */ + /** + * Adds 'Proxy-Authorization' header (if needed) to request headers array + * + * @param array &$headers request headers + * @param string $requestUrl request URL (needed for digest authentication) + * + * @throws HTTP_Request2_NotImplementedException + */ protected function addProxyAuthorizationHeader(&$headers, $requestUrl) { - if (!$this->request->getConfig('proxy_host') || - !($user = $this->request->getConfig('proxy_user')) || - (0 == strcasecmp('https', $this->request->getUrl()->getScheme()) && - HTTP_Request2::METHOD_CONNECT != $this->request->getMethod()) + if (!$this->request->getConfig('proxy_host') + || !($user = $this->request->getConfig('proxy_user')) + || (0 == strcasecmp('https', $this->request->getUrl()->getScheme()) + && HTTP_Request2::METHOD_CONNECT != $this->request->getMethod()) ) { return; } $password = $this->request->getConfig('proxy_password'); switch ($this->request->getConfig('proxy_auth_scheme')) { - case HTTP_Request2::AUTH_BASIC: - $headers['proxy-authorization'] = - 'Basic ' . base64_encode($user . ':' . $password); - break; + case HTTP_Request2::AUTH_BASIC: + $headers['proxy-authorization'] = 'Basic ' . base64_encode( + $user . ':' . $password + ); + break; - case HTTP_Request2::AUTH_DIGEST: - unset($this->proxyChallenge); - $proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') . - ':' . $this->request->getConfig('proxy_port'); - if (!empty(self::$challenges[$proxyUrl])) { - $headers['proxy-authorization'] = $this->createDigestResponse( - $user, $password, - $requestUrl, self::$challenges[$proxyUrl] - ); - $this->proxyChallenge =& self::$challenges[$proxyUrl]; - } - break; - - default: - throw new HTTP_Request2_NotImplementedException( - "Unknown HTTP authentication scheme '" . - $this->request->getConfig('proxy_auth_scheme') . "'" + case HTTP_Request2::AUTH_DIGEST: + unset($this->proxyChallenge); + $proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') . + ':' . $this->request->getConfig('proxy_port'); + if (!empty(self::$challenges[$proxyUrl])) { + $headers['proxy-authorization'] = $this->createDigestResponse( + $user, $password, + $requestUrl, self::$challenges[$proxyUrl] ); + $this->proxyChallenge =& self::$challenges[$proxyUrl]; + } + break; + + default: + throw new HTTP_Request2_NotImplementedException( + "Unknown HTTP authentication scheme '" . + $this->request->getConfig('proxy_auth_scheme') . "'" + ); } } - /** - * Creates the string with the Request-Line and request headers - * - * @return string - * @throws HTTP_Request2_Exception - */ + /** + * Creates the string with the Request-Line and request headers + * + * @return string + * @throws HTTP_Request2_Exception + */ protected function prepareHeaders() { $headers = $this->request->getHeaders(); @@ -845,8 +836,9 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $requestUrl = $host; } else { - if (!$this->request->getConfig('proxy_host') || - 0 == strcasecmp($url->getScheme(), 'https') + if (!$this->request->getConfig('proxy_host') + || 'http' != $this->request->getConfig('proxy_type') + || 0 == strcasecmp($url->getScheme(), 'https') ) { $requestUrl = ''; } else { @@ -857,8 +849,8 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query); } - if ('1.1' == $this->request->getConfig('protocol_version') && - extension_loaded('zlib') && !isset($headers['accept-encoding']) + if ('1.1' == $this->request->getConfig('protocol_version') + && extension_loaded('zlib') && !isset($headers['accept-encoding']) ) { $headers['accept-encoding'] = 'gzip, deflate'; } @@ -881,15 +873,15 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter return $headersStr . "\r\n"; } - /** - * Sends the request body - * - * @throws HTTP_Request2_MessageException - */ + /** + * Sends the request body + * + * @throws HTTP_Request2_MessageException + */ protected function writeBody() { - if (in_array($this->request->getMethod(), self::$bodyDisallowed) || - 0 == $this->contentLength + if (in_array($this->request->getMethod(), self::$bodyDisallowed) + || 0 == $this->contentLength ) { return; } @@ -904,9 +896,7 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter } else { $str = $this->requestBody->read($bufferSize); } - if (false === @fwrite($this->socket, $str, strlen($str))) { - throw new HTTP_Request2_MessageException('Error writing request'); - } + $this->socket->write($str); // Provide the length of written string to the observer, request #7630 $this->request->setLastEvent('sentBodyPart', strlen($str)); $position += strlen($str); @@ -914,22 +904,22 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $this->request->setLastEvent('sentBody', $this->contentLength); } - /** - * Reads the remote server's response - * - * @return HTTP_Request2_Response - * @throws HTTP_Request2_Exception - */ + /** + * Reads the remote server's response + * + * @return HTTP_Request2_Response + * @throws HTTP_Request2_Exception + */ protected function readResponse() { $bufferSize = $this->request->getConfig('buffer_size'); do { $response = new HTTP_Request2_Response( - $this->readLine($bufferSize), true, $this->request->getUrl() + $this->socket->readLine($bufferSize), true, $this->request->getUrl() ); do { - $headerLine = $this->readLine($bufferSize); + $headerLine = $this->socket->readLine($bufferSize); $response->parseHeaderLine($headerLine); } while ('' != $headerLine); } 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); // No body possible in such responses - if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod() || - (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() && - 200 <= $response->getStatus() && 300 > $response->getStatus()) || - in_array($response->getStatus(), array(204, 304)) + if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod() + || (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() + && 200 <= $response->getStatus() && 300 > $response->getStatus()) + || in_array($response->getStatus(), array(204, 304)) ) { return $response; } @@ -956,16 +946,16 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter $toRead = ($chunked || null === $length)? null: $length; $this->chunkLength = 0; - while (!feof($this->socket) && (is_null($toRead) || 0 < $toRead)) { + while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) { if ($chunked) { $data = $this->readChunked($bufferSize); } elseif (is_null($toRead)) { - $data = $this->fread($bufferSize); + $data = $this->socket->read($bufferSize); } else { - $data = $this->fread(min($toRead, $bufferSize)); + $data = $this->socket->read(min($toRead, $bufferSize)); $toRead -= strlen($data); } - if ('' == $data && (!$this->chunkLength || feof($this->socket))) { + if ('' == $data && (!$this->chunkLength || $this->socket->eof())) { break; } @@ -987,77 +977,19 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter 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 - * - * @param int buffer size to use for reading - * @return string - * @throws HTTP_Request2_MessageException - */ + /** + * Reads a part of response body encoded with chunked Transfer-Encoding + * + * @param int $bufferSize buffer size to use for reading + * + * @return string + * @throws HTTP_Request2_MessageException + */ protected function readChunked($bufferSize) { // at start of the next chunk? if (0 == $this->chunkLength) { - $line = $this->readLine($bufferSize); + $line = $this->socket->readLine($bufferSize); if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) { throw new HTTP_Request2_MessageException( "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]); // Chunk with zero length indicates the end if (0 == $this->chunkLength) { - $this->readLine($bufferSize); + $this->socket->readLine($bufferSize); return ''; } } } - $data = $this->fread(min($this->chunkLength, $bufferSize)); + $data = $this->socket->read(min($this->chunkLength, $bufferSize)); $this->chunkLength -= strlen($data); if (0 == $this->chunkLength) { - $this->readLine($bufferSize); // Trailing CRLF + $this->socket->readLine($bufferSize); // Trailing CRLF } return $data; } diff --git a/extlib/HTTP/Request2/CookieJar.php b/extlib/HTTP/Request2/CookieJar.php index af7534f18d..904186791a 100644 --- a/extlib/HTTP/Request2/CookieJar.php +++ b/extlib/HTTP/Request2/CookieJar.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,12 +33,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: CookieJar.php 308629 2011-02-24 17:34:24Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: CookieJar.php 324415 2012-03-21 10:50:50Z avb $ + * @link http://pear.php.net/package/HTTP_Request2 */ /** Class representing a HTTP request message */ @@ -47,65 +47,70 @@ require_once 'HTTP/Request2.php'; /** * Stores cookies and passes them between HTTP requests * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @version Release: @package_version@ + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/HTTP_Request2 */ class HTTP_Request2_CookieJar implements Serializable { - /** - * Array of stored cookies - * - * The array is indexed by domain, path and cookie name - * .example.com - * / - * some_cookie => cookie data - * /subdir - * other_cookie => cookie data - * .example.org - * ... - * - * @var array - */ + /** + * Array of stored cookies + * + * The array is indexed by domain, path and cookie name + * .example.com + * / + * some_cookie => cookie data + * /subdir + * other_cookie => cookie data + * .example.org + * ... + * + * @var array + */ protected $cookies = array(); - /** - * Whether session cookies should be serialized when serializing the jar - * @var bool - */ + /** + * Whether session cookies should be serialized when serializing the jar + * @var bool + */ protected $serializeSession = false; - /** - * Whether Public Suffix List should be used for domain matching - * @var bool - */ + /** + * Whether Public Suffix List should be used for domain matching + * @var bool + */ protected $useList = true; - /** - * Array with Public Suffix List data - * @var array - * @link http://publicsuffix.org/ - */ + /** + * Array with Public Suffix List data + * @var array + * @link http://publicsuffix.org/ + */ protected static $psl = array(); - /** - * Class constructor, sets various options - * - * @param bool Controls serializing session cookies, see {@link serializeSessionCookies()} - * @param bool Controls using Public Suffix List, see {@link usePublicSuffixList()} - */ - public function __construct($serializeSessionCookies = false, $usePublicSuffixList = true) - { + /** + * Class constructor, sets various options + * + * @param bool $serializeSessionCookies Controls serializing session cookies, + * see {@link serializeSessionCookies()} + * @param bool $usePublicSuffixList Controls using Public Suffix List, + * see {@link usePublicSuffixList()} + */ + public function __construct( + $serializeSessionCookies = false, $usePublicSuffixList = true + ) { $this->serializeSessionCookies($serializeSessionCookies); $this->usePublicSuffixList($usePublicSuffixList); } - /** - * Returns current time formatted in ISO-8601 at UTC timezone - * - * @return string - */ + /** + * Returns current time formatted in ISO-8601 at UTC timezone + * + * @return string + */ protected function now() { $dt = new DateTime(); @@ -113,28 +118,30 @@ class HTTP_Request2_CookieJar implements Serializable return $dt->format(DateTime::ISO8601); } - /** - * Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields - * - * The checks are as follows: - * - cookie array should contain 'name' and 'value' fields; - * - name and value should not contain disallowed symbols; - * - 'expires' should be either empty parseable by DateTime; - * - 'domain' and 'path' should be either not empty or an URL where - * cookie was set should be provided. - * - if $setter is provided, then document at that URL should be allowed - * to set a cookie for that 'domain'. If $setter is not provided, - * then no domain checks will be made. - * - * 'expires' field will be converted to ISO8601 format from COOKIE format, - * 'domain' and 'path' will be set from setter URL if empty. - * - * @param array cookie data, as returned by {@link HTTP_Request2_Response::getCookies()} - * @param Net_URL2 URL of the document that sent Set-Cookie header - * @return array Updated cookie array - * @throws HTTP_Request2_LogicException - * @throws HTTP_Request2_MessageException - */ + /** + * Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields + * + * The checks are as follows: + * - cookie array should contain 'name' and 'value' fields; + * - name and value should not contain disallowed symbols; + * - 'expires' should be either empty parseable by DateTime; + * - 'domain' and 'path' should be either not empty or an URL where + * cookie was set should be provided. + * - if $setter is provided, then document at that URL should be allowed + * to set a cookie for that 'domain'. If $setter is not provided, + * then no domain checks will be made. + * + * 'expires' field will be converted to ISO8601 format from COOKIE format, + * 'domain' and 'path' will be set from setter URL if empty. + * + * @param array $cookie cookie data, as returned by + * {@link HTTP_Request2_Response::getCookies()} + * @param Net_URL2 $setter URL of the document that sent Set-Cookie header + * + * @return array Updated cookie array + * @throws HTTP_Request2_LogicException + * @throws HTTP_Request2_MessageException + */ protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null) { if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) { @@ -203,13 +210,15 @@ class HTTP_Request2_CookieJar implements Serializable return $cookie; } - /** - * Stores a cookie in the jar - * - * @param array cookie data, as returned by {@link HTTP_Request2_Response::getCookies()} - * @param Net_URL2 URL of the document that sent Set-Cookie header - * @throws HTTP_Request2_Exception - */ + /** + * Stores a cookie in the jar + * + * @param array $cookie cookie data, as returned by + * {@link HTTP_Request2_Response::getCookies()} + * @param Net_URL2 $setter URL of the document that sent Set-Cookie header + * + * @throws HTTP_Request2_Exception + */ public function store(array $cookie, Net_URL2 $setter = null) { $cookie = $this->checkAndUpdateFields($cookie, $setter); @@ -230,13 +239,13 @@ class HTTP_Request2_CookieJar implements Serializable } } - /** - * Adds cookies set in HTTP response to the jar - * - * @param HTTP_Request2_Response response - * @param Net_URL2 original request URL, needed for setting - * default domain/path - */ + /** + * Adds cookies set in HTTP response to the jar + * + * @param HTTP_Request2_Response $response HTTP response message + * @param Net_URL2 $setter original request URL, needed for + * setting default domain/path + */ public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter) { foreach ($response->getCookies() as $cookie) { @@ -244,18 +253,19 @@ class HTTP_Request2_CookieJar implements Serializable } } - /** - * Returns all cookies matching a given request URL - * - * The following checks are made: - * - cookie domain should match request host - * - cookie path should be a prefix for request path - * - 'secure' cookies will only be sent for HTTPS requests - * - * @param Net_URL2 - * @param bool Whether to return cookies as string for "Cookie: " header - * @return array - */ + /** + * Returns all cookies matching a given request URL + * + * The following checks are made: + * - cookie domain should match request host + * - cookie path should be a prefix for request path + * - 'secure' cookies will only be sent for HTTPS requests + * + * @param Net_URL2 $url Request url + * @param bool $asString Whether to return cookies as string for "Cookie: " header + * + * @return array|string Matching cookies + */ public function getMatching(Net_URL2 $url, $asString = false) { $host = $url->getHost(); @@ -291,11 +301,11 @@ class HTTP_Request2_CookieJar implements Serializable } } - /** - * Returns all cookies stored in a jar - * - * @return array - */ + /** + * Returns all cookies stored in a jar + * + * @return array + */ public function getAll() { $cookies = array(); @@ -309,47 +319,49 @@ class HTTP_Request2_CookieJar implements Serializable return $cookies; } - /** - * Sets whether session cookies should be serialized when serializing the jar - * - * @param boolean - */ + /** + * Sets whether session cookies should be serialized when serializing the jar + * + * @param boolean $serialize serialize? + */ public function serializeSessionCookies($serialize) { $this->serializeSession = (bool)$serialize; } - /** - * Sets whether Public Suffix List should be used for restricting cookie-setting - * - * Without PSL {@link domainMatch()} will only prevent setting cookies for - * top-level domains like '.com' or '.org'. However, it will not prevent - * setting a cookie for '.co.uk' even though only third-level registrations - * are possible in .uk domain. - * - * With the List it is possible to find the highest level at which a domain - * may be registered for a particular top-level domain and consequently - * prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by - * Firefox, Chrome and Opera browsers to restrict cookie setting. - * - * Note that PSL is licensed differently to HTTP_Request2 package (refer to - * the license information in public-suffix-list.php), so you can disable - * its use if this is an issue for you. - * - * @param boolean - * @link http://publicsuffix.org/learn/ - */ + /** + * Sets whether Public Suffix List should be used for restricting cookie-setting + * + * Without PSL {@link domainMatch()} will only prevent setting cookies for + * top-level domains like '.com' or '.org'. However, it will not prevent + * setting a cookie for '.co.uk' even though only third-level registrations + * are possible in .uk domain. + * + * With the List it is possible to find the highest level at which a domain + * may be registered for a particular top-level domain and consequently + * prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by + * Firefox, Chrome and Opera browsers to restrict cookie setting. + * + * Note that PSL is licensed differently to HTTP_Request2 package (refer to + * the license information in public-suffix-list.php), so you can disable + * its use if this is an issue for you. + * + * @param boolean $useList use the list? + * + * @link http://publicsuffix.org/learn/ + */ public function usePublicSuffixList($useList) { $this->useList = (bool)$useList; } - /** - * Returns string representation of object - * - * @return string - * @see Serializable::serialize() - */ + /** + * Returns string representation of object + * + * @return string + * + * @see Serializable::serialize() + */ public function serialize() { $cookies = $this->getAll(); @@ -367,12 +379,13 @@ class HTTP_Request2_CookieJar implements Serializable )); } - /** - * Constructs the object from serialized string - * - * @param string string representation - * @see Serializable::unserialize() - */ + /** + * Constructs the object from serialized string + * + * @param string $serialized string representation + * + * @see Serializable::unserialize() + */ public function unserialize($serialized) { $data = unserialize($serialized); @@ -393,17 +406,18 @@ class HTTP_Request2_CookieJar implements Serializable } } - /** - * Checks whether a cookie domain matches a request host. - * - * The method is used by {@link store()} to check for whether a document - * at given URL can set a cookie with a given domain attribute and by - * {@link getMatching()} to find cookies matching the request URL. - * - * @param string request host - * @param string cookie domain - * @return bool match success - */ + /** + * Checks whether a cookie domain matches a request host. + * + * The method is used by {@link store()} to check for whether a document + * at given URL can set a cookie with a given domain attribute and by + * {@link getMatching()} to find cookies matching the request URL. + * + * @param string $requestHost request host + * @param string $cookieDomain cookie domain + * + * @return bool match success + */ public function domainMatch($requestHost, $cookieDomain) { if ($requestHost == $cookieDomain) { @@ -425,17 +439,18 @@ class HTTP_Request2_CookieJar implements Serializable return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain; } - /** - * Removes subdomains to get the registered domain (the first after top-level) - * - * The method will check Public Suffix List to find out where top-level - * domain ends and registered domain starts. It will remove domain parts - * to the left of registered one. - * - * @param string domain name - * @return string|bool registered domain, will return false if $domain is - * either invalid or a TLD itself - */ + /** + * Removes subdomains to get the registered domain (the first after top-level) + * + * The method will check Public Suffix List to find out where top-level + * domain ends and registered domain starts. It will remove domain parts + * to the left of registered one. + * + * @param string $domain domain name + * + * @return string|bool registered domain, will return false if $domain is + * either invalid or a TLD itself + */ public static function getRegisteredDomain($domain) { $domainParts = explode('.', ltrim($domain, '.')); @@ -444,8 +459,10 @@ class HTTP_Request2_CookieJar implements Serializable if (empty(self::$psl)) { $path = '@data_dir@' . DIRECTORY_SEPARATOR . 'HTTP_Request2'; if (0 === strpos($path, '@' . 'data_dir@')) { - $path = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' - . DIRECTORY_SEPARATOR . 'data'); + $path = realpath( + dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' + . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data' + ); } self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php'; } @@ -466,13 +483,14 @@ class HTTP_Request2_CookieJar implements Serializable return $result; } - /** - * Recursive helper method for {@link getRegisteredDomain()} - * - * @param array remaining domain parts - * @param mixed node in {@link HTTP_Request2_CookieJar::$psl} to check - * @return string|null concatenated domain parts, null in case of error - */ + /** + * Recursive helper method for {@link getRegisteredDomain()} + * + * @param array $domainParts remaining domain parts + * @param mixed $listNode node in {@link HTTP_Request2_CookieJar::$psl} to check + * + * @return string|null concatenated domain parts, null in case of error + */ protected static function checkDomainsList(array $domainParts, $listNode) { $sub = array_pop($domainParts); @@ -480,7 +498,7 @@ class HTTP_Request2_CookieJar implements Serializable if (!is_array($listNode) || is_null($sub) || array_key_exists('!' . $sub, $listNode) - ) { + ) { return $sub; } elseif (array_key_exists($sub, $listNode)) { diff --git a/extlib/HTTP/Request2/Exception.php b/extlib/HTTP/Request2/Exception.php index 530c23b9ce..b7b8d8d037 100644 --- a/extlib/HTTP/Request2/Exception.php +++ b/extlib/HTTP/Request2/Exception.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,12 +33,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: Exception.php 308629 2011-02-24 17:34:24Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Exception.php 324415 2012-03-21 10:50:50Z avb $ + * @link http://pear.php.net/package/HTTP_Request2 */ /** @@ -49,10 +49,13 @@ require_once 'PEAR/Exception.php'; /** * Base exception class for HTTP_Request2 package * - * @category HTTP - * @package HTTP_Request2 - * @version Release: 2.0.0RC1 - * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 2.1.1 + * @link http://pear.php.net/package/HTTP_Request2 + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132 */ class HTTP_Request2_Exception extends PEAR_Exception { @@ -76,34 +79,34 @@ class HTTP_Request2_Exception extends PEAR_Exception /** Redirect to a protocol other than http(s):// */ const NON_HTTP_REDIRECT = 50; - /** - * Native error code - * @var int - */ + /** + * Native error code + * @var int + */ private $_nativeCode; - /** - * Constructor, can set package error code and native error code - * - * @param string exception message - * @param int package error code, one of class constants - * @param int error code from underlying PHP extension - */ + /** + * Constructor, can set package error code and native error code + * + * @param string $message exception message + * @param int $code package error code, one of class constants + * @param int $nativeCode error code from underlying PHP extension + */ public function __construct($message = null, $code = null, $nativeCode = null) { parent::__construct($message, $code); $this->_nativeCode = $nativeCode; } - /** - * Returns error code produced by underlying PHP extension - * - * For Socket Adapter this may contain error number returned by - * stream_socket_client(), for Curl Adapter this will contain error number - * returned by curl_errno() - * - * @return integer - */ + /** + * Returns error code produced by underlying PHP extension + * + * For Socket Adapter this may contain error number returned by + * stream_socket_client(), for Curl Adapter this will contain error number + * returned by curl_errno() + * + * @return integer + */ public function getNativeCode() { return $this->_nativeCode; @@ -113,11 +116,16 @@ class HTTP_Request2_Exception extends PEAR_Exception /** * Exception thrown in case of missing features * - * @category HTTP - * @package HTTP_Request2 - * @version Release: 2.0.0RC1 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 @@ -129,11 +137,16 @@ class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception {} * * The exception will usually contain a package error code. * - * @category HTTP - * @package HTTP_Request2 - * @version Release: 2.0.0RC1 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 @@ -141,20 +154,30 @@ class HTTP_Request2_LogicException extends HTTP_Request2_Exception {} * The exception will not contain a package error code, but will contain * native error code, as returned by stream_socket_client() or curl_errno(). * - * @category HTTP - * @package HTTP_Request2 - * @version Release: 2.0.0RC1 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 * * The exception may contain both package error code and native error code. * - * @category HTTP - * @package HTTP_Request2 - * @version Release: 2.0.0RC1 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 +{ +} ?> \ No newline at end of file diff --git a/extlib/HTTP/Request2/MultipartBody.php b/extlib/HTTP/Request2/MultipartBody.php index a7bd948baf..53e0c1b9ea 100644 --- a/extlib/HTTP/Request2/MultipartBody.php +++ b/extlib/HTTP/Request2/MultipartBody.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,12 +33,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: MultipartBody.php 308322 2011-02-14 13:58:03Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: MultipartBody.php 324415 2012-03-21 10:50:50Z avb $ + * @link http://pear.php.net/package/HTTP_Request2 */ /** @@ -47,62 +47,66 @@ * The class helps to reduce memory consumption by streaming large file uploads * from disk, it also allows monitoring of upload progress (see request #7630) * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @version Release: 2.0.0RC1 - * @link http://tools.ietf.org/html/rfc1867 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 */ class HTTP_Request2_MultipartBody { - /** - * MIME boundary - * @var string - */ + /** + * MIME boundary + * @var string + */ private $_boundary; - /** - * Form parameters added via {@link HTTP_Request2::addPostParameter()} - * @var array - */ + /** + * Form parameters added via {@link HTTP_Request2::addPostParameter()} + * @var array + */ private $_params = array(); - /** - * File uploads added via {@link HTTP_Request2::addUpload()} - * @var array - */ + /** + * File uploads added via {@link HTTP_Request2::addUpload()} + * @var array + */ private $_uploads = array(); - /** - * Header for parts with parameters - * @var string - */ + /** + * Header for parts with parameters + * @var string + */ private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n"; - /** - * Header for parts with uploads - * @var string - */ + /** + * Header for parts with uploads + * @var string + */ private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n"; - /** - * Current position in parameter and upload arrays - * - * First number is index of "current" part, second number is position within - * "current" part - * - * @var array - */ + /** + * Current position in parameter and upload arrays + * + * First number is index of "current" part, second number is position within + * "current" part + * + * @var array + */ private $_pos = array(0, 0); - /** - * Constructor. Sets the arrays with POST data. - * - * @param array values of form fields set via {@link HTTP_Request2::addPostParameter()} - * @param array file uploads set via {@link HTTP_Request2::addUpload()} - * @param bool whether to append brackets to array variable names - */ + /** + * Constructor. Sets the arrays with POST data. + * + * @param array $params values of form fields set via + * {@link HTTP_Request2::addPostParameter()} + * @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) { $this->_params = self::_flattenArray('', $params, $useBrackets); @@ -123,11 +127,11 @@ class HTTP_Request2_MultipartBody } } - /** - * Returns the length of the body to use in Content-Length header - * - * @return integer - */ + /** + * Returns the length of the body to use in Content-Length header + * + * @return integer + */ public function getLength() { $boundaryLength = strlen($this->getBoundary()); @@ -144,11 +148,11 @@ class HTTP_Request2_MultipartBody return $length; } - /** - * Returns the boundary to use in Content-Type header - * - * @return string - */ + /** + * Returns the boundary to use in Content-Type header + * + * @return string + */ public function getBoundary() { if (empty($this->_boundary)) { @@ -157,12 +161,13 @@ class HTTP_Request2_MultipartBody return $this->_boundary; } - /** - * Returns next chunk of request body - * - * @param integer Amount of bytes to read - * @return string Up to $length bytes of data, empty string if at end - */ + /** + * Returns next chunk of request body + * + * @param integer $length Number of bytes to read + * + * @return string Up to $length bytes of data, empty string if at end + */ public function read($length) { $ret = ''; @@ -172,18 +177,18 @@ class HTTP_Request2_MultipartBody while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) { $oldLength = $length; if ($this->_pos[0] < $paramCount) { - $param = sprintf($this->_headerParam, $boundary, - $this->_params[$this->_pos[0]][0]) . - $this->_params[$this->_pos[0]][1] . "\r\n"; + $param = sprintf( + $this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0] + ) . $this->_params[$this->_pos[0]][1] . "\r\n"; $ret .= substr($param, $this->_pos[1], $length); $length -= min(strlen($param) - $this->_pos[1], $length); } elseif ($this->_pos[0] < $paramCount + $uploadCount) { $pos = $this->_pos[0] - $paramCount; - $header = sprintf($this->_headerUpload, $boundary, - $this->_uploads[$pos]['name'], - $this->_uploads[$pos]['filename'], - $this->_uploads[$pos]['type']); + $header = sprintf( + $this->_headerUpload, $boundary, $this->_uploads[$pos]['name'], + $this->_uploads[$pos]['filename'], $this->_uploads[$pos]['type'] + ); if ($this->_pos[1] < strlen($header)) { $ret .= substr($header, $this->_pos[1], $length); $length -= min(strlen($header) - $this->_pos[1], $length); @@ -214,11 +219,11 @@ class HTTP_Request2_MultipartBody return $ret; } - /** - * Sets the current position to the start of the body - * - * This allows reusing the same body in another request - */ + /** + * Sets the current position to the start of the body + * + * This allows reusing the same body in another request + */ public function rewind() { $this->_pos = array(0, 0); @@ -227,14 +232,14 @@ class HTTP_Request2_MultipartBody } } - /** - * Returns the body as string - * - * Note that it reads all file uploads into memory so it is a good idea not - * to use this method with large file uploads and rely on read() instead. - * - * @return string - */ + /** + * Returns the body as string + * + * Note that it reads all file uploads into memory so it is a good idea not + * to use this method with large file uploads and rely on read() instead. + * + * @return string + */ public function __toString() { $this->rewind(); @@ -242,15 +247,16 @@ class HTTP_Request2_MultipartBody } - /** - * Helper function to change the (probably multidimensional) associative array - * into the simple one. - * - * @param string name for item - * @param mixed item's values - * @param bool whether to append [] to array variables' names - * @return array array with the following items: array('item name', 'item value'); - */ + /** + * Helper function to change the (probably multidimensional) associative array + * into the simple one. + * + * @param string $name name for item + * @param mixed $values item's values + * @param bool $useBrackets whether to append [] to array variables' names + * + * @return array array with the following items: array('item name', 'item value'); + */ private static function _flattenArray($name, $values, $useBrackets) { if (!is_array($values)) { diff --git a/extlib/HTTP/Request2/Observer/Log.php b/extlib/HTTP/Request2/Observer/Log.php index 7865906f65..8520f61c21 100644 --- a/extlib/HTTP/Request2/Observer/Log.php +++ b/extlib/HTTP/Request2/Observer/Log.php @@ -6,7 +6,7 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,7 +38,7 @@ * @author David Jean Louis * @author Alexey Borzov * @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 */ @@ -87,7 +87,7 @@ require_once 'HTTP/Request2/Exception.php'; * @author David Jean Louis * @author Alexey Borzov * @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 */ 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'); break; case 'receivedHeaders': - $this->log(sprintf('< HTTP/%s %s %s', - $event['data']->getVersion(), - $event['data']->getStatus(), - $event['data']->getReasonPhrase())); + $this->log(sprintf( + '< HTTP/%s %s %s', $event['data']->getVersion(), + $event['data']->getStatus(), $event['data']->getReasonPhrase() + )); $headers = $event['data']->getHeader(); foreach ($headers as $key => $val) { $this->log('< ' . $key . ': ' . $val); diff --git a/extlib/HTTP/Request2/Response.php b/extlib/HTTP/Request2/Response.php index 73e9a5dc82..96682d795b 100644 --- a/extlib/HTTP/Request2/Response.php +++ b/extlib/HTTP/Request2/Response.php @@ -6,19 +6,19 @@ * * LICENSE: * - * Copyright (c) 2008-2011, Alexey Borzov + * Copyright (c) 2008-2012, Alexey Borzov * 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 + * * 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 + * * 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 + * * 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 @@ -33,12 +33,12 @@ * 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 - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version SVN: $Id: Response.php 309921 2011-04-03 16:43:02Z avb $ - * @link http://pear.php.net/package/HTTP_Request2 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Response.php 324936 2012-04-07 07:49:03Z avb $ + * @link http://pear.php.net/package/HTTP_Request2 */ /** @@ -66,84 +66,85 @@ require_once 'HTTP/Request2/Exception.php'; * var_dump($response->getHeader(), $response->getCookies(), $response->getBody()); * * - * - * @category HTTP - * @package HTTP_Request2 - * @author Alexey Borzov - * @version Release: 2.0.0RC1 - * @link http://tools.ietf.org/html/rfc2616#section-6 + * @category HTTP + * @package HTTP_Request2 + * @author Alexey Borzov + * @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 */ class HTTP_Request2_Response { - /** - * HTTP protocol version (e.g. 1.0, 1.1) - * @var string - */ + /** + * HTTP protocol version (e.g. 1.0, 1.1) + * @var string + */ protected $version; - /** - * Status code - * @var integer - * @link http://tools.ietf.org/html/rfc2616#section-6.1.1 - */ + /** + * Status code + * @var integer + * @link http://tools.ietf.org/html/rfc2616#section-6.1.1 + */ protected $code; - /** - * Reason phrase - * @var string - * @link http://tools.ietf.org/html/rfc2616#section-6.1.1 - */ + /** + * Reason phrase + * @var string + * @link http://tools.ietf.org/html/rfc2616#section-6.1.1 + */ protected $reasonPhrase; - /** - * Effective URL (may be different from original request URL in case of redirects) - * @var string - */ + /** + * Effective URL (may be different from original request URL in case of redirects) + * @var string + */ protected $effectiveUrl; - /** - * Associative array of response headers - * @var array - */ + /** + * Associative array of response headers + * @var array + */ protected $headers = array(); - /** - * Cookies set in the response - * @var array - */ + /** + * Cookies set in the response + * @var array + */ protected $cookies = array(); - /** - * Name of last header processed by parseHederLine() - * - * Used to handle the headers that span multiple lines - * - * @var string - */ + /** + * Name of last header processed by parseHederLine() + * + * Used to handle the headers that span multiple lines + * + * @var string + */ protected $lastHeader = null; - /** - * Response body - * @var string - */ + /** + * Response body + * @var string + */ protected $body = ''; - /** - * Whether the body is still encoded by Content-Encoding - * - * cURL provides the decoded body to the callback; if we are reading from - * socket the body is still gzipped / deflated - * - * @var bool - */ + /** + * Whether the body is still encoded by Content-Encoding + * + * cURL provides the decoded body to the callback; if we are reading from + * socket the body is still gzipped / deflated + * + * @var bool + */ protected $bodyEncoded; - /** - * Associative array of HTTP status code / reason phrase. - * - * @var array - * @link http://tools.ietf.org/html/rfc2616#section-10 - */ + /** + * Associative array of HTTP status code / reason phrase. + * + * @var array + * @link http://tools.ietf.org/html/rfc2616#section-10 + */ protected static $phrases = array( // 1xx: Informational - Request received, continuing process @@ -203,14 +204,34 @@ class HTTP_Request2_Response ); - /** - * Constructor, parses the response status line - * - * @param string Response status line (e.g. "HTTP/1.1 200 OK") - * @param bool Whether body is still encoded by Content-Encoding - * @param string Effective URL of the response - * @throws HTTP_Request2_MessageException if status line is invalid according to spec - */ + /** + * 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 + * + * @param string $statusLine Response status line (e.g. "HTTP/1.1 200 OK") + * @param bool $bodyEncoded Whether body is still encoded by Content-Encoding + * @param string $effectiveUrl Effective URL of the response + * + * @throws HTTP_Request2_MessageException if status line is invalid according to spec + */ public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null) { if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) { @@ -219,33 +240,29 @@ class HTTP_Request2_Response HTTP_Request2_Exception::MALFORMED_RESPONSE ); } - $this->version = $m[1]; - $this->code = intval($m[2]); - if (!empty($m[3])) { - $this->reasonPhrase = trim($m[3]); - } elseif (!empty(self::$phrases[$this->code])) { - $this->reasonPhrase = self::$phrases[$this->code]; - } + $this->version = $m[1]; + $this->code = intval($m[2]); + $this->reasonPhrase = !empty($m[3]) ? trim($m[3]) : self::getDefaultReasonPhrase($this->code); $this->bodyEncoded = (bool)$bodyEncoded; $this->effectiveUrl = (string)$effectiveUrl; } - /** - * Parses the line from HTTP response filling $headers array - * - * The method should be called after reading the line from socket or receiving - * it into cURL callback. Passing an empty string here indicates the end of - * response headers and triggers additional processing, so be sure to pass an - * empty string in the end. - * - * @param string Line from HTTP response - */ + /** + * Parses the line from HTTP response filling $headers array + * + * The method should be called after reading the line from socket or receiving + * it into cURL callback. Passing an empty string here indicates the end of + * response headers and triggers additional processing, so be sure to pass an + * empty string in the end. + * + * @param string $headerLine Line from HTTP response + */ public function parseHeaderLine($headerLine) { $headerLine = trim($headerLine, "\r\n"); - // empty string signals the end of headers, process the received ones if ('' == $headerLine) { + // empty string signals the end of headers, process the received ones if (!empty($this->headers['set-cookie'])) { $cookies = is_array($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)) { + // string of the form header-name: header value $name = strtolower($m[1]); $value = trim($m[2]); if (empty($this->headers[$name])) { @@ -275,8 +292,8 @@ class HTTP_Request2_Response } $this->lastHeader = $name; - // continuation of a previous header } elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) { + // continuation of a previous header if (!is_array($this->headers[$this->lastHeader])) { $this->headers[$this->lastHeader] .= ' ' . trim($m[1]); } else { @@ -286,12 +303,13 @@ class HTTP_Request2_Response } } - /** - * Parses a Set-Cookie header to fill $cookies array - * - * @param string value of Set-Cookie header - * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html - */ + /** + * Parses a Set-Cookie header to fill $cookies array + * + * @param string $cookieString value of Set-Cookie header + * + * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html + */ protected function parseCookie($cookieString) { $cookie = array( @@ -301,14 +319,14 @@ class HTTP_Request2_Response 'secure' => false ); - // Only a name=value pair if (!strpos($cookieString, ';')) { + // Only a name=value pair $pos = strpos($cookieString, '='); $cookie['name'] = trim(substr($cookieString, 0, $pos)); $cookie['value'] = trim(substr($cookieString, $pos + 1)); - // Some optional parameters are supplied } else { + // Some optional parameters are supplied $elements = explode(';', $cookieString); $pos = strpos($elements[0], '='); $cookie['name'] = trim(substr($elements[0], 0, $pos)); @@ -336,64 +354,69 @@ class HTTP_Request2_Response $this->cookies[] = $cookie; } - /** - * Appends a string to the response body - * @param string - */ + /** + * Appends a string to the response body + * + * @param string $bodyChunk part of response body + */ public function appendBody($bodyChunk) { $this->body .= $bodyChunk; } - /** - * Returns the effective URL of the response - * - * This may be different from the request URL if redirects were followed. - * - * @return string - * @link http://pear.php.net/bugs/bug.php?id=18412 - */ + /** + * Returns the effective URL of the response + * + * This may be different from the request URL if redirects were followed. + * + * @return string + * @link http://pear.php.net/bugs/bug.php?id=18412 + */ public function getEffectiveUrl() { return $this->effectiveUrl; } - /** - * Returns the status code - * @return integer - */ + /** + * Returns the status code + * + * @return integer + */ public function getStatus() { return $this->code; } - /** - * Returns the reason phrase - * @return string - */ + /** + * Returns the reason phrase + * + * @return string + */ public function getReasonPhrase() { return $this->reasonPhrase; } - /** - * Whether response is a redirect that can be automatically handled by HTTP_Request2 - * @return bool - */ + /** + * Whether response is a redirect that can be automatically handled by HTTP_Request2 + * + * @return bool + */ public function isRedirect() { return in_array($this->code, array(300, 301, 302, 303, 307)) && isset($this->headers['location']); } - /** - * Returns either the named header or all response headers - * - * @param string Name of header to return - * @return string|array Value of $headerName header (null if header is - * not present), array of all response headers if - * $headerName is null - */ + /** + * Returns either the named header or all response headers + * + * @param string $headerName Name of header to return + * + * @return string|array Value of $headerName header (null if header is + * not present), array of all response headers if + * $headerName is null + */ public function getHeader($headerName = null) { if (null === $headerName) { @@ -404,42 +427,42 @@ class HTTP_Request2_Response } } - /** - * Returns cookies set in response - * - * @return array - */ + /** + * Returns cookies set in response + * + * @return array + */ public function getCookies() { return $this->cookies; } - /** - * Returns the body of the response - * - * @return string - * @throws HTTP_Request2_Exception if body cannot be decoded - */ + /** + * Returns the body of the response + * + * @return string + * @throws HTTP_Request2_Exception if body cannot be decoded + */ public function getBody() { - if (0 == strlen($this->body) || !$this->bodyEncoded || - !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate')) + if (0 == strlen($this->body) || !$this->bodyEncoded + || !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate')) ) { return $this->body; } else { if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) { $oldEncoding = mb_internal_encoding(); - mb_internal_encoding('iso-8859-1'); + mb_internal_encoding('8bit'); } try { switch (strtolower($this->getHeader('content-encoding'))) { - case 'gzip': - $decoded = self::decodeGzip($this->body); - break; - case 'deflate': - $decoded = self::decodeDeflate($this->body); + case 'gzip': + $decoded = self::decodeGzip($this->body); + break; + case 'deflate': + $decoded = self::decodeDeflate($this->body); } } catch (Exception $e) { } @@ -454,29 +477,30 @@ class HTTP_Request2_Response } } - /** - * Get the HTTP version of the response - * - * @return string - */ + /** + * Get the HTTP version of the response + * + * @return string + */ public function getVersion() { return $this->version; } - /** - * Decodes the message-body encoded by gzip - * - * The real decoding work is done by gzinflate() built-in function, this - * method only parses the header and checks data for compliance with - * RFC 1952 - * - * @param string gzip-encoded data - * @return string decoded data - * @throws HTTP_Request2_LogicException - * @throws HTTP_Request2_MessageException - * @link http://tools.ietf.org/html/rfc1952 - */ + /** + * Decodes the message-body encoded by gzip + * + * The real decoding work is done by gzinflate() built-in function, this + * method only parses the header and checks data for compliance with + * RFC 1952 + * + * @param string $data gzip-encoded data + * + * @return string decoded data + * @throws HTTP_Request2_LogicException + * @throws HTTP_Request2_MessageException + * @link http://tools.ietf.org/html/rfc1952 + */ public static function decodeGzip($data) { $length = strlen($data); @@ -603,13 +627,14 @@ class HTTP_Request2_Response return $unpacked; } - /** - * Decodes the message-body encoded by deflate - * - * @param string deflate-encoded data - * @return string decoded data - * @throws HTTP_Request2_LogicException - */ + /** + * Decodes the message-body encoded by deflate + * + * @param string $data deflate-encoded data + * + * @return string decoded data + * @throws HTTP_Request2_LogicException + */ public static function decodeDeflate($data) { if (!function_exists('gzuncompress')) { diff --git a/extlib/HTTP/Request2/SOCKS5.php b/extlib/HTTP/Request2/SOCKS5.php new file mode 100644 index 0000000000..518289e9c7 --- /dev/null +++ b/extlib/HTTP/Request2/SOCKS5.php @@ -0,0 +1,158 @@ + + * 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 + * @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 + * @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'] + ); + } + } +} +?> \ No newline at end of file diff --git a/extlib/HTTP/Request2/SocketWrapper.php b/extlib/HTTP/Request2/SocketWrapper.php new file mode 100644 index 0000000000..f56af406bc --- /dev/null +++ b/extlib/HTTP/Request2/SocketWrapper.php @@ -0,0 +1,283 @@ + + * 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 + * @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 + * @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; + } +} +?> diff --git a/extlib/Net/URL.php b/extlib/Net/URL.php deleted file mode 100644 index 3dcfef60d0..0000000000 --- a/extlib/Net/URL.php +++ /dev/null @@ -1,485 +0,0 @@ - | -// +-----------------------------------------------------------------------+ -// -// $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 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 - */ - 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]; - } - -} -?> diff --git a/extlib/Net/URL2.php b/extlib/Net/URL2.php old mode 100644 new mode 100755 index f7fbcd9ce7..9989404d2a --- a/extlib/Net/URL2.php +++ b/extlib/Net/URL2.php @@ -18,9 +18,9 @@ * * 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. - * * Neither the name of the PHP_LexerGenerator nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * * Neither the name of the Net_URL2 nor the names of its contributors may + * 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, @@ -36,10 +36,10 @@ * * @category Networking * @package Net_URL2 - * @author Christian Schmidt - * @copyright 2007-2008 Peytz & Co. A/S + * @author Christian Schmidt + * @copyright 2007-2009 Peytz & Co. A/S * @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 */ @@ -48,8 +48,8 @@ * * @category Networking * @package Net_URL2 - * @author Christian Schmidt - * @copyright 2007-2008 Peytz & Co. ApS + * @author Christian Schmidt + * @copyright 2007-2009 Peytz & Co. A/S * @license http://www.opensource.org/licenses/bsd-license.php New BSD License * @version Release: @package_version@ * @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 - * is considered a separator. Default is specified by the - * arg_separator.input php.ini setting (this defaults to "&"). + * is considered a separator. Default is "&". */ const OPTION_SEPARATOR_INPUT = 'input_separator'; /** * Query variable separator used when generating the query string. Default - * is specified by the arg_separator.output php.ini setting (this defaults - * to "&"). + * is "&". */ const OPTION_SEPARATOR_OUTPUT = 'output_separator'; @@ -93,8 +91,8 @@ class Net_URL2 self::OPTION_STRICT => true, self::OPTION_USE_BRACKETS => true, self::OPTION_ENCODE_KEYS => true, - self::OPTION_SEPARATOR_INPUT => 'x&', - self::OPTION_SEPARATOR_OUTPUT => 'x&', + self::OPTION_SEPARATOR_INPUT => '&', + self::OPTION_SEPARATOR_OUTPUT => '&', ); /** @@ -113,7 +111,7 @@ class Net_URL2 private $_host = false; /** - * @var int|bool + * @var string|bool */ private $_port = false; @@ -137,41 +135,19 @@ class Net_URL2 * * @param string $url an absolute or relative URL * @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) { - $this->setOption($optionName, $value); + foreach ($options as $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->_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); - } + $this->parseUrl($url); } /** @@ -191,13 +167,13 @@ class Net_URL2 $this->$method($arg); } } - + /** * Magic Getter. * - * This is the magic get method to retrieve the private variable + * This is the magic get method to retrieve the private variable * that was set by either __set() or it's setter... - * + * * @param string $var The property name to retrieve. * @return mixed $this->$var Either a boolean false if the * property is not set or the value @@ -209,10 +185,10 @@ class Net_URL2 if (method_exists($this, $method)) { return $this->$method(); } - + return false; } - + /** * Returns the scheme, e.g. "http" or "urn", or false if there is no * scheme specified, i.e. if this is a relative URL. @@ -232,12 +208,13 @@ class Net_URL2 * scheme specified, i.e. if this is a relative * URL * - * @return void + * @return $this * @see getScheme() */ public function setScheme($scheme) { $this->_scheme = $scheme; + return $this; } /** @@ -286,7 +263,7 @@ class Net_URL2 * @param string|bool $userinfo userinfo or username * @param string|bool $password optional password, or false * - * @return void + * @return $this */ public function setUserinfo($userinfo, $password = false) { @@ -294,6 +271,7 @@ class Net_URL2 if ($password !== false) { $this->_userinfo .= ':' . $password; } + return $this; } /** @@ -313,18 +291,19 @@ class Net_URL2 * * @param string|bool $host a hostname, an IP address, or false * - * @return void + * @return $this */ public function setHost($host) { $this->_host = $host; + return $this; } /** * Returns the port number, or false if there is no port number specified, * i.e. if the default port is to be used. * - * @return int|bool + * @return string|bool */ public function getPort() { @@ -335,13 +314,14 @@ class Net_URL2 * Sets the port number. Specify false if there is no port number specified, * 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) { - $this->_port = intval($port); + $this->_port = $port; + return $this; } /** @@ -379,7 +359,7 @@ class Net_URL2 * with userinfo prefixed and port number * appended, e.g. "foo:bar@example.org:81". * - * @return void + * @return $this */ public function setAuthority($authority) { @@ -393,9 +373,10 @@ class Net_URL2 $this->_host = $reg[3]; 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 * - * @return void + * @return $this */ public function setPath($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" * - * @return void - * @see self::setQueryVariables() + * @return $this + * @see self::setQueryVariables() */ public function setQuery($query) { $this->_query = $query; + return $this; } /** @@ -462,11 +445,12 @@ class Net_URL2 * @param string|bool $fragment a fragment excluding the leading "#", or * false * - * @return void + * @return $this */ public function setFragment($fragment) { $this->_fragment = $fragment; + return $this; } /** @@ -532,33 +516,19 @@ class Net_URL2 * * @param array $array (name => value) array * - * @return void + * @return $this */ public function setQueryVariables(array $array) { if (!$array) { $this->_query = false; } else { - foreach ($array as $name => $value) { - if ($this->getOption(self::OPTION_ENCODE_KEYS)) { - $name = self::urlencode($name); - } - - 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); + $this->_query = $this->buildQuery( + $array, + $this->getOption(self::OPTION_SEPARATOR_OUTPUT) + ); } + return $this; } /** @@ -567,13 +537,14 @@ class Net_URL2 * @param string $name variable name * @param mixed $value variable value * - * @return array + * @return $this */ public function setQueryVariable($name, $value) { $array = $this->getQueryVariables(); $array[$name] = $value; $this->setQueryVariables($array); + return $this; } /** @@ -785,7 +756,7 @@ class Net_URL2 // Make sure not to be trapped in an infinite loop due to a bug in this // method - $j = 0; + $j = 0; while ($path && $j++ < 100) { if (substr($path, 0, 2) == './') { // Step 2.A @@ -832,15 +803,16 @@ class Net_URL2 public static function urlencode($string) { $encoded = rawurlencode($string); - // This is only necessary in PHP < 5.3. - $encoded = str_replace('%7E', '~', $encoded); - return $encoded; + + // This is only necessary in PHP < 5.3. + $encoded = str_replace('%7E', '~', $encoded); + return $encoded; } /** * Returns a Net_URL2 instance representing the canonical URL of the * currently executing PHP script. - * + * * @return string */ public static function getCanonical() @@ -854,7 +826,7 @@ class Net_URL2 $url = new self($_SERVER['PHP_SELF']); $url->_scheme = isset($_SERVER['HTTPS']) ? 'https' : 'http'; $url->_host = $_SERVER['SERVER_NAME']; - $port = intval($_SERVER['SERVER_PORT']); + $port = $_SERVER['SERVER_PORT']; if ($url->_scheme == 'http' && $port != 80 || $url->_scheme == 'https' && $port != 443) { @@ -894,25 +866,6 @@ class Net_URL2 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. * @@ -920,9 +873,70 @@ class Net_URL2 * * @return mixed */ - function getOption($optionName) + public function getOption($optionName) { return isset($this->_options[$optionName]) ? $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; + } } diff --git a/extlib/data/generate-list.php b/extlib/data/generate-list.php new file mode 100644 index 0000000000..839266bf99 --- /dev/null +++ b/extlib/data/generate-list.php @@ -0,0 +1,98 @@ + "); + } + + 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, ""); +fclose($fp); +?> \ No newline at end of file diff --git a/extlib/data/public-suffix-list.php b/extlib/data/public-suffix-list.php new file mode 100644 index 0000000000..77d9fd0196 --- /dev/null +++ b/extlib/data/public-suffix-list.php @@ -0,0 +1,4831 @@ +. +// Portions created by the Initial Developer are Copyright (C) 2007 +// the Initial Developer. All Rights Reserved. +// +// Contributor(s): +// Ruben Arakelyan +// Gervase Markham +// Pamela Greene +// David Triendl +// Jothan Frakes +// The kind representatives of many TLD registries +// +// Alternatively, the contents of this file may be used under the terms of +// either the GNU General Public License Version 2 or later (the "GPL"), or +// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +// in which case the provisions of the GPL or the LGPL are applicable instead +// of those above. If you wish to allow use of your version of this file only +// under the terms of either the GPL or the LGPL, and not to allow others to +// use your version of this file under the terms of the MPL, indicate your +// decision by deleting the provisions above and replace them with the notice +// and other provisions required by the GPL or the LGPL. If you do not delete +// the provisions above, a recipient may use your version of this file under +// the terms of any one of the MPL, the GPL or the LGPL. +// +// ***** END LICENSE BLOCK ***** + +return array( + 'ac' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'net' => true, + 'mil' => true, + 'org' => true + ), + 'ad' => array( + 'nom' => true + ), + 'ae' => array( + 'co' => true, + 'net' => true, + 'org' => true, + 'sch' => true, + 'ac' => true, + 'gov' => true, + 'mil' => true + ), + 'aero' => array( + 'accident-investigation' => true, + 'accident-prevention' => true, + 'aerobatic' => true, + 'aeroclub' => true, + 'aerodrome' => true, + 'agents' => true, + 'aircraft' => true, + 'airline' => true, + 'airport' => true, + 'air-surveillance' => true, + 'airtraffic' => true, + 'air-traffic-control' => true, + 'ambulance' => true, + 'amusement' => true, + 'association' => true, + 'author' => true, + 'ballooning' => true, + 'broker' => true, + 'caa' => true, + 'cargo' => true, + 'catering' => true, + 'certification' => true, + 'championship' => true, + 'charter' => true, + 'civilaviation' => true, + 'club' => true, + 'conference' => true, + 'consultant' => true, + 'consulting' => true, + 'control' => true, + 'council' => true, + 'crew' => true, + 'design' => true, + 'dgca' => true, + 'educator' => true, + 'emergency' => true, + 'engine' => true, + 'engineer' => true, + 'entertainment' => true, + 'equipment' => true, + 'exchange' => true, + 'express' => true, + 'federation' => true, + 'flight' => true, + 'freight' => true, + 'fuel' => true, + 'gliding' => true, + 'government' => true, + 'groundhandling' => true, + 'group' => true, + 'hanggliding' => true, + 'homebuilt' => true, + 'insurance' => true, + 'journal' => true, + 'journalist' => true, + 'leasing' => true, + 'logistics' => true, + 'magazine' => true, + 'maintenance' => true, + 'marketplace' => true, + 'media' => true, + 'microlight' => true, + 'modelling' => true, + 'navigation' => true, + 'parachuting' => true, + 'paragliding' => true, + 'passenger-association' => true, + 'pilot' => true, + 'press' => true, + 'production' => true, + 'recreation' => true, + 'repbody' => true, + 'res' => true, + 'research' => true, + 'rotorcraft' => true, + 'safety' => true, + 'scientist' => true, + 'services' => true, + 'show' => true, + 'skydiving' => true, + 'software' => true, + 'student' => true, + 'taxi' => true, + 'trader' => true, + 'trading' => true, + 'trainer' => true, + 'union' => true, + 'workinggroup' => true, + 'works' => true + ), + 'af' => array( + 'gov' => true, + 'com' => true, + 'org' => true, + 'net' => true, + 'edu' => true + ), + 'ag' => array( + 'com' => true, + 'org' => true, + 'net' => true, + 'co' => true, + 'nom' => true + ), + 'ai' => array( + 'off' => true, + 'com' => true, + 'net' => true, + 'org' => true + ), + 'al' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'mil' => true, + 'net' => true, + 'org' => true + ), + 'am' => true, + 'an' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'edu' => true + ), + 'ao' => array( + 'ed' => true, + 'gv' => true, + 'og' => true, + 'co' => true, + 'pb' => true, + 'it' => true + ), + 'aq' => true, + 'ar' => array( + '*' => true, + '!congresodelalengua3' => true, + '!educ' => true, + '!gobiernoelectronico' => true, + '!mecon' => true, + '!nacion' => true, + '!nic' => true, + '!promocion' => true, + '!retina' => true, + '!uba' => true + ), + 'arpa' => array( + 'e164' => true, + 'in-addr' => true, + 'ip6' => true, + 'iris' => true, + 'uri' => true, + 'urn' => true + ), + 'as' => array( + 'gov' => true + ), + 'asia' => true, + 'at' => array( + 'ac' => true, + 'co' => true, + 'gv' => true, + 'or' => true, + 'biz' => true, + 'info' => true, + 'priv' => true + ), + 'au' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'edu' => array( + 'act' => true, + 'nsw' => true, + 'nt' => true, + 'qld' => true, + 'sa' => true, + 'tas' => true, + 'vic' => true, + 'wa' => true + ), + 'gov' => array( + 'act' => true, + 'nt' => true, + 'qld' => true, + 'sa' => true, + 'tas' => true, + 'vic' => true, + 'wa' => true + ), + 'csiro' => true, + 'asn' => true, + 'id' => true, + 'info' => true, + 'conf' => true, + 'oz' => true, + 'act' => true, + 'nsw' => true, + 'nt' => true, + 'qld' => true, + 'sa' => true, + 'tas' => true, + 'vic' => true, + 'wa' => true + ), + 'aw' => array( + 'com' => true + ), + 'ax' => true, + 'az' => array( + 'com' => true, + 'net' => true, + 'int' => true, + 'gov' => true, + 'org' => true, + 'edu' => true, + 'info' => true, + 'pp' => true, + 'mil' => true, + 'name' => true, + 'pro' => true, + 'biz' => true + ), + 'ba' => array( + 'org' => true, + 'net' => true, + 'edu' => true, + 'gov' => true, + 'mil' => true, + 'unsa' => true, + 'unbi' => true, + 'co' => true, + 'com' => true, + 'rs' => true + ), + 'bb' => array( + 'biz' => true, + 'com' => true, + 'edu' => true, + 'gov' => true, + 'info' => true, + 'net' => true, + 'org' => true, + 'store' => true + ), + 'bd' => array( + '*' => true + ), + 'be' => array( + 'ac' => true + ), + 'bf' => array( + 'gov' => true + ), + 'bg' => array( + 'a' => true, + 'b' => true, + 'c' => true, + 'd' => true, + 'e' => true, + 'f' => true, + 'g' => true, + 'h' => true, + 'i' => true, + 'j' => true, + 'k' => true, + 'l' => true, + 'm' => true, + 'n' => true, + 'o' => true, + 'p' => true, + 'q' => true, + 'r' => true, + 's' => true, + 't' => true, + 'u' => true, + 'v' => true, + 'w' => true, + 'x' => true, + 'y' => true, + 'z' => true, + '0' => true, + '1' => true, + '2' => true, + '3' => true, + '4' => true, + '5' => true, + '6' => true, + '7' => true, + '8' => true, + '9' => true + ), + 'bh' => array( + 'com' => true, + 'edu' => true, + 'net' => true, + 'org' => true, + 'gov' => true + ), + 'bi' => array( + 'co' => true, + 'com' => true, + 'edu' => true, + 'or' => true, + 'org' => true + ), + 'biz' => array( + 'dyndns' => true, + 'for-better' => true, + 'for-more' => true, + 'for-some' => true, + 'for-the' => true, + 'selfip' => true, + 'webhop' => true + ), + 'bj' => array( + 'asso' => true, + 'barreau' => true, + 'gouv' => true + ), + 'bm' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'net' => true, + 'org' => true + ), + 'bn' => array( + '*' => true + ), + 'bo' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'gob' => true, + 'int' => true, + 'org' => true, + 'net' => true, + 'mil' => true, + 'tv' => true + ), + 'br' => array( + 'adm' => true, + 'adv' => true, + 'agr' => true, + 'am' => true, + 'arq' => true, + 'art' => true, + 'ato' => true, + 'b' => true, + 'bio' => true, + 'blog' => true, + 'bmd' => true, + 'can' => true, + 'cim' => true, + 'cng' => true, + 'cnt' => true, + 'com' => true, + 'coop' => true, + 'ecn' => true, + 'edu' => true, + 'emp' => true, + 'eng' => true, + 'esp' => true, + 'etc' => true, + 'eti' => true, + 'far' => true, + 'flog' => true, + 'fm' => true, + 'fnd' => true, + 'fot' => true, + 'fst' => true, + 'g12' => true, + 'ggf' => true, + 'gov' => true, + 'imb' => true, + 'ind' => true, + 'inf' => true, + 'jor' => true, + 'jus' => true, + 'lel' => true, + 'mat' => true, + 'med' => true, + 'mil' => true, + 'mus' => true, + 'net' => true, + 'nom' => true, + 'not' => true, + 'ntr' => true, + 'odo' => true, + 'org' => true, + 'ppg' => true, + 'pro' => true, + 'psc' => true, + 'psi' => true, + 'qsl' => true, + 'radio' => true, + 'rec' => true, + 'slg' => true, + 'srv' => true, + 'taxi' => true, + 'teo' => true, + 'tmp' => true, + 'trd' => true, + 'tur' => true, + 'tv' => true, + 'vet' => true, + 'vlog' => true, + 'wiki' => true, + 'zlg' => true + ), + 'bs' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'edu' => true, + 'gov' => true + ), + 'bt' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'net' => true, + 'org' => true + ), + 'bw' => array( + 'co' => true, + 'org' => true + ), + 'by' => array( + 'gov' => true, + 'mil' => true, + 'com' => true, + 'of' => true + ), + 'bz' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'edu' => true, + 'gov' => true + ), + 'ca' => array( + 'ab' => true, + 'bc' => true, + 'mb' => true, + 'nb' => true, + 'nf' => true, + 'nl' => true, + 'ns' => true, + 'nt' => true, + 'nu' => true, + 'on' => true, + 'pe' => true, + 'qc' => true, + 'sk' => true, + 'yk' => true, + 'gc' => true, + 'co' => true + ), + 'cat' => true, + 'cc' => array( + 'ftpaccess' => true, + 'game-server' => true, + 'myphotos' => true, + 'scrapping' => true + ), + 'cd' => array( + 'gov' => true + ), + 'cf' => true, + 'cg' => true, + 'ch' => true, + 'ci' => array( + 'org' => true, + 'or' => true, + 'com' => true, + 'co' => true, + 'edu' => true, + 'ed' => true, + 'ac' => true, + 'net' => true, + 'go' => true, + 'asso' => true, + 'aéroport' => true, + 'int' => true, + 'presse' => true, + 'md' => true, + 'gouv' => true + ), + 'ck' => array( + '*' => true, + '!www' => true + ), + 'cl' => array( + 'gov' => true, + 'gob' => true, + 'co' => true, + 'mil' => true + ), + 'cm' => array( + 'gov' => true + ), + 'cn' => array( + 'ac' => true, + 'com' => true, + 'edu' => true, + 'gov' => true, + 'net' => true, + 'org' => true, + 'mil' => true, + '公司' => true, + '网络' => true, + '網絡' => true, + 'ah' => true, + 'bj' => true, + 'cq' => true, + 'fj' => true, + 'gd' => true, + 'gs' => true, + 'gz' => true, + 'gx' => true, + 'ha' => true, + 'hb' => true, + 'he' => true, + 'hi' => true, + 'hl' => true, + 'hn' => true, + 'jl' => true, + 'js' => true, + 'jx' => true, + 'ln' => true, + 'nm' => true, + 'nx' => true, + 'qh' => true, + 'sc' => true, + 'sd' => true, + 'sh' => true, + 'sn' => true, + 'sx' => true, + 'tj' => true, + 'xj' => true, + 'xz' => true, + 'yn' => true, + 'zj' => true, + 'hk' => true, + 'mo' => true, + 'tw' => true + ), + 'co' => array( + 'arts' => true, + 'com' => true, + 'edu' => true, + 'firm' => true, + 'gov' => true, + 'info' => true, + 'int' => true, + 'mil' => true, + 'net' => true, + 'nom' => true, + 'org' => true, + 'rec' => true, + 'web' => true + ), + 'com' => array( + 'ar' => true, + 'br' => true, + 'cn' => true, + 'de' => true, + 'eu' => true, + 'gb' => true, + 'gr' => true, + 'hu' => true, + 'jpn' => true, + 'kr' => true, + 'no' => true, + 'qc' => true, + 'ru' => true, + 'sa' => true, + 'se' => true, + 'uk' => true, + 'us' => true, + 'uy' => true, + 'za' => true, + 'operaunite' => true, + 'appspot' => true, + 'dyndns-at-home' => true, + 'dyndns-at-work' => true, + 'dyndns-blog' => true, + 'dyndns-free' => true, + 'dyndns-home' => true, + 'dyndns-ip' => true, + 'dyndns-mail' => true, + 'dyndns-office' => true, + 'dyndns-pics' => true, + 'dyndns-remote' => true, + 'dyndns-server' => true, + 'dyndns-web' => true, + 'dyndns-wiki' => true, + 'dyndns-work' => true, + 'blogdns' => true, + 'cechire' => true, + 'dnsalias' => true, + 'dnsdojo' => true, + 'doesntexist' => true, + 'dontexist' => true, + 'doomdns' => true, + 'dyn-o-saur' => true, + 'dynalias' => true, + 'est-a-la-maison' => true, + 'est-a-la-masion' => true, + 'est-le-patron' => true, + 'est-mon-blogueur' => true, + 'from-ak' => true, + 'from-al' => true, + 'from-ar' => true, + 'from-ca' => true, + 'from-ct' => true, + 'from-dc' => true, + 'from-de' => true, + 'from-fl' => true, + 'from-ga' => true, + 'from-hi' => true, + 'from-ia' => true, + 'from-id' => true, + 'from-il' => true, + 'from-in' => true, + 'from-ks' => true, + 'from-ky' => true, + 'from-ma' => true, + 'from-md' => true, + 'from-mi' => true, + 'from-mn' => true, + 'from-mo' => true, + 'from-ms' => true, + 'from-mt' => true, + 'from-nc' => true, + 'from-nd' => true, + 'from-ne' => true, + 'from-nh' => true, + 'from-nj' => true, + 'from-nm' => true, + 'from-nv' => true, + 'from-oh' => true, + 'from-ok' => true, + 'from-or' => true, + 'from-pa' => true, + 'from-pr' => true, + 'from-ri' => true, + 'from-sc' => true, + 'from-sd' => true, + 'from-tn' => true, + 'from-tx' => true, + 'from-ut' => true, + 'from-va' => true, + 'from-vt' => true, + 'from-wa' => true, + 'from-wi' => true, + 'from-wv' => true, + 'from-wy' => true, + 'getmyip' => true, + 'gotdns' => true, + 'hobby-site' => true, + 'homelinux' => true, + 'homeunix' => true, + 'iamallama' => true, + 'is-a-anarchist' => true, + 'is-a-blogger' => true, + 'is-a-bookkeeper' => true, + 'is-a-bulls-fan' => true, + 'is-a-caterer' => true, + 'is-a-chef' => true, + 'is-a-conservative' => true, + 'is-a-cpa' => true, + 'is-a-cubicle-slave' => true, + 'is-a-democrat' => true, + 'is-a-designer' => true, + 'is-a-doctor' => true, + 'is-a-financialadvisor' => true, + 'is-a-geek' => true, + 'is-a-green' => true, + 'is-a-guru' => true, + 'is-a-hard-worker' => true, + 'is-a-hunter' => true, + 'is-a-landscaper' => true, + 'is-a-lawyer' => true, + 'is-a-liberal' => true, + 'is-a-libertarian' => true, + 'is-a-llama' => true, + 'is-a-musician' => true, + 'is-a-nascarfan' => true, + 'is-a-nurse' => true, + 'is-a-painter' => true, + 'is-a-personaltrainer' => true, + 'is-a-photographer' => true, + 'is-a-player' => true, + 'is-a-republican' => true, + 'is-a-rockstar' => true, + 'is-a-socialist' => true, + 'is-a-student' => true, + 'is-a-teacher' => true, + 'is-a-techie' => true, + 'is-a-therapist' => true, + 'is-an-accountant' => true, + 'is-an-actor' => true, + 'is-an-actress' => true, + 'is-an-anarchist' => true, + 'is-an-artist' => true, + 'is-an-engineer' => true, + 'is-an-entertainer' => true, + 'is-certified' => true, + 'is-gone' => true, + 'is-into-anime' => true, + 'is-into-cars' => true, + 'is-into-cartoons' => true, + 'is-into-games' => true, + 'is-leet' => true, + 'is-not-certified' => true, + 'is-slick' => true, + 'is-uberleet' => true, + 'is-with-theband' => true, + 'isa-geek' => true, + 'isa-hockeynut' => true, + 'issmarterthanyou' => true, + 'likes-pie' => true, + 'likescandy' => true, + 'neat-url' => true, + 'saves-the-whales' => true, + 'selfip' => true, + 'sells-for-less' => true, + 'sells-for-u' => true, + 'servebbs' => true, + 'simple-url' => true, + 'space-to-rent' => true, + 'teaches-yoga' => true, + 'writesthisblog' => true + ), + 'coop' => true, + 'cr' => array( + 'ac' => true, + 'co' => true, + 'ed' => true, + 'fi' => true, + 'go' => true, + 'or' => true, + 'sa' => true + ), + 'cu' => array( + 'com' => true, + 'edu' => true, + 'org' => true, + 'net' => true, + 'gov' => true, + 'inf' => true + ), + 'cv' => true, + 'cx' => array( + 'gov' => true, + 'ath' => true + ), + 'cy' => array( + '*' => true + ), + 'cz' => true, + 'de' => array( + 'com' => true, + 'fuettertdasnetz' => true, + 'isteingeek' => true, + 'istmein' => true, + 'lebtimnetz' => true, + 'leitungsen' => true, + 'traeumtgerade' => true + ), + 'dj' => true, + 'dk' => true, + 'dm' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'edu' => true, + 'gov' => true + ), + 'do' => array( + 'art' => true, + 'com' => true, + 'edu' => true, + 'gob' => true, + 'gov' => true, + 'mil' => true, + 'net' => true, + 'org' => true, + 'sld' => true, + 'web' => true + ), + 'dz' => array( + 'com' => true, + 'org' => true, + 'net' => true, + 'gov' => true, + 'edu' => true, + 'asso' => true, + 'pol' => true, + 'art' => true + ), + 'ec' => array( + 'com' => true, + 'info' => true, + 'net' => true, + 'fin' => true, + 'k12' => true, + 'med' => true, + 'pro' => true, + 'org' => true, + 'edu' => true, + 'gov' => true, + 'gob' => true, + 'mil' => true + ), + 'edu' => true, + 'ee' => array( + 'edu' => true, + 'gov' => true, + 'riik' => true, + 'lib' => true, + 'med' => true, + 'com' => true, + 'pri' => true, + 'aip' => true, + 'org' => true, + 'fie' => true + ), + 'eg' => array( + 'com' => true, + 'edu' => true, + 'eun' => true, + 'gov' => true, + 'mil' => true, + 'name' => true, + 'net' => true, + 'org' => true, + 'sci' => true + ), + 'er' => array( + '*' => true + ), + 'es' => array( + 'com' => true, + 'nom' => true, + 'org' => true, + 'gob' => true, + 'edu' => true + ), + 'et' => array( + '*' => true + ), + 'eu' => true, + 'fi' => array( + 'aland' => true, + 'iki' => true + ), + 'fj' => array( + '*' => true + ), + 'fk' => array( + '*' => true + ), + 'fm' => true, + 'fo' => true, + 'fr' => array( + 'com' => true, + 'asso' => true, + 'nom' => true, + 'prd' => true, + 'presse' => true, + 'tm' => true, + 'aeroport' => true, + 'assedic' => true, + 'avocat' => true, + 'avoues' => true, + 'cci' => true, + 'chambagri' => true, + 'chirurgiens-dentistes' => true, + 'experts-comptables' => true, + 'geometre-expert' => true, + 'gouv' => true, + 'greta' => true, + 'huissier-justice' => true, + 'medecin' => true, + 'notaires' => true, + 'pharmacien' => true, + 'port' => true, + 'veterinaire' => true + ), + 'ga' => true, + 'gd' => true, + 'ge' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'org' => true, + 'mil' => true, + 'net' => true, + 'pvt' => true + ), + 'gf' => true, + 'gg' => array( + 'co' => true, + 'org' => true, + 'net' => true, + 'sch' => true, + 'gov' => true + ), + 'gh' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'org' => true, + 'mil' => true + ), + 'gi' => array( + 'com' => true, + 'ltd' => true, + 'gov' => true, + 'mod' => true, + 'edu' => true, + 'org' => true + ), + 'gl' => true, + 'gm' => true, + 'gn' => array( + 'ac' => true, + 'com' => true, + 'edu' => true, + 'gov' => true, + 'org' => true, + 'net' => true + ), + 'gov' => true, + 'gp' => array( + 'com' => true, + 'net' => true, + 'mobi' => true, + 'edu' => true, + 'org' => true, + 'asso' => true + ), + 'gq' => true, + 'gr' => array( + 'com' => true, + 'edu' => true, + 'net' => true, + 'org' => true, + 'gov' => true + ), + 'gs' => true, + 'gt' => array( + '*' => true, + '!www' => true + ), + 'gu' => array( + '*' => true + ), + 'gw' => true, + 'gy' => array( + 'co' => true, + 'com' => true, + 'net' => true + ), + 'hk' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'idv' => true, + 'net' => true, + 'org' => true, + '公司' => true, + '教育' => true, + '敎育' => true, + '政府' => true, + '個人' => true, + '个人' => true, + '箇人' => true, + '網络' => true, + '网络' => true, + '组織' => true, + '網絡' => true, + '网絡' => true, + '组织' => true, + '組織' => true, + '組织' => true + ), + 'hm' => true, + 'hn' => array( + 'com' => true, + 'edu' => true, + 'org' => true, + 'net' => true, + 'mil' => true, + 'gob' => true + ), + 'hr' => array( + 'iz' => true, + 'from' => true, + 'name' => true, + 'com' => true + ), + 'ht' => array( + 'com' => true, + 'shop' => true, + 'firm' => true, + 'info' => true, + 'adult' => true, + 'net' => true, + 'pro' => true, + 'org' => true, + 'med' => true, + 'art' => true, + 'coop' => true, + 'pol' => true, + 'asso' => true, + 'edu' => true, + 'rel' => true, + 'gouv' => true, + 'perso' => true + ), + 'hu' => array( + 'co' => true, + 'info' => true, + 'org' => true, + 'priv' => true, + 'sport' => true, + 'tm' => true, + '2000' => true, + 'agrar' => true, + 'bolt' => true, + 'casino' => true, + 'city' => true, + 'erotica' => true, + 'erotika' => true, + 'film' => true, + 'forum' => true, + 'games' => true, + 'hotel' => true, + 'ingatlan' => true, + 'jogasz' => true, + 'konyvelo' => true, + 'lakas' => true, + 'media' => true, + 'news' => true, + 'reklam' => true, + 'sex' => true, + 'shop' => true, + 'suli' => true, + 'szex' => true, + 'tozsde' => true, + 'utazas' => true, + 'video' => true + ), + 'id' => array( + 'ac' => true, + 'co' => true, + 'go' => true, + 'mil' => true, + 'net' => true, + 'or' => true, + 'sch' => true, + 'web' => true + ), + 'ie' => array( + 'gov' => true + ), + 'il' => array( + '*' => true + ), + 'im' => array( + 'co' => array( + 'ltd' => true, + 'plc' => true + ), + 'net' => true, + 'gov' => true, + 'org' => true, + 'nic' => true, + 'ac' => true + ), + 'in' => array( + 'co' => true, + 'firm' => true, + 'net' => true, + 'org' => true, + 'gen' => true, + 'ind' => true, + 'nic' => true, + 'ac' => true, + 'edu' => true, + 'res' => true, + 'gov' => true, + 'mil' => true + ), + 'info' => array( + 'dyndns' => true, + 'barrel-of-knowledge' => true, + 'barrell-of-knowledge' => true, + 'for-our' => true, + 'groks-the' => true, + 'groks-this' => true, + 'here-for-more' => true, + 'knowsitall' => true, + 'selfip' => true, + 'webhop' => true + ), + 'int' => array( + 'eu' => true + ), + 'io' => array( + 'com' => true + ), + 'iq' => array( + 'gov' => true, + 'edu' => true, + 'mil' => true, + 'com' => true, + 'org' => true, + 'net' => true + ), + 'ir' => array( + 'ac' => true, + 'co' => true, + 'gov' => true, + 'id' => true, + 'net' => true, + 'org' => true, + 'sch' => true, + 'ایران' => true, + 'ايران' => true + ), + 'is' => array( + 'net' => true, + 'com' => true, + 'edu' => true, + 'gov' => true, + 'org' => true, + 'int' => true + ), + 'it' => array( + 'gov' => true, + 'edu' => true, + 'agrigento' => true, + 'ag' => true, + 'alessandria' => true, + 'al' => true, + 'ancona' => true, + 'an' => true, + 'aosta' => true, + 'aoste' => true, + 'ao' => true, + 'arezzo' => true, + 'ar' => true, + 'ascoli-piceno' => true, + 'ascolipiceno' => true, + 'ap' => true, + 'asti' => true, + 'at' => true, + 'avellino' => true, + 'av' => true, + 'bari' => true, + 'ba' => true, + 'andria-barletta-trani' => true, + 'andriabarlettatrani' => true, + 'trani-barletta-andria' => true, + 'tranibarlettaandria' => true, + 'barletta-trani-andria' => true, + 'barlettatraniandria' => true, + 'andria-trani-barletta' => true, + 'andriatranibarletta' => true, + 'trani-andria-barletta' => true, + 'traniandriabarletta' => true, + 'bt' => true, + 'belluno' => true, + 'bl' => true, + 'benevento' => true, + 'bn' => true, + 'bergamo' => true, + 'bg' => true, + 'biella' => true, + 'bi' => true, + 'bologna' => true, + 'bo' => true, + 'bolzano' => true, + 'bozen' => true, + 'balsan' => true, + 'alto-adige' => true, + 'altoadige' => true, + 'suedtirol' => true, + 'bz' => true, + 'brescia' => true, + 'bs' => true, + 'brindisi' => true, + 'br' => true, + 'cagliari' => true, + 'ca' => true, + 'caltanissetta' => true, + 'cl' => true, + 'campobasso' => true, + 'cb' => true, + 'carboniaiglesias' => true, + 'carbonia-iglesias' => true, + 'iglesias-carbonia' => true, + 'iglesiascarbonia' => true, + 'ci' => true, + 'caserta' => true, + 'ce' => true, + 'catania' => true, + 'ct' => true, + 'catanzaro' => true, + 'cz' => true, + 'chieti' => true, + 'ch' => true, + 'como' => true, + 'co' => true, + 'cosenza' => true, + 'cs' => true, + 'cremona' => true, + 'cr' => true, + 'crotone' => true, + 'kr' => true, + 'cuneo' => true, + 'cn' => true, + 'dell-ogliastra' => true, + 'dellogliastra' => true, + 'ogliastra' => true, + 'og' => true, + 'enna' => true, + 'en' => true, + 'ferrara' => true, + 'fe' => true, + 'fermo' => true, + 'fm' => true, + 'firenze' => true, + 'florence' => true, + 'fi' => true, + 'foggia' => true, + 'fg' => true, + 'forli-cesena' => true, + 'forlicesena' => true, + 'cesena-forli' => true, + 'cesenaforli' => true, + 'fc' => true, + 'frosinone' => true, + 'fr' => true, + 'genova' => true, + 'genoa' => true, + 'ge' => true, + 'gorizia' => true, + 'go' => true, + 'grosseto' => true, + 'gr' => true, + 'imperia' => true, + 'im' => true, + 'isernia' => true, + 'is' => true, + 'laquila' => true, + 'aquila' => true, + 'aq' => true, + 'la-spezia' => true, + 'laspezia' => true, + 'sp' => true, + 'latina' => true, + 'lt' => true, + 'lecce' => true, + 'le' => true, + 'lecco' => true, + 'lc' => true, + 'livorno' => true, + 'li' => true, + 'lodi' => true, + 'lo' => true, + 'lucca' => true, + 'lu' => true, + 'macerata' => true, + 'mc' => true, + 'mantova' => true, + 'mn' => true, + 'massa-carrara' => true, + 'massacarrara' => true, + 'carrara-massa' => true, + 'carraramassa' => true, + 'ms' => true, + 'matera' => true, + 'mt' => true, + 'medio-campidano' => true, + 'mediocampidano' => true, + 'campidano-medio' => true, + 'campidanomedio' => true, + 'vs' => true, + 'messina' => true, + 'me' => true, + 'milano' => true, + 'milan' => true, + 'mi' => true, + 'modena' => true, + 'mo' => true, + 'monza' => true, + 'monza-brianza' => true, + 'monzabrianza' => true, + 'monzaebrianza' => true, + 'monzaedellabrianza' => true, + 'monza-e-della-brianza' => true, + 'mb' => true, + 'napoli' => true, + 'naples' => true, + 'na' => true, + 'novara' => true, + 'no' => true, + 'nuoro' => true, + 'nu' => true, + 'oristano' => true, + 'or' => true, + 'padova' => true, + 'padua' => true, + 'pd' => true, + 'palermo' => true, + 'pa' => true, + 'parma' => true, + 'pr' => true, + 'pavia' => true, + 'pv' => true, + 'perugia' => true, + 'pg' => true, + 'pescara' => true, + 'pe' => true, + 'pesaro-urbino' => true, + 'pesarourbino' => true, + 'urbino-pesaro' => true, + 'urbinopesaro' => true, + 'pu' => true, + 'piacenza' => true, + 'pc' => true, + 'pisa' => true, + 'pi' => true, + 'pistoia' => true, + 'pt' => true, + 'pordenone' => true, + 'pn' => true, + 'potenza' => true, + 'pz' => true, + 'prato' => true, + 'po' => true, + 'ragusa' => true, + 'rg' => true, + 'ravenna' => true, + 'ra' => true, + 'reggio-calabria' => true, + 'reggiocalabria' => true, + 'rc' => true, + 'reggio-emilia' => true, + 'reggioemilia' => true, + 're' => true, + 'rieti' => true, + 'ri' => true, + 'rimini' => true, + 'rn' => true, + 'roma' => true, + 'rome' => true, + 'rm' => true, + 'rovigo' => true, + 'ro' => true, + 'salerno' => true, + 'sa' => true, + 'sassari' => true, + 'ss' => true, + 'savona' => true, + 'sv' => true, + 'siena' => true, + 'si' => true, + 'siracusa' => true, + 'sr' => true, + 'sondrio' => true, + 'so' => true, + 'taranto' => true, + 'ta' => true, + 'tempio-olbia' => true, + 'tempioolbia' => true, + 'olbia-tempio' => true, + 'olbiatempio' => true, + 'ot' => true, + 'teramo' => true, + 'te' => true, + 'terni' => true, + 'tr' => true, + 'torino' => true, + 'turin' => true, + 'to' => true, + 'trapani' => true, + 'tp' => true, + 'trento' => true, + 'trentino' => true, + 'tn' => true, + 'treviso' => true, + 'tv' => true, + 'trieste' => true, + 'ts' => true, + 'udine' => true, + 'ud' => true, + 'varese' => true, + 'va' => true, + 'venezia' => true, + 'venice' => true, + 've' => true, + 'verbania' => true, + 'vb' => true, + 'vercelli' => true, + 'vc' => true, + 'verona' => true, + 'vr' => true, + 'vibo-valentia' => true, + 'vibovalentia' => true, + 'vv' => true, + 'vicenza' => true, + 'vi' => true, + 'viterbo' => true, + 'vt' => true + ), + 'je' => array( + 'co' => true, + 'org' => true, + 'net' => true, + 'sch' => true, + 'gov' => true + ), + 'jm' => array( + '*' => true + ), + 'jo' => array( + 'com' => true, + 'org' => true, + 'net' => true, + 'edu' => true, + 'sch' => true, + 'gov' => true, + 'mil' => true, + 'name' => true + ), + 'jobs' => true, + 'jp' => array( + 'ac' => true, + 'ad' => true, + 'co' => true, + 'ed' => true, + 'go' => true, + 'gr' => true, + 'lg' => true, + 'ne' => true, + 'or' => true, + 'aichi' => array( + '*' => true, + '!pref' => true + ), + 'akita' => array( + '*' => true, + '!pref' => true + ), + 'aomori' => array( + '*' => true, + '!pref' => true + ), + 'chiba' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'ehime' => array( + '*' => true, + '!pref' => true + ), + 'fukui' => array( + '*' => true, + '!pref' => true + ), + 'fukuoka' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'fukushima' => array( + '*' => true, + '!pref' => true + ), + 'gifu' => array( + '*' => true, + '!pref' => true + ), + 'gunma' => array( + '*' => true, + '!pref' => true + ), + 'hiroshima' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'hokkaido' => array( + '*' => true, + '!pref' => true + ), + 'hyogo' => array( + '*' => true, + '!pref' => true + ), + 'ibaraki' => array( + '*' => true, + '!pref' => true + ), + 'ishikawa' => array( + '*' => true, + '!pref' => true + ), + 'iwate' => array( + '*' => true, + '!pref' => true + ), + 'kagawa' => array( + '*' => true, + '!pref' => true + ), + 'kagoshima' => array( + '*' => true, + '!pref' => true + ), + 'kanagawa' => array( + '*' => true, + '!pref' => true + ), + 'kawasaki' => array( + '*' => true, + '!city' => true + ), + 'kitakyushu' => array( + '*' => true, + '!city' => true + ), + 'kobe' => array( + '*' => true, + '!city' => true + ), + 'kochi' => array( + '*' => true, + '!pref' => true + ), + 'kumamoto' => array( + '*' => true, + '!pref' => true + ), + 'kyoto' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'mie' => array( + '*' => true, + '!pref' => true + ), + 'miyagi' => array( + '*' => true, + '!pref' => true + ), + 'miyazaki' => array( + '*' => true, + '!pref' => true + ), + 'nagano' => array( + '*' => true, + '!pref' => true + ), + 'nagasaki' => array( + '*' => true, + '!pref' => true + ), + 'nagoya' => array( + '*' => true, + '!city' => true + ), + 'nara' => array( + '*' => true, + '!pref' => true + ), + 'niigata' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'oita' => array( + '*' => true, + '!pref' => true + ), + 'okayama' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'okinawa' => array( + '*' => true, + '!pref' => true + ), + 'osaka' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'saga' => array( + '*' => true, + '!pref' => true + ), + 'saitama' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'sapporo' => array( + '*' => true, + '!city' => true + ), + 'sendai' => array( + '*' => true, + '!city' => true + ), + 'shiga' => array( + '*' => true, + '!pref' => true + ), + 'shimane' => array( + '*' => true, + '!pref' => true + ), + 'shizuoka' => array( + '*' => true, + '!pref' => true, + '!city' => true + ), + 'tochigi' => array( + '*' => true, + '!pref' => true + ), + 'tokushima' => array( + '*' => true, + '!pref' => true + ), + 'tokyo' => array( + '*' => true, + '!metro' => true + ), + 'tottori' => array( + '*' => true, + '!pref' => true + ), + 'toyama' => array( + '*' => true, + '!pref' => true + ), + 'wakayama' => array( + '*' => true, + '!pref' => true + ), + 'yamagata' => array( + '*' => true, + '!pref' => true + ), + 'yamaguchi' => array( + '*' => true, + '!pref' => true + ), + 'yamanashi' => array( + '*' => true, + '!pref' => true + ), + 'yokohama' => array( + '*' => true, + '!city' => true + ) + ), + 'ke' => array( + '*' => true + ), + 'kg' => array( + 'org' => true, + 'net' => true, + 'com' => true, + 'edu' => true, + 'gov' => true, + 'mil' => true + ), + 'kh' => array( + '*' => true + ), + 'ki' => array( + 'edu' => true, + 'biz' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'info' => true, + 'com' => true + ), + 'km' => array( + 'org' => true, + 'nom' => true, + 'gov' => true, + 'prd' => true, + 'tm' => true, + 'edu' => true, + 'mil' => true, + 'ass' => true, + 'com' => true, + 'coop' => true, + 'asso' => true, + 'presse' => true, + 'medecin' => true, + 'notaires' => true, + 'pharmaciens' => true, + 'veterinaire' => true, + 'gouv' => true + ), + 'kn' => array( + 'net' => true, + 'org' => true, + 'edu' => true, + 'gov' => true + ), + 'kp' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'org' => true, + 'rep' => true, + 'tra' => true + ), + 'kr' => array( + 'ac' => true, + 'co' => true, + 'es' => true, + 'go' => true, + 'hs' => true, + 'kg' => true, + 'mil' => true, + 'ms' => true, + 'ne' => true, + 'or' => true, + 'pe' => true, + 're' => true, + 'sc' => true, + 'busan' => true, + 'chungbuk' => true, + 'chungnam' => true, + 'daegu' => true, + 'daejeon' => true, + 'gangwon' => true, + 'gwangju' => true, + 'gyeongbuk' => true, + 'gyeonggi' => true, + 'gyeongnam' => true, + 'incheon' => true, + 'jeju' => true, + 'jeonbuk' => true, + 'jeonnam' => true, + 'seoul' => true, + 'ulsan' => true + ), + 'kw' => array( + '*' => true + ), + 'ky' => array( + 'edu' => true, + 'gov' => true, + 'com' => true, + 'org' => true, + 'net' => true + ), + 'kz' => array( + 'org' => true, + 'edu' => true, + 'net' => true, + 'gov' => true, + 'mil' => true, + 'com' => true + ), + 'la' => array( + 'int' => true, + 'net' => true, + 'info' => true, + 'edu' => true, + 'gov' => true, + 'per' => true, + 'com' => true, + 'org' => true, + 'c' => true + ), + 'lb' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'net' => true, + 'org' => true + ), + 'lc' => array( + 'com' => true, + 'net' => true, + 'co' => true, + 'org' => true, + 'edu' => true, + 'gov' => true + ), + 'li' => true, + 'lk' => array( + 'gov' => true, + 'sch' => true, + 'net' => true, + 'int' => true, + 'com' => true, + 'org' => true, + 'edu' => true, + 'ngo' => true, + 'soc' => true, + 'web' => true, + 'ltd' => true, + 'assn' => true, + 'grp' => true, + 'hotel' => true + ), + 'lr' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'org' => true, + 'net' => true + ), + 'ls' => array( + 'co' => true, + 'org' => true + ), + 'lt' => array( + 'gov' => true + ), + 'lu' => true, + 'lv' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'org' => true, + 'mil' => true, + 'id' => true, + 'net' => true, + 'asn' => true, + 'conf' => true + ), + 'ly' => array( + 'com' => true, + 'net' => true, + 'gov' => true, + 'plc' => true, + 'edu' => true, + 'sch' => true, + 'med' => true, + 'org' => true, + 'id' => true + ), + 'ma' => array( + 'co' => true, + 'net' => true, + 'gov' => true, + 'org' => true, + 'ac' => true, + 'press' => true + ), + 'mc' => array( + 'tm' => true, + 'asso' => true + ), + 'md' => true, + 'me' => array( + 'co' => true, + 'net' => true, + 'org' => true, + 'edu' => true, + 'ac' => true, + 'gov' => true, + 'its' => true, + 'priv' => true + ), + 'mg' => array( + 'org' => true, + 'nom' => true, + 'gov' => true, + 'prd' => true, + 'tm' => true, + 'edu' => true, + 'mil' => true, + 'com' => true + ), + 'mh' => true, + 'mil' => true, + 'mk' => array( + 'com' => true, + 'org' => true, + 'net' => true, + 'edu' => true, + 'gov' => true, + 'inf' => true, + 'name' => true + ), + 'ml' => array( + 'com' => true, + 'edu' => true, + 'gouv' => true, + 'gov' => true, + 'net' => true, + 'org' => true, + 'presse' => true + ), + 'mm' => array( + '*' => true + ), + 'mn' => array( + 'gov' => true, + 'edu' => true, + 'org' => true + ), + 'mo' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'edu' => true, + 'gov' => true + ), + 'mobi' => true, + 'mp' => true, + 'mq' => true, + 'mr' => array( + 'gov' => true + ), + 'ms' => true, + 'mt' => array( + '*' => true + ), + 'mu' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'ac' => true, + 'co' => true, + 'or' => true + ), + 'museum' => array( + 'academy' => true, + 'agriculture' => true, + 'air' => true, + 'airguard' => true, + 'alabama' => true, + 'alaska' => true, + 'amber' => true, + 'ambulance' => true, + 'american' => true, + 'americana' => true, + 'americanantiques' => true, + 'americanart' => true, + 'amsterdam' => true, + 'and' => true, + 'annefrank' => true, + 'anthro' => true, + 'anthropology' => true, + 'antiques' => true, + 'aquarium' => true, + 'arboretum' => true, + 'archaeological' => true, + 'archaeology' => true, + 'architecture' => true, + 'art' => true, + 'artanddesign' => true, + 'artcenter' => true, + 'artdeco' => true, + 'arteducation' => true, + 'artgallery' => true, + 'arts' => true, + 'artsandcrafts' => true, + 'asmatart' => true, + 'assassination' => true, + 'assisi' => true, + 'association' => true, + 'astronomy' => true, + 'atlanta' => true, + 'austin' => true, + 'australia' => true, + 'automotive' => true, + 'aviation' => true, + 'axis' => true, + 'badajoz' => true, + 'baghdad' => true, + 'bahn' => true, + 'bale' => true, + 'baltimore' => true, + 'barcelona' => true, + 'baseball' => true, + 'basel' => true, + 'baths' => true, + 'bauern' => true, + 'beauxarts' => true, + 'beeldengeluid' => true, + 'bellevue' => true, + 'bergbau' => true, + 'berkeley' => true, + 'berlin' => true, + 'bern' => true, + 'bible' => true, + 'bilbao' => true, + 'bill' => true, + 'birdart' => true, + 'birthplace' => true, + 'bonn' => true, + 'boston' => true, + 'botanical' => true, + 'botanicalgarden' => true, + 'botanicgarden' => true, + 'botany' => true, + 'brandywinevalley' => true, + 'brasil' => true, + 'bristol' => true, + 'british' => true, + 'britishcolumbia' => true, + 'broadcast' => true, + 'brunel' => true, + 'brussel' => true, + 'brussels' => true, + 'bruxelles' => true, + 'building' => true, + 'burghof' => true, + 'bus' => true, + 'bushey' => true, + 'cadaques' => true, + 'california' => true, + 'cambridge' => true, + 'can' => true, + 'canada' => true, + 'capebreton' => true, + 'carrier' => true, + 'cartoonart' => true, + 'casadelamoneda' => true, + 'castle' => true, + 'castres' => true, + 'celtic' => true, + 'center' => true, + 'chattanooga' => true, + 'cheltenham' => true, + 'chesapeakebay' => true, + 'chicago' => true, + 'children' => true, + 'childrens' => true, + 'childrensgarden' => true, + 'chiropractic' => true, + 'chocolate' => true, + 'christiansburg' => true, + 'cincinnati' => true, + 'cinema' => true, + 'circus' => true, + 'civilisation' => true, + 'civilization' => true, + 'civilwar' => true, + 'clinton' => true, + 'clock' => true, + 'coal' => true, + 'coastaldefence' => true, + 'cody' => true, + 'coldwar' => true, + 'collection' => true, + 'colonialwilliamsburg' => true, + 'coloradoplateau' => true, + 'columbia' => true, + 'columbus' => true, + 'communication' => true, + 'communications' => true, + 'community' => true, + 'computer' => true, + 'computerhistory' => true, + 'comunicações' => true, + 'contemporary' => true, + 'contemporaryart' => true, + 'convent' => true, + 'copenhagen' => true, + 'corporation' => true, + 'correios-e-telecomunicações' => true, + 'corvette' => true, + 'costume' => true, + 'countryestate' => true, + 'county' => true, + 'crafts' => true, + 'cranbrook' => true, + 'creation' => true, + 'cultural' => true, + 'culturalcenter' => true, + 'culture' => true, + 'cyber' => true, + 'cymru' => true, + 'dali' => true, + 'dallas' => true, + 'database' => true, + 'ddr' => true, + 'decorativearts' => true, + 'delaware' => true, + 'delmenhorst' => true, + 'denmark' => true, + 'depot' => true, + 'design' => true, + 'detroit' => true, + 'dinosaur' => true, + 'discovery' => true, + 'dolls' => true, + 'donostia' => true, + 'durham' => true, + 'eastafrica' => true, + 'eastcoast' => true, + 'education' => true, + 'educational' => true, + 'egyptian' => true, + 'eisenbahn' => true, + 'elburg' => true, + 'elvendrell' => true, + 'embroidery' => true, + 'encyclopedic' => true, + 'england' => true, + 'entomology' => true, + 'environment' => true, + 'environmentalconservation' => true, + 'epilepsy' => true, + 'essex' => true, + 'estate' => true, + 'ethnology' => true, + 'exeter' => true, + 'exhibition' => true, + 'family' => true, + 'farm' => true, + 'farmequipment' => true, + 'farmers' => true, + 'farmstead' => true, + 'field' => true, + 'figueres' => true, + 'filatelia' => true, + 'film' => true, + 'fineart' => true, + 'finearts' => true, + 'finland' => true, + 'flanders' => true, + 'florida' => true, + 'force' => true, + 'fortmissoula' => true, + 'fortworth' => true, + 'foundation' => true, + 'francaise' => true, + 'frankfurt' => true, + 'franziskaner' => true, + 'freemasonry' => true, + 'freiburg' => true, + 'fribourg' => true, + 'frog' => true, + 'fundacio' => true, + 'furniture' => true, + 'gallery' => true, + 'garden' => true, + 'gateway' => true, + 'geelvinck' => true, + 'gemological' => true, + 'geology' => true, + 'georgia' => true, + 'giessen' => true, + 'glas' => true, + 'glass' => true, + 'gorge' => true, + 'grandrapids' => true, + 'graz' => true, + 'guernsey' => true, + 'halloffame' => true, + 'hamburg' => true, + 'handson' => true, + 'harvestcelebration' => true, + 'hawaii' => true, + 'health' => true, + 'heimatunduhren' => true, + 'hellas' => true, + 'helsinki' => true, + 'hembygdsforbund' => true, + 'heritage' => true, + 'histoire' => true, + 'historical' => true, + 'historicalsociety' => true, + 'historichouses' => true, + 'historisch' => true, + 'historisches' => true, + 'history' => true, + 'historyofscience' => true, + 'horology' => true, + 'house' => true, + 'humanities' => true, + 'illustration' => true, + 'imageandsound' => true, + 'indian' => true, + 'indiana' => true, + 'indianapolis' => true, + 'indianmarket' => true, + 'intelligence' => true, + 'interactive' => true, + 'iraq' => true, + 'iron' => true, + 'isleofman' => true, + 'jamison' => true, + 'jefferson' => true, + 'jerusalem' => true, + 'jewelry' => true, + 'jewish' => true, + 'jewishart' => true, + 'jfk' => true, + 'journalism' => true, + 'judaica' => true, + 'judygarland' => true, + 'juedisches' => true, + 'juif' => true, + 'karate' => true, + 'karikatur' => true, + 'kids' => true, + 'koebenhavn' => true, + 'koeln' => true, + 'kunst' => true, + 'kunstsammlung' => true, + 'kunstunddesign' => true, + 'labor' => true, + 'labour' => true, + 'lajolla' => true, + 'lancashire' => true, + 'landes' => true, + 'lans' => true, + 'läns' => true, + 'larsson' => true, + 'lewismiller' => true, + 'lincoln' => true, + 'linz' => true, + 'living' => true, + 'livinghistory' => true, + 'localhistory' => true, + 'london' => true, + 'losangeles' => true, + 'louvre' => true, + 'loyalist' => true, + 'lucerne' => true, + 'luxembourg' => true, + 'luzern' => true, + 'mad' => true, + 'madrid' => true, + 'mallorca' => true, + 'manchester' => true, + 'mansion' => true, + 'mansions' => true, + 'manx' => true, + 'marburg' => true, + 'maritime' => true, + 'maritimo' => true, + 'maryland' => true, + 'marylhurst' => true, + 'media' => true, + 'medical' => true, + 'medizinhistorisches' => true, + 'meeres' => true, + 'memorial' => true, + 'mesaverde' => true, + 'michigan' => true, + 'midatlantic' => true, + 'military' => true, + 'mill' => true, + 'miners' => true, + 'mining' => true, + 'minnesota' => true, + 'missile' => true, + 'missoula' => true, + 'modern' => true, + 'moma' => true, + 'money' => true, + 'monmouth' => true, + 'monticello' => true, + 'montreal' => true, + 'moscow' => true, + 'motorcycle' => true, + 'muenchen' => true, + 'muenster' => true, + 'mulhouse' => true, + 'muncie' => true, + 'museet' => true, + 'museumcenter' => true, + 'museumvereniging' => true, + 'music' => true, + 'national' => true, + 'nationalfirearms' => true, + 'nationalheritage' => true, + 'nativeamerican' => true, + 'naturalhistory' => true, + 'naturalhistorymuseum' => true, + 'naturalsciences' => true, + 'nature' => true, + 'naturhistorisches' => true, + 'natuurwetenschappen' => true, + 'naumburg' => true, + 'naval' => true, + 'nebraska' => true, + 'neues' => true, + 'newhampshire' => true, + 'newjersey' => true, + 'newmexico' => true, + 'newport' => true, + 'newspaper' => true, + 'newyork' => true, + 'niepce' => true, + 'norfolk' => true, + 'north' => true, + 'nrw' => true, + 'nuernberg' => true, + 'nuremberg' => true, + 'nyc' => true, + 'nyny' => true, + 'oceanographic' => true, + 'oceanographique' => true, + 'omaha' => true, + 'online' => true, + 'ontario' => true, + 'openair' => true, + 'oregon' => true, + 'oregontrail' => true, + 'otago' => true, + 'oxford' => true, + 'pacific' => true, + 'paderborn' => true, + 'palace' => true, + 'paleo' => true, + 'palmsprings' => true, + 'panama' => true, + 'paris' => true, + 'pasadena' => true, + 'pharmacy' => true, + 'philadelphia' => true, + 'philadelphiaarea' => true, + 'philately' => true, + 'phoenix' => true, + 'photography' => true, + 'pilots' => true, + 'pittsburgh' => true, + 'planetarium' => true, + 'plantation' => true, + 'plants' => true, + 'plaza' => true, + 'portal' => true, + 'portland' => true, + 'portlligat' => true, + 'posts-and-telecommunications' => true, + 'preservation' => true, + 'presidio' => true, + 'press' => true, + 'project' => true, + 'public' => true, + 'pubol' => true, + 'quebec' => true, + 'railroad' => true, + 'railway' => true, + 'research' => true, + 'resistance' => true, + 'riodejaneiro' => true, + 'rochester' => true, + 'rockart' => true, + 'roma' => true, + 'russia' => true, + 'saintlouis' => true, + 'salem' => true, + 'salvadordali' => true, + 'salzburg' => true, + 'sandiego' => true, + 'sanfrancisco' => true, + 'santabarbara' => true, + 'santacruz' => true, + 'santafe' => true, + 'saskatchewan' => true, + 'satx' => true, + 'savannahga' => true, + 'schlesisches' => true, + 'schoenbrunn' => true, + 'schokoladen' => true, + 'school' => true, + 'schweiz' => true, + 'science' => true, + 'scienceandhistory' => true, + 'scienceandindustry' => true, + 'sciencecenter' => true, + 'sciencecenters' => true, + 'science-fiction' => true, + 'sciencehistory' => true, + 'sciences' => true, + 'sciencesnaturelles' => true, + 'scotland' => true, + 'seaport' => true, + 'settlement' => true, + 'settlers' => true, + 'shell' => true, + 'sherbrooke' => true, + 'sibenik' => true, + 'silk' => true, + 'ski' => true, + 'skole' => true, + 'society' => true, + 'sologne' => true, + 'soundandvision' => true, + 'southcarolina' => true, + 'southwest' => true, + 'space' => true, + 'spy' => true, + 'square' => true, + 'stadt' => true, + 'stalbans' => true, + 'starnberg' => true, + 'state' => true, + 'stateofdelaware' => true, + 'station' => true, + 'steam' => true, + 'steiermark' => true, + 'stjohn' => true, + 'stockholm' => true, + 'stpetersburg' => true, + 'stuttgart' => true, + 'suisse' => true, + 'surgeonshall' => true, + 'surrey' => true, + 'svizzera' => true, + 'sweden' => true, + 'sydney' => true, + 'tank' => true, + 'tcm' => true, + 'technology' => true, + 'telekommunikation' => true, + 'television' => true, + 'texas' => true, + 'textile' => true, + 'theater' => true, + 'time' => true, + 'timekeeping' => true, + 'topology' => true, + 'torino' => true, + 'touch' => true, + 'town' => true, + 'transport' => true, + 'tree' => true, + 'trolley' => true, + 'trust' => true, + 'trustee' => true, + 'uhren' => true, + 'ulm' => true, + 'undersea' => true, + 'university' => true, + 'usa' => true, + 'usantiques' => true, + 'usarts' => true, + 'uscountryestate' => true, + 'usculture' => true, + 'usdecorativearts' => true, + 'usgarden' => true, + 'ushistory' => true, + 'ushuaia' => true, + 'uslivinghistory' => true, + 'utah' => true, + 'uvic' => true, + 'valley' => true, + 'vantaa' => true, + 'versailles' => true, + 'viking' => true, + 'village' => true, + 'virginia' => true, + 'virtual' => true, + 'virtuel' => true, + 'vlaanderen' => true, + 'volkenkunde' => true, + 'wales' => true, + 'wallonie' => true, + 'war' => true, + 'washingtondc' => true, + 'watchandclock' => true, + 'watch-and-clock' => true, + 'western' => true, + 'westfalen' => true, + 'whaling' => true, + 'wildlife' => true, + 'williamsburg' => true, + 'windmill' => true, + 'workshop' => true, + 'york' => true, + 'yorkshire' => true, + 'yosemite' => true, + 'youth' => true, + 'zoological' => true, + 'zoology' => true, + 'ירושלים' => true, + 'иком' => true + ), + 'mv' => array( + 'aero' => true, + 'biz' => true, + 'com' => true, + 'coop' => true, + 'edu' => true, + 'gov' => true, + 'info' => true, + 'int' => true, + 'mil' => true, + 'museum' => true, + 'name' => true, + 'net' => true, + 'org' => true, + 'pro' => true + ), + 'mw' => array( + 'ac' => true, + 'biz' => true, + 'co' => true, + 'com' => true, + 'coop' => true, + 'edu' => true, + 'gov' => true, + 'int' => true, + 'museum' => true, + 'net' => true, + 'org' => true + ), + 'mx' => array( + 'com' => true, + 'org' => true, + 'gob' => true, + 'edu' => true, + 'net' => true + ), + 'my' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'edu' => true, + 'mil' => true, + 'name' => true + ), + 'mz' => array( + '*' => true + ), + 'na' => array( + 'info' => true, + 'pro' => true, + 'name' => true, + 'school' => true, + 'or' => true, + 'dr' => true, + 'us' => true, + 'mx' => true, + 'ca' => true, + 'in' => true, + 'cc' => true, + 'tv' => true, + 'ws' => true, + 'mobi' => true, + 'co' => true, + 'com' => true, + 'org' => true + ), + 'name' => array( + 'her' => array( + 'forgot' => true + ), + 'his' => array( + 'forgot' => true + ) + ), + 'nc' => array( + 'asso' => true + ), + 'ne' => true, + 'net' => array( + 'gb' => true, + 'jp' => true, + 'se' => true, + 'uk' => true, + 'za' => true, + 'at-band-camp' => true, + 'blogdns' => true, + 'broke-it' => true, + 'buyshouses' => true, + 'dnsalias' => true, + 'dnsdojo' => true, + 'does-it' => true, + 'dontexist' => true, + 'dynalias' => true, + 'dynathome' => true, + 'endofinternet' => true, + 'from-az' => true, + 'from-co' => true, + 'from-la' => true, + 'from-ny' => true, + 'gets-it' => true, + 'ham-radio-op' => true, + 'homeftp' => true, + 'homeip' => true, + 'homelinux' => true, + 'homeunix' => true, + 'in-the-band' => true, + 'is-a-chef' => true, + 'is-a-geek' => true, + 'isa-geek' => true, + 'kicks-ass' => true, + 'office-on-the' => true, + 'podzone' => true, + 'scrapper-site' => true, + 'selfip' => true, + 'sells-it' => true, + 'servebbs' => true, + 'serveftp' => true, + 'thruhere' => true, + 'webhop' => true + ), + 'nf' => array( + 'com' => true, + 'net' => true, + 'per' => true, + 'rec' => true, + 'web' => true, + 'arts' => true, + 'firm' => true, + 'info' => true, + 'other' => true, + 'store' => true + ), + 'ng' => array( + 'ac' => true, + 'com' => true, + 'edu' => true, + 'gov' => true, + 'net' => true, + 'org' => true + ), + 'ni' => array( + '*' => true + ), + 'nl' => array( + 'bv' => true, + 'co' => true + ), + 'no' => array( + 'fhs' => true, + 'vgs' => true, + 'fylkesbibl' => true, + 'folkebibl' => true, + 'museum' => true, + 'idrett' => true, + 'priv' => true, + 'mil' => true, + 'stat' => true, + 'dep' => true, + 'kommune' => true, + 'herad' => true, + 'aa' => array( + 'gs' => true + ), + 'ah' => array( + 'gs' => true + ), + 'bu' => array( + 'gs' => true + ), + 'fm' => array( + 'gs' => true + ), + 'hl' => array( + 'gs' => true + ), + 'hm' => array( + 'gs' => true + ), + 'jan-mayen' => array( + 'gs' => true + ), + 'mr' => array( + 'gs' => true + ), + 'nl' => array( + 'gs' => true + ), + 'nt' => array( + 'gs' => true + ), + 'of' => array( + 'gs' => true + ), + 'ol' => array( + 'gs' => true + ), + 'oslo' => array( + 'gs' => true + ), + 'rl' => array( + 'gs' => true + ), + 'sf' => array( + 'gs' => true + ), + 'st' => array( + 'gs' => true + ), + 'svalbard' => array( + 'gs' => true + ), + 'tm' => array( + 'gs' => true + ), + 'tr' => array( + 'gs' => true + ), + 'va' => array( + 'gs' => true + ), + 'vf' => array( + 'gs' => true + ), + 'akrehamn' => true, + 'åkrehamn' => true, + 'algard' => true, + 'ålgård' => true, + 'arna' => true, + 'brumunddal' => true, + 'bryne' => true, + 'bronnoysund' => true, + 'brønnøysund' => true, + 'drobak' => true, + 'drøbak' => true, + 'egersund' => true, + 'fetsund' => true, + 'floro' => true, + 'florø' => true, + 'fredrikstad' => true, + 'hokksund' => true, + 'honefoss' => true, + 'hønefoss' => true, + 'jessheim' => true, + 'jorpeland' => true, + 'jørpeland' => true, + 'kirkenes' => true, + 'kopervik' => true, + 'krokstadelva' => true, + 'langevag' => true, + 'langevåg' => true, + 'leirvik' => true, + 'mjondalen' => true, + 'mjøndalen' => true, + 'mo-i-rana' => true, + 'mosjoen' => true, + 'mosjøen' => true, + 'nesoddtangen' => true, + 'orkanger' => true, + 'osoyro' => true, + 'osøyro' => true, + 'raholt' => true, + 'råholt' => true, + 'sandnessjoen' => true, + 'sandnessjøen' => true, + 'skedsmokorset' => true, + 'slattum' => true, + 'spjelkavik' => true, + 'stathelle' => true, + 'stavern' => true, + 'stjordalshalsen' => true, + 'stjørdalshalsen' => true, + 'tananger' => true, + 'tranby' => true, + 'vossevangen' => true, + 'afjord' => true, + 'åfjord' => true, + 'agdenes' => true, + 'al' => true, + 'ål' => true, + 'alesund' => true, + 'ålesund' => true, + 'alstahaug' => true, + 'alta' => true, + 'áltá' => true, + 'alaheadju' => true, + 'álaheadju' => true, + 'alvdal' => true, + 'amli' => true, + 'åmli' => true, + 'amot' => true, + 'åmot' => true, + 'andebu' => true, + 'andoy' => true, + 'andøy' => true, + 'andasuolo' => true, + 'ardal' => true, + 'årdal' => true, + 'aremark' => true, + 'arendal' => true, + 'ås' => true, + 'aseral' => true, + 'åseral' => true, + 'asker' => true, + 'askim' => true, + 'askvoll' => true, + 'askoy' => true, + 'askøy' => true, + 'asnes' => true, + 'åsnes' => true, + 'audnedaln' => true, + 'aukra' => true, + 'aure' => true, + 'aurland' => true, + 'aurskog-holand' => true, + 'aurskog-høland' => true, + 'austevoll' => true, + 'austrheim' => true, + 'averoy' => true, + 'averøy' => true, + 'balestrand' => true, + 'ballangen' => true, + 'balat' => true, + 'bálát' => true, + 'balsfjord' => true, + 'bahccavuotna' => true, + 'báhccavuotna' => true, + 'bamble' => true, + 'bardu' => true, + 'beardu' => true, + 'beiarn' => true, + 'bajddar' => true, + 'bájddar' => true, + 'baidar' => true, + 'báidár' => true, + 'berg' => true, + 'bergen' => true, + 'berlevag' => true, + 'berlevåg' => true, + 'bearalvahki' => true, + 'bearalváhki' => true, + 'bindal' => true, + 'birkenes' => true, + 'bjarkoy' => true, + 'bjarkøy' => true, + 'bjerkreim' => true, + 'bjugn' => true, + 'bodo' => true, + 'bodø' => true, + 'badaddja' => true, + 'bådåddjå' => true, + 'budejju' => true, + 'bokn' => true, + 'bremanger' => true, + 'bronnoy' => true, + 'brønnøy' => true, + 'bygland' => true, + 'bykle' => true, + 'barum' => true, + 'bærum' => true, + 'telemark' => array( + 'bo' => true, + 'bø' => true + ), + 'nordland' => array( + 'bo' => true, + 'bø' => true, + 'heroy' => true, + 'herøy' => true + ), + 'bievat' => true, + 'bievát' => true, + 'bomlo' => true, + 'bømlo' => true, + 'batsfjord' => true, + 'båtsfjord' => true, + 'bahcavuotna' => true, + 'báhcavuotna' => true, + 'dovre' => true, + 'drammen' => true, + 'drangedal' => true, + 'dyroy' => true, + 'dyrøy' => true, + 'donna' => true, + 'dønna' => true, + 'eid' => true, + 'eidfjord' => true, + 'eidsberg' => true, + 'eidskog' => true, + 'eidsvoll' => true, + 'eigersund' => true, + 'elverum' => true, + 'enebakk' => true, + 'engerdal' => true, + 'etne' => true, + 'etnedal' => true, + 'evenes' => true, + 'evenassi' => true, + 'evenášši' => true, + 'evje-og-hornnes' => true, + 'farsund' => true, + 'fauske' => true, + 'fuossko' => true, + 'fuoisku' => true, + 'fedje' => true, + 'fet' => true, + 'finnoy' => true, + 'finnøy' => true, + 'fitjar' => true, + 'fjaler' => true, + 'fjell' => true, + 'flakstad' => true, + 'flatanger' => true, + 'flekkefjord' => true, + 'flesberg' => true, + 'flora' => true, + 'fla' => true, + 'flå' => true, + 'folldal' => true, + 'forsand' => true, + 'fosnes' => true, + 'frei' => true, + 'frogn' => true, + 'froland' => true, + 'frosta' => true, + 'frana' => true, + 'fræna' => true, + 'froya' => true, + 'frøya' => true, + 'fusa' => true, + 'fyresdal' => true, + 'forde' => true, + 'førde' => true, + 'gamvik' => true, + 'gangaviika' => true, + 'gáŋgaviika' => true, + 'gaular' => true, + 'gausdal' => true, + 'gildeskal' => true, + 'gildeskål' => true, + 'giske' => true, + 'gjemnes' => true, + 'gjerdrum' => true, + 'gjerstad' => true, + 'gjesdal' => true, + 'gjovik' => true, + 'gjøvik' => true, + 'gloppen' => true, + 'gol' => true, + 'gran' => true, + 'grane' => true, + 'granvin' => true, + 'gratangen' => true, + 'grimstad' => true, + 'grong' => true, + 'kraanghke' => true, + 'kråanghke' => true, + 'grue' => true, + 'gulen' => true, + 'hadsel' => true, + 'halden' => true, + 'halsa' => true, + 'hamar' => true, + 'hamaroy' => true, + 'habmer' => true, + 'hábmer' => true, + 'hapmir' => true, + 'hápmir' => true, + 'hammerfest' => true, + 'hammarfeasta' => true, + 'hámmárfeasta' => true, + 'haram' => true, + 'hareid' => true, + 'harstad' => true, + 'hasvik' => true, + 'aknoluokta' => true, + 'ákŋoluokta' => true, + 'hattfjelldal' => true, + 'aarborte' => true, + 'haugesund' => true, + 'hemne' => true, + 'hemnes' => true, + 'hemsedal' => true, + 'more-og-romsdal' => array( + 'heroy' => true, + 'sande' => true + ), + 'møre-og-romsdal' => array( + 'herøy' => true, + 'sande' => true + ), + 'hitra' => true, + 'hjartdal' => true, + 'hjelmeland' => true, + 'hobol' => true, + 'hobøl' => true, + 'hof' => true, + 'hol' => true, + 'hole' => true, + 'holmestrand' => true, + 'holtalen' => true, + 'holtålen' => true, + 'hornindal' => true, + 'horten' => true, + 'hurdal' => true, + 'hurum' => true, + 'hvaler' => true, + 'hyllestad' => true, + 'hagebostad' => true, + 'hægebostad' => true, + 'hoyanger' => true, + 'høyanger' => true, + 'hoylandet' => true, + 'høylandet' => true, + 'ha' => true, + 'hå' => true, + 'ibestad' => true, + 'inderoy' => true, + 'inderøy' => true, + 'iveland' => true, + 'jevnaker' => true, + 'jondal' => true, + 'jolster' => true, + 'jølster' => true, + 'karasjok' => true, + 'karasjohka' => true, + 'kárášjohka' => true, + 'karlsoy' => true, + 'galsa' => true, + 'gálsá' => true, + 'karmoy' => true, + 'karmøy' => true, + 'kautokeino' => true, + 'guovdageaidnu' => true, + 'klepp' => true, + 'klabu' => true, + 'klæbu' => true, + 'kongsberg' => true, + 'kongsvinger' => true, + 'kragero' => true, + 'kragerø' => true, + 'kristiansand' => true, + 'kristiansund' => true, + 'krodsherad' => true, + 'krødsherad' => true, + 'kvalsund' => true, + 'rahkkeravju' => true, + 'ráhkkerávju' => true, + 'kvam' => true, + 'kvinesdal' => true, + 'kvinnherad' => true, + 'kviteseid' => true, + 'kvitsoy' => true, + 'kvitsøy' => true, + 'kvafjord' => true, + 'kvæfjord' => true, + 'giehtavuoatna' => true, + 'kvanangen' => true, + 'kvænangen' => true, + 'navuotna' => true, + 'návuotna' => true, + 'kafjord' => true, + 'kåfjord' => true, + 'gaivuotna' => true, + 'gáivuotna' => true, + 'larvik' => true, + 'lavangen' => true, + 'lavagis' => true, + 'loabat' => true, + 'loabát' => true, + 'lebesby' => true, + 'davvesiida' => true, + 'leikanger' => true, + 'leirfjord' => true, + 'leka' => true, + 'leksvik' => true, + 'lenvik' => true, + 'leangaviika' => true, + 'leaŋgaviika' => true, + 'lesja' => true, + 'levanger' => true, + 'lier' => true, + 'lierne' => true, + 'lillehammer' => true, + 'lillesand' => true, + 'lindesnes' => true, + 'lindas' => true, + 'lindås' => true, + 'lom' => true, + 'loppa' => true, + 'lahppi' => true, + 'láhppi' => true, + 'lund' => true, + 'lunner' => true, + 'luroy' => true, + 'lurøy' => true, + 'luster' => true, + 'lyngdal' => true, + 'lyngen' => true, + 'ivgu' => true, + 'lardal' => true, + 'lerdal' => true, + 'lærdal' => true, + 'lodingen' => true, + 'lødingen' => true, + 'lorenskog' => true, + 'lørenskog' => true, + 'loten' => true, + 'løten' => true, + 'malvik' => true, + 'masoy' => true, + 'måsøy' => true, + 'muosat' => true, + 'muosát' => true, + 'mandal' => true, + 'marker' => true, + 'marnardal' => true, + 'masfjorden' => true, + 'meland' => true, + 'meldal' => true, + 'melhus' => true, + 'meloy' => true, + 'meløy' => true, + 'meraker' => true, + 'meråker' => true, + 'moareke' => true, + 'moåreke' => true, + 'midsund' => true, + 'midtre-gauldal' => true, + 'modalen' => true, + 'modum' => true, + 'molde' => true, + 'moskenes' => true, + 'moss' => true, + 'mosvik' => true, + 'malselv' => true, + 'målselv' => true, + 'malatvuopmi' => true, + 'málatvuopmi' => true, + 'namdalseid' => true, + 'aejrie' => true, + 'namsos' => true, + 'namsskogan' => true, + 'naamesjevuemie' => true, + 'nååmesjevuemie' => true, + 'laakesvuemie' => true, + 'nannestad' => true, + 'narvik' => true, + 'narviika' => true, + 'naustdal' => true, + 'nedre-eiker' => true, + 'akershus' => array( + 'nes' => true + ), + 'buskerud' => array( + 'nes' => true + ), + 'nesna' => true, + 'nesodden' => true, + 'nesseby' => true, + 'unjarga' => true, + 'unjárga' => true, + 'nesset' => true, + 'nissedal' => true, + 'nittedal' => true, + 'nord-aurdal' => true, + 'nord-fron' => true, + 'nord-odal' => true, + 'norddal' => true, + 'nordkapp' => true, + 'davvenjarga' => true, + 'davvenjárga' => true, + 'nordre-land' => true, + 'nordreisa' => true, + 'raisa' => true, + 'ráisa' => true, + 'nore-og-uvdal' => true, + 'notodden' => true, + 'naroy' => true, + 'nærøy' => true, + 'notteroy' => true, + 'nøtterøy' => true, + 'odda' => true, + 'oksnes' => true, + 'øksnes' => true, + 'oppdal' => true, + 'oppegard' => true, + 'oppegård' => true, + 'orkdal' => true, + 'orland' => true, + 'ørland' => true, + 'orskog' => true, + 'ørskog' => true, + 'orsta' => true, + 'ørsta' => true, + 'hedmark' => array( + 'os' => true, + 'valer' => true, + 'våler' => true + ), + 'hordaland' => array( + 'os' => true + ), + 'osen' => true, + 'osteroy' => true, + 'osterøy' => true, + 'ostre-toten' => true, + 'østre-toten' => true, + 'overhalla' => true, + 'ovre-eiker' => true, + 'øvre-eiker' => true, + 'oyer' => true, + 'øyer' => true, + 'oygarden' => true, + 'øygarden' => true, + 'oystre-slidre' => true, + 'øystre-slidre' => true, + 'porsanger' => true, + 'porsangu' => true, + 'porsáŋgu' => true, + 'porsgrunn' => true, + 'radoy' => true, + 'radøy' => true, + 'rakkestad' => true, + 'rana' => true, + 'ruovat' => true, + 'randaberg' => true, + 'rauma' => true, + 'rendalen' => true, + 'rennebu' => true, + 'rennesoy' => true, + 'rennesøy' => true, + 'rindal' => true, + 'ringebu' => true, + 'ringerike' => true, + 'ringsaker' => true, + 'rissa' => true, + 'risor' => true, + 'risør' => true, + 'roan' => true, + 'rollag' => true, + 'rygge' => true, + 'ralingen' => true, + 'rælingen' => true, + 'rodoy' => true, + 'rødøy' => true, + 'romskog' => true, + 'rømskog' => true, + 'roros' => true, + 'røros' => true, + 'rost' => true, + 'røst' => true, + 'royken' => true, + 'røyken' => true, + 'royrvik' => true, + 'røyrvik' => true, + 'rade' => true, + 'råde' => true, + 'salangen' => true, + 'siellak' => true, + 'saltdal' => true, + 'salat' => true, + 'sálát' => true, + 'sálat' => true, + 'samnanger' => true, + 'vestfold' => array( + 'sande' => true + ), + 'sandefjord' => true, + 'sandnes' => true, + 'sandoy' => true, + 'sandøy' => true, + 'sarpsborg' => true, + 'sauda' => true, + 'sauherad' => true, + 'sel' => true, + 'selbu' => true, + 'selje' => true, + 'seljord' => true, + 'sigdal' => true, + 'siljan' => true, + 'sirdal' => true, + 'skaun' => true, + 'skedsmo' => true, + 'ski' => true, + 'skien' => true, + 'skiptvet' => true, + 'skjervoy' => true, + 'skjervøy' => true, + 'skierva' => true, + 'skiervá' => true, + 'skjak' => true, + 'skjåk' => true, + 'skodje' => true, + 'skanland' => true, + 'skånland' => true, + 'skanit' => true, + 'skánit' => true, + 'smola' => true, + 'smøla' => true, + 'snillfjord' => true, + 'snasa' => true, + 'snåsa' => true, + 'snoasa' => true, + 'snaase' => true, + 'snåase' => true, + 'sogndal' => true, + 'sokndal' => true, + 'sola' => true, + 'solund' => true, + 'songdalen' => true, + 'sortland' => true, + 'spydeberg' => true, + 'stange' => true, + 'stavanger' => true, + 'steigen' => true, + 'steinkjer' => true, + 'stjordal' => true, + 'stjørdal' => true, + 'stokke' => true, + 'stor-elvdal' => true, + 'stord' => true, + 'stordal' => true, + 'storfjord' => true, + 'omasvuotna' => true, + 'strand' => true, + 'stranda' => true, + 'stryn' => true, + 'sula' => true, + 'suldal' => true, + 'sund' => true, + 'sunndal' => true, + 'surnadal' => true, + 'sveio' => true, + 'svelvik' => true, + 'sykkylven' => true, + 'sogne' => true, + 'søgne' => true, + 'somna' => true, + 'sømna' => true, + 'sondre-land' => true, + 'søndre-land' => true, + 'sor-aurdal' => true, + 'sør-aurdal' => true, + 'sor-fron' => true, + 'sør-fron' => true, + 'sor-odal' => true, + 'sør-odal' => true, + 'sor-varanger' => true, + 'sør-varanger' => true, + 'matta-varjjat' => true, + 'mátta-várjjat' => true, + 'sorfold' => true, + 'sørfold' => true, + 'sorreisa' => true, + 'sørreisa' => true, + 'sorum' => true, + 'sørum' => true, + 'tana' => true, + 'deatnu' => true, + 'time' => true, + 'tingvoll' => true, + 'tinn' => true, + 'tjeldsund' => true, + 'dielddanuorri' => true, + 'tjome' => true, + 'tjøme' => true, + 'tokke' => true, + 'tolga' => true, + 'torsken' => true, + 'tranoy' => true, + 'tranøy' => true, + 'tromso' => true, + 'tromsø' => true, + 'tromsa' => true, + 'romsa' => true, + 'trondheim' => true, + 'troandin' => true, + 'trysil' => true, + 'trana' => true, + 'træna' => true, + 'trogstad' => true, + 'trøgstad' => true, + 'tvedestrand' => true, + 'tydal' => true, + 'tynset' => true, + 'tysfjord' => true, + 'divtasvuodna' => true, + 'divttasvuotna' => true, + 'tysnes' => true, + 'tysvar' => true, + 'tysvær' => true, + 'tonsberg' => true, + 'tønsberg' => true, + 'ullensaker' => true, + 'ullensvang' => true, + 'ulvik' => true, + 'utsira' => true, + 'vadso' => true, + 'vadsø' => true, + 'cahcesuolo' => true, + 'čáhcesuolo' => true, + 'vaksdal' => true, + 'valle' => true, + 'vang' => true, + 'vanylven' => true, + 'vardo' => true, + 'vardø' => true, + 'varggat' => true, + 'várggát' => true, + 'vefsn' => true, + 'vaapste' => true, + 'vega' => true, + 'vegarshei' => true, + 'vegårshei' => true, + 'vennesla' => true, + 'verdal' => true, + 'verran' => true, + 'vestby' => true, + 'vestnes' => true, + 'vestre-slidre' => true, + 'vestre-toten' => true, + 'vestvagoy' => true, + 'vestvågøy' => true, + 'vevelstad' => true, + 'vik' => true, + 'vikna' => true, + 'vindafjord' => true, + 'volda' => true, + 'voss' => true, + 'varoy' => true, + 'værøy' => true, + 'vagan' => true, + 'vågan' => true, + 'voagat' => true, + 'vagsoy' => true, + 'vågsøy' => true, + 'vaga' => true, + 'vågå' => true, + 'ostfold' => array( + 'valer' => true + ), + 'østfold' => array( + 'våler' => true + ), + 'co' => true + ), + 'np' => array( + '*' => true + ), + 'nr' => array( + 'biz' => true, + 'info' => true, + 'gov' => true, + 'edu' => true, + 'org' => true, + 'net' => true, + 'com' => true + ), + 'nu' => array( + 'merseine' => true, + 'mine' => true, + 'shacknet' => true + ), + 'nz' => array( + '*' => true + ), + 'om' => array( + '*' => true, + '!mediaphone' => true, + '!nawrastelecom' => true, + '!nawras' => true, + '!omanmobile' => true, + '!omanpost' => true, + '!omantel' => true, + '!rakpetroleum' => true, + '!siemens' => true, + '!songfest' => true, + '!statecouncil' => true + ), + 'org' => array( + 'ae' => true, + 'us' => true, + 'za' => true, + 'dyndns' => array( + 'go' => true, + 'home' => true + ), + 'blogdns' => true, + 'blogsite' => true, + 'boldlygoingnowhere' => true, + 'dnsalias' => true, + 'dnsdojo' => true, + 'doesntexist' => true, + 'dontexist' => true, + 'doomdns' => true, + 'dvrdns' => true, + 'dynalias' => true, + 'endofinternet' => true, + 'endoftheinternet' => true, + 'from-me' => true, + 'game-host' => true, + 'gotdns' => true, + 'hobby-site' => true, + 'homedns' => true, + 'homeftp' => true, + 'homelinux' => true, + 'homeunix' => true, + 'is-a-bruinsfan' => true, + 'is-a-candidate' => true, + 'is-a-celticsfan' => true, + 'is-a-chef' => true, + 'is-a-geek' => true, + 'is-a-knight' => true, + 'is-a-linux-user' => true, + 'is-a-patsfan' => true, + 'is-a-soxfan' => true, + 'is-found' => true, + 'is-lost' => true, + 'is-saved' => true, + 'is-very-bad' => true, + 'is-very-evil' => true, + 'is-very-good' => true, + 'is-very-nice' => true, + 'is-very-sweet' => true, + 'isa-geek' => true, + 'kicks-ass' => true, + 'misconfused' => true, + 'podzone' => true, + 'readmyblog' => true, + 'selfip' => true, + 'sellsyourhome' => true, + 'servebbs' => true, + 'serveftp' => true, + 'servegame' => true, + 'stuff-4-sale' => true, + 'webhop' => true + ), + 'pa' => array( + 'ac' => true, + 'gob' => true, + 'com' => true, + 'org' => true, + 'sld' => true, + 'edu' => true, + 'net' => true, + 'ing' => true, + 'abo' => true, + 'med' => true, + 'nom' => true + ), + 'pe' => array( + 'edu' => true, + 'gob' => true, + 'nom' => true, + 'mil' => true, + 'org' => true, + 'com' => true, + 'net' => true + ), + 'pf' => array( + 'com' => true, + 'org' => true, + 'edu' => true + ), + 'pg' => array( + '*' => true + ), + 'ph' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'edu' => true, + 'ngo' => true, + 'mil' => true, + 'i' => true + ), + 'pk' => array( + 'com' => true, + 'net' => true, + 'edu' => true, + 'org' => true, + 'fam' => true, + 'biz' => true, + 'web' => true, + 'gov' => true, + 'gob' => true, + 'gok' => true, + 'gon' => true, + 'gop' => true, + 'gos' => true, + 'info' => true + ), + 'pl' => array( + 'aid' => true, + 'agro' => true, + 'atm' => true, + 'auto' => true, + 'biz' => true, + 'com' => true, + 'edu' => true, + 'gmina' => true, + 'gsm' => true, + 'info' => true, + 'mail' => true, + 'miasta' => true, + 'media' => true, + 'mil' => true, + 'net' => true, + 'nieruchomosci' => true, + 'nom' => true, + 'org' => true, + 'pc' => true, + 'powiat' => true, + 'priv' => true, + 'realestate' => true, + 'rel' => true, + 'sex' => true, + 'shop' => true, + 'sklep' => true, + 'sos' => true, + 'szkola' => true, + 'targi' => true, + 'tm' => true, + 'tourism' => true, + 'travel' => true, + 'turystyka' => true, + '6bone' => true, + 'art' => true, + 'mbone' => true, + 'gov' => array( + 'uw' => true, + 'um' => true, + 'ug' => true, + 'upow' => true, + 'starostwo' => true, + 'so' => true, + 'sr' => true, + 'po' => true, + 'pa' => true + ), + 'ngo' => true, + 'irc' => true, + 'usenet' => true, + 'augustow' => true, + 'babia-gora' => true, + 'bedzin' => true, + 'beskidy' => true, + 'bialowieza' => true, + 'bialystok' => true, + 'bielawa' => true, + 'bieszczady' => true, + 'boleslawiec' => true, + 'bydgoszcz' => true, + 'bytom' => true, + 'cieszyn' => true, + 'czeladz' => true, + 'czest' => true, + 'dlugoleka' => true, + 'elblag' => true, + 'elk' => true, + 'glogow' => true, + 'gniezno' => true, + 'gorlice' => true, + 'grajewo' => true, + 'ilawa' => true, + 'jaworzno' => true, + 'jelenia-gora' => true, + 'jgora' => true, + 'kalisz' => true, + 'kazimierz-dolny' => true, + 'karpacz' => true, + 'kartuzy' => true, + 'kaszuby' => true, + 'katowice' => true, + 'kepno' => true, + 'ketrzyn' => true, + 'klodzko' => true, + 'kobierzyce' => true, + 'kolobrzeg' => true, + 'konin' => true, + 'konskowola' => true, + 'kutno' => true, + 'lapy' => true, + 'lebork' => true, + 'legnica' => true, + 'lezajsk' => true, + 'limanowa' => true, + 'lomza' => true, + 'lowicz' => true, + 'lubin' => true, + 'lukow' => true, + 'malbork' => true, + 'malopolska' => true, + 'mazowsze' => true, + 'mazury' => true, + 'mielec' => true, + 'mielno' => true, + 'mragowo' => true, + 'naklo' => true, + 'nowaruda' => true, + 'nysa' => true, + 'olawa' => true, + 'olecko' => true, + 'olkusz' => true, + 'olsztyn' => true, + 'opoczno' => true, + 'opole' => true, + 'ostroda' => true, + 'ostroleka' => true, + 'ostrowiec' => true, + 'ostrowwlkp' => true, + 'pila' => true, + 'pisz' => true, + 'podhale' => true, + 'podlasie' => true, + 'polkowice' => true, + 'pomorze' => true, + 'pomorskie' => true, + 'prochowice' => true, + 'pruszkow' => true, + 'przeworsk' => true, + 'pulawy' => true, + 'radom' => true, + 'rawa-maz' => true, + 'rybnik' => true, + 'rzeszow' => true, + 'sanok' => true, + 'sejny' => true, + 'siedlce' => true, + 'slask' => true, + 'slupsk' => true, + 'sosnowiec' => true, + 'stalowa-wola' => true, + 'skoczow' => true, + 'starachowice' => true, + 'stargard' => true, + 'suwalki' => true, + 'swidnica' => true, + 'swiebodzin' => true, + 'swinoujscie' => true, + 'szczecin' => true, + 'szczytno' => true, + 'tarnobrzeg' => true, + 'tgory' => true, + 'turek' => true, + 'tychy' => true, + 'ustka' => true, + 'walbrzych' => true, + 'warmia' => true, + 'warszawa' => true, + 'waw' => true, + 'wegrow' => true, + 'wielun' => true, + 'wlocl' => true, + 'wloclawek' => true, + 'wodzislaw' => true, + 'wolomin' => true, + 'wroclaw' => true, + 'zachpomor' => true, + 'zagan' => true, + 'zarow' => true, + 'zgora' => true, + 'zgorzelec' => true, + 'gda' => true, + 'gdansk' => true, + 'gdynia' => true, + 'med' => true, + 'sopot' => true, + 'gliwice' => true, + 'krakow' => true, + 'poznan' => true, + 'wroc' => true, + 'zakopane' => true, + 'co' => true + ), + 'pm' => true, + 'pn' => array( + 'gov' => true, + 'co' => true, + 'org' => true, + 'edu' => true, + 'net' => true + ), + 'pr' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'edu' => true, + 'isla' => true, + 'pro' => true, + 'biz' => true, + 'info' => true, + 'name' => true, + 'est' => true, + 'prof' => true, + 'ac' => true + ), + 'pro' => array( + 'aca' => true, + 'bar' => true, + 'cpa' => true, + 'jur' => true, + 'law' => true, + 'med' => true, + 'eng' => true + ), + 'ps' => array( + 'edu' => true, + 'gov' => true, + 'sec' => true, + 'plo' => true, + 'com' => true, + 'org' => true, + 'net' => true + ), + 'pt' => array( + 'net' => true, + 'gov' => true, + 'org' => true, + 'edu' => true, + 'int' => true, + 'publ' => true, + 'com' => true, + 'nome' => true + ), + 'pw' => array( + 'co' => true, + 'ne' => true, + 'or' => true, + 'ed' => true, + 'go' => true, + 'belau' => true + ), + 'py' => array( + '*' => true + ), + 'qa' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'mil' => true, + 'name' => true, + 'net' => true, + 'org' => true, + 'sch' => true + ), + 're' => array( + 'com' => true, + 'asso' => true, + 'nom' => true + ), + 'ro' => array( + 'com' => true, + 'org' => true, + 'tm' => true, + 'nt' => true, + 'nom' => true, + 'info' => true, + 'rec' => true, + 'arts' => true, + 'firm' => true, + 'store' => true, + 'www' => true + ), + 'rs' => array( + 'co' => true, + 'org' => true, + 'edu' => true, + 'ac' => true, + 'gov' => true, + 'in' => true + ), + 'ru' => array( + 'ac' => true, + 'com' => true, + 'edu' => true, + 'int' => true, + 'net' => true, + 'org' => true, + 'pp' => true, + 'adygeya' => true, + 'altai' => true, + 'amur' => true, + 'arkhangelsk' => true, + 'astrakhan' => true, + 'bashkiria' => true, + 'belgorod' => true, + 'bir' => true, + 'bryansk' => true, + 'buryatia' => true, + 'cbg' => true, + 'chel' => true, + 'chelyabinsk' => true, + 'chita' => true, + 'chukotka' => true, + 'chuvashia' => true, + 'dagestan' => true, + 'dudinka' => true, + 'e-burg' => true, + 'grozny' => true, + 'irkutsk' => true, + 'ivanovo' => true, + 'izhevsk' => true, + 'jar' => true, + 'joshkar-ola' => true, + 'kalmykia' => true, + 'kaluga' => true, + 'kamchatka' => true, + 'karelia' => true, + 'kazan' => true, + 'kchr' => true, + 'kemerovo' => true, + 'khabarovsk' => true, + 'khakassia' => true, + 'khv' => true, + 'kirov' => true, + 'koenig' => true, + 'komi' => true, + 'kostroma' => true, + 'krasnoyarsk' => true, + 'kuban' => true, + 'kurgan' => true, + 'kursk' => true, + 'lipetsk' => true, + 'magadan' => true, + 'mari' => true, + 'mari-el' => true, + 'marine' => true, + 'mordovia' => true, + 'mosreg' => true, + 'msk' => true, + 'murmansk' => true, + 'nalchik' => true, + 'nnov' => true, + 'nov' => true, + 'novosibirsk' => true, + 'nsk' => true, + 'omsk' => true, + 'orenburg' => true, + 'oryol' => true, + 'palana' => true, + 'penza' => true, + 'perm' => true, + 'pskov' => true, + 'ptz' => true, + 'rnd' => true, + 'ryazan' => true, + 'sakhalin' => true, + 'samara' => true, + 'saratov' => true, + 'simbirsk' => true, + 'smolensk' => true, + 'spb' => true, + 'stavropol' => true, + 'stv' => true, + 'surgut' => true, + 'tambov' => true, + 'tatarstan' => true, + 'tom' => true, + 'tomsk' => true, + 'tsaritsyn' => true, + 'tsk' => true, + 'tula' => true, + 'tuva' => true, + 'tver' => true, + 'tyumen' => true, + 'udm' => true, + 'udmurtia' => true, + 'ulan-ude' => true, + 'vladikavkaz' => true, + 'vladimir' => true, + 'vladivostok' => true, + 'volgograd' => true, + 'vologda' => true, + 'voronezh' => true, + 'vrn' => true, + 'vyatka' => true, + 'yakutia' => true, + 'yamal' => true, + 'yaroslavl' => true, + 'yekaterinburg' => true, + 'yuzhno-sakhalinsk' => true, + 'amursk' => true, + 'baikal' => true, + 'cmw' => true, + 'fareast' => true, + 'jamal' => true, + 'kms' => true, + 'k-uralsk' => true, + 'kustanai' => true, + 'kuzbass' => true, + 'magnitka' => true, + 'mytis' => true, + 'nakhodka' => true, + 'nkz' => true, + 'norilsk' => true, + 'oskol' => true, + 'pyatigorsk' => true, + 'rubtsovsk' => true, + 'snz' => true, + 'syzran' => true, + 'vdonsk' => true, + 'zgrad' => true, + 'gov' => true, + 'mil' => true, + 'test' => true + ), + 'rw' => array( + 'gov' => true, + 'net' => true, + 'edu' => true, + 'ac' => true, + 'com' => true, + 'co' => true, + 'int' => true, + 'mil' => true, + 'gouv' => true + ), + 'sa' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'med' => true, + 'pub' => true, + 'edu' => true, + 'sch' => true + ), + 'sb' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'net' => true, + 'org' => true + ), + 'sc' => array( + 'com' => true, + 'gov' => true, + 'net' => true, + 'org' => true, + 'edu' => true + ), + 'sd' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'edu' => true, + 'med' => true, + 'gov' => true, + 'info' => true + ), + 'se' => array( + 'a' => true, + 'ac' => true, + 'b' => true, + 'bd' => true, + 'brand' => true, + 'c' => true, + 'd' => true, + 'e' => true, + 'f' => true, + 'fh' => true, + 'fhsk' => true, + 'fhv' => true, + 'g' => true, + 'h' => true, + 'i' => true, + 'k' => true, + 'komforb' => true, + 'kommunalforbund' => true, + 'komvux' => true, + 'l' => true, + 'lanbib' => true, + 'm' => true, + 'n' => true, + 'naturbruksgymn' => true, + 'o' => true, + 'org' => true, + 'p' => true, + 'parti' => true, + 'pp' => true, + 'press' => true, + 'r' => true, + 's' => true, + 'sshn' => true, + 't' => true, + 'tm' => true, + 'u' => true, + 'w' => true, + 'x' => true, + 'y' => true, + 'z' => true + ), + 'sg' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'edu' => true, + 'per' => true + ), + 'sh' => true, + 'si' => true, + 'sk' => true, + 'sl' => array( + 'com' => true, + 'net' => true, + 'edu' => true, + 'gov' => true, + 'org' => true + ), + 'sm' => true, + 'sn' => array( + 'art' => true, + 'com' => true, + 'edu' => true, + 'gouv' => true, + 'org' => true, + 'perso' => true, + 'univ' => true + ), + 'so' => array( + 'com' => true, + 'net' => true, + 'org' => true + ), + 'sr' => true, + 'st' => array( + 'co' => true, + 'com' => true, + 'consulado' => true, + 'edu' => true, + 'embaixada' => true, + 'gov' => true, + 'mil' => true, + 'net' => true, + 'org' => true, + 'principe' => true, + 'saotome' => true, + 'store' => true + ), + 'su' => true, + 'sv' => array( + '*' => true + ), + 'sy' => array( + 'edu' => true, + 'gov' => true, + 'net' => true, + 'mil' => true, + 'com' => true, + 'org' => true + ), + 'sz' => array( + 'co' => true, + 'ac' => true, + 'org' => true + ), + 'tc' => true, + 'td' => true, + 'tel' => true, + 'tf' => true, + 'tg' => true, + 'th' => array( + 'ac' => true, + 'co' => true, + 'go' => true, + 'in' => true, + 'mi' => true, + 'net' => true, + 'or' => true + ), + 'tj' => array( + 'ac' => true, + 'biz' => true, + 'co' => true, + 'com' => true, + 'edu' => true, + 'go' => true, + 'gov' => true, + 'int' => true, + 'mil' => true, + 'name' => true, + 'net' => true, + 'nic' => true, + 'org' => true, + 'test' => true, + 'web' => true + ), + 'tk' => true, + 'tl' => array( + 'gov' => true + ), + 'tm' => true, + 'tn' => array( + 'com' => true, + 'ens' => true, + 'fin' => true, + 'gov' => true, + 'ind' => true, + 'intl' => true, + 'nat' => true, + 'net' => true, + 'org' => true, + 'info' => true, + 'perso' => true, + 'tourism' => true, + 'edunet' => true, + 'rnrt' => true, + 'rns' => true, + 'rnu' => true, + 'mincom' => true, + 'agrinet' => true, + 'defense' => true, + 'turen' => true + ), + 'to' => array( + 'com' => true, + 'gov' => true, + 'net' => true, + 'org' => true, + 'edu' => true, + 'mil' => true + ), + 'tr' => array( + '*' => true, + '!nic' => true, + 'nc' => array( + 'gov' => true + ) + ), + 'travel' => true, + 'tt' => array( + 'co' => true, + 'com' => true, + 'org' => true, + 'net' => true, + 'biz' => true, + 'info' => true, + 'pro' => true, + 'int' => true, + 'coop' => true, + 'jobs' => true, + 'mobi' => true, + 'travel' => true, + 'museum' => true, + 'aero' => true, + 'name' => true, + 'gov' => true, + 'edu' => true + ), + 'tv' => array( + 'dyndns' => true, + 'better-than' => true, + 'on-the-web' => true, + 'worse-than' => true + ), + 'tw' => array( + 'edu' => true, + 'gov' => true, + 'mil' => true, + 'com' => true, + 'net' => true, + 'org' => true, + 'idv' => true, + 'game' => true, + 'ebiz' => true, + 'club' => true, + '網路' => true, + '組織' => true, + '商業' => true + ), + 'tz' => array( + 'ac' => true, + 'co' => true, + 'go' => true, + 'mil' => true, + 'ne' => true, + 'or' => true, + 'sc' => true + ), + 'ua' => array( + 'com' => true, + 'edu' => true, + 'gov' => true, + 'in' => true, + 'net' => true, + 'org' => true, + 'cherkassy' => true, + 'chernigov' => true, + 'chernovtsy' => true, + 'ck' => true, + 'cn' => true, + 'crimea' => true, + 'cv' => true, + 'dn' => true, + 'dnepropetrovsk' => true, + 'donetsk' => true, + 'dp' => true, + 'if' => true, + 'ivano-frankivsk' => true, + 'kh' => true, + 'kharkov' => true, + 'kherson' => true, + 'khmelnitskiy' => true, + 'kiev' => true, + 'kirovograd' => true, + 'km' => true, + 'kr' => true, + 'ks' => true, + 'kv' => true, + 'lg' => true, + 'lugansk' => true, + 'lutsk' => true, + 'lviv' => true, + 'mk' => true, + 'nikolaev' => true, + 'od' => true, + 'odessa' => true, + 'pl' => true, + 'poltava' => true, + 'rovno' => true, + 'rv' => true, + 'sebastopol' => true, + 'sumy' => true, + 'te' => true, + 'ternopil' => true, + 'uzhgorod' => true, + 'vinnica' => true, + 'vn' => true, + 'zaporizhzhe' => true, + 'zp' => true, + 'zhitomir' => true, + 'zt' => true, + 'co' => true, + 'pp' => true + ), + 'ug' => array( + 'co' => true, + 'ac' => true, + 'sc' => true, + 'go' => true, + 'ne' => true, + 'or' => true + ), + 'uk' => array( + '*' => true, + 'sch' => array( + '*' => true + ), + '!bl' => true, + '!british-library' => true, + '!icnet' => true, + '!jet' => true, + '!mod' => true, + '!nel' => true, + '!nhs' => true, + '!nic' => true, + '!nls' => true, + '!national-library-scotland' => true, + '!parliament' => true, + '!police' => true + ), + 'us' => array( + 'dni' => true, + 'fed' => true, + 'isa' => true, + 'kids' => true, + 'nsn' => true, + 'ak' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'al' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ar' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'as' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'az' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ca' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'co' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ct' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'dc' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'de' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'fl' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ga' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'gu' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'hi' => array( + 'cc' => true, + 'lib' => true + ), + 'ia' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'id' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'il' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'in' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ks' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ky' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'la' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ma' => array( + 'k12' => array( + 'pvt' => true, + 'chtr' => true, + 'paroch' => true + ), + 'cc' => true, + 'lib' => true + ), + 'md' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'me' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'mi' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'mn' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'mo' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ms' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'mt' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'nc' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'nd' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ne' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'nh' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'nj' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'nm' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'nv' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ny' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'oh' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ok' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'or' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'pa' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'pr' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ri' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'sc' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'sd' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'tn' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'tx' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'ut' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'vi' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'vt' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'va' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'wa' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'wi' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'wv' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'wy' => array( + 'k12' => true, + 'cc' => true, + 'lib' => true + ), + 'is-by' => true, + 'land-4-sale' => true, + 'stuff-4-sale' => true + ), + 'uy' => array( + '*' => true + ), + 'uz' => array( + 'com' => true, + 'co' => true + ), + 'va' => true, + 'vc' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'mil' => true, + 'edu' => true + ), + 've' => array( + '*' => true + ), + 'vg' => true, + 'vi' => array( + 'co' => true, + 'com' => true, + 'k12' => true, + 'net' => true, + 'org' => true + ), + 'vn' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'edu' => true, + 'gov' => true, + 'int' => true, + 'ac' => true, + 'biz' => true, + 'info' => true, + 'name' => true, + 'pro' => true, + 'health' => true + ), + 'vu' => true, + 'wf' => true, + 'ws' => array( + 'com' => true, + 'net' => true, + 'org' => true, + 'gov' => true, + 'edu' => true, + 'dyndns' => true, + 'mypets' => true + ), + 'yt' => true, + 'امارات' => true, + 'বাংলা' => true, + '中国' => true, + '中國' => true, + 'الجزائر' => true, + 'مصر' => true, + 'გე' => true, + '香港' => true, + 'भारत' => true, + 'بھارت' => true, + 'భారత్' => true, + 'ભારત' => true, + 'ਭਾਰਤ' => true, + 'ভারত' => true, + 'இந்தியா' => true, + 'ایران' => true, + 'ايران' => true, + 'الاردن' => true, + '한국' => true, + 'ලංකා' => true, + 'இலங்கை' => true, + 'المغرب' => true, + 'عمان' => true, + 'فلسطين' => true, + 'срб' => true, + 'рф' => true, + 'قطر' => true, + 'السعودية' => true, + 'السعودیة' => true, + 'السعودیۃ' => true, + 'السعوديه' => true, + 'سورية' => true, + 'سوريا' => true, + '新加坡' => true, + 'சிங்கப்பூர்' => true, + 'ไทย' => true, + 'تونس' => true, + '台灣' => true, + '台湾' => true, + '臺灣' => true, + 'укр' => true, + 'اليمن' => true, + 'xxx' => true, + 'ye' => array( + '*' => true + ), + 'za' => array( + '*' => true + ), + 'zm' => array( + '*' => true + ), + 'zw' => array( + '*' => true + ) +); +?> \ No newline at end of file