*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Request2.php 308735 2011-02-27 20:31:28Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: Request2.php 324936 2012-04-07 07:49:03Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/**\r
/**\r
* Class representing a HTTP request message\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: 2.0.0RC1\r
- * @link http://tools.ietf.org/html/rfc2616#section-5\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
+ * @link http://tools.ietf.org/html/rfc2616#section-5\r
*/\r
class HTTP_Request2 implements SplSubject\r
{\r
- /**#@+\r
- * Constants for HTTP request methods\r
- *\r
- * @link http://tools.ietf.org/html/rfc2616#section-5.1.1\r
- */\r
+ /**#@+\r
+ * Constants for HTTP request methods\r
+ *\r
+ * @link http://tools.ietf.org/html/rfc2616#section-5.1.1\r
+ */\r
const METHOD_OPTIONS = 'OPTIONS';\r
const METHOD_GET = 'GET';\r
const METHOD_HEAD = 'HEAD';\r
const METHOD_DELETE = 'DELETE';\r
const METHOD_TRACE = 'TRACE';\r
const METHOD_CONNECT = 'CONNECT';\r
- /**#@-*/\r
+ /**#@-*/\r
\r
- /**#@+\r
- * Constants for HTTP authentication schemes\r
- *\r
- * @link http://tools.ietf.org/html/rfc2617\r
- */\r
+ /**#@+\r
+ * Constants for HTTP authentication schemes\r
+ *\r
+ * @link http://tools.ietf.org/html/rfc2617\r
+ */\r
const AUTH_BASIC = 'basic';\r
const AUTH_DIGEST = 'digest';\r
- /**#@-*/\r
+ /**#@-*/\r
\r
- /**\r
- * Regular expression used to check for invalid symbols in RFC 2616 tokens\r
- * @link http://pear.php.net/bugs/bug.php?id=15630\r
- */\r
+ /**\r
+ * Regular expression used to check for invalid symbols in RFC 2616 tokens\r
+ * @link http://pear.php.net/bugs/bug.php?id=15630\r
+ */\r
const REGEXP_INVALID_TOKEN = '![\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]!';\r
\r
- /**\r
- * Regular expression used to check for invalid symbols in cookie strings\r
- * @link http://pear.php.net/bugs/bug.php?id=15630\r
- * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html\r
- */\r
+ /**\r
+ * Regular expression used to check for invalid symbols in cookie strings\r
+ * @link http://pear.php.net/bugs/bug.php?id=15630\r
+ * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html\r
+ */\r
const REGEXP_INVALID_COOKIE = '/[\s,;]/';\r
\r
- /**\r
- * Fileinfo magic database resource\r
- * @var resource\r
- * @see detectMimeType()\r
- */\r
+ /**\r
+ * Fileinfo magic database resource\r
+ * @var resource\r
+ * @see detectMimeType()\r
+ */\r
private static $_fileinfoDb;\r
\r
- /**\r
- * Observers attached to the request (instances of SplObserver)\r
- * @var array\r
- */\r
+ /**\r
+ * Observers attached to the request (instances of SplObserver)\r
+ * @var array\r
+ */\r
protected $observers = array();\r
\r
- /**\r
- * Request URL\r
- * @var Net_URL2\r
- */\r
+ /**\r
+ * Request URL\r
+ * @var Net_URL2\r
+ */\r
protected $url;\r
\r
- /**\r
- * Request method\r
- * @var string\r
- */\r
+ /**\r
+ * Request method\r
+ * @var string\r
+ */\r
protected $method = self::METHOD_GET;\r
\r
- /**\r
- * Authentication data\r
- * @var array\r
- * @see getAuth()\r
- */\r
+ /**\r
+ * Authentication data\r
+ * @var array\r
+ * @see getAuth()\r
+ */\r
protected $auth;\r
\r
- /**\r
- * Request headers\r
- * @var array\r
- */\r
+ /**\r
+ * Request headers\r
+ * @var array\r
+ */\r
protected $headers = array();\r
\r
- /**\r
- * Configuration parameters\r
- * @var array\r
- * @see setConfig()\r
- */\r
+ /**\r
+ * Configuration parameters\r
+ * @var array\r
+ * @see setConfig()\r
+ */\r
protected $config = array(\r
'adapter' => 'HTTP_Request2_Adapter_Socket',\r
'connect_timeout' => 10,\r
'proxy_user' => '',\r
'proxy_password' => '',\r
'proxy_auth_scheme' => self::AUTH_BASIC,\r
+ 'proxy_type' => 'http',\r
\r
'ssl_verify_peer' => true,\r
'ssl_verify_host' => true,\r
'strict_redirects' => false\r
);\r
\r
- /**\r
- * Last event in request / response handling, intended for observers\r
- * @var array\r
- * @see getLastEvent()\r
- */\r
+ /**\r
+ * Last event in request / response handling, intended for observers\r
+ * @var array\r
+ * @see getLastEvent()\r
+ */\r
protected $lastEvent = array(\r
'name' => 'start',\r
'data' => null\r
);\r
\r
- /**\r
- * Request body\r
- * @var string|resource\r
- * @see setBody()\r
- */\r
+ /**\r
+ * Request body\r
+ * @var string|resource\r
+ * @see setBody()\r
+ */\r
protected $body = '';\r
\r
- /**\r
- * Array of POST parameters\r
- * @var array\r
- */\r
+ /**\r
+ * Array of POST parameters\r
+ * @var array\r
+ */\r
protected $postParams = array();\r
\r
- /**\r
- * Array of file uploads (for multipart/form-data POST requests)\r
- * @var array\r
- */\r
+ /**\r
+ * Array of file uploads (for multipart/form-data POST requests)\r
+ * @var array\r
+ */\r
protected $uploads = array();\r
\r
- /**\r
- * Adapter used to perform actual HTTP request\r
- * @var HTTP_Request2_Adapter\r
- */\r
+ /**\r
+ * Adapter used to perform actual HTTP request\r
+ * @var HTTP_Request2_Adapter\r
+ */\r
protected $adapter;\r
\r
- /**\r
- * Cookie jar to persist cookies between requests\r
- * @var HTTP_Request2_CookieJar\r
- */\r
+ /**\r
+ * Cookie jar to persist cookies between requests\r
+ * @var HTTP_Request2_CookieJar\r
+ */\r
protected $cookieJar = null;\r
\r
- /**\r
- * Constructor. Can set request URL, method and configuration array.\r
- *\r
- * Also sets a default value for User-Agent header.\r
- *\r
- * @param string|Net_Url2 Request URL\r
- * @param string Request method\r
- * @param array Configuration for this Request instance\r
- */\r
- public function __construct($url = null, $method = self::METHOD_GET, array $config = array())\r
- {\r
+ /**\r
+ * Constructor. Can set request URL, method and configuration array.\r
+ *\r
+ * Also sets a default value for User-Agent header.\r
+ *\r
+ * @param string|Net_Url2 $url Request URL\r
+ * @param string $method Request method\r
+ * @param array $config Configuration for this Request instance\r
+ */\r
+ public function __construct(\r
+ $url = null, $method = self::METHOD_GET, array $config = array()\r
+ ) {\r
$this->setConfig($config);\r
if (!empty($url)) {\r
$this->setUrl($url);\r
if (!empty($method)) {\r
$this->setMethod($method);\r
}\r
- $this->setHeader('user-agent', 'HTTP_Request2/2.0.0RC1 ' .\r
- '(http://pear.php.net/package/http_request2) ' .\r
- 'PHP/' . phpversion());\r
+ $this->setHeader(\r
+ 'user-agent', 'HTTP_Request2/2.1.1 ' .\r
+ '(http://pear.php.net/package/http_request2) PHP/' . phpversion()\r
+ );\r
}\r
\r
- /**\r
- * Sets the URL for this request\r
- *\r
- * If the URL has userinfo part (username & password) these will be removed\r
- * and converted to auth data. If the URL does not have a path component,\r
- * that will be set to '/'.\r
- *\r
- * @param string|Net_URL2 Request URL\r
- * @return HTTP_Request2\r
- * @throws HTTP_Request2_LogicException\r
- */\r
+ /**\r
+ * Sets the URL for this request\r
+ *\r
+ * If the URL has userinfo part (username & password) these will be removed\r
+ * and converted to auth data. If the URL does not have a path component,\r
+ * that will be set to '/'.\r
+ *\r
+ * @param string|Net_URL2 $url Request URL\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
public function setUrl($url)\r
{\r
if (is_string($url)) {\r
return $this;\r
}\r
\r
- /**\r
- * Returns the request URL\r
- *\r
- * @return Net_URL2\r
- */\r
+ /**\r
+ * Returns the request URL\r
+ *\r
+ * @return Net_URL2\r
+ */\r
public function getUrl()\r
{\r
return $this->url;\r
}\r
\r
- /**\r
- * Sets the request method\r
- *\r
- * @param string\r
- * @return HTTP_Request2\r
- * @throws HTTP_Request2_LogicException if the method name is invalid\r
- */\r
+ /**\r
+ * Sets the request method\r
+ *\r
+ * @param string $method one of the methods defined in RFC 2616\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException if the method name is invalid\r
+ */\r
public function setMethod($method)\r
{\r
// Method name should be a token: http://tools.ietf.org/html/rfc2616#section-5.1.1\r
return $this;\r
}\r
\r
- /**\r
- * Returns the request method\r
- *\r
- * @return string\r
- */\r
+ /**\r
+ * Returns the request method\r
+ *\r
+ * @return string\r
+ */\r
public function getMethod()\r
{\r
return $this->method;\r
}\r
\r
- /**\r
- * Sets the configuration parameter(s)\r
- *\r
- * The following parameters are available:\r
- * <ul>\r
- * <li> 'adapter' - adapter to use (string)</li>\r
- * <li> 'connect_timeout' - Connection timeout in seconds (integer)</li>\r
- * <li> 'timeout' - Total number of seconds a request can take.\r
- * Use 0 for no limit, should be greater than\r
- * 'connect_timeout' if set (integer)</li>\r
- * <li> 'use_brackets' - Whether to append [] to array variable names (bool)</li>\r
- * <li> 'protocol_version' - HTTP Version to use, '1.0' or '1.1' (string)</li>\r
- * <li> 'buffer_size' - Buffer size to use for reading and writing (int)</li>\r
- * <li> 'store_body' - Whether to store response body in response object.\r
- * Set to false if receiving a huge response and\r
- * using an Observer to save it (boolean)</li>\r
- * <li> 'proxy_host' - Proxy server host (string)</li>\r
- * <li> 'proxy_port' - Proxy server port (integer)</li>\r
- * <li> 'proxy_user' - Proxy auth username (string)</li>\r
- * <li> 'proxy_password' - Proxy auth password (string)</li>\r
- * <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li>\r
- * <li> 'ssl_verify_peer' - Whether to verify peer's SSL certificate (bool)</li>\r
- * <li> 'ssl_verify_host' - Whether to check that Common Name in SSL\r
- * certificate matches host name (bool)</li>\r
- * <li> 'ssl_cafile' - Cerificate Authority file to verify the peer\r
- * with (use with 'ssl_verify_peer') (string)</li>\r
- * <li> 'ssl_capath' - Directory holding multiple Certificate\r
- * Authority files (string)</li>\r
- * <li> 'ssl_local_cert' - Name of a file containing local cerificate (string)</li>\r
- * <li> 'ssl_passphrase' - Passphrase with which local certificate\r
- * was encoded (string)</li>\r
- * <li> 'digest_compat_ie' - Whether to imitate behaviour of MSIE 5 and 6\r
- * in using URL without query string in digest\r
- * authentication (boolean)</li>\r
- * <li> 'follow_redirects' - Whether to automatically follow HTTP Redirects (boolean)</li>\r
- * <li> 'max_redirects' - Maximum number of redirects to follow (integer)</li>\r
- * <li> 'strict_redirects' - Whether to keep request method on redirects via status 301 and\r
- * 302 (true, needed for compatibility with RFC 2616)\r
- * or switch to GET (false, needed for compatibility with most\r
- * browsers) (boolean)</li>\r
- * </ul>\r
- *\r
- * @param string|array configuration parameter name or array\r
- * ('parameter name' => 'parameter value')\r
- * @param mixed parameter value if $nameOrConfig is not an array\r
- * @return HTTP_Request2\r
- * @throws HTTP_Request2_LogicException If the parameter is unknown\r
- */\r
+ /**\r
+ * Sets the configuration parameter(s)\r
+ *\r
+ * The following parameters are available:\r
+ * <ul>\r
+ * <li> 'adapter' - adapter to use (string)</li>\r
+ * <li> 'connect_timeout' - Connection timeout in seconds (integer)</li>\r
+ * <li> 'timeout' - Total number of seconds a request can take.\r
+ * Use 0 for no limit, should be greater than\r
+ * 'connect_timeout' if set (integer)</li>\r
+ * <li> 'use_brackets' - Whether to append [] to array variable names (bool)</li>\r
+ * <li> 'protocol_version' - HTTP Version to use, '1.0' or '1.1' (string)</li>\r
+ * <li> 'buffer_size' - Buffer size to use for reading and writing (int)</li>\r
+ * <li> 'store_body' - Whether to store response body in response object.\r
+ * Set to false if receiving a huge response and\r
+ * using an Observer to save it (boolean)</li>\r
+ * <li> 'proxy_type' - Proxy type, 'http' or 'socks5' (string)</li>\r
+ * <li> 'proxy_host' - Proxy server host (string)</li>\r
+ * <li> 'proxy_port' - Proxy server port (integer)</li>\r
+ * <li> 'proxy_user' - Proxy auth username (string)</li>\r
+ * <li> 'proxy_password' - Proxy auth password (string)</li>\r
+ * <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li>\r
+ * <li> 'proxy' - Shorthand for proxy_* parameters, proxy given as URL,\r
+ * e.g. 'socks5://localhost:1080/' (string)</li>\r
+ * <li> 'ssl_verify_peer' - Whether to verify peer's SSL certificate (bool)</li>\r
+ * <li> 'ssl_verify_host' - Whether to check that Common Name in SSL\r
+ * certificate matches host name (bool)</li>\r
+ * <li> 'ssl_cafile' - Cerificate Authority file to verify the peer\r
+ * with (use with 'ssl_verify_peer') (string)</li>\r
+ * <li> 'ssl_capath' - Directory holding multiple Certificate\r
+ * Authority files (string)</li>\r
+ * <li> 'ssl_local_cert' - Name of a file containing local cerificate (string)</li>\r
+ * <li> 'ssl_passphrase' - Passphrase with which local certificate\r
+ * was encoded (string)</li>\r
+ * <li> 'digest_compat_ie' - Whether to imitate behaviour of MSIE 5 and 6\r
+ * in using URL without query string in digest\r
+ * authentication (boolean)</li>\r
+ * <li> 'follow_redirects' - Whether to automatically follow HTTP Redirects (boolean)</li>\r
+ * <li> 'max_redirects' - Maximum number of redirects to follow (integer)</li>\r
+ * <li> 'strict_redirects' - Whether to keep request method on redirects via status 301 and\r
+ * 302 (true, needed for compatibility with RFC 2616)\r
+ * or switch to GET (false, needed for compatibility with most\r
+ * browsers) (boolean)</li>\r
+ * </ul>\r
+ *\r
+ * @param string|array $nameOrConfig configuration parameter name or array\r
+ * ('parameter name' => 'parameter value')\r
+ * @param mixed $value parameter value if $nameOrConfig is not an array\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException If the parameter is unknown\r
+ */\r
public function setConfig($nameOrConfig, $value = null)\r
{\r
if (is_array($nameOrConfig)) {\r
$this->setConfig($name, $value);\r
}\r
\r
+ } elseif ('proxy' == $nameOrConfig) {\r
+ $url = new Net_URL2($value);\r
+ $this->setConfig(array(\r
+ 'proxy_type' => $url->getScheme(),\r
+ 'proxy_host' => $url->getHost(),\r
+ 'proxy_port' => $url->getPort(),\r
+ 'proxy_user' => rawurldecode($url->getUser()),\r
+ 'proxy_password' => rawurldecode($url->getPassword())\r
+ ));\r
+\r
} else {\r
if (!array_key_exists($nameOrConfig, $this->config)) {\r
throw new HTTP_Request2_LogicException(\r
return $this;\r
}\r
\r
- /**\r
- * Returns the value(s) of the configuration parameter(s)\r
- *\r
- * @param string parameter name\r
- * @return mixed value of $name parameter, array of all configuration\r
- * parameters if $name is not given\r
- * @throws HTTP_Request2_LogicException If the parameter is unknown\r
- */\r
+ /**\r
+ * Returns the value(s) of the configuration parameter(s)\r
+ *\r
+ * @param string $name parameter name\r
+ *\r
+ * @return mixed value of $name parameter, array of all configuration\r
+ * parameters if $name is not given\r
+ * @throws HTTP_Request2_LogicException If the parameter is unknown\r
+ */\r
public function getConfig($name = null)\r
{\r
if (null === $name) {\r
return $this->config[$name];\r
}\r
\r
- /**\r
- * Sets the autentification data\r
- *\r
- * @param string user name\r
- * @param string password\r
- * @param string authentication scheme\r
- * @return HTTP_Request2\r
- */\r
+ /**\r
+ * Sets the autentification data\r
+ *\r
+ * @param string $user user name\r
+ * @param string $password password\r
+ * @param string $scheme authentication scheme\r
+ *\r
+ * @return HTTP_Request2\r
+ */\r
public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC)\r
{\r
if (empty($user)) {\r
return $this;\r
}\r
\r
- /**\r
- * Returns the authentication data\r
- *\r
- * The array has the keys 'user', 'password' and 'scheme', where 'scheme'\r
- * is one of the HTTP_Request2::AUTH_* constants.\r
- *\r
- * @return array\r
- */\r
+ /**\r
+ * Returns the authentication data\r
+ *\r
+ * The array has the keys 'user', 'password' and 'scheme', where 'scheme'\r
+ * is one of the HTTP_Request2::AUTH_* constants.\r
+ *\r
+ * @return array\r
+ */\r
public function getAuth()\r
{\r
return $this->auth;\r
}\r
\r
- /**\r
- * Sets request header(s)\r
- *\r
- * The first parameter may be either a full header string 'header: value' or\r
- * header name. In the former case $value parameter is ignored, in the latter\r
- * the header's value will either be set to $value or the header will be\r
- * removed if $value is null. The first parameter can also be an array of\r
- * headers, in that case method will be called recursively.\r
- *\r
- * Note that headers are treated case insensitively as per RFC 2616.\r
- *\r
- * <code>\r
- * $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar'\r
- * $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz'\r
- * $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux'\r
- * $req->setHeader('FOO'); // removes 'Foo' header from request\r
- * </code>\r
- *\r
- * @param string|array header name, header string ('Header: value')\r
- * or an array of headers\r
- * @param string|array|null header value if $name is not an array,\r
- * header will be removed if value is null\r
- * @param bool whether to replace previous header with the\r
- * same name or append to its value\r
- * @return HTTP_Request2\r
- * @throws HTTP_Request2_LogicException\r
- */\r
+ /**\r
+ * Sets request header(s)\r
+ *\r
+ * The first parameter may be either a full header string 'header: value' or\r
+ * header name. In the former case $value parameter is ignored, in the latter\r
+ * the header's value will either be set to $value or the header will be\r
+ * removed if $value is null. The first parameter can also be an array of\r
+ * headers, in that case method will be called recursively.\r
+ *\r
+ * Note that headers are treated case insensitively as per RFC 2616.\r
+ *\r
+ * <code>\r
+ * $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar'\r
+ * $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz'\r
+ * $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux'\r
+ * $req->setHeader('FOO'); // removes 'Foo' header from request\r
+ * </code>\r
+ *\r
+ * @param string|array $name header name, header string ('Header: value')\r
+ * or an array of headers\r
+ * @param string|array|null $value header value if $name is not an array,\r
+ * header will be removed if value is null\r
+ * @param bool $replace whether to replace previous header with the\r
+ * same name or append to its value\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
public function setHeader($name, $value = null, $replace = true)\r
{\r
if (is_array($name)) {\r
return $this;\r
}\r
\r
- /**\r
- * Returns the request headers\r
- *\r
- * The array is of the form ('header name' => 'header value'), header names\r
- * are lowercased\r
- *\r
- * @return array\r
- */\r
+ /**\r
+ * Returns the request headers\r
+ *\r
+ * The array is of the form ('header name' => 'header value'), header names\r
+ * are lowercased\r
+ *\r
+ * @return array\r
+ */\r
public function getHeaders()\r
{\r
return $this->headers;\r
}\r
\r
- /**\r
- * Adds a cookie to the request\r
- *\r
- * If the request does not have a CookieJar object set, this method simply\r
- * appends a cookie to "Cookie:" header.\r
- *\r
- * If a CookieJar object is available, the cookie is stored in that object.\r
- * Data from request URL will be used for setting its 'domain' and 'path'\r
- * parameters, 'expires' and 'secure' will be set to null and false,\r
- * respectively. If you need further control, use CookieJar's methods.\r
- *\r
- * @param string cookie name\r
- * @param string cookie value\r
- * @return HTTP_Request2\r
- * @throws HTTP_Request2_LogicException\r
- * @see setCookieJar()\r
- */\r
+ /**\r
+ * Adds a cookie to the request\r
+ *\r
+ * If the request does not have a CookieJar object set, this method simply\r
+ * appends a cookie to "Cookie:" header.\r
+ *\r
+ * If a CookieJar object is available, the cookie is stored in that object.\r
+ * Data from request URL will be used for setting its 'domain' and 'path'\r
+ * parameters, 'expires' and 'secure' will be set to null and false,\r
+ * respectively. If you need further control, use CookieJar's methods.\r
+ *\r
+ * @param string $name cookie name\r
+ * @param string $value cookie value\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException\r
+ * @see setCookieJar()\r
+ */\r
public function addCookie($name, $value)\r
{\r
if (!empty($this->cookieJar)) {\r
- $this->cookieJar->store(array('name' => $name, 'value' => $value),\r
- $this->url);\r
+ $this->cookieJar->store(\r
+ array('name' => $name, 'value' => $value), $this->url\r
+ );\r
\r
} else {\r
$cookie = $name . '=' . $value;\r
return $this;\r
}\r
\r
- /**\r
- * Sets the request body\r
- *\r
- * If you provide file pointer rather than file name, it should support\r
- * fstat() and rewind() operations.\r
- *\r
- * @param string|resource|HTTP_Request2_MultipartBody Either a string\r
- * with the body or filename containing body or pointer to\r
- * an open file or object with multipart body data\r
- * @param bool Whether first parameter is a filename\r
- * @return HTTP_Request2\r
- * @throws HTTP_Request2_LogicException\r
- */\r
+ /**\r
+ * Sets the request body\r
+ *\r
+ * If you provide file pointer rather than file name, it should support\r
+ * fstat() and rewind() operations.\r
+ *\r
+ * @param string|resource|HTTP_Request2_MultipartBody $body Either a\r
+ * string with the body or filename containing body or\r
+ * pointer to an open file or object with multipart body data\r
+ * @param bool $isFilename Whether\r
+ * first parameter is a filename\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
public function setBody($body, $isFilename = false)\r
{\r
if (!$isFilename && !is_resource($body)) {\r
return $this;\r
}\r
\r
- /**\r
- * Returns the request body\r
- *\r
- * @return string|resource|HTTP_Request2_MultipartBody\r
- */\r
+ /**\r
+ * Returns the request body\r
+ *\r
+ * @return string|resource|HTTP_Request2_MultipartBody\r
+ */\r
public function getBody()\r
{\r
- if (self::METHOD_POST == $this->method &&\r
- (!empty($this->postParams) || !empty($this->uploads))\r
+ if (self::METHOD_POST == $this->method\r
+ && (!empty($this->postParams) || !empty($this->uploads))\r
) {\r
if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) {\r
$body = http_build_query($this->postParams, '', '&');\r
return $this->body;\r
}\r
\r
- /**\r
- * Adds a file to form-based file upload\r
- *\r
- * Used to emulate file upload via a HTML form. The method also sets\r
- * Content-Type of HTTP request to 'multipart/form-data'.\r
- *\r
- * If you just want to send the contents of a file as the body of HTTP\r
- * request you should use setBody() method.\r
- *\r
- * If you provide file pointers rather than file names, they should support\r
- * fstat() and rewind() operations.\r
- *\r
- * @param string name of file-upload field\r
- * @param string|resource|array full name of local file, pointer to\r
- * open file or an array of files\r
- * @param string filename to send in the request\r
- * @param string content-type of file being uploaded\r
- * @return HTTP_Request2\r
- * @throws HTTP_Request2_LogicException\r
- */\r
- public function addUpload($fieldName, $filename, $sendFilename = null,\r
- $contentType = null)\r
- {\r
+ /**\r
+ * Adds a file to form-based file upload\r
+ *\r
+ * Used to emulate file upload via a HTML form. The method also sets\r
+ * Content-Type of HTTP request to 'multipart/form-data'.\r
+ *\r
+ * If you just want to send the contents of a file as the body of HTTP\r
+ * request you should use setBody() method.\r
+ *\r
+ * If you provide file pointers rather than file names, they should support\r
+ * fstat() and rewind() operations.\r
+ *\r
+ * @param string $fieldName name of file-upload field\r
+ * @param string|resource|array $filename full name of local file,\r
+ * pointer to open file or an array of files\r
+ * @param string $sendFilename filename to send in the request\r
+ * @param string $contentType content-type of file being uploaded\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
+ public function addUpload(\r
+ $fieldName, $filename, $sendFilename = null, $contentType = null\r
+ ) {\r
if (!is_array($filename)) {\r
$fileData = $this->fopenWrapper($filename, empty($contentType));\r
$this->uploads[$fieldName] = array(\r
'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types\r
);\r
}\r
- if (empty($this->headers['content-type']) ||\r
- 'application/x-www-form-urlencoded' == $this->headers['content-type']\r
+ if (empty($this->headers['content-type'])\r
+ || 'application/x-www-form-urlencoded' == $this->headers['content-type']\r
) {\r
$this->setHeader('content-type', 'multipart/form-data');\r
}\r
return $this;\r
}\r
\r
- /**\r
- * Adds POST parameter(s) to the request.\r
- *\r
- * @param string|array parameter name or array ('name' => 'value')\r
- * @param mixed parameter value (can be an array)\r
- * @return HTTP_Request2\r
- */\r
+ /**\r
+ * Adds POST parameter(s) to the request.\r
+ *\r
+ * @param string|array $name parameter name or array ('name' => 'value')\r
+ * @param mixed $value parameter value (can be an array)\r
+ *\r
+ * @return HTTP_Request2\r
+ */\r
public function addPostParameter($name, $value = null)\r
{\r
if (!is_array($name)) {\r
return $this;\r
}\r
\r
- /**\r
- * Attaches a new observer\r
- *\r
- * @param SplObserver\r
- */\r
+ /**\r
+ * Attaches a new observer\r
+ *\r
+ * @param SplObserver $observer any object implementing SplObserver\r
+ */\r
public function attach(SplObserver $observer)\r
{\r
foreach ($this->observers as $attached) {\r
$this->observers[] = $observer;\r
}\r
\r
- /**\r
- * Detaches an existing observer\r
- *\r
- * @param SplObserver\r
- */\r
+ /**\r
+ * Detaches an existing observer\r
+ *\r
+ * @param SplObserver $observer any object implementing SplObserver\r
+ */\r
public function detach(SplObserver $observer)\r
{\r
foreach ($this->observers as $key => $attached) {\r
}\r
}\r
\r
- /**\r
- * Notifies all observers\r
- */\r
+ /**\r
+ * Notifies all observers\r
+ */\r
public function notify()\r
{\r
foreach ($this->observers as $observer) {\r
}\r
}\r
\r
- /**\r
- * Sets the last event\r
- *\r
- * Adapters should use this method to set the current state of the request\r
- * and notify the observers.\r
- *\r
- * @param string event name\r
- * @param mixed event data\r
- */\r
+ /**\r
+ * Sets the last event\r
+ *\r
+ * Adapters should use this method to set the current state of the request\r
+ * and notify the observers.\r
+ *\r
+ * @param string $name event name\r
+ * @param mixed $data event data\r
+ */\r
public function setLastEvent($name, $data = null)\r
{\r
$this->lastEvent = array(\r
$this->notify();\r
}\r
\r
- /**\r
- * Returns the last event\r
- *\r
- * Observers should use this method to access the last change in request.\r
- * The following event names are possible:\r
- * <ul>\r
- * <li>'connect' - after connection to remote server,\r
- * data is the destination (string)</li>\r
- * <li>'disconnect' - after disconnection from server</li>\r
- * <li>'sentHeaders' - after sending the request headers,\r
- * data is the headers sent (string)</li>\r
- * <li>'sentBodyPart' - after sending a part of the request body,\r
- * data is the length of that part (int)</li>\r
- * <li>'sentBody' - after sending the whole request body,\r
- * data is request body length (int)</li>\r
- * <li>'receivedHeaders' - after receiving the response headers,\r
- * data is HTTP_Request2_Response object</li>\r
- * <li>'receivedBodyPart' - after receiving a part of the response\r
- * body, data is that part (string)</li>\r
- * <li>'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still\r
- * encoded by Content-Encoding</li>\r
- * <li>'receivedBody' - after receiving the complete response\r
- * body, data is HTTP_Request2_Response object</li>\r
- * </ul>\r
- * Different adapters may not send all the event types. Mock adapter does\r
- * not send any events to the observers.\r
- *\r
- * @return array The array has two keys: 'name' and 'data'\r
- */\r
+ /**\r
+ * Returns the last event\r
+ *\r
+ * Observers should use this method to access the last change in request.\r
+ * The following event names are possible:\r
+ * <ul>\r
+ * <li>'connect' - after connection to remote server,\r
+ * data is the destination (string)</li>\r
+ * <li>'disconnect' - after disconnection from server</li>\r
+ * <li>'sentHeaders' - after sending the request headers,\r
+ * data is the headers sent (string)</li>\r
+ * <li>'sentBodyPart' - after sending a part of the request body,\r
+ * data is the length of that part (int)</li>\r
+ * <li>'sentBody' - after sending the whole request body,\r
+ * data is request body length (int)</li>\r
+ * <li>'receivedHeaders' - after receiving the response headers,\r
+ * data is HTTP_Request2_Response object</li>\r
+ * <li>'receivedBodyPart' - after receiving a part of the response\r
+ * body, data is that part (string)</li>\r
+ * <li>'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still\r
+ * encoded by Content-Encoding</li>\r
+ * <li>'receivedBody' - after receiving the complete response\r
+ * body, data is HTTP_Request2_Response object</li>\r
+ * </ul>\r
+ * Different adapters may not send all the event types. Mock adapter does\r
+ * not send any events to the observers.\r
+ *\r
+ * @return array The array has two keys: 'name' and 'data'\r
+ */\r
public function getLastEvent()\r
{\r
return $this->lastEvent;\r
}\r
\r
- /**\r
- * Sets the adapter used to actually perform the request\r
- *\r
- * You can pass either an instance of a class implementing HTTP_Request2_Adapter\r
- * or a class name. The method will only try to include a file if the class\r
- * name starts with HTTP_Request2_Adapter_, it will also try to prepend this\r
- * prefix to the class name if it doesn't contain any underscores, so that\r
- * <code>\r
- * $request->setAdapter('curl');\r
- * </code>\r
- * will work.\r
- *\r
- * @param string|HTTP_Request2_Adapter\r
- * @return HTTP_Request2\r
- * @throws HTTP_Request2_LogicException\r
- */\r
+ /**\r
+ * Sets the adapter used to actually perform the request\r
+ *\r
+ * You can pass either an instance of a class implementing HTTP_Request2_Adapter\r
+ * or a class name. The method will only try to include a file if the class\r
+ * name starts with HTTP_Request2_Adapter_, it will also try to prepend this\r
+ * prefix to the class name if it doesn't contain any underscores, so that\r
+ * <code>\r
+ * $request->setAdapter('curl');\r
+ * </code>\r
+ * will work.\r
+ *\r
+ * @param string|HTTP_Request2_Adapter $adapter Adapter to use\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
public function setAdapter($adapter)\r
{\r
if (is_string($adapter)) {\r
if (false === strpos($adapter, '_')) {\r
$adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter);\r
}\r
- if (preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)) {\r
+ if (!class_exists($adapter, false)\r
+ && preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)\r
+ ) {\r
include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php';\r
}\r
if (!class_exists($adapter, false)) {\r
return $this;\r
}\r
\r
- /**\r
- * Sets the cookie jar\r
- *\r
- * A cookie jar is used to maintain cookies across HTTP requests and\r
- * responses. Cookies from jar will be automatically added to the request\r
- * headers based on request URL.\r
- *\r
- * @param HTTP_Request2_CookieJar|bool Existing CookieJar object, true to\r
- * create a new one, false to remove\r
- */\r
+ /**\r
+ * Sets the cookie jar\r
+ *\r
+ * A cookie jar is used to maintain cookies across HTTP requests and\r
+ * responses. Cookies from jar will be automatically added to the request\r
+ * headers based on request URL.\r
+ *\r
+ * @param HTTP_Request2_CookieJar|bool $jar Existing CookieJar object, true to\r
+ * create a new one, false to remove\r
+ *\r
+ * @return HTTP_Request2\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
public function setCookieJar($jar = true)\r
{\r
if (!class_exists('HTTP_Request2_CookieJar', false)) {\r
return $this;\r
}\r
\r
- /**\r
- * Returns current CookieJar object or null if none\r
- *\r
- * @return HTTP_Request2_CookieJar|null\r
- */\r
+ /**\r
+ * Returns current CookieJar object or null if none\r
+ *\r
+ * @return HTTP_Request2_CookieJar|null\r
+ */\r
public function getCookieJar()\r
{\r
return $this->cookieJar;\r
}\r
\r
- /**\r
- * Sends the request and returns the response\r
- *\r
- * @throws HTTP_Request2_Exception\r
- * @return HTTP_Request2_Response\r
- */\r
+ /**\r
+ * Sends the request and returns the response\r
+ *\r
+ * @throws HTTP_Request2_Exception\r
+ * @return HTTP_Request2_Response\r
+ */\r
public function send()\r
{\r
// Sanity check for URL\r
throw new HTTP_Request2_LogicException(\r
'HTTP_Request2 needs an absolute HTTP(S) request URL, '\r
. ($this->url instanceof Net_URL2\r
- ? 'none' : "'" . $this->url->__toString() . "'")\r
+ ? "'" . $this->url->__toString() . "'" : 'none')\r
. ' given',\r
HTTP_Request2_Exception::INVALID_ARGUMENT\r
);\r
// strlen() and substr(); see bug #1781, bug #10605\r
if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {\r
$oldEncoding = mb_internal_encoding();\r
- mb_internal_encoding('iso-8859-1');\r
+ mb_internal_encoding('8bit');\r
}\r
\r
try {\r
return $response;\r
}\r
\r
- /**\r
- * Wrapper around fopen()/fstat() used by setBody() and addUpload()\r
- *\r
- * @param string|resource file name or pointer to open file\r
- * @param bool whether to try autodetecting MIME type of file,\r
- * will only work if $file is a filename, not pointer\r
- * @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type)\r
- * @throws HTTP_Request2_LogicException\r
- */\r
+ /**\r
+ * Wrapper around fopen()/fstat() used by setBody() and addUpload()\r
+ *\r
+ * @param string|resource $file file name or pointer to open file\r
+ * @param bool $detectType whether to try autodetecting MIME\r
+ * type of file, will only work if $file is a\r
+ * filename, not pointer\r
+ *\r
+ * @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type)\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
protected function fopenWrapper($file, $detectType = false)\r
{\r
if (!is_string($file) && !is_resource($file)) {\r
'size' => 0\r
);\r
if (is_string($file)) {\r
- $track = @ini_set('track_errors', 1);\r
if (!($fileData['fp'] = @fopen($file, 'rb'))) {\r
- $e = new HTTP_Request2_LogicException(\r
- $php_errormsg, HTTP_Request2_Exception::READ_ERROR\r
+ $error = error_get_last();\r
+ throw new HTTP_Request2_LogicException(\r
+ $error['message'], HTTP_Request2_Exception::READ_ERROR\r
);\r
}\r
- @ini_set('track_errors', $track);\r
- if (isset($e)) {\r
- throw $e;\r
- }\r
if ($detectType) {\r
$fileData['type'] = self::detectMimeType($file);\r
}\r
return $fileData;\r
}\r
\r
- /**\r
- * Tries to detect MIME type of a file\r
- *\r
- * The method will try to use fileinfo extension if it is available,\r
- * deprecated mime_content_type() function in the other case. If neither\r
- * works, default 'application/octet-stream' MIME type is returned\r
- *\r
- * @param string filename\r
- * @return string file MIME type\r
- */\r
+ /**\r
+ * Tries to detect MIME type of a file\r
+ *\r
+ * The method will try to use fileinfo extension if it is available,\r
+ * deprecated mime_content_type() function in the other case. If neither\r
+ * works, default 'application/octet-stream' MIME type is returned\r
+ *\r
+ * @param string $filename file name\r
+ *\r
+ * @return string file MIME type\r
+ */\r
protected static function detectMimeType($filename)\r
{\r
// finfo extension from PECL available\r
return empty($info)? 'application/octet-stream': $info;\r
}\r
}\r
-?>
\ No newline at end of file
+?>\r
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Adapter.php 308322 2011-02-14 13:58:03Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: Adapter.php 324415 2012-03-21 10:50:50Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/**\r
* data, all actual work of sending the request to the remote server and\r
* receiving its response is performed by adapters.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
abstract class HTTP_Request2_Adapter\r
{\r
- /**\r
- * A list of methods that MUST NOT have a request body, per RFC 2616\r
- * @var array\r
- */\r
+ /**\r
+ * A list of methods that MUST NOT have a request body, per RFC 2616\r
+ * @var array\r
+ */\r
protected static $bodyDisallowed = array('TRACE');\r
\r
- /**\r
- * Methods having defined semantics for request body\r
- *\r
- * Content-Length header (indicating that the body follows, section 4.3 of\r
- * RFC 2616) will be sent for these methods even if no body was added\r
- *\r
- * @var array\r
- * @link http://pear.php.net/bugs/bug.php?id=12900\r
- * @link http://pear.php.net/bugs/bug.php?id=14740\r
- */\r
+ /**\r
+ * Methods having defined semantics for request body\r
+ *\r
+ * Content-Length header (indicating that the body follows, section 4.3 of\r
+ * RFC 2616) will be sent for these methods even if no body was added\r
+ *\r
+ * @var array\r
+ * @link http://pear.php.net/bugs/bug.php?id=12900\r
+ * @link http://pear.php.net/bugs/bug.php?id=14740\r
+ */\r
protected static $bodyRequired = array('POST', 'PUT');\r
\r
- /**\r
- * Request being sent\r
- * @var HTTP_Request2\r
- */\r
+ /**\r
+ * Request being sent\r
+ * @var HTTP_Request2\r
+ */\r
protected $request;\r
\r
- /**\r
- * Request body\r
- * @var string|resource|HTTP_Request2_MultipartBody\r
- * @see HTTP_Request2::getBody()\r
- */\r
+ /**\r
+ * Request body\r
+ * @var string|resource|HTTP_Request2_MultipartBody\r
+ * @see HTTP_Request2::getBody()\r
+ */\r
protected $requestBody;\r
\r
- /**\r
- * Length of the request body\r
- * @var integer\r
- */\r
+ /**\r
+ * Length of the request body\r
+ * @var integer\r
+ */\r
protected $contentLength;\r
\r
- /**\r
- * Sends request to the remote server and returns its response\r
- *\r
- * @param HTTP_Request2\r
- * @return HTTP_Request2_Response\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Sends request to the remote server and returns its response\r
+ *\r
+ * @param HTTP_Request2 $request HTTP request message\r
+ *\r
+ * @return HTTP_Request2_Response\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
abstract public function sendRequest(HTTP_Request2 $request);\r
\r
- /**\r
- * Calculates length of the request body, adds proper headers\r
- *\r
- * @param array associative array of request headers, this method will\r
- * add proper 'Content-Length' and 'Content-Type' headers\r
- * to this array (or remove them if not needed)\r
- */\r
+ /**\r
+ * Calculates length of the request body, adds proper headers\r
+ *\r
+ * @param array &$headers associative array of request headers, this method\r
+ * will add proper 'Content-Length' and 'Content-Type'\r
+ * headers to this array (or remove them if not needed)\r
+ */\r
protected function calculateRequestLength(&$headers)\r
{\r
$this->requestBody = $this->request->getBody();\r
$this->requestBody->rewind();\r
}\r
\r
- if (in_array($this->request->getMethod(), self::$bodyDisallowed) ||\r
- 0 == $this->contentLength\r
+ if (in_array($this->request->getMethod(), self::$bodyDisallowed)\r
+ || 0 == $this->contentLength\r
) {\r
// No body: send a Content-Length header nonetheless (request #12900),\r
// but do that only for methods that require a body (bug #14740)\r
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Curl.php 310800 2011-05-06 07:29:56Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: Curl.php 324746 2012-04-03 15:09:16Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/**\r
/**\r
* Adapter for HTTP_Request2 wrapping around cURL extension\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter\r
{\r
- /**\r
- * Mapping of header names to cURL options\r
- * @var array\r
- */\r
+ /**\r
+ * Mapping of header names to cURL options\r
+ * @var array\r
+ */\r
protected static $headerMap = array(\r
'accept-encoding' => CURLOPT_ENCODING,\r
'cookie' => CURLOPT_COOKIE,\r
'user-agent' => CURLOPT_USERAGENT\r
);\r
\r
- /**\r
- * Mapping of SSL context options to cURL options\r
- * @var array\r
- */\r
+ /**\r
+ * Mapping of SSL context options to cURL options\r
+ * @var array\r
+ */\r
protected static $sslContextMap = array(\r
'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER,\r
'ssl_cafile' => CURLOPT_CAINFO,\r
'ssl_capath' => CURLOPT_CAPATH,\r
'ssl_local_cert' => CURLOPT_SSLCERT,\r
'ssl_passphrase' => CURLOPT_SSLCERTPASSWD\r
- );\r
+ );\r
\r
- /**\r
- * Mapping of CURLE_* constants to Exception subclasses and error codes\r
- * @var array\r
- */\r
+ /**\r
+ * Mapping of CURLE_* constants to Exception subclasses and error codes\r
+ * @var array\r
+ */\r
protected static $errorMap = array(\r
CURLE_UNSUPPORTED_PROTOCOL => array('HTTP_Request2_MessageException',\r
HTTP_Request2_Exception::NON_HTTP_REDIRECT),\r
CURLE_BAD_CONTENT_ENCODING => array('HTTP_Request2_MessageException'),\r
);\r
\r
- /**\r
- * Response being received\r
- * @var HTTP_Request2_Response\r
- */\r
+ /**\r
+ * Response being received\r
+ * @var HTTP_Request2_Response\r
+ */\r
protected $response;\r
\r
- /**\r
- * Whether 'sentHeaders' event was sent to observers\r
- * @var boolean\r
- */\r
+ /**\r
+ * Whether 'sentHeaders' event was sent to observers\r
+ * @var boolean\r
+ */\r
protected $eventSentHeaders = false;\r
\r
- /**\r
- * Whether 'receivedHeaders' event was sent to observers\r
- * @var boolean\r
- */\r
+ /**\r
+ * Whether 'receivedHeaders' event was sent to observers\r
+ * @var boolean\r
+ */\r
protected $eventReceivedHeaders = false;\r
\r
- /**\r
- * Position within request body\r
- * @var integer\r
- * @see callbackReadBody()\r
- */\r
+ /**\r
+ * Position within request body\r
+ * @var integer\r
+ * @see callbackReadBody()\r
+ */\r
protected $position = 0;\r
\r
- /**\r
- * Information about last transfer, as returned by curl_getinfo()\r
- * @var array\r
- */\r
+ /**\r
+ * Information about last transfer, as returned by curl_getinfo()\r
+ * @var array\r
+ */\r
protected $lastInfo;\r
\r
- /**\r
- * Creates a subclass of HTTP_Request2_Exception from curl error data\r
- *\r
- * @param resource curl handle\r
- * @return HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Creates a subclass of HTTP_Request2_Exception from curl error data\r
+ *\r
+ * @param resource $ch curl handle\r
+ *\r
+ * @return HTTP_Request2_Exception\r
+ */\r
protected static function wrapCurlError($ch)\r
{\r
$nativeCode = curl_errno($ch);\r
}\r
}\r
\r
- /**\r
- * Sends request to the remote server and returns its response\r
- *\r
- * @param HTTP_Request2\r
- * @return HTTP_Request2_Response\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Sends request to the remote server and returns its response\r
+ *\r
+ * @param HTTP_Request2 $request HTTP request message\r
+ *\r
+ * @return HTTP_Request2_Response\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
public function sendRequest(HTTP_Request2 $request)\r
{\r
if (!extension_loaded('curl')) {\r
return $response;\r
}\r
\r
- /**\r
- * Returns information about last transfer\r
- *\r
- * @return array associative array as returned by curl_getinfo()\r
- */\r
+ /**\r
+ * Returns information about last transfer\r
+ *\r
+ * @return array associative array as returned by curl_getinfo()\r
+ */\r
public function getInfo()\r
{\r
return $this->lastInfo;\r
}\r
\r
- /**\r
- * Creates a new cURL handle and populates it with data from the request\r
- *\r
- * @return resource a cURL handle, as created by curl_init()\r
- * @throws HTTP_Request2_LogicException\r
- */\r
+ /**\r
+ * Creates a new cURL handle and populates it with data from the request\r
+ *\r
+ * @return resource a cURL handle, as created by curl_init()\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
protected function createCurlHandle()\r
{\r
$ch = curl_init();\r
\r
// set HTTP version\r
switch ($this->request->getConfig('protocol_version')) {\r
- case '1.0':\r
- curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);\r
- break;\r
- case '1.1':\r
- curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);\r
+ case '1.0':\r
+ curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);\r
+ break;\r
+ case '1.1':\r
+ curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);\r
}\r
\r
// set request method\r
switch ($this->request->getMethod()) {\r
- case HTTP_Request2::METHOD_GET:\r
- curl_setopt($ch, CURLOPT_HTTPGET, true);\r
- break;\r
- case HTTP_Request2::METHOD_POST:\r
- curl_setopt($ch, CURLOPT_POST, true);\r
- break;\r
- case HTTP_Request2::METHOD_HEAD:\r
- curl_setopt($ch, CURLOPT_NOBODY, true);\r
- break;\r
- case HTTP_Request2::METHOD_PUT:\r
- curl_setopt($ch, CURLOPT_UPLOAD, true);\r
- break;\r
- default:\r
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());\r
+ case HTTP_Request2::METHOD_GET:\r
+ curl_setopt($ch, CURLOPT_HTTPGET, true);\r
+ break;\r
+ case HTTP_Request2::METHOD_POST:\r
+ curl_setopt($ch, CURLOPT_POST, true);\r
+ break;\r
+ case HTTP_Request2::METHOD_HEAD:\r
+ curl_setopt($ch, CURLOPT_NOBODY, true);\r
+ break;\r
+ case HTTP_Request2::METHOD_PUT:\r
+ curl_setopt($ch, CURLOPT_UPLOAD, true);\r
+ break;\r
+ default:\r
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());\r
}\r
\r
// set proxy, if needed\r
}\r
curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);\r
if ($user = $this->request->getConfig('proxy_user')) {\r
- curl_setopt($ch, CURLOPT_PROXYUSERPWD, $user . ':' .\r
- $this->request->getConfig('proxy_password'));\r
+ curl_setopt(\r
+ $ch, CURLOPT_PROXYUSERPWD,\r
+ $user . ':' . $this->request->getConfig('proxy_password')\r
+ );\r
switch ($this->request->getConfig('proxy_auth_scheme')) {\r
- case HTTP_Request2::AUTH_BASIC:\r
- curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);\r
- break;\r
- case HTTP_Request2::AUTH_DIGEST:\r
- curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);\r
+ case HTTP_Request2::AUTH_BASIC:\r
+ curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);\r
+ break;\r
+ case HTTP_Request2::AUTH_DIGEST:\r
+ curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);\r
+ }\r
+ }\r
+ if ($type = $this->request->getConfig('proxy_type')) {\r
+ switch ($type) {\r
+ case 'http':\r
+ curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);\r
+ break;\r
+ case 'socks5':\r
+ curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);\r
+ break;\r
+ default:\r
+ throw new HTTP_Request2_NotImplementedException(\r
+ "Proxy type '{$type}' is not supported"\r
+ );\r
}\r
}\r
}\r
if ($auth = $this->request->getAuth()) {\r
curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);\r
switch ($auth['scheme']) {\r
- case HTTP_Request2::AUTH_BASIC:\r
- curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);\r
- break;\r
- case HTTP_Request2::AUTH_DIGEST:\r
- curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);\r
+ case HTTP_Request2::AUTH_BASIC:\r
+ curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);\r
+ break;\r
+ case HTTP_Request2::AUTH_DIGEST:\r
+ curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);\r
}\r
}\r
\r
return $ch;\r
}\r
\r
- /**\r
- * Workaround for PHP bug #47204 that prevents rewinding request body\r
- *\r
- * The workaround consists of reading the entire request body into memory\r
- * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large\r
- * file uploads, use Socket adapter instead.\r
- *\r
- * @param resource cURL handle\r
- * @param array Request headers\r
- */\r
+ /**\r
+ * Workaround for PHP bug #47204 that prevents rewinding request body\r
+ *\r
+ * The workaround consists of reading the entire request body into memory\r
+ * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large\r
+ * file uploads, use Socket adapter instead.\r
+ *\r
+ * @param resource $ch cURL handle\r
+ * @param array &$headers Request headers\r
+ */\r
protected function workaroundPhpBug47204($ch, &$headers)\r
{\r
// no redirects, no digest auth -> probably no rewind needed\r
) {\r
curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));\r
\r
- // rewind may be needed, read the whole body into memory\r
} else {\r
+ // rewind may be needed, read the whole body into memory\r
if ($this->requestBody instanceof HTTP_Request2_MultipartBody) {\r
$this->requestBody = $this->requestBody->__toString();\r
\r
}\r
}\r
\r
- /**\r
- * Callback function called by cURL for reading the request body\r
- *\r
- * @param resource cURL handle\r
- * @param resource file descriptor (not used)\r
- * @param integer maximum length of data to return\r
- * @return string part of the request body, up to $length bytes\r
- */\r
+ /**\r
+ * Callback function called by cURL for reading the request body\r
+ *\r
+ * @param resource $ch cURL handle\r
+ * @param resource $fd file descriptor (not used)\r
+ * @param integer $length maximum length of data to return\r
+ *\r
+ * @return string part of the request body, up to $length bytes\r
+ */\r
protected function callbackReadBody($ch, $fd, $length)\r
{\r
if (!$this->eventSentHeaders) {\r
);\r
$this->eventSentHeaders = true;\r
}\r
- if (in_array($this->request->getMethod(), self::$bodyDisallowed) ||\r
- 0 == $this->contentLength || $this->position >= $this->contentLength\r
+ if (in_array($this->request->getMethod(), self::$bodyDisallowed)\r
+ || 0 == $this->contentLength || $this->position >= $this->contentLength\r
) {\r
return '';\r
}\r
return $string;\r
}\r
\r
- /**\r
- * Callback function called by cURL for saving the response headers\r
- *\r
- * @param resource cURL handle\r
- * @param string response header (with trailing CRLF)\r
- * @return integer number of bytes saved\r
- * @see HTTP_Request2_Response::parseHeaderLine()\r
- */\r
+ /**\r
+ * Callback function called by cURL for saving the response headers\r
+ *\r
+ * @param resource $ch cURL handle\r
+ * @param string $string response header (with trailing CRLF)\r
+ *\r
+ * @return integer number of bytes saved\r
+ * @see HTTP_Request2_Response::parseHeaderLine()\r
+ */\r
protected function callbackWriteHeader($ch, $string)\r
{\r
// we may receive a second set of headers if doing e.g. digest auth\r
if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {\r
// don't bother with 100-Continue responses (bug #15785)\r
- if (!$this->eventSentHeaders ||\r
- $this->response->getStatus() >= 200\r
+ if (!$this->eventSentHeaders\r
+ || $this->response->getStatus() >= 200\r
) {\r
$this->request->setLastEvent(\r
'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)\r
return strlen($string);\r
}\r
\r
- /**\r
- * Callback function called by cURL for saving the response body\r
- *\r
- * @param resource cURL handle (not used)\r
- * @param string part of the response body\r
- * @return integer number of bytes saved\r
- * @see HTTP_Request2_Response::appendBody()\r
- */\r
+ /**\r
+ * Callback function called by cURL for saving the response body\r
+ *\r
+ * @param resource $ch cURL handle (not used)\r
+ * @param string $string part of the response body\r
+ *\r
+ * @return integer number of bytes saved\r
+ * @throws HTTP_Request2_MessageException\r
+ * @see HTTP_Request2_Response::appendBody()\r
+ */\r
protected function callbackWriteBody($ch, $string)\r
{\r
// cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if\r
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Mock.php 308322 2011-02-14 13:58:03Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: Mock.php 324937 2012-04-07 10:05:57Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/**\r
* $response = $req->send();\r
* </code>\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter\r
{\r
- /**\r
- * A queue of responses to be returned by sendRequest()\r
- * @var array\r
- */\r
+ /**\r
+ * A queue of responses to be returned by sendRequest()\r
+ * @var array\r
+ */\r
protected $responses = array();\r
\r
- /**\r
- * Returns the next response from the queue built by addResponse()\r
- *\r
- * If the queue is empty it will return default empty response with status 400,\r
- * if an Exception object was added to the queue it will be thrown.\r
- *\r
- * @param HTTP_Request2\r
- * @return HTTP_Request2_Response\r
- * @throws Exception\r
- */\r
+ /**\r
+ * Returns the next response from the queue built by addResponse()\r
+ *\r
+ * Only responses without explicit URLs or with URLs equal to request URL\r
+ * will be considered. If matching response is not found or the queue is\r
+ * empty then default empty response with status 400 will be returned,\r
+ * if an Exception object was added to the queue it will be thrown.\r
+ *\r
+ * @param HTTP_Request2 $request HTTP request message\r
+ *\r
+ * @return HTTP_Request2_Response\r
+ * @throws Exception\r
+ */\r
public function sendRequest(HTTP_Request2 $request)\r
{\r
- if (count($this->responses) > 0) {\r
- $response = array_shift($this->responses);\r
- if ($response instanceof HTTP_Request2_Response) {\r
- return $response;\r
- } else {\r
- // rethrow the exception\r
- $class = get_class($response);\r
- $message = $response->getMessage();\r
- $code = $response->getCode();\r
- throw new $class($message, $code);\r
+ $requestUrl = (string)$request->getUrl();\r
+ $response = null;\r
+ foreach ($this->responses as $k => $v) {\r
+ if (!$v[1] || $requestUrl == $v[1]) {\r
+ $response = $v[0];\r
+ array_splice($this->responses, $k, 1);\r
+ break;\r
}\r
- } else {\r
+ }\r
+ if (!$response) {\r
return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");\r
+\r
+ } elseif ($response instanceof HTTP_Request2_Response) {\r
+ return $response;\r
+\r
+ } else {\r
+ // rethrow the exception\r
+ $class = get_class($response);\r
+ $message = $response->getMessage();\r
+ $code = $response->getCode();\r
+ throw new $class($message, $code);\r
}\r
}\r
\r
- /**\r
- * Adds response to the queue\r
- *\r
- * @param mixed either a string, a pointer to an open file,\r
- * an instance of HTTP_Request2_Response or Exception\r
- * @throws HTTP_Request2_Exception\r
- */\r
- public function addResponse($response)\r
+ /**\r
+ * Adds response to the queue\r
+ *\r
+ * @param mixed $response either a string, a pointer to an open file,\r
+ * an instance of HTTP_Request2_Response or Exception\r
+ * @param string $url A request URL this response should be valid for\r
+ * (see {@link http://pear.php.net/bugs/bug.php?id=19276})\r
+ *\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
+ public function addResponse($response, $url = null)\r
{\r
if (is_string($response)) {\r
$response = self::createResponseFromString($response);\r
) {\r
throw new HTTP_Request2_Exception('Parameter is not a valid response');\r
}\r
- $this->responses[] = $response;\r
+ $this->responses[] = array($response, $url);\r
}\r
\r
- /**\r
- * Creates a new HTTP_Request2_Response object from a string\r
- *\r
- * @param string\r
- * @return HTTP_Request2_Response\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Creates a new HTTP_Request2_Response object from a string\r
+ *\r
+ * @param string $str string containing HTTP response message\r
+ *\r
+ * @return HTTP_Request2_Response\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
public static function createResponseFromString($str)\r
{\r
$parts = preg_split('!(\r?\n){2}!m', $str, 2);\r
return $response;\r
}\r
\r
- /**\r
- * Creates a new HTTP_Request2_Response object from a file\r
- *\r
- * @param resource file pointer returned by fopen()\r
- * @return HTTP_Request2_Response\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Creates a new HTTP_Request2_Response object from a file\r
+ *\r
+ * @param resource $fp file pointer returned by fopen()\r
+ *\r
+ * @return HTTP_Request2_Response\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
public static function createResponseFromFile($fp)\r
{\r
$response = new HTTP_Request2_Response(fgets($fp));\r
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Socket.php 309921 2011-04-03 16:43:02Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: Socket.php 324953 2012-04-08 07:24:12Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
-/**\r
- * Base class for HTTP_Request2 adapters\r
- */\r
+/** Base class for HTTP_Request2 adapters */\r
require_once 'HTTP/Request2/Adapter.php';\r
\r
+/** Socket wrapper class */\r
+require_once 'HTTP/Request2/SocketWrapper.php';\r
+\r
/**\r
* Socket-based adapter for HTTP_Request2\r
*\r
* This adapter uses only PHP sockets and will work on almost any PHP\r
* environment. Code is based on original HTTP_Request PEAR package.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter\r
{\r
- /**\r
- * Regular expression for 'token' rule from RFC 2616\r
- */\r
+ /**\r
+ * Regular expression for 'token' rule from RFC 2616\r
+ */\r
const REGEXP_TOKEN = '[^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+';\r
\r
- /**\r
- * Regular expression for 'quoted-string' rule from RFC 2616\r
- */\r
+ /**\r
+ * Regular expression for 'quoted-string' rule from RFC 2616\r
+ */\r
const REGEXP_QUOTED_STRING = '"(?:\\\\.|[^\\\\"])*"';\r
\r
- /**\r
- * Connected sockets, needed for Keep-Alive support\r
- * @var array\r
- * @see connect()\r
- */\r
+ /**\r
+ * Connected sockets, needed for Keep-Alive support\r
+ * @var array\r
+ * @see connect()\r
+ */\r
protected static $sockets = array();\r
\r
- /**\r
- * Data for digest authentication scheme\r
- *\r
- * The keys for the array are URL prefixes.\r
- *\r
- * The values are associative arrays with data (realm, nonce, nonce-count,\r
- * opaque...) needed for digest authentication. Stored here to prevent making\r
- * duplicate requests to digest-protected resources after we have already\r
- * received the challenge.\r
- *\r
- * @var array\r
- */\r
+ /**\r
+ * Data for digest authentication scheme\r
+ *\r
+ * The keys for the array are URL prefixes.\r
+ *\r
+ * The values are associative arrays with data (realm, nonce, nonce-count,\r
+ * opaque...) needed for digest authentication. Stored here to prevent making\r
+ * duplicate requests to digest-protected resources after we have already\r
+ * received the challenge.\r
+ *\r
+ * @var array\r
+ */\r
protected static $challenges = array();\r
\r
- /**\r
- * Connected socket\r
- * @var resource\r
- * @see connect()\r
- */\r
+ /**\r
+ * Connected socket\r
+ * @var HTTP_Request2_SocketWrapper\r
+ * @see connect()\r
+ */\r
protected $socket;\r
\r
- /**\r
- * Challenge used for server digest authentication\r
- * @var array\r
- */\r
+ /**\r
+ * Challenge used for server digest authentication\r
+ * @var array\r
+ */\r
protected $serverChallenge;\r
\r
- /**\r
- * Challenge used for proxy digest authentication\r
- * @var array\r
- */\r
+ /**\r
+ * Challenge used for proxy digest authentication\r
+ * @var array\r
+ */\r
protected $proxyChallenge;\r
\r
- /**\r
- * Sum of start time and global timeout, exception will be thrown if request continues past this time\r
- * @var integer\r
- */\r
- protected $deadline = null;\r
-\r
- /**\r
- * Remaining length of the current chunk, when reading chunked response\r
- * @var integer\r
- * @see readChunked()\r
- */\r
+ /**\r
+ * Remaining length of the current chunk, when reading chunked response\r
+ * @var integer\r
+ * @see readChunked()\r
+ */\r
protected $chunkLength = 0;\r
\r
- /**\r
- * Remaining amount of redirections to follow\r
- *\r
- * Starts at 'max_redirects' configuration parameter and is reduced on each\r
- * subsequent redirect. An Exception will be thrown once it reaches zero.\r
- *\r
- * @var integer\r
- */\r
+ /**\r
+ * Remaining amount of redirections to follow\r
+ *\r
+ * Starts at 'max_redirects' configuration parameter and is reduced on each\r
+ * subsequent redirect. An Exception will be thrown once it reaches zero.\r
+ *\r
+ * @var integer\r
+ */\r
protected $redirectCountdown = null;\r
\r
- /**\r
- * Sends request to the remote server and returns its response\r
- *\r
- * @param HTTP_Request2\r
- * @return HTTP_Request2_Response\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Sends request to the remote server and returns its response\r
+ *\r
+ * @param HTTP_Request2 $request HTTP request message\r
+ *\r
+ * @return HTTP_Request2_Response\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
public function sendRequest(HTTP_Request2 $request)\r
{\r
$this->request = $request;\r
\r
- // Use global request timeout if given, see feature requests #5735, #8964\r
- if ($timeout = $request->getConfig('timeout')) {\r
- $this->deadline = time() + $timeout;\r
- } else {\r
- $this->deadline = null;\r
- }\r
-\r
try {\r
$keepAlive = $this->connect();\r
$headers = $this->prepareHeaders();\r
- if (false === @fwrite($this->socket, $headers, strlen($headers))) {\r
- throw new HTTP_Request2_MessageException('Error writing request');\r
- }\r
+ $this->socket->write($headers);\r
// provide request headers to the observer, see request #7633\r
$this->request->setLastEvent('sentHeaders', $headers);\r
$this->writeBody();\r
\r
- if ($this->deadline && time() > $this->deadline) {\r
- throw new HTTP_Request2_MessageException(\r
- 'Request timed out after ' .\r
- $request->getConfig('timeout') . ' second(s)',\r
- HTTP_Request2_Exception::TIMEOUT\r
- );\r
- }\r
-\r
$response = $this->readResponse();\r
\r
if ($jar = $request->getCookieJar()) {\r
}\r
}\r
\r
- /**\r
- * Connects to the remote server\r
- *\r
- * @return bool whether the connection can be persistent\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Connects to the remote server\r
+ *\r
+ * @return bool whether the connection can be persistent\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
protected function connect()\r
{\r
$secure = 0 == strcasecmp($this->request->getUrl()->getScheme(), 'https');\r
$reqPort = $secure? 443: 80;\r
}\r
\r
- if ($host = $this->request->getConfig('proxy_host')) {\r
+ $httpProxy = $socksProxy = false;\r
+ if (!($host = $this->request->getConfig('proxy_host'))) {\r
+ $host = $reqHost;\r
+ $port = $reqPort;\r
+ } else {\r
if (!($port = $this->request->getConfig('proxy_port'))) {\r
throw new HTTP_Request2_LogicException(\r
'Proxy port not provided',\r
HTTP_Request2_Exception::MISSING_VALUE\r
);\r
}\r
- $proxy = true;\r
- } else {\r
- $host = $reqHost;\r
- $port = $reqPort;\r
- $proxy = false;\r
+ if ('http' == ($type = $this->request->getConfig('proxy_type'))) {\r
+ $httpProxy = true;\r
+ } elseif ('socks5' == $type) {\r
+ $socksProxy = true;\r
+ } else {\r
+ throw new HTTP_Request2_NotImplementedException(\r
+ "Proxy type '{$type}' is not supported"\r
+ );\r
+ }\r
}\r
\r
- if ($tunnel && !$proxy) {\r
+ if ($tunnel && !$httpProxy) {\r
throw new HTTP_Request2_LogicException(\r
"Trying to perform CONNECT request without proxy",\r
HTTP_Request2_Exception::MISSING_VALUE\r
\r
// RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive\r
// connection token to a proxy server...\r
- if ($proxy && !$secure &&\r
- !empty($headers['connection']) && 'Keep-Alive' == $headers['connection']\r
+ if ($httpProxy && !$secure && !empty($headers['connection'])\r
+ && 'Keep-Alive' == $headers['connection']\r
) {\r
$this->request->setHeader('connection');\r
}\r
empty($headers['connection'])) ||\r
(!empty($headers['connection']) &&\r
'Keep-Alive' == $headers['connection']);\r
- $host = ((!$secure || $proxy)? 'tcp://': 'ssl://') . $host;\r
\r
$options = array();\r
if ($secure || $tunnel) {\r
ksort($options);\r
}\r
\r
+ // Use global request timeout if given, see feature requests #5735, #8964\r
+ if ($timeout = $this->request->getConfig('timeout')) {\r
+ $deadline = time() + $timeout;\r
+ } else {\r
+ $deadline = null;\r
+ }\r
+\r
// Changing SSL context options after connection is established does *not*\r
// work, we need a new connection if options change\r
- $remote = $host . ':' . $port;\r
- $socketKey = $remote . (($secure && $proxy)? "->{$reqHost}:{$reqPort}": '') .\r
- (empty($options)? '': ':' . serialize($options));\r
+ $remote = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://')\r
+ . $host . ':' . $port;\r
+ $socketKey = $remote . (\r
+ ($secure && $httpProxy || $socksProxy)\r
+ ? "->{$reqHost}:{$reqPort}" : ''\r
+ ) . (empty($options)? '': ':' . serialize($options));\r
unset($this->socket);\r
\r
// We use persistent connections and have a connected socket?\r
// Ensure that the socket is still connected, see bug #16149\r
- if ($keepAlive && !empty(self::$sockets[$socketKey]) &&\r
- !feof(self::$sockets[$socketKey])\r
+ if ($keepAlive && !empty(self::$sockets[$socketKey])\r
+ && !self::$sockets[$socketKey]->eof()\r
) {\r
$this->socket =& self::$sockets[$socketKey];\r
\r
- } elseif ($secure && $proxy && !$tunnel) {\r
- $this->establishTunnel();\r
- $this->request->setLastEvent(\r
- 'connect', "ssl://{$reqHost}:{$reqPort} via {$host}:{$port}"\r
- );\r
- self::$sockets[$socketKey] =& $this->socket;\r
-\r
} else {\r
- // Set SSL context options if doing HTTPS request or creating a tunnel\r
- $context = stream_context_create();\r
- foreach ($options as $name => $value) {\r
- if (!stream_context_set_option($context, 'ssl', $name, $value)) {\r
- throw new HTTP_Request2_LogicException(\r
- "Error setting SSL context option '{$name}'"\r
- );\r
+ if ($socksProxy) {\r
+ require_once 'HTTP/Request2/SOCKS5.php';\r
+\r
+ $this->socket = new HTTP_Request2_SOCKS5(\r
+ $remote, $this->request->getConfig('connect_timeout'),\r
+ $options, $this->request->getConfig('proxy_user'),\r
+ $this->request->getConfig('proxy_password')\r
+ );\r
+ // handle request timeouts ASAP\r
+ $this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));\r
+ $this->socket->connect($reqHost, $reqPort);\r
+ if (!$secure) {\r
+ $conninfo = "tcp://{$reqHost}:{$reqPort} via {$remote}";\r
+ } else {\r
+ $this->socket->enableCrypto();\r
+ $conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";\r
}\r
- }\r
- $track = @ini_set('track_errors', 1);\r
- $this->socket = @stream_socket_client(\r
- $remote, $errno, $errstr,\r
- $this->request->getConfig('connect_timeout'),\r
- STREAM_CLIENT_CONNECT, $context\r
- );\r
- if (!$this->socket) {\r
- $e = new HTTP_Request2_ConnectionException(\r
- "Unable to connect to {$remote}. Error: "\r
- . (empty($errstr)? $php_errormsg: $errstr), 0, $errno\r
+\r
+ } elseif ($secure && $httpProxy && !$tunnel) {\r
+ $this->establishTunnel();\r
+ $conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";\r
+\r
+ } else {\r
+ $this->socket = new HTTP_Request2_SocketWrapper(\r
+ $remote, $this->request->getConfig('connect_timeout'), $options\r
);\r
}\r
- @ini_set('track_errors', $track);\r
- if (isset($e)) {\r
- throw $e;\r
- }\r
- $this->request->setLastEvent('connect', $remote);\r
+ $this->request->setLastEvent('connect', empty($conninfo)? $remote: $conninfo);\r
self::$sockets[$socketKey] =& $this->socket;\r
}\r
+ $this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));\r
return $keepAlive;\r
}\r
\r
- /**\r
- * Establishes a tunnel to a secure remote server via HTTP CONNECT request\r
- *\r
- * This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP\r
- * sees that we are connected to a proxy server (duh!) rather than the server\r
- * that presents its certificate.\r
- *\r
- * @link http://tools.ietf.org/html/rfc2817#section-5.2\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Establishes a tunnel to a secure remote server via HTTP CONNECT request\r
+ *\r
+ * This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP\r
+ * sees that we are connected to a proxy server (duh!) rather than the server\r
+ * that presents its certificate.\r
+ *\r
+ * @link http://tools.ietf.org/html/rfc2817#section-5.2\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
protected function establishTunnel()\r
{\r
$donor = new self;\r
$connect = new HTTP_Request2(\r
$this->request->getUrl(), HTTP_Request2::METHOD_CONNECT,\r
- array_merge($this->request->getConfig(),\r
- array('adapter' => $donor))\r
+ array_merge($this->request->getConfig(), array('adapter' => $donor))\r
);\r
$response = $connect->send();\r
// Need any successful (2XX) response\r
);\r
}\r
$this->socket = $donor->socket;\r
-\r
- $modes = array(\r
- STREAM_CRYPTO_METHOD_TLS_CLIENT,\r
- STREAM_CRYPTO_METHOD_SSLv3_CLIENT,\r
- STREAM_CRYPTO_METHOD_SSLv23_CLIENT,\r
- STREAM_CRYPTO_METHOD_SSLv2_CLIENT\r
- );\r
-\r
- foreach ($modes as $mode) {\r
- if (stream_socket_enable_crypto($this->socket, true, $mode)) {\r
- return;\r
- }\r
- }\r
- throw new HTTP_Request2_ConnectionException(\r
- 'Failed to enable secure connection when connecting through proxy'\r
- );\r
+ $this->socket->enableCrypto();\r
}\r
\r
- /**\r
- * Checks whether current connection may be reused or should be closed\r
- *\r
- * @param boolean whether connection could be persistent\r
- * in the first place\r
- * @param HTTP_Request2_Response response object to check\r
- * @return boolean\r
- */\r
+ /**\r
+ * Checks whether current connection may be reused or should be closed\r
+ *\r
+ * @param boolean $requestKeepAlive whether connection could\r
+ * be persistent in the first place\r
+ * @param HTTP_Request2_Response $response response object to check\r
+ *\r
+ * @return boolean\r
+ */\r
protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response)\r
{\r
// Do not close socket on successful CONNECT request\r
- if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() &&\r
- 200 <= $response->getStatus() && 300 > $response->getStatus()\r
+ if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()\r
+ && 200 <= $response->getStatus() && 300 > $response->getStatus()\r
) {\r
return true;\r
}\r
return $requestKeepAlive && $lengthKnown && $persistent;\r
}\r
\r
- /**\r
- * Disconnects from the remote server\r
- */\r
+ /**\r
+ * Disconnects from the remote server\r
+ */\r
protected function disconnect()\r
{\r
- if (is_resource($this->socket)) {\r
- fclose($this->socket);\r
+ if (!empty($this->socket)) {\r
$this->socket = null;\r
$this->request->setLastEvent('disconnect');\r
}\r
}\r
\r
- /**\r
- * Handles HTTP redirection\r
- *\r
- * This method will throw an Exception if redirect to a non-HTTP(S) location\r
- * is attempted, also if number of redirects performed already is equal to\r
- * 'max_redirects' configuration parameter.\r
- *\r
- * @param HTTP_Request2 Original request\r
- * @param HTTP_Request2_Response Response containing redirect\r
- * @return HTTP_Request2_Response Response from a new location\r
- * @throws HTTP_Request2_Exception\r
- */\r
- protected function handleRedirect(HTTP_Request2 $request,\r
- HTTP_Request2_Response $response)\r
- {\r
+ /**\r
+ * Handles HTTP redirection\r
+ *\r
+ * This method will throw an Exception if redirect to a non-HTTP(S) location\r
+ * is attempted, also if number of redirects performed already is equal to\r
+ * 'max_redirects' configuration parameter.\r
+ *\r
+ * @param HTTP_Request2 $request Original request\r
+ * @param HTTP_Request2_Response $response Response containing redirect\r
+ *\r
+ * @return HTTP_Request2_Response Response from a new location\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
+ protected function handleRedirect(\r
+ HTTP_Request2 $request, HTTP_Request2_Response $response\r
+ ) {\r
if (is_null($this->redirectCountdown)) {\r
$this->redirectCountdown = $request->getConfig('max_redirects');\r
}\r
if (0 == $this->redirectCountdown) {\r
$this->redirectCountdown = null;\r
// Copying cURL behaviour\r
- throw new HTTP_Request2_MessageException (\r
+ throw new HTTP_Request2_MessageException(\r
'Maximum (' . $request->getConfig('max_redirects') . ') redirects followed',\r
HTTP_Request2_Exception::TOO_MANY_REDIRECTS\r
);\r
}\r
$redirect = clone $request;\r
$redirect->setUrl($redirectUrl);\r
- if (303 == $response->getStatus() || (!$request->getConfig('strict_redirects')\r
- && in_array($response->getStatus(), array(301, 302)))\r
+ if (303 == $response->getStatus()\r
+ || (!$request->getConfig('strict_redirects')\r
+ && in_array($response->getStatus(), array(301, 302)))\r
) {\r
$redirect->setMethod(HTTP_Request2::METHOD_GET);\r
$redirect->setBody('');\r
return $this->sendRequest($redirect);\r
}\r
\r
- /**\r
- * Checks whether another request should be performed with server digest auth\r
- *\r
- * Several conditions should be satisfied for it to return true:\r
- * - response status should be 401\r
- * - auth credentials should be set in the request object\r
- * - response should contain WWW-Authenticate header with digest challenge\r
- * - there is either no challenge stored for this URL or new challenge\r
- * contains stale=true parameter (in other case we probably just failed\r
- * due to invalid username / password)\r
- *\r
- * The method stores challenge values in $challenges static property\r
- *\r
- * @param HTTP_Request2_Response response to check\r
- * @return boolean whether another request should be performed\r
- * @throws HTTP_Request2_Exception in case of unsupported challenge parameters\r
- */\r
+ /**\r
+ * Checks whether another request should be performed with server digest auth\r
+ *\r
+ * Several conditions should be satisfied for it to return true:\r
+ * - response status should be 401\r
+ * - auth credentials should be set in the request object\r
+ * - response should contain WWW-Authenticate header with digest challenge\r
+ * - there is either no challenge stored for this URL or new challenge\r
+ * contains stale=true parameter (in other case we probably just failed\r
+ * due to invalid username / password)\r
+ *\r
+ * The method stores challenge values in $challenges static property\r
+ *\r
+ * @param HTTP_Request2_Response $response response to check\r
+ *\r
+ * @return boolean whether another request should be performed\r
+ * @throws HTTP_Request2_Exception in case of unsupported challenge parameters\r
+ */\r
protected function shouldUseServerDigestAuth(HTTP_Request2_Response $response)\r
{\r
// no sense repeating a request if we don't have credentials\r
$scheme = $url->getScheme();\r
$host = $scheme . '://' . $url->getHost();\r
if ($port = $url->getPort()) {\r
- if ((0 == strcasecmp($scheme, 'http') && 80 != $port) ||\r
- (0 == strcasecmp($scheme, 'https') && 443 != $port)\r
+ if ((0 == strcasecmp($scheme, 'http') && 80 != $port)\r
+ || (0 == strcasecmp($scheme, 'https') && 443 != $port)\r
) {\r
$host .= ':' . $port;\r
}\r
\r
$ret = true;\r
foreach ($prefixes as $prefix) {\r
- if (!empty(self::$challenges[$prefix]) &&\r
- (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))\r
+ if (!empty(self::$challenges[$prefix])\r
+ && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))\r
) {\r
// probably credentials are invalid\r
$ret = false;\r
return $ret;\r
}\r
\r
- /**\r
- * Checks whether another request should be performed with proxy digest auth\r
- *\r
- * Several conditions should be satisfied for it to return true:\r
- * - response status should be 407\r
- * - proxy auth credentials should be set in the request object\r
- * - response should contain Proxy-Authenticate header with digest challenge\r
- * - there is either no challenge stored for this proxy or new challenge\r
- * contains stale=true parameter (in other case we probably just failed\r
- * due to invalid username / password)\r
- *\r
- * The method stores challenge values in $challenges static property\r
- *\r
- * @param HTTP_Request2_Response response to check\r
- * @return boolean whether another request should be performed\r
- * @throws HTTP_Request2_Exception in case of unsupported challenge parameters\r
- */\r
+ /**\r
+ * Checks whether another request should be performed with proxy digest auth\r
+ *\r
+ * Several conditions should be satisfied for it to return true:\r
+ * - response status should be 407\r
+ * - proxy auth credentials should be set in the request object\r
+ * - response should contain Proxy-Authenticate header with digest challenge\r
+ * - there is either no challenge stored for this proxy or new challenge\r
+ * contains stale=true parameter (in other case we probably just failed\r
+ * due to invalid username / password)\r
+ *\r
+ * The method stores challenge values in $challenges static property\r
+ *\r
+ * @param HTTP_Request2_Response $response response to check\r
+ *\r
+ * @return boolean whether another request should be performed\r
+ * @throws HTTP_Request2_Exception in case of unsupported challenge parameters\r
+ */\r
protected function shouldUseProxyDigestAuth(HTTP_Request2_Response $response)\r
{\r
if (407 != $response->getStatus() || !$this->request->getConfig('proxy_user')) {\r
$key = 'proxy://' . $this->request->getConfig('proxy_host') .\r
':' . $this->request->getConfig('proxy_port');\r
\r
- if (!empty(self::$challenges[$key]) &&\r
- (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))\r
+ if (!empty(self::$challenges[$key])\r
+ && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))\r
) {\r
$ret = false;\r
} else {\r
return $ret;\r
}\r
\r
- /**\r
- * Extracts digest method challenge from (WWW|Proxy)-Authenticate header value\r
- *\r
- * There is a problem with implementation of RFC 2617: several of the parameters\r
- * are defined as quoted-string there and thus may contain backslash escaped\r
- * double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as\r
- * just value of quoted-string X without surrounding quotes, it doesn't speak\r
- * about removing backslash escaping.\r
- *\r
- * Now realm parameter is user-defined and human-readable, strange things\r
- * happen when it contains quotes:\r
- * - Apache allows quotes in realm, but apparently uses realm value without\r
- * backslashes for digest computation\r
- * - Squid allows (manually escaped) quotes there, but it is impossible to\r
- * authorize with either escaped or unescaped quotes used in digest,\r
- * probably it can't parse the response (?)\r
- * - Both IE and Firefox display realm value with backslashes in\r
- * the password popup and apparently use the same value for digest\r
- *\r
- * HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in\r
- * quoted-string handling, unfortunately that means failure to authorize\r
- * sometimes\r
- *\r
- * @param string value of WWW-Authenticate or Proxy-Authenticate header\r
- * @return mixed associative array with challenge parameters, false if\r
- * no challenge is present in header value\r
- * @throws HTTP_Request2_NotImplementedException in case of unsupported challenge parameters\r
- */\r
+ /**\r
+ * Extracts digest method challenge from (WWW|Proxy)-Authenticate header value\r
+ *\r
+ * There is a problem with implementation of RFC 2617: several of the parameters\r
+ * are defined as quoted-string there and thus may contain backslash escaped\r
+ * double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as\r
+ * just value of quoted-string X without surrounding quotes, it doesn't speak\r
+ * about removing backslash escaping.\r
+ *\r
+ * Now realm parameter is user-defined and human-readable, strange things\r
+ * happen when it contains quotes:\r
+ * - Apache allows quotes in realm, but apparently uses realm value without\r
+ * backslashes for digest computation\r
+ * - Squid allows (manually escaped) quotes there, but it is impossible to\r
+ * authorize with either escaped or unescaped quotes used in digest,\r
+ * probably it can't parse the response (?)\r
+ * - Both IE and Firefox display realm value with backslashes in\r
+ * the password popup and apparently use the same value for digest\r
+ *\r
+ * HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in\r
+ * quoted-string handling, unfortunately that means failure to authorize\r
+ * sometimes\r
+ *\r
+ * @param string $headerValue value of WWW-Authenticate or Proxy-Authenticate header\r
+ *\r
+ * @return mixed associative array with challenge parameters, false if\r
+ * no challenge is present in header value\r
+ * @throws HTTP_Request2_NotImplementedException in case of unsupported challenge parameters\r
+ */\r
protected function parseDigestChallenge($headerValue)\r
{\r
$authParam = '(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .\r
}\r
}\r
// we only support qop=auth\r
- if (!empty($paramsAry['qop']) &&\r
- !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))\r
+ if (!empty($paramsAry['qop'])\r
+ && !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))\r
) {\r
throw new HTTP_Request2_NotImplementedException(\r
"Only 'auth' qop is currently supported in digest authentication, " .\r
return $paramsAry;\r
}\r
\r
- /**\r
- * Parses [Proxy-]Authentication-Info header value and updates challenge\r
- *\r
- * @param array challenge to update\r
- * @param string value of [Proxy-]Authentication-Info header\r
- * @todo validate server rspauth response\r
- */\r
+ /**\r
+ * Parses [Proxy-]Authentication-Info header value and updates challenge\r
+ *\r
+ * @param array &$challenge challenge to update\r
+ * @param string $headerValue value of [Proxy-]Authentication-Info header\r
+ *\r
+ * @todo validate server rspauth response\r
+ */\r
protected function updateChallenge(&$challenge, $headerValue)\r
{\r
$authParam = '!(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .\r
}\r
}\r
\r
- /**\r
- * Creates a value for [Proxy-]Authorization header when using digest authentication\r
- *\r
- * @param string user name\r
- * @param string password\r
- * @param string request URL\r
- * @param array digest challenge parameters\r
- * @return string value of [Proxy-]Authorization request header\r
- * @link http://tools.ietf.org/html/rfc2617#section-3.2.2\r
- */\r
+ /**\r
+ * Creates a value for [Proxy-]Authorization header when using digest authentication\r
+ *\r
+ * @param string $user user name\r
+ * @param string $password password\r
+ * @param string $url request URL\r
+ * @param array &$challenge digest challenge parameters\r
+ *\r
+ * @return string value of [Proxy-]Authorization request header\r
+ * @link http://tools.ietf.org/html/rfc2617#section-3.2.2\r
+ */\r
protected function createDigestResponse($user, $password, $url, &$challenge)\r
{\r
- if (false !== ($q = strpos($url, '?')) &&\r
- $this->request->getConfig('digest_compat_ie')\r
+ if (false !== ($q = strpos($url, '?'))\r
+ && $this->request->getConfig('digest_compat_ie')\r
) {\r
$url = substr($url, 0, $q);\r
}\r
$challenge['nc'] = 1;\r
}\r
$nc = sprintf('%08x', $challenge['nc']++);\r
- $digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .\r
- $challenge['cnonce'] . ':auth:' . $a2);\r
+ $digest = md5(\r
+ $a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .\r
+ $challenge['cnonce'] . ':auth:' . $a2\r
+ );\r
}\r
return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' .\r
'realm="' . $challenge['realm'] . '", ' .\r
'');\r
}\r
\r
- /**\r
- * Adds 'Authorization' header (if needed) to request headers array\r
- *\r
- * @param array request headers\r
- * @param string request host (needed for digest authentication)\r
- * @param string request URL (needed for digest authentication)\r
- * @throws HTTP_Request2_NotImplementedException\r
- */\r
+ /**\r
+ * Adds 'Authorization' header (if needed) to request headers array\r
+ *\r
+ * @param array &$headers request headers\r
+ * @param string $requestHost request host (needed for digest authentication)\r
+ * @param string $requestUrl request URL (needed for digest authentication)\r
+ *\r
+ * @throws HTTP_Request2_NotImplementedException\r
+ */\r
protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl)\r
{\r
if (!($auth = $this->request->getAuth())) {\r
return;\r
}\r
switch ($auth['scheme']) {\r
- case HTTP_Request2::AUTH_BASIC:\r
- $headers['authorization'] =\r
- 'Basic ' . base64_encode($auth['user'] . ':' . $auth['password']);\r
- break;\r
-\r
- case HTTP_Request2::AUTH_DIGEST:\r
- unset($this->serverChallenge);\r
- $fullUrl = ('/' == $requestUrl[0])?\r
- $this->request->getUrl()->getScheme() . '://' .\r
- $requestHost . $requestUrl:\r
- $requestUrl;\r
- foreach (array_keys(self::$challenges) as $key) {\r
- if ($key == substr($fullUrl, 0, strlen($key))) {\r
- $headers['authorization'] = $this->createDigestResponse(\r
- $auth['user'], $auth['password'],\r
- $requestUrl, self::$challenges[$key]\r
- );\r
- $this->serverChallenge =& self::$challenges[$key];\r
- break;\r
- }\r
+ case HTTP_Request2::AUTH_BASIC:\r
+ $headers['authorization'] = 'Basic ' . base64_encode(\r
+ $auth['user'] . ':' . $auth['password']\r
+ );\r
+ break;\r
+\r
+ case HTTP_Request2::AUTH_DIGEST:\r
+ unset($this->serverChallenge);\r
+ $fullUrl = ('/' == $requestUrl[0])?\r
+ $this->request->getUrl()->getScheme() . '://' .\r
+ $requestHost . $requestUrl:\r
+ $requestUrl;\r
+ foreach (array_keys(self::$challenges) as $key) {\r
+ if ($key == substr($fullUrl, 0, strlen($key))) {\r
+ $headers['authorization'] = $this->createDigestResponse(\r
+ $auth['user'], $auth['password'],\r
+ $requestUrl, self::$challenges[$key]\r
+ );\r
+ $this->serverChallenge =& self::$challenges[$key];\r
+ break;\r
}\r
- break;\r
+ }\r
+ break;\r
\r
- default:\r
- throw new HTTP_Request2_NotImplementedException(\r
- "Unknown HTTP authentication scheme '{$auth['scheme']}'"\r
- );\r
+ default:\r
+ throw new HTTP_Request2_NotImplementedException(\r
+ "Unknown HTTP authentication scheme '{$auth['scheme']}'"\r
+ );\r
}\r
}\r
\r
- /**\r
- * Adds 'Proxy-Authorization' header (if needed) to request headers array\r
- *\r
- * @param array request headers\r
- * @param string request URL (needed for digest authentication)\r
- * @throws HTTP_Request2_NotImplementedException\r
- */\r
+ /**\r
+ * Adds 'Proxy-Authorization' header (if needed) to request headers array\r
+ *\r
+ * @param array &$headers request headers\r
+ * @param string $requestUrl request URL (needed for digest authentication)\r
+ *\r
+ * @throws HTTP_Request2_NotImplementedException\r
+ */\r
protected function addProxyAuthorizationHeader(&$headers, $requestUrl)\r
{\r
- if (!$this->request->getConfig('proxy_host') ||\r
- !($user = $this->request->getConfig('proxy_user')) ||\r
- (0 == strcasecmp('https', $this->request->getUrl()->getScheme()) &&\r
- HTTP_Request2::METHOD_CONNECT != $this->request->getMethod())\r
+ if (!$this->request->getConfig('proxy_host')\r
+ || !($user = $this->request->getConfig('proxy_user'))\r
+ || (0 == strcasecmp('https', $this->request->getUrl()->getScheme())\r
+ && HTTP_Request2::METHOD_CONNECT != $this->request->getMethod())\r
) {\r
return;\r
}\r
\r
$password = $this->request->getConfig('proxy_password');\r
switch ($this->request->getConfig('proxy_auth_scheme')) {\r
- case HTTP_Request2::AUTH_BASIC:\r
- $headers['proxy-authorization'] =\r
- 'Basic ' . base64_encode($user . ':' . $password);\r
- break;\r
-\r
- case HTTP_Request2::AUTH_DIGEST:\r
- unset($this->proxyChallenge);\r
- $proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .\r
- ':' . $this->request->getConfig('proxy_port');\r
- if (!empty(self::$challenges[$proxyUrl])) {\r
- $headers['proxy-authorization'] = $this->createDigestResponse(\r
- $user, $password,\r
- $requestUrl, self::$challenges[$proxyUrl]\r
- );\r
- $this->proxyChallenge =& self::$challenges[$proxyUrl];\r
- }\r
- break;\r
-\r
- default:\r
- throw new HTTP_Request2_NotImplementedException(\r
- "Unknown HTTP authentication scheme '" .\r
- $this->request->getConfig('proxy_auth_scheme') . "'"\r
+ case HTTP_Request2::AUTH_BASIC:\r
+ $headers['proxy-authorization'] = 'Basic ' . base64_encode(\r
+ $user . ':' . $password\r
+ );\r
+ break;\r
+\r
+ case HTTP_Request2::AUTH_DIGEST:\r
+ unset($this->proxyChallenge);\r
+ $proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .\r
+ ':' . $this->request->getConfig('proxy_port');\r
+ if (!empty(self::$challenges[$proxyUrl])) {\r
+ $headers['proxy-authorization'] = $this->createDigestResponse(\r
+ $user, $password,\r
+ $requestUrl, self::$challenges[$proxyUrl]\r
);\r
+ $this->proxyChallenge =& self::$challenges[$proxyUrl];\r
+ }\r
+ break;\r
+\r
+ default:\r
+ throw new HTTP_Request2_NotImplementedException(\r
+ "Unknown HTTP authentication scheme '" .\r
+ $this->request->getConfig('proxy_auth_scheme') . "'"\r
+ );\r
}\r
}\r
\r
\r
- /**\r
- * Creates the string with the Request-Line and request headers\r
- *\r
- * @return string\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Creates the string with the Request-Line and request headers\r
+ *\r
+ * @return string\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
protected function prepareHeaders()\r
{\r
$headers = $this->request->getHeaders();\r
$requestUrl = $host;\r
\r
} else {\r
- if (!$this->request->getConfig('proxy_host') ||\r
- 0 == strcasecmp($url->getScheme(), 'https')\r
+ if (!$this->request->getConfig('proxy_host')\r
+ || 'http' != $this->request->getConfig('proxy_type')\r
+ || 0 == strcasecmp($url->getScheme(), 'https')\r
) {\r
$requestUrl = '';\r
} else {\r
$requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query);\r
}\r
\r
- if ('1.1' == $this->request->getConfig('protocol_version') &&\r
- extension_loaded('zlib') && !isset($headers['accept-encoding'])\r
+ if ('1.1' == $this->request->getConfig('protocol_version')\r
+ && extension_loaded('zlib') && !isset($headers['accept-encoding'])\r
) {\r
$headers['accept-encoding'] = 'gzip, deflate';\r
}\r
return $headersStr . "\r\n";\r
}\r
\r
- /**\r
- * Sends the request body\r
- *\r
- * @throws HTTP_Request2_MessageException\r
- */\r
+ /**\r
+ * Sends the request body\r
+ *\r
+ * @throws HTTP_Request2_MessageException\r
+ */\r
protected function writeBody()\r
{\r
- if (in_array($this->request->getMethod(), self::$bodyDisallowed) ||\r
- 0 == $this->contentLength\r
+ if (in_array($this->request->getMethod(), self::$bodyDisallowed)\r
+ || 0 == $this->contentLength\r
) {\r
return;\r
}\r
} else {\r
$str = $this->requestBody->read($bufferSize);\r
}\r
- if (false === @fwrite($this->socket, $str, strlen($str))) {\r
- throw new HTTP_Request2_MessageException('Error writing request');\r
- }\r
+ $this->socket->write($str);\r
// Provide the length of written string to the observer, request #7630\r
$this->request->setLastEvent('sentBodyPart', strlen($str));\r
$position += strlen($str);\r
$this->request->setLastEvent('sentBody', $this->contentLength);\r
}\r
\r
- /**\r
- * Reads the remote server's response\r
- *\r
- * @return HTTP_Request2_Response\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Reads the remote server's response\r
+ *\r
+ * @return HTTP_Request2_Response\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
protected function readResponse()\r
{\r
$bufferSize = $this->request->getConfig('buffer_size');\r
\r
do {\r
$response = new HTTP_Request2_Response(\r
- $this->readLine($bufferSize), true, $this->request->getUrl()\r
+ $this->socket->readLine($bufferSize), true, $this->request->getUrl()\r
);\r
do {\r
- $headerLine = $this->readLine($bufferSize);\r
+ $headerLine = $this->socket->readLine($bufferSize);\r
$response->parseHeaderLine($headerLine);\r
} while ('' != $headerLine);\r
} while (in_array($response->getStatus(), array(100, 101)));\r
$this->request->setLastEvent('receivedHeaders', $response);\r
\r
// No body possible in such responses\r
- if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod() ||\r
- (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() &&\r
- 200 <= $response->getStatus() && 300 > $response->getStatus()) ||\r
- in_array($response->getStatus(), array(204, 304))\r
+ if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod()\r
+ || (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()\r
+ && 200 <= $response->getStatus() && 300 > $response->getStatus())\r
+ || in_array($response->getStatus(), array(204, 304))\r
) {\r
return $response;\r
}\r
$toRead = ($chunked || null === $length)? null: $length;\r
$this->chunkLength = 0;\r
\r
- while (!feof($this->socket) && (is_null($toRead) || 0 < $toRead)) {\r
+ while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) {\r
if ($chunked) {\r
$data = $this->readChunked($bufferSize);\r
} elseif (is_null($toRead)) {\r
- $data = $this->fread($bufferSize);\r
+ $data = $this->socket->read($bufferSize);\r
} else {\r
- $data = $this->fread(min($toRead, $bufferSize));\r
+ $data = $this->socket->read(min($toRead, $bufferSize));\r
$toRead -= strlen($data);\r
}\r
- if ('' == $data && (!$this->chunkLength || feof($this->socket))) {\r
+ if ('' == $data && (!$this->chunkLength || $this->socket->eof())) {\r
break;\r
}\r
\r
return $response;\r
}\r
\r
- /**\r
- * Reads until either the end of the socket or a newline, whichever comes first\r
- *\r
- * Strips the trailing newline from the returned data, handles global\r
- * request timeout. Method idea borrowed from Net_Socket PEAR package.\r
- *\r
- * @param int buffer size to use for reading\r
- * @return Available data up to the newline (not including newline)\r
- * @throws HTTP_Request2_MessageException In case of timeout\r
- */\r
- protected function readLine($bufferSize)\r
- {\r
- $line = '';\r
- while (!feof($this->socket)) {\r
- if ($this->deadline) {\r
- stream_set_timeout($this->socket, max($this->deadline - time(), 1));\r
- }\r
- $line .= @fgets($this->socket, $bufferSize);\r
- $info = stream_get_meta_data($this->socket);\r
- if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {\r
- $reason = $this->deadline\r
- ? 'after ' . $this->request->getConfig('timeout') . ' second(s)'\r
- : 'due to default_socket_timeout php.ini setting';\r
- throw new HTTP_Request2_MessageException(\r
- "Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT\r
- );\r
- }\r
- if (substr($line, -1) == "\n") {\r
- return rtrim($line, "\r\n");\r
- }\r
- }\r
- return $line;\r
- }\r
-\r
- /**\r
- * Wrapper around fread(), handles global request timeout\r
- *\r
- * @param int Reads up to this number of bytes\r
- * @return Data read from socket\r
- * @throws HTTP_Request2_MessageException In case of timeout\r
- */\r
- protected function fread($length)\r
- {\r
- if ($this->deadline) {\r
- stream_set_timeout($this->socket, max($this->deadline - time(), 1));\r
- }\r
- $data = fread($this->socket, $length);\r
- $info = stream_get_meta_data($this->socket);\r
- if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {\r
- $reason = $this->deadline\r
- ? 'after ' . $this->request->getConfig('timeout') . ' second(s)'\r
- : 'due to default_socket_timeout php.ini setting';\r
- throw new HTTP_Request2_MessageException(\r
- "Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT\r
- );\r
- }\r
- return $data;\r
- }\r
-\r
- /**\r
- * Reads a part of response body encoded with chunked Transfer-Encoding\r
- *\r
- * @param int buffer size to use for reading\r
- * @return string\r
- * @throws HTTP_Request2_MessageException\r
- */\r
+ /**\r
+ * Reads a part of response body encoded with chunked Transfer-Encoding\r
+ *\r
+ * @param int $bufferSize buffer size to use for reading\r
+ *\r
+ * @return string\r
+ * @throws HTTP_Request2_MessageException\r
+ */\r
protected function readChunked($bufferSize)\r
{\r
// at start of the next chunk?\r
if (0 == $this->chunkLength) {\r
- $line = $this->readLine($bufferSize);\r
+ $line = $this->socket->readLine($bufferSize);\r
if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {\r
throw new HTTP_Request2_MessageException(\r
"Cannot decode chunked response, invalid chunk length '{$line}'",\r
$this->chunkLength = hexdec($matches[1]);\r
// Chunk with zero length indicates the end\r
if (0 == $this->chunkLength) {\r
- $this->readLine($bufferSize);\r
+ $this->socket->readLine($bufferSize);\r
return '';\r
}\r
}\r
}\r
- $data = $this->fread(min($this->chunkLength, $bufferSize));\r
+ $data = $this->socket->read(min($this->chunkLength, $bufferSize));\r
$this->chunkLength -= strlen($data);\r
if (0 == $this->chunkLength) {\r
- $this->readLine($bufferSize); // Trailing CRLF\r
+ $this->socket->readLine($bufferSize); // Trailing CRLF\r
}\r
return $data;\r
}\r
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: CookieJar.php 308629 2011-02-24 17:34:24Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: CookieJar.php 324415 2012-03-21 10:50:50Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/** Class representing a HTTP request message */\r
/**\r
* Stores cookies and passes them between HTTP requests\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: @package_version@\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: @package_version@\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
class HTTP_Request2_CookieJar implements Serializable\r
{\r
- /**\r
- * Array of stored cookies\r
- *\r
- * The array is indexed by domain, path and cookie name\r
- * .example.com\r
- * /\r
- * some_cookie => cookie data\r
- * /subdir\r
- * other_cookie => cookie data\r
- * .example.org\r
- * ...\r
- *\r
- * @var array\r
- */\r
+ /**\r
+ * Array of stored cookies\r
+ *\r
+ * The array is indexed by domain, path and cookie name\r
+ * .example.com\r
+ * /\r
+ * some_cookie => cookie data\r
+ * /subdir\r
+ * other_cookie => cookie data\r
+ * .example.org\r
+ * ...\r
+ *\r
+ * @var array\r
+ */\r
protected $cookies = array();\r
\r
- /**\r
- * Whether session cookies should be serialized when serializing the jar\r
- * @var bool\r
- */\r
+ /**\r
+ * Whether session cookies should be serialized when serializing the jar\r
+ * @var bool\r
+ */\r
protected $serializeSession = false;\r
\r
- /**\r
- * Whether Public Suffix List should be used for domain matching\r
- * @var bool\r
- */\r
+ /**\r
+ * Whether Public Suffix List should be used for domain matching\r
+ * @var bool\r
+ */\r
protected $useList = true;\r
\r
- /**\r
- * Array with Public Suffix List data\r
- * @var array\r
- * @link http://publicsuffix.org/\r
- */\r
+ /**\r
+ * Array with Public Suffix List data\r
+ * @var array\r
+ * @link http://publicsuffix.org/\r
+ */\r
protected static $psl = array();\r
\r
- /**\r
- * Class constructor, sets various options\r
- *\r
- * @param bool Controls serializing session cookies, see {@link serializeSessionCookies()}\r
- * @param bool Controls using Public Suffix List, see {@link usePublicSuffixList()}\r
- */\r
- public function __construct($serializeSessionCookies = false, $usePublicSuffixList = true)\r
- {\r
+ /**\r
+ * Class constructor, sets various options\r
+ *\r
+ * @param bool $serializeSessionCookies Controls serializing session cookies,\r
+ * see {@link serializeSessionCookies()}\r
+ * @param bool $usePublicSuffixList Controls using Public Suffix List,\r
+ * see {@link usePublicSuffixList()}\r
+ */\r
+ public function __construct(\r
+ $serializeSessionCookies = false, $usePublicSuffixList = true\r
+ ) {\r
$this->serializeSessionCookies($serializeSessionCookies);\r
$this->usePublicSuffixList($usePublicSuffixList);\r
}\r
\r
- /**\r
- * Returns current time formatted in ISO-8601 at UTC timezone\r
- *\r
- * @return string\r
- */\r
+ /**\r
+ * Returns current time formatted in ISO-8601 at UTC timezone\r
+ *\r
+ * @return string\r
+ */\r
protected function now()\r
{\r
$dt = new DateTime();\r
return $dt->format(DateTime::ISO8601);\r
}\r
\r
- /**\r
- * Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields\r
- *\r
- * The checks are as follows:\r
- * - cookie array should contain 'name' and 'value' fields;\r
- * - name and value should not contain disallowed symbols;\r
- * - 'expires' should be either empty parseable by DateTime;\r
- * - 'domain' and 'path' should be either not empty or an URL where\r
- * cookie was set should be provided.\r
- * - if $setter is provided, then document at that URL should be allowed\r
- * to set a cookie for that 'domain'. If $setter is not provided,\r
- * then no domain checks will be made.\r
- *\r
- * 'expires' field will be converted to ISO8601 format from COOKIE format,\r
- * 'domain' and 'path' will be set from setter URL if empty.\r
- *\r
- * @param array cookie data, as returned by {@link HTTP_Request2_Response::getCookies()}\r
- * @param Net_URL2 URL of the document that sent Set-Cookie header\r
- * @return array Updated cookie array\r
- * @throws HTTP_Request2_LogicException\r
- * @throws HTTP_Request2_MessageException\r
- */\r
+ /**\r
+ * Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields\r
+ *\r
+ * The checks are as follows:\r
+ * - cookie array should contain 'name' and 'value' fields;\r
+ * - name and value should not contain disallowed symbols;\r
+ * - 'expires' should be either empty parseable by DateTime;\r
+ * - 'domain' and 'path' should be either not empty or an URL where\r
+ * cookie was set should be provided.\r
+ * - if $setter is provided, then document at that URL should be allowed\r
+ * to set a cookie for that 'domain'. If $setter is not provided,\r
+ * then no domain checks will be made.\r
+ *\r
+ * 'expires' field will be converted to ISO8601 format from COOKIE format,\r
+ * 'domain' and 'path' will be set from setter URL if empty.\r
+ *\r
+ * @param array $cookie cookie data, as returned by\r
+ * {@link HTTP_Request2_Response::getCookies()}\r
+ * @param Net_URL2 $setter URL of the document that sent Set-Cookie header\r
+ *\r
+ * @return array Updated cookie array\r
+ * @throws HTTP_Request2_LogicException\r
+ * @throws HTTP_Request2_MessageException\r
+ */\r
protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null)\r
{\r
if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) {\r
return $cookie;\r
}\r
\r
- /**\r
- * Stores a cookie in the jar\r
- *\r
- * @param array cookie data, as returned by {@link HTTP_Request2_Response::getCookies()}\r
- * @param Net_URL2 URL of the document that sent Set-Cookie header\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Stores a cookie in the jar\r
+ *\r
+ * @param array $cookie cookie data, as returned by\r
+ * {@link HTTP_Request2_Response::getCookies()}\r
+ * @param Net_URL2 $setter URL of the document that sent Set-Cookie header\r
+ *\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
public function store(array $cookie, Net_URL2 $setter = null)\r
{\r
$cookie = $this->checkAndUpdateFields($cookie, $setter);\r
}\r
}\r
\r
- /**\r
- * Adds cookies set in HTTP response to the jar\r
- *\r
- * @param HTTP_Request2_Response response\r
- * @param Net_URL2 original request URL, needed for setting\r
- * default domain/path\r
- */\r
+ /**\r
+ * Adds cookies set in HTTP response to the jar\r
+ *\r
+ * @param HTTP_Request2_Response $response HTTP response message\r
+ * @param Net_URL2 $setter original request URL, needed for\r
+ * setting default domain/path\r
+ */\r
public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter)\r
{\r
foreach ($response->getCookies() as $cookie) {\r
}\r
}\r
\r
- /**\r
- * Returns all cookies matching a given request URL\r
- *\r
- * The following checks are made:\r
- * - cookie domain should match request host\r
- * - cookie path should be a prefix for request path\r
- * - 'secure' cookies will only be sent for HTTPS requests\r
- *\r
- * @param Net_URL2\r
- * @param bool Whether to return cookies as string for "Cookie: " header\r
- * @return array\r
- */\r
+ /**\r
+ * Returns all cookies matching a given request URL\r
+ *\r
+ * The following checks are made:\r
+ * - cookie domain should match request host\r
+ * - cookie path should be a prefix for request path\r
+ * - 'secure' cookies will only be sent for HTTPS requests\r
+ *\r
+ * @param Net_URL2 $url Request url\r
+ * @param bool $asString Whether to return cookies as string for "Cookie: " header\r
+ *\r
+ * @return array|string Matching cookies\r
+ */\r
public function getMatching(Net_URL2 $url, $asString = false)\r
{\r
$host = $url->getHost();\r
}\r
}\r
\r
- /**\r
- * Returns all cookies stored in a jar\r
- *\r
- * @return array\r
- */\r
+ /**\r
+ * Returns all cookies stored in a jar\r
+ *\r
+ * @return array\r
+ */\r
public function getAll()\r
{\r
$cookies = array();\r
return $cookies;\r
}\r
\r
- /**\r
- * Sets whether session cookies should be serialized when serializing the jar\r
- *\r
- * @param boolean\r
- */\r
+ /**\r
+ * Sets whether session cookies should be serialized when serializing the jar\r
+ *\r
+ * @param boolean $serialize serialize?\r
+ */\r
public function serializeSessionCookies($serialize)\r
{\r
$this->serializeSession = (bool)$serialize;\r
}\r
\r
- /**\r
- * Sets whether Public Suffix List should be used for restricting cookie-setting\r
- *\r
- * Without PSL {@link domainMatch()} will only prevent setting cookies for\r
- * top-level domains like '.com' or '.org'. However, it will not prevent\r
- * setting a cookie for '.co.uk' even though only third-level registrations\r
- * are possible in .uk domain.\r
- *\r
- * With the List it is possible to find the highest level at which a domain\r
- * may be registered for a particular top-level domain and consequently\r
- * prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by\r
- * Firefox, Chrome and Opera browsers to restrict cookie setting.\r
- *\r
- * Note that PSL is licensed differently to HTTP_Request2 package (refer to\r
- * the license information in public-suffix-list.php), so you can disable\r
- * its use if this is an issue for you.\r
- *\r
- * @param boolean\r
- * @link http://publicsuffix.org/learn/\r
- */\r
+ /**\r
+ * Sets whether Public Suffix List should be used for restricting cookie-setting\r
+ *\r
+ * Without PSL {@link domainMatch()} will only prevent setting cookies for\r
+ * top-level domains like '.com' or '.org'. However, it will not prevent\r
+ * setting a cookie for '.co.uk' even though only third-level registrations\r
+ * are possible in .uk domain.\r
+ *\r
+ * With the List it is possible to find the highest level at which a domain\r
+ * may be registered for a particular top-level domain and consequently\r
+ * prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by\r
+ * Firefox, Chrome and Opera browsers to restrict cookie setting.\r
+ *\r
+ * Note that PSL is licensed differently to HTTP_Request2 package (refer to\r
+ * the license information in public-suffix-list.php), so you can disable\r
+ * its use if this is an issue for you.\r
+ *\r
+ * @param boolean $useList use the list?\r
+ *\r
+ * @link http://publicsuffix.org/learn/\r
+ */\r
public function usePublicSuffixList($useList)\r
{\r
$this->useList = (bool)$useList;\r
}\r
\r
- /**\r
- * Returns string representation of object\r
- *\r
- * @return string\r
- * @see Serializable::serialize()\r
- */\r
+ /**\r
+ * Returns string representation of object\r
+ *\r
+ * @return string\r
+ *\r
+ * @see Serializable::serialize()\r
+ */\r
public function serialize()\r
{\r
$cookies = $this->getAll();\r
));\r
}\r
\r
- /**\r
- * Constructs the object from serialized string\r
- *\r
- * @param string string representation\r
- * @see Serializable::unserialize()\r
- */\r
+ /**\r
+ * Constructs the object from serialized string\r
+ *\r
+ * @param string $serialized string representation\r
+ *\r
+ * @see Serializable::unserialize()\r
+ */\r
public function unserialize($serialized)\r
{\r
$data = unserialize($serialized);\r
}\r
}\r
\r
- /**\r
- * Checks whether a cookie domain matches a request host.\r
- *\r
- * The method is used by {@link store()} to check for whether a document\r
- * at given URL can set a cookie with a given domain attribute and by\r
- * {@link getMatching()} to find cookies matching the request URL.\r
- *\r
- * @param string request host\r
- * @param string cookie domain\r
- * @return bool match success\r
- */\r
+ /**\r
+ * Checks whether a cookie domain matches a request host.\r
+ *\r
+ * The method is used by {@link store()} to check for whether a document\r
+ * at given URL can set a cookie with a given domain attribute and by\r
+ * {@link getMatching()} to find cookies matching the request URL.\r
+ *\r
+ * @param string $requestHost request host\r
+ * @param string $cookieDomain cookie domain\r
+ *\r
+ * @return bool match success\r
+ */\r
public function domainMatch($requestHost, $cookieDomain)\r
{\r
if ($requestHost == $cookieDomain) {\r
return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain;\r
}\r
\r
- /**\r
- * Removes subdomains to get the registered domain (the first after top-level)\r
- *\r
- * The method will check Public Suffix List to find out where top-level\r
- * domain ends and registered domain starts. It will remove domain parts\r
- * to the left of registered one.\r
- *\r
- * @param string domain name\r
- * @return string|bool registered domain, will return false if $domain is\r
- * either invalid or a TLD itself\r
- */\r
+ /**\r
+ * Removes subdomains to get the registered domain (the first after top-level)\r
+ *\r
+ * The method will check Public Suffix List to find out where top-level\r
+ * domain ends and registered domain starts. It will remove domain parts\r
+ * to the left of registered one.\r
+ *\r
+ * @param string $domain domain name\r
+ *\r
+ * @return string|bool registered domain, will return false if $domain is\r
+ * either invalid or a TLD itself\r
+ */\r
public static function getRegisteredDomain($domain)\r
{\r
$domainParts = explode('.', ltrim($domain, '.'));\r
if (empty(self::$psl)) {\r
$path = '@data_dir@' . DIRECTORY_SEPARATOR . 'HTTP_Request2';\r
if (0 === strpos($path, '@' . 'data_dir@')) {\r
- $path = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'\r
- . DIRECTORY_SEPARATOR . 'data');\r
+ $path = realpath(\r
+ dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'\r
+ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data'\r
+ );\r
}\r
self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php';\r
}\r
return $result;\r
}\r
\r
- /**\r
- * Recursive helper method for {@link getRegisteredDomain()}\r
- *\r
- * @param array remaining domain parts\r
- * @param mixed node in {@link HTTP_Request2_CookieJar::$psl} to check\r
- * @return string|null concatenated domain parts, null in case of error\r
- */\r
+ /**\r
+ * Recursive helper method for {@link getRegisteredDomain()}\r
+ *\r
+ * @param array $domainParts remaining domain parts\r
+ * @param mixed $listNode node in {@link HTTP_Request2_CookieJar::$psl} to check\r
+ *\r
+ * @return string|null concatenated domain parts, null in case of error\r
+ */\r
protected static function checkDomainsList(array $domainParts, $listNode)\r
{\r
$sub = array_pop($domainParts);\r
\r
if (!is_array($listNode) || is_null($sub)\r
|| array_key_exists('!' . $sub, $listNode)\r
- ) {\r
+ ) {\r
return $sub;\r
\r
} elseif (array_key_exists($sub, $listNode)) {\r
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Exception.php 308629 2011-02-24 17:34:24Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: Exception.php 324415 2012-03-21 10:50:50Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/**\r
/**\r
* Base exception class for HTTP_Request2 package\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @version Release: 2.0.0RC1\r
- * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
+ * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132\r
*/\r
class HTTP_Request2_Exception extends PEAR_Exception\r
{\r
/** Redirect to a protocol other than http(s):// */\r
const NON_HTTP_REDIRECT = 50;\r
\r
- /**\r
- * Native error code\r
- * @var int\r
- */\r
+ /**\r
+ * Native error code\r
+ * @var int\r
+ */\r
private $_nativeCode;\r
\r
- /**\r
- * Constructor, can set package error code and native error code\r
- *\r
- * @param string exception message\r
- * @param int package error code, one of class constants\r
- * @param int error code from underlying PHP extension\r
- */\r
+ /**\r
+ * Constructor, can set package error code and native error code\r
+ *\r
+ * @param string $message exception message\r
+ * @param int $code package error code, one of class constants\r
+ * @param int $nativeCode error code from underlying PHP extension\r
+ */\r
public function __construct($message = null, $code = null, $nativeCode = null)\r
{\r
parent::__construct($message, $code);\r
$this->_nativeCode = $nativeCode;\r
}\r
\r
- /**\r
- * Returns error code produced by underlying PHP extension\r
- *\r
- * For Socket Adapter this may contain error number returned by\r
- * stream_socket_client(), for Curl Adapter this will contain error number\r
- * returned by curl_errno()\r
- *\r
- * @return integer\r
- */\r
+ /**\r
+ * Returns error code produced by underlying PHP extension\r
+ *\r
+ * For Socket Adapter this may contain error number returned by\r
+ * stream_socket_client(), for Curl Adapter this will contain error number\r
+ * returned by curl_errno()\r
+ *\r
+ * @return integer\r
+ */\r
public function getNativeCode()\r
{\r
return $this->_nativeCode;\r
/**\r
* Exception thrown in case of missing features\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
-class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception {}\r
+class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception\r
+{\r
+}\r
\r
/**\r
* Exception that represents error in the program logic\r
*\r
* The exception will usually contain a package error code.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
-class HTTP_Request2_LogicException extends HTTP_Request2_Exception {}\r
+class HTTP_Request2_LogicException extends HTTP_Request2_Exception\r
+{\r
+}\r
\r
/**\r
* Exception thrown when connection to a web or proxy server fails\r
* The exception will not contain a package error code, but will contain\r
* native error code, as returned by stream_socket_client() or curl_errno().\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
-class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception {}\r
+class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception\r
+{\r
+}\r
\r
/**\r
* Exception thrown when sending or receiving HTTP message fails\r
*\r
* The exception may contain both package error code and native error code.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
-class HTTP_Request2_MessageException extends HTTP_Request2_Exception {}\r
+class HTTP_Request2_MessageException extends HTTP_Request2_Exception\r
+{\r
+}\r
?>
\ No newline at end of file
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: MultipartBody.php 308322 2011-02-14 13:58:03Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: MultipartBody.php 324415 2012-03-21 10:50:50Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/**\r
* The class helps to reduce memory consumption by streaming large file uploads\r
* from disk, it also allows monitoring of upload progress (see request #7630)\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: 2.0.0RC1\r
- * @link http://tools.ietf.org/html/rfc1867\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
+ * @link http://tools.ietf.org/html/rfc1867\r
*/\r
class HTTP_Request2_MultipartBody\r
{\r
- /**\r
- * MIME boundary\r
- * @var string\r
- */\r
+ /**\r
+ * MIME boundary\r
+ * @var string\r
+ */\r
private $_boundary;\r
\r
- /**\r
- * Form parameters added via {@link HTTP_Request2::addPostParameter()}\r
- * @var array\r
- */\r
+ /**\r
+ * Form parameters added via {@link HTTP_Request2::addPostParameter()}\r
+ * @var array\r
+ */\r
private $_params = array();\r
\r
- /**\r
- * File uploads added via {@link HTTP_Request2::addUpload()}\r
- * @var array\r
- */\r
+ /**\r
+ * File uploads added via {@link HTTP_Request2::addUpload()}\r
+ * @var array\r
+ */\r
private $_uploads = array();\r
\r
- /**\r
- * Header for parts with parameters\r
- * @var string\r
- */\r
+ /**\r
+ * Header for parts with parameters\r
+ * @var string\r
+ */\r
private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n";\r
\r
- /**\r
- * Header for parts with uploads\r
- * @var string\r
- */\r
+ /**\r
+ * Header for parts with uploads\r
+ * @var string\r
+ */\r
private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n";\r
\r
- /**\r
- * Current position in parameter and upload arrays\r
- *\r
- * First number is index of "current" part, second number is position within\r
- * "current" part\r
- *\r
- * @var array\r
- */\r
+ /**\r
+ * Current position in parameter and upload arrays\r
+ *\r
+ * First number is index of "current" part, second number is position within\r
+ * "current" part\r
+ *\r
+ * @var array\r
+ */\r
private $_pos = array(0, 0);\r
\r
\r
- /**\r
- * Constructor. Sets the arrays with POST data.\r
- *\r
- * @param array values of form fields set via {@link HTTP_Request2::addPostParameter()}\r
- * @param array file uploads set via {@link HTTP_Request2::addUpload()}\r
- * @param bool whether to append brackets to array variable names\r
- */\r
+ /**\r
+ * Constructor. Sets the arrays with POST data.\r
+ *\r
+ * @param array $params values of form fields set via\r
+ * {@link HTTP_Request2::addPostParameter()}\r
+ * @param array $uploads file uploads set via\r
+ * {@link HTTP_Request2::addUpload()}\r
+ * @param bool $useBrackets whether to append brackets to array variable names\r
+ */\r
public function __construct(array $params, array $uploads, $useBrackets = true)\r
{\r
$this->_params = self::_flattenArray('', $params, $useBrackets);\r
}\r
}\r
\r
- /**\r
- * Returns the length of the body to use in Content-Length header\r
- *\r
- * @return integer\r
- */\r
+ /**\r
+ * Returns the length of the body to use in Content-Length header\r
+ *\r
+ * @return integer\r
+ */\r
public function getLength()\r
{\r
$boundaryLength = strlen($this->getBoundary());\r
return $length;\r
}\r
\r
- /**\r
- * Returns the boundary to use in Content-Type header\r
- *\r
- * @return string\r
- */\r
+ /**\r
+ * Returns the boundary to use in Content-Type header\r
+ *\r
+ * @return string\r
+ */\r
public function getBoundary()\r
{\r
if (empty($this->_boundary)) {\r
return $this->_boundary;\r
}\r
\r
- /**\r
- * Returns next chunk of request body\r
- *\r
- * @param integer Amount of bytes to read\r
- * @return string Up to $length bytes of data, empty string if at end\r
- */\r
+ /**\r
+ * Returns next chunk of request body\r
+ *\r
+ * @param integer $length Number of bytes to read\r
+ *\r
+ * @return string Up to $length bytes of data, empty string if at end\r
+ */\r
public function read($length)\r
{\r
$ret = '';\r
while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) {\r
$oldLength = $length;\r
if ($this->_pos[0] < $paramCount) {\r
- $param = sprintf($this->_headerParam, $boundary,\r
- $this->_params[$this->_pos[0]][0]) .\r
- $this->_params[$this->_pos[0]][1] . "\r\n";\r
+ $param = sprintf(\r
+ $this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0]\r
+ ) . $this->_params[$this->_pos[0]][1] . "\r\n";\r
$ret .= substr($param, $this->_pos[1], $length);\r
$length -= min(strlen($param) - $this->_pos[1], $length);\r
\r
} elseif ($this->_pos[0] < $paramCount + $uploadCount) {\r
$pos = $this->_pos[0] - $paramCount;\r
- $header = sprintf($this->_headerUpload, $boundary,\r
- $this->_uploads[$pos]['name'],\r
- $this->_uploads[$pos]['filename'],\r
- $this->_uploads[$pos]['type']);\r
+ $header = sprintf(\r
+ $this->_headerUpload, $boundary, $this->_uploads[$pos]['name'],\r
+ $this->_uploads[$pos]['filename'], $this->_uploads[$pos]['type']\r
+ );\r
if ($this->_pos[1] < strlen($header)) {\r
$ret .= substr($header, $this->_pos[1], $length);\r
$length -= min(strlen($header) - $this->_pos[1], $length);\r
return $ret;\r
}\r
\r
- /**\r
- * Sets the current position to the start of the body\r
- *\r
- * This allows reusing the same body in another request\r
- */\r
+ /**\r
+ * Sets the current position to the start of the body\r
+ *\r
+ * This allows reusing the same body in another request\r
+ */\r
public function rewind()\r
{\r
$this->_pos = array(0, 0);\r
}\r
}\r
\r
- /**\r
- * Returns the body as string\r
- *\r
- * Note that it reads all file uploads into memory so it is a good idea not\r
- * to use this method with large file uploads and rely on read() instead.\r
- *\r
- * @return string\r
- */\r
+ /**\r
+ * Returns the body as string\r
+ *\r
+ * Note that it reads all file uploads into memory so it is a good idea not\r
+ * to use this method with large file uploads and rely on read() instead.\r
+ *\r
+ * @return string\r
+ */\r
public function __toString()\r
{\r
$this->rewind();\r
}\r
\r
\r
- /**\r
- * Helper function to change the (probably multidimensional) associative array\r
- * into the simple one.\r
- *\r
- * @param string name for item\r
- * @param mixed item's values\r
- * @param bool whether to append [] to array variables' names\r
- * @return array array with the following items: array('item name', 'item value');\r
- */\r
+ /**\r
+ * Helper function to change the (probably multidimensional) associative array\r
+ * into the simple one.\r
+ *\r
+ * @param string $name name for item\r
+ * @param mixed $values item's values\r
+ * @param bool $useBrackets whether to append [] to array variables' names\r
+ *\r
+ * @return array array with the following items: array('item name', 'item value');\r
+ */\r
private static function _flattenArray($name, $values, $useBrackets)\r
{\r
if (!is_array($values)) {\r
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* @author David Jean Louis <izi@php.net>\r
* @author Alexey Borzov <avb@php.net>\r
* @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Log.php 308680 2011-02-25 17:40:17Z avb $\r
+ * @version SVN: $Id: Log.php 324415 2012-03-21 10:50:50Z avb $\r
* @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
* @author David Jean Louis <izi@php.net>\r
* @author Alexey Borzov <avb@php.net>\r
* @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version Release: 2.0.0RC1\r
+ * @version Release: 2.1.1\r
* @link http://pear.php.net/package/HTTP_Request2\r
*/\r
class HTTP_Request2_Observer_Log implements SplObserver\r
$this->log('> ' . $event['data'] . ' byte(s) sent');\r
break;\r
case 'receivedHeaders':\r
- $this->log(sprintf('< HTTP/%s %s %s',\r
- $event['data']->getVersion(),\r
- $event['data']->getStatus(),\r
- $event['data']->getReasonPhrase()));\r
+ $this->log(sprintf(\r
+ '< HTTP/%s %s %s', $event['data']->getVersion(),\r
+ $event['data']->getStatus(), $event['data']->getReasonPhrase()\r
+ ));\r
$headers = $event['data']->getHeader();\r
foreach ($headers as $key => $val) {\r
$this->log('< ' . $key . ': ' . $val);\r
*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* modification, are permitted provided that the following conditions\r
* are met:\r
*\r
- * * Redistributions of source code must retain the above copyright\r
+ * * Redistributions of source code must retain the above copyright\r
* notice, this list of conditions and the following disclaimer.\r
- * * Redistributions in binary form must reproduce the above copyright\r
+ * * Redistributions in binary form must reproduce the above copyright\r
* notice, this list of conditions and the following disclaimer in the\r
* documentation and/or other materials provided with the distribution.\r
- * * The names of the authors may not be used to endorse or promote products\r
+ * * The names of the authors may not be used to endorse or promote products\r
* derived from this software without specific prior written permission.\r
*\r
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Response.php 309921 2011-04-03 16:43:02Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: Response.php 324936 2012-04-07 07:49:03Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/**\r
* var_dump($response->getHeader(), $response->getCookies(), $response->getBody());\r
* </code>\r
*\r
- *\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: 2.0.0RC1\r
- * @link http://tools.ietf.org/html/rfc2616#section-6\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
+ * @link http://tools.ietf.org/html/rfc2616#section-6\r
*/\r
class HTTP_Request2_Response\r
{\r
- /**\r
- * HTTP protocol version (e.g. 1.0, 1.1)\r
- * @var string\r
- */\r
+ /**\r
+ * HTTP protocol version (e.g. 1.0, 1.1)\r
+ * @var string\r
+ */\r
protected $version;\r
\r
- /**\r
- * Status code\r
- * @var integer\r
- * @link http://tools.ietf.org/html/rfc2616#section-6.1.1\r
- */\r
+ /**\r
+ * Status code\r
+ * @var integer\r
+ * @link http://tools.ietf.org/html/rfc2616#section-6.1.1\r
+ */\r
protected $code;\r
\r
- /**\r
- * Reason phrase\r
- * @var string\r
- * @link http://tools.ietf.org/html/rfc2616#section-6.1.1\r
- */\r
+ /**\r
+ * Reason phrase\r
+ * @var string\r
+ * @link http://tools.ietf.org/html/rfc2616#section-6.1.1\r
+ */\r
protected $reasonPhrase;\r
\r
- /**\r
- * Effective URL (may be different from original request URL in case of redirects)\r
- * @var string\r
- */\r
+ /**\r
+ * Effective URL (may be different from original request URL in case of redirects)\r
+ * @var string\r
+ */\r
protected $effectiveUrl;\r
\r
- /**\r
- * Associative array of response headers\r
- * @var array\r
- */\r
+ /**\r
+ * Associative array of response headers\r
+ * @var array\r
+ */\r
protected $headers = array();\r
\r
- /**\r
- * Cookies set in the response\r
- * @var array\r
- */\r
+ /**\r
+ * Cookies set in the response\r
+ * @var array\r
+ */\r
protected $cookies = array();\r
\r
- /**\r
- * Name of last header processed by parseHederLine()\r
- *\r
- * Used to handle the headers that span multiple lines\r
- *\r
- * @var string\r
- */\r
+ /**\r
+ * Name of last header processed by parseHederLine()\r
+ *\r
+ * Used to handle the headers that span multiple lines\r
+ *\r
+ * @var string\r
+ */\r
protected $lastHeader = null;\r
\r
- /**\r
- * Response body\r
- * @var string\r
- */\r
+ /**\r
+ * Response body\r
+ * @var string\r
+ */\r
protected $body = '';\r
\r
- /**\r
- * Whether the body is still encoded by Content-Encoding\r
- *\r
- * cURL provides the decoded body to the callback; if we are reading from\r
- * socket the body is still gzipped / deflated\r
- *\r
- * @var bool\r
- */\r
+ /**\r
+ * Whether the body is still encoded by Content-Encoding\r
+ *\r
+ * cURL provides the decoded body to the callback; if we are reading from\r
+ * socket the body is still gzipped / deflated\r
+ *\r
+ * @var bool\r
+ */\r
protected $bodyEncoded;\r
\r
- /**\r
- * Associative array of HTTP status code / reason phrase.\r
- *\r
- * @var array\r
- * @link http://tools.ietf.org/html/rfc2616#section-10\r
- */\r
+ /**\r
+ * Associative array of HTTP status code / reason phrase.\r
+ *\r
+ * @var array\r
+ * @link http://tools.ietf.org/html/rfc2616#section-10\r
+ */\r
protected static $phrases = array(\r
\r
// 1xx: Informational - Request received, continuing process\r
\r
);\r
\r
- /**\r
- * Constructor, parses the response status line\r
- *\r
- * @param string Response status line (e.g. "HTTP/1.1 200 OK")\r
- * @param bool Whether body is still encoded by Content-Encoding\r
- * @param string Effective URL of the response\r
- * @throws HTTP_Request2_MessageException if status line is invalid according to spec\r
- */\r
+ /**\r
+ * Returns the default reason phrase for the given code or all reason phrases\r
+ *\r
+ * @param int $code Response code\r
+ *\r
+ * @return string|array|null Default reason phrase for $code if $code is given\r
+ * (null if no phrase is available), array of all\r
+ * reason phrases if $code is null\r
+ * @link http://pear.php.net/bugs/18716\r
+ */\r
+ public static function getDefaultReasonPhrase($code = null)\r
+ {\r
+ if (null === $code) {\r
+ return self::$phrases;\r
+ } else {\r
+ return isset(self::$phrases[$code]) ? self::$phrases[$code] : null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Constructor, parses the response status line\r
+ *\r
+ * @param string $statusLine Response status line (e.g. "HTTP/1.1 200 OK")\r
+ * @param bool $bodyEncoded Whether body is still encoded by Content-Encoding\r
+ * @param string $effectiveUrl Effective URL of the response\r
+ *\r
+ * @throws HTTP_Request2_MessageException if status line is invalid according to spec\r
+ */\r
public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null)\r
{\r
if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) {\r
HTTP_Request2_Exception::MALFORMED_RESPONSE\r
);\r
}\r
- $this->version = $m[1];\r
- $this->code = intval($m[2]);\r
- if (!empty($m[3])) {\r
- $this->reasonPhrase = trim($m[3]);\r
- } elseif (!empty(self::$phrases[$this->code])) {\r
- $this->reasonPhrase = self::$phrases[$this->code];\r
- }\r
+ $this->version = $m[1];\r
+ $this->code = intval($m[2]);\r
+ $this->reasonPhrase = !empty($m[3]) ? trim($m[3]) : self::getDefaultReasonPhrase($this->code);\r
$this->bodyEncoded = (bool)$bodyEncoded;\r
$this->effectiveUrl = (string)$effectiveUrl;\r
}\r
\r
- /**\r
- * Parses the line from HTTP response filling $headers array\r
- *\r
- * The method should be called after reading the line from socket or receiving\r
- * it into cURL callback. Passing an empty string here indicates the end of\r
- * response headers and triggers additional processing, so be sure to pass an\r
- * empty string in the end.\r
- *\r
- * @param string Line from HTTP response\r
- */\r
+ /**\r
+ * Parses the line from HTTP response filling $headers array\r
+ *\r
+ * The method should be called after reading the line from socket or receiving\r
+ * it into cURL callback. Passing an empty string here indicates the end of\r
+ * response headers and triggers additional processing, so be sure to pass an\r
+ * empty string in the end.\r
+ *\r
+ * @param string $headerLine Line from HTTP response\r
+ */\r
public function parseHeaderLine($headerLine)\r
{\r
$headerLine = trim($headerLine, "\r\n");\r
\r
- // empty string signals the end of headers, process the received ones\r
if ('' == $headerLine) {\r
+ // empty string signals the end of headers, process the received ones\r
if (!empty($this->headers['set-cookie'])) {\r
$cookies = is_array($this->headers['set-cookie'])?\r
$this->headers['set-cookie']:\r
}\r
}\r
\r
- // string of the form header-name: header value\r
} elseif (preg_match('!^([^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+):(.+)$!', $headerLine, $m)) {\r
+ // string of the form header-name: header value\r
$name = strtolower($m[1]);\r
$value = trim($m[2]);\r
if (empty($this->headers[$name])) {\r
}\r
$this->lastHeader = $name;\r
\r
- // continuation of a previous header\r
} elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {\r
+ // continuation of a previous header\r
if (!is_array($this->headers[$this->lastHeader])) {\r
$this->headers[$this->lastHeader] .= ' ' . trim($m[1]);\r
} else {\r
}\r
}\r
\r
- /**\r
- * Parses a Set-Cookie header to fill $cookies array\r
- *\r
- * @param string value of Set-Cookie header\r
- * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html\r
- */\r
+ /**\r
+ * Parses a Set-Cookie header to fill $cookies array\r
+ *\r
+ * @param string $cookieString value of Set-Cookie header\r
+ *\r
+ * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html\r
+ */\r
protected function parseCookie($cookieString)\r
{\r
$cookie = array(\r
'secure' => false\r
);\r
\r
- // Only a name=value pair\r
if (!strpos($cookieString, ';')) {\r
+ // Only a name=value pair\r
$pos = strpos($cookieString, '=');\r
$cookie['name'] = trim(substr($cookieString, 0, $pos));\r
$cookie['value'] = trim(substr($cookieString, $pos + 1));\r
\r
- // Some optional parameters are supplied\r
} else {\r
+ // Some optional parameters are supplied\r
$elements = explode(';', $cookieString);\r
$pos = strpos($elements[0], '=');\r
$cookie['name'] = trim(substr($elements[0], 0, $pos));\r
$this->cookies[] = $cookie;\r
}\r
\r
- /**\r
- * Appends a string to the response body\r
- * @param string\r
- */\r
+ /**\r
+ * Appends a string to the response body\r
+ *\r
+ * @param string $bodyChunk part of response body\r
+ */\r
public function appendBody($bodyChunk)\r
{\r
$this->body .= $bodyChunk;\r
}\r
\r
- /**\r
- * Returns the effective URL of the response\r
- *\r
- * This may be different from the request URL if redirects were followed.\r
- *\r
- * @return string\r
- * @link http://pear.php.net/bugs/bug.php?id=18412\r
- */\r
+ /**\r
+ * Returns the effective URL of the response\r
+ *\r
+ * This may be different from the request URL if redirects were followed.\r
+ *\r
+ * @return string\r
+ * @link http://pear.php.net/bugs/bug.php?id=18412\r
+ */\r
public function getEffectiveUrl()\r
{\r
return $this->effectiveUrl;\r
}\r
\r
- /**\r
- * Returns the status code\r
- * @return integer\r
- */\r
+ /**\r
+ * Returns the status code\r
+ *\r
+ * @return integer\r
+ */\r
public function getStatus()\r
{\r
return $this->code;\r
}\r
\r
- /**\r
- * Returns the reason phrase\r
- * @return string\r
- */\r
+ /**\r
+ * Returns the reason phrase\r
+ *\r
+ * @return string\r
+ */\r
public function getReasonPhrase()\r
{\r
return $this->reasonPhrase;\r
}\r
\r
- /**\r
- * Whether response is a redirect that can be automatically handled by HTTP_Request2\r
- * @return bool\r
- */\r
+ /**\r
+ * Whether response is a redirect that can be automatically handled by HTTP_Request2\r
+ *\r
+ * @return bool\r
+ */\r
public function isRedirect()\r
{\r
return in_array($this->code, array(300, 301, 302, 303, 307))\r
&& isset($this->headers['location']);\r
}\r
\r
- /**\r
- * Returns either the named header or all response headers\r
- *\r
- * @param string Name of header to return\r
- * @return string|array Value of $headerName header (null if header is\r
- * not present), array of all response headers if\r
- * $headerName is null\r
- */\r
+ /**\r
+ * Returns either the named header or all response headers\r
+ *\r
+ * @param string $headerName Name of header to return\r
+ *\r
+ * @return string|array Value of $headerName header (null if header is\r
+ * not present), array of all response headers if\r
+ * $headerName is null\r
+ */\r
public function getHeader($headerName = null)\r
{\r
if (null === $headerName) {\r
}\r
}\r
\r
- /**\r
- * Returns cookies set in response\r
- *\r
- * @return array\r
- */\r
+ /**\r
+ * Returns cookies set in response\r
+ *\r
+ * @return array\r
+ */\r
public function getCookies()\r
{\r
return $this->cookies;\r
}\r
\r
- /**\r
- * Returns the body of the response\r
- *\r
- * @return string\r
- * @throws HTTP_Request2_Exception if body cannot be decoded\r
- */\r
+ /**\r
+ * Returns the body of the response\r
+ *\r
+ * @return string\r
+ * @throws HTTP_Request2_Exception if body cannot be decoded\r
+ */\r
public function getBody()\r
{\r
- if (0 == strlen($this->body) || !$this->bodyEncoded ||\r
- !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))\r
+ if (0 == strlen($this->body) || !$this->bodyEncoded\r
+ || !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))\r
) {\r
return $this->body;\r
\r
} else {\r
if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {\r
$oldEncoding = mb_internal_encoding();\r
- mb_internal_encoding('iso-8859-1');\r
+ mb_internal_encoding('8bit');\r
}\r
\r
try {\r
switch (strtolower($this->getHeader('content-encoding'))) {\r
- case 'gzip':\r
- $decoded = self::decodeGzip($this->body);\r
- break;\r
- case 'deflate':\r
- $decoded = self::decodeDeflate($this->body);\r
+ case 'gzip':\r
+ $decoded = self::decodeGzip($this->body);\r
+ break;\r
+ case 'deflate':\r
+ $decoded = self::decodeDeflate($this->body);\r
}\r
} catch (Exception $e) {\r
}\r
}\r
}\r
\r
- /**\r
- * Get the HTTP version of the response\r
- *\r
- * @return string\r
- */\r
+ /**\r
+ * Get the HTTP version of the response\r
+ *\r
+ * @return string\r
+ */\r
public function getVersion()\r
{\r
return $this->version;\r
}\r
\r
- /**\r
- * Decodes the message-body encoded by gzip\r
- *\r
- * The real decoding work is done by gzinflate() built-in function, this\r
- * method only parses the header and checks data for compliance with\r
- * RFC 1952\r
- *\r
- * @param string gzip-encoded data\r
- * @return string decoded data\r
- * @throws HTTP_Request2_LogicException\r
- * @throws HTTP_Request2_MessageException\r
- * @link http://tools.ietf.org/html/rfc1952\r
- */\r
+ /**\r
+ * Decodes the message-body encoded by gzip\r
+ *\r
+ * The real decoding work is done by gzinflate() built-in function, this\r
+ * method only parses the header and checks data for compliance with\r
+ * RFC 1952\r
+ *\r
+ * @param string $data gzip-encoded data\r
+ *\r
+ * @return string decoded data\r
+ * @throws HTTP_Request2_LogicException\r
+ * @throws HTTP_Request2_MessageException\r
+ * @link http://tools.ietf.org/html/rfc1952\r
+ */\r
public static function decodeGzip($data)\r
{\r
$length = strlen($data);\r
return $unpacked;\r
}\r
\r
- /**\r
- * Decodes the message-body encoded by deflate\r
- *\r
- * @param string deflate-encoded data\r
- * @return string decoded data\r
- * @throws HTTP_Request2_LogicException\r
- */\r
+ /**\r
+ * Decodes the message-body encoded by deflate\r
+ *\r
+ * @param string $data deflate-encoded data\r
+ *\r
+ * @return string decoded data\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
public static function decodeDeflate($data)\r
{\r
if (!function_exists('gzuncompress')) {\r
--- /dev/null
+<?php\r
+/**\r
+ * SOCKS5 proxy connection class\r
+ *\r
+ * PHP version 5\r
+ *\r
+ * LICENSE:\r
+ *\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * The names of the authors may not be used to endorse or promote products\r
+ * derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS\r
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\r
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: SOCKS5.php 324953 2012-04-08 07:24:12Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
+ */\r
+\r
+/** Socket wrapper class used by Socket Adapter */\r
+require_once 'HTTP/Request2/SocketWrapper.php';\r
+\r
+/**\r
+ * SOCKS5 proxy connection class (used by Socket Adapter)\r
+ *\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
+ * @link http://pear.php.net/bugs/bug.php?id=19332\r
+ * @link http://tools.ietf.org/html/rfc1928\r
+ */\r
+class HTTP_Request2_SOCKS5 extends HTTP_Request2_SocketWrapper\r
+{\r
+ /**\r
+ * Constructor, tries to connect and authenticate to a SOCKS5 proxy\r
+ *\r
+ * @param string $address Proxy address, e.g. 'tcp://localhost:1080'\r
+ * @param int $timeout Connection timeout (seconds)\r
+ * @param array $sslOptions SSL context options\r
+ * @param string $username Proxy user name\r
+ * @param string $password Proxy password\r
+ *\r
+ * @throws HTTP_Request2_LogicException\r
+ * @throws HTTP_Request2_ConnectionException\r
+ * @throws HTTP_Request2_MessageException\r
+ */\r
+ public function __construct(\r
+ $address, $timeout = 10, array $sslOptions = array(),\r
+ $username = null, $password = null\r
+ ) {\r
+ parent::__construct($address, $timeout, $sslOptions);\r
+\r
+ if (strlen($username)) {\r
+ $request = pack('C4', 5, 2, 0, 2);\r
+ } else {\r
+ $request = pack('C3', 5, 1, 0);\r
+ }\r
+ $this->write($request);\r
+ $response = unpack('Cversion/Cmethod', $this->read(3));\r
+ if (5 != $response['version']) {\r
+ throw new HTTP_Request2_MessageException(\r
+ 'Invalid version received from SOCKS5 proxy: ' . $response['version'],\r
+ HTTP_Request2_Exception::MALFORMED_RESPONSE\r
+ );\r
+ }\r
+ switch ($response['method']) {\r
+ case 2:\r
+ $this->performAuthentication($username, $password);\r
+ case 0:\r
+ break;\r
+ default:\r
+ throw new HTTP_Request2_ConnectionException(\r
+ "Connection rejected by proxy due to unsupported auth method"\r
+ );\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Performs username/password authentication for SOCKS5\r
+ *\r
+ * @param string $username Proxy user name\r
+ * @param string $password Proxy password\r
+ *\r
+ * @throws HTTP_Request2_ConnectionException\r
+ * @throws HTTP_Request2_MessageException\r
+ * @link http://tools.ietf.org/html/rfc1929\r
+ */\r
+ protected function performAuthentication($username, $password)\r
+ {\r
+ $request = pack('C2', 1, strlen($username)) . $username\r
+ . pack('C', strlen($password)) . $password;\r
+\r
+ $this->write($request);\r
+ $response = unpack('Cvn/Cstatus', $this->read(3));\r
+ if (1 != $response['vn'] || 0 != $response['status']) {\r
+ throw new HTTP_Request2_ConnectionException(\r
+ 'Connection rejected by proxy due to invalid username and/or password'\r
+ );\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Connects to a remote host via proxy\r
+ *\r
+ * @param string $remoteHost Remote host\r
+ * @param int $remotePort Remote port\r
+ *\r
+ * @throws HTTP_Request2_ConnectionException\r
+ * @throws HTTP_Request2_MessageException\r
+ */\r
+ public function connect($remoteHost, $remotePort)\r
+ {\r
+ $request = pack('C5', 0x05, 0x01, 0x00, 0x03, strlen($remoteHost))\r
+ . $remoteHost . pack('n', $remotePort);\r
+\r
+ $this->write($request);\r
+ $response = unpack('Cversion/Creply/Creserved', $this->read(1024));\r
+ if (5 != $response['version'] || 0 != $response['reserved']) {\r
+ throw new HTTP_Request2_MessageException(\r
+ 'Invalid response received from SOCKS5 proxy',\r
+ HTTP_Request2_Exception::MALFORMED_RESPONSE\r
+ );\r
+ } elseif (0 != $response['reply']) {\r
+ throw new HTTP_Request2_ConnectionException(\r
+ "Unable to connect to {$remoteHost}:{$remotePort} through SOCKS5 proxy",\r
+ 0, $response['reply']\r
+ );\r
+ }\r
+ }\r
+}\r
+?>
\ No newline at end of file
--- /dev/null
+<?php\r
+/**\r
+ * Socket wrapper class used by Socket Adapter\r
+ *\r
+ * PHP version 5\r
+ *\r
+ * LICENSE:\r
+ *\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * The names of the authors may not be used to endorse or promote products\r
+ * derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS\r
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\r
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: SocketWrapper.php 324935 2012-04-07 07:10:50Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
+ */\r
+\r
+/** Exception classes for HTTP_Request2 package */\r
+require_once 'HTTP/Request2/Exception.php';\r
+\r
+/**\r
+ * Socket wrapper class used by Socket Adapter\r
+ *\r
+ * Needed to properly handle connection errors, global timeout support and\r
+ * similar things. Loosely based on Net_Socket used by older HTTP_Request.\r
+ *\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
+ * @link http://pear.php.net/bugs/bug.php?id=19332\r
+ * @link http://tools.ietf.org/html/rfc1928\r
+ */\r
+class HTTP_Request2_SocketWrapper\r
+{\r
+ /**\r
+ * PHP warning messages raised during stream_socket_client() call\r
+ * @var array\r
+ */\r
+ protected $connectionWarnings = array();\r
+\r
+ /**\r
+ * Connected socket\r
+ * @var resource\r
+ */\r
+ protected $socket;\r
+\r
+ /**\r
+ * Sum of start time and global timeout, exception will be thrown if request continues past this time\r
+ * @var integer\r
+ */\r
+ protected $deadline;\r
+\r
+ /**\r
+ * Global timeout value, mostly for exception messages\r
+ * @var integer\r
+ */\r
+ protected $timeout;\r
+\r
+ /**\r
+ * Class constructor, tries to establish connection\r
+ *\r
+ * @param string $address Address for stream_socket_client() call,\r
+ * e.g. 'tcp://localhost:80'\r
+ * @param int $timeout Connection timeout (seconds)\r
+ * @param array $sslOptions SSL context options\r
+ *\r
+ * @throws HTTP_Request2_LogicException\r
+ * @throws HTTP_Request2_ConnectionException\r
+ */\r
+ public function __construct($address, $timeout, array $sslOptions = array())\r
+ {\r
+ $context = stream_context_create();\r
+ foreach ($sslOptions as $name => $value) {\r
+ if (!stream_context_set_option($context, 'ssl', $name, $value)) {\r
+ throw new HTTP_Request2_LogicException(\r
+ "Error setting SSL context option '{$name}'"\r
+ );\r
+ }\r
+ }\r
+ set_error_handler(array($this, 'connectionWarningsHandler'));\r
+ $this->socket = stream_socket_client(\r
+ $address, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context\r
+ );\r
+ restore_error_handler();\r
+ if (!$this->socket) {\r
+ $error = $errstr ? $errstr : implode("\n", $this->connectionWarnings);\r
+ throw new HTTP_Request2_ConnectionException(\r
+ "Unable to connect to {$address}. Error: {$error}", 0, $errno\r
+ );\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Destructor, disconnects socket\r
+ */\r
+ public function __destruct()\r
+ {\r
+ fclose($this->socket);\r
+ }\r
+\r
+ /**\r
+ * Wrapper around fread(), handles global request timeout\r
+ *\r
+ * @param int $length Reads up to this number of bytes\r
+ *\r
+ * @return string Data read from socket\r
+ * @throws HTTP_Request2_MessageException In case of timeout\r
+ */\r
+ public function read($length)\r
+ {\r
+ if ($this->deadline) {\r
+ stream_set_timeout($this->socket, max($this->deadline - time(), 1));\r
+ }\r
+ $data = fread($this->socket, $length);\r
+ $this->checkTimeout();\r
+ return $data;\r
+ }\r
+\r
+ /**\r
+ * Reads until either the end of the socket or a newline, whichever comes first\r
+ *\r
+ * Strips the trailing newline from the returned data, handles global\r
+ * request timeout. Method idea borrowed from Net_Socket PEAR package.\r
+ *\r
+ * @param int $bufferSize buffer size to use for reading\r
+ *\r
+ * @return string Available data up to the newline (not including newline)\r
+ * @throws HTTP_Request2_MessageException In case of timeout\r
+ */\r
+ public function readLine($bufferSize)\r
+ {\r
+ $line = '';\r
+ while (!feof($this->socket)) {\r
+ if ($this->deadline) {\r
+ stream_set_timeout($this->socket, max($this->deadline - time(), 1));\r
+ }\r
+ $line .= @fgets($this->socket, $bufferSize);\r
+ $this->checkTimeout();\r
+ if (substr($line, -1) == "\n") {\r
+ return rtrim($line, "\r\n");\r
+ }\r
+ }\r
+ return $line;\r
+ }\r
+\r
+ /**\r
+ * Wrapper around fwrite(), handles global request timeout\r
+ *\r
+ * @param string $data String to be written\r
+ *\r
+ * @return int\r
+ * @throws HTTP_Request2_MessageException\r
+ */\r
+ public function write($data)\r
+ {\r
+ if ($this->deadline) {\r
+ stream_set_timeout($this->socket, max($this->deadline - time(), 1));\r
+ }\r
+ $written = fwrite($this->socket, $data);\r
+ $this->checkTimeout();\r
+ // http://www.php.net/manual/en/function.fwrite.php#96951\r
+ if ($written < strlen($data)) {\r
+ throw new HTTP_Request2_MessageException('Error writing request');\r
+ }\r
+ return $written;\r
+ }\r
+\r
+ /**\r
+ * Tests for end-of-file on a socket\r
+ *\r
+ * @return bool\r
+ */\r
+ public function eof()\r
+ {\r
+ return feof($this->socket);\r
+ }\r
+\r
+ /**\r
+ * Sets request deadline\r
+ *\r
+ * @param int $deadline Exception will be thrown if request continues\r
+ * past this time\r
+ * @param int $timeout Original request timeout value, to use in\r
+ * Exception message\r
+ */\r
+ public function setDeadline($deadline, $timeout)\r
+ {\r
+ $this->deadline = $deadline;\r
+ $this->timeout = $timeout;\r
+ }\r
+\r
+ /**\r
+ * Turns on encryption on a socket\r
+ *\r
+ * @throws HTTP_Request2_ConnectionException\r
+ */\r
+ public function enableCrypto()\r
+ {\r
+ $modes = array(\r
+ STREAM_CRYPTO_METHOD_TLS_CLIENT,\r
+ STREAM_CRYPTO_METHOD_SSLv3_CLIENT,\r
+ STREAM_CRYPTO_METHOD_SSLv23_CLIENT,\r
+ STREAM_CRYPTO_METHOD_SSLv2_CLIENT\r
+ );\r
+\r
+ foreach ($modes as $mode) {\r
+ if (stream_socket_enable_crypto($this->socket, true, $mode)) {\r
+ return;\r
+ }\r
+ }\r
+ throw new HTTP_Request2_ConnectionException(\r
+ 'Failed to enable secure connection when connecting through proxy'\r
+ );\r
+ }\r
+\r
+ /**\r
+ * Throws an Exception if stream timed out\r
+ *\r
+ * @throws HTTP_Request2_MessageException\r
+ */\r
+ protected function checkTimeout()\r
+ {\r
+ $info = stream_get_meta_data($this->socket);\r
+ if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {\r
+ $reason = $this->deadline\r
+ ? "after {$this->timeout} second(s)"\r
+ : 'due to default_socket_timeout php.ini setting';\r
+ throw new HTTP_Request2_MessageException(\r
+ "Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT\r
+ );\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Error handler to use during stream_socket_client() call\r
+ *\r
+ * One stream_socket_client() call may produce *multiple* PHP warnings\r
+ * (especially OpenSSL-related), we keep them in an array to later use for\r
+ * the message of HTTP_Request2_ConnectionException\r
+ *\r
+ * @param int $errno error level\r
+ * @param string $errstr error message\r
+ *\r
+ * @return bool\r
+ */\r
+ protected function connectionWarningsHandler($errno, $errstr)\r
+ {\r
+ if ($errno & E_WARNING) {\r
+ array_unshift($this->connectionWarnings, $errstr);\r
+ }\r
+ return true;\r
+ }\r
+}\r
+?>\r
+++ /dev/null
-<?php
-// +-----------------------------------------------------------------------+
-// | Copyright (c) 2002-2004, Richard Heyes |
-// | All rights reserved. |
-// | |
-// | Redistribution and use in source and binary forms, with or without |
-// | modification, are permitted provided that the following conditions |
-// | are met: |
-// | |
-// | o Redistributions of source code must retain the above copyright |
-// | notice, this list of conditions and the following disclaimer. |
-// | o Redistributions in binary form must reproduce the above copyright |
-// | notice, this list of conditions and the following disclaimer in the |
-// | documentation and/or other materials provided with the distribution.|
-// | o The names of the authors may not be used to endorse or promote |
-// | products derived from this software without specific prior written |
-// | permission. |
-// | |
-// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
-// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
-// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
-// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
-// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
-// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
-// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
-// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
-// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
-// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
-// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
-// | |
-// +-----------------------------------------------------------------------+
-// | Author: Richard Heyes <richard at php net> |
-// +-----------------------------------------------------------------------+
-//
-// $Id: URL.php,v 1.49 2007/06/28 14:43:07 davidc Exp $
-//
-// Net_URL Class
-
-
-class Net_URL
-{
- var $options = array('encode_query_keys' => false);
- /**
- * Full url
- * @var string
- */
- var $url;
-
- /**
- * Protocol
- * @var string
- */
- var $protocol;
-
- /**
- * Username
- * @var string
- */
- var $username;
-
- /**
- * Password
- * @var string
- */
- var $password;
-
- /**
- * Host
- * @var string
- */
- var $host;
-
- /**
- * Port
- * @var integer
- */
- var $port;
-
- /**
- * Path
- * @var string
- */
- var $path;
-
- /**
- * Query string
- * @var array
- */
- var $querystring;
-
- /**
- * Anchor
- * @var string
- */
- var $anchor;
-
- /**
- * Whether to use []
- * @var bool
- */
- var $useBrackets;
-
- /**
- * PHP4 Constructor
- *
- * @see __construct()
- */
- function Net_URL($url = null, $useBrackets = true)
- {
- $this->__construct($url, $useBrackets);
- }
-
- /**
- * PHP5 Constructor
- *
- * Parses the given url and stores the various parts
- * Defaults are used in certain cases
- *
- * @param string $url Optional URL
- * @param bool $useBrackets Whether to use square brackets when
- * multiple querystrings with the same name
- * exist
- */
- function __construct($url = null, $useBrackets = true)
- {
- $this->url = $url;
- $this->useBrackets = $useBrackets;
-
- $this->initialize();
- }
-
- function initialize()
- {
- $HTTP_SERVER_VARS = !empty($_SERVER) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
-
- $this->user = '';
- $this->pass = '';
- $this->host = '';
- $this->port = 80;
- $this->path = '';
- $this->querystring = array();
- $this->anchor = '';
-
- // Only use defaults if not an absolute URL given
- if (!preg_match('/^[a-z0-9]+:\/\//i', $this->url)) {
- $this->protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http');
-
- /**
- * Figure out host/port
- */
- if (!empty($HTTP_SERVER_VARS['HTTP_HOST']) &&
- preg_match('/^(.*)(:([0-9]+))?$/U', $HTTP_SERVER_VARS['HTTP_HOST'], $matches))
- {
- $host = $matches[1];
- if (!empty($matches[3])) {
- $port = $matches[3];
- } else {
- $port = $this->getStandardPort($this->protocol);
- }
- }
-
- $this->user = '';
- $this->pass = '';
- $this->host = !empty($host) ? $host : (isset($HTTP_SERVER_VARS['SERVER_NAME']) ? $HTTP_SERVER_VARS['SERVER_NAME'] : 'localhost');
- $this->port = !empty($port) ? $port : (isset($HTTP_SERVER_VARS['SERVER_PORT']) ? $HTTP_SERVER_VARS['SERVER_PORT'] : $this->getStandardPort($this->protocol));
- $this->path = !empty($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : '/';
- $this->querystring = isset($HTTP_SERVER_VARS['QUERY_STRING']) ? $this->_parseRawQuerystring($HTTP_SERVER_VARS['QUERY_STRING']) : null;
- $this->anchor = '';
- }
-
- // Parse the url and store the various parts
- if (!empty($this->url)) {
- $urlinfo = parse_url($this->url);
-
- // Default querystring
- $this->querystring = array();
-
- foreach ($urlinfo as $key => $value) {
- switch ($key) {
- case 'scheme':
- $this->protocol = $value;
- $this->port = $this->getStandardPort($value);
- break;
-
- case 'user':
- case 'pass':
- case 'host':
- case 'port':
- $this->$key = $value;
- break;
-
- case 'path':
- if ($value{0} == '/') {
- $this->path = $value;
- } else {
- $path = dirname($this->path) == DIRECTORY_SEPARATOR ? '' : dirname($this->path);
- $this->path = sprintf('%s/%s', $path, $value);
- }
- break;
-
- case 'query':
- $this->querystring = $this->_parseRawQueryString($value);
- break;
-
- case 'fragment':
- $this->anchor = $value;
- break;
- }
- }
- }
- }
- /**
- * Returns full url
- *
- * @return string Full url
- * @access public
- */
- function getURL()
- {
- $querystring = $this->getQueryString();
-
- $this->url = $this->protocol . '://'
- . $this->user . (!empty($this->pass) ? ':' : '')
- . $this->pass . (!empty($this->user) ? '@' : '')
- . $this->host . ($this->port == $this->getStandardPort($this->protocol) ? '' : ':' . $this->port)
- . $this->path
- . (!empty($querystring) ? '?' . $querystring : '')
- . (!empty($this->anchor) ? '#' . $this->anchor : '');
-
- return $this->url;
- }
-
- /**
- * Adds or updates a querystring item (URL parameter).
- * Automatically encodes parameters with rawurlencode() if $preencoded
- * is false.
- * You can pass an array to $value, it gets mapped via [] in the URL if
- * $this->useBrackets is activated.
- *
- * @param string $name Name of item
- * @param string $value Value of item
- * @param bool $preencoded Whether value is urlencoded or not, default = not
- * @access public
- */
- function addQueryString($name, $value, $preencoded = false)
- {
- if ($this->getOption('encode_query_keys')) {
- $name = rawurlencode($name);
- }
-
- if ($preencoded) {
- $this->querystring[$name] = $value;
- } else {
- $this->querystring[$name] = is_array($value) ? array_map('rawurlencode', $value): rawurlencode($value);
- }
- }
-
- /**
- * Removes a querystring item
- *
- * @param string $name Name of item
- * @access public
- */
- function removeQueryString($name)
- {
- if ($this->getOption('encode_query_keys')) {
- $name = rawurlencode($name);
- }
-
- if (isset($this->querystring[$name])) {
- unset($this->querystring[$name]);
- }
- }
-
- /**
- * Sets the querystring to literally what you supply
- *
- * @param string $querystring The querystring data. Should be of the format foo=bar&x=y etc
- * @access public
- */
- function addRawQueryString($querystring)
- {
- $this->querystring = $this->_parseRawQueryString($querystring);
- }
-
- /**
- * Returns flat querystring
- *
- * @return string Querystring
- * @access public
- */
- function getQueryString()
- {
- if (!empty($this->querystring)) {
- foreach ($this->querystring as $name => $value) {
- // Encode var name
- $name = rawurlencode($name);
-
- if (is_array($value)) {
- foreach ($value as $k => $v) {
- $querystring[] = $this->useBrackets ? sprintf('%s[%s]=%s', $name, $k, $v) : ($name . '=' . $v);
- }
- } elseif (!is_null($value)) {
- $querystring[] = $name . '=' . $value;
- } else {
- $querystring[] = $name;
- }
- }
- $querystring = implode(ini_get('arg_separator.output'), $querystring);
- } else {
- $querystring = '';
- }
-
- return $querystring;
- }
-
- /**
- * Parses raw querystring and returns an array of it
- *
- * @param string $querystring The querystring to parse
- * @return array An array of the querystring data
- * @access private
- */
- function _parseRawQuerystring($querystring)
- {
- $parts = preg_split('/[' . preg_quote(ini_get('arg_separator.input'), '/') . ']/', $querystring, -1, PREG_SPLIT_NO_EMPTY);
- $return = array();
-
- foreach ($parts as $part) {
- if (strpos($part, '=') !== false) {
- $value = substr($part, strpos($part, '=') + 1);
- $key = substr($part, 0, strpos($part, '='));
- } else {
- $value = null;
- $key = $part;
- }
-
- if (!$this->getOption('encode_query_keys')) {
- $key = rawurldecode($key);
- }
-
- if (preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $key, $matches)) {
- $key = $matches[1];
- $idx = $matches[2];
-
- // Ensure is an array
- if (empty($return[$key]) || !is_array($return[$key])) {
- $return[$key] = array();
- }
-
- // Add data
- if ($idx === '') {
- $return[$key][] = $value;
- } else {
- $return[$key][$idx] = $value;
- }
- } elseif (!$this->useBrackets AND !empty($return[$key])) {
- $return[$key] = (array)$return[$key];
- $return[$key][] = $value;
- } else {
- $return[$key] = $value;
- }
- }
-
- return $return;
- }
-
- /**
- * Resolves //, ../ and ./ from a path and returns
- * the result. Eg:
- *
- * /foo/bar/../boo.php => /foo/boo.php
- * /foo/bar/../../boo.php => /boo.php
- * /foo/bar/.././/boo.php => /foo/boo.php
- *
- * This method can also be called statically.
- *
- * @param string $path URL path to resolve
- * @return string The result
- */
- function resolvePath($path)
- {
- $path = explode('/', str_replace('//', '/', $path));
-
- for ($i=0; $i<count($path); $i++) {
- if ($path[$i] == '.') {
- unset($path[$i]);
- $path = array_values($path);
- $i--;
-
- } elseif ($path[$i] == '..' AND ($i > 1 OR ($i == 1 AND $path[0] != '') ) ) {
- unset($path[$i]);
- unset($path[$i-1]);
- $path = array_values($path);
- $i -= 2;
-
- } elseif ($path[$i] == '..' AND $i == 1 AND $path[0] == '') {
- unset($path[$i]);
- $path = array_values($path);
- $i--;
-
- } else {
- continue;
- }
- }
-
- return implode('/', $path);
- }
-
- /**
- * Returns the standard port number for a protocol
- *
- * @param string $scheme The protocol to lookup
- * @return integer Port number or NULL if no scheme matches
- *
- * @author Philippe Jausions <Philippe.Jausions@11abacus.com>
- */
- function getStandardPort($scheme)
- {
- switch (strtolower($scheme)) {
- case 'http': return 80;
- case 'https': return 443;
- case 'ftp': return 21;
- case 'imap': return 143;
- case 'imaps': return 993;
- case 'pop3': return 110;
- case 'pop3s': return 995;
- default: return null;
- }
- }
-
- /**
- * Forces the URL to a particular protocol
- *
- * @param string $protocol Protocol to force the URL to
- * @param integer $port Optional port (standard port is used by default)
- */
- function setProtocol($protocol, $port = null)
- {
- $this->protocol = $protocol;
- $this->port = is_null($port) ? $this->getStandardPort($protocol) : $port;
- }
-
- /**
- * Set an option
- *
- * This function set an option
- * to be used thorough the script.
- *
- * @access public
- * @param string $optionName The optionname to set
- * @param string $value The value of this option.
- */
- function setOption($optionName, $value)
- {
- if (!array_key_exists($optionName, $this->options)) {
- return false;
- }
-
- $this->options[$optionName] = $value;
- $this->initialize();
- }
-
- /**
- * Get an option
- *
- * This function gets an option
- * from the $this->options array
- * and return it's value.
- *
- * @access public
- * @param string $opionName The name of the option to retrieve
- * @see $this->options
- */
- function getOption($optionName)
- {
- if (!isset($this->options[$optionName])) {
- return false;
- }
-
- return $this->options[$optionName];
- }
-
-}
-?>
* * 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,
*
* @category Networking
* @package Net_URL2
- * @author Christian Schmidt <chsc@peytz.dk>
- * @copyright 2007-2008 Peytz & Co. A/S
+ * @author Christian Schmidt <schmidt@php.net>
+ * @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
*/
*
* @category Networking
* @package Net_URL2
- * @author Christian Schmidt <chsc@peytz.dk>
- * @copyright 2007-2008 Peytz & Co. ApS
+ * @author Christian Schmidt <schmidt@php.net>
+ * @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
/**
* 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';
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 => '&',
);
/**
private $_host = false;
/**
- * @var int|bool
+ * @var string|bool
*/
private $_port = false;
*
* @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);
}
/**
$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
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.
* 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;
}
/**
* @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)
{
if ($password !== false) {
$this->_userinfo .= ':' . $password;
}
+ return $this;
}
/**
*
* @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()
{
* 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;
}
/**
* with userinfo prefixed and port number
* appended, e.g. "foo:bar@example.org:81".
*
- * @return void
+ * @return $this
*/
public function setAuthority($authority)
{
$this->_host = $reg[3];
if (isset($reg[5])) {
- $this->_port = intval($reg[5]);
+ $this->_port = $reg[5];
}
}
+ return $this;
}
/**
*
* @param string $path a path
*
- * @return void
+ * @return $this
*/
public function setPath($path)
{
$this->_path = $path;
+ return $this;
}
/**
*
* @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;
}
/**
* @param string|bool $fragment a fragment excluding the leading "#", or
* false
*
- * @return void
+ * @return $this
*/
public function setFragment($fragment)
{
$this->_fragment = $fragment;
+ return $this;
}
/**
*
* @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;
}
/**
* @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;
}
/**
// 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
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()
$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) {
}
/**
- * Sets the specified option.
+ * Returns the value of the specified option.
*
- * @param string $optionName a self::OPTION_ constant
- * @param mixed $value option value
+ * @param string $optionName The name of the option to retrieve
*
- * @return void
- * @see self::OPTION_STRICT
- * @see self::OPTION_USE_BRACKETS
- * @see self::OPTION_ENCODE_KEYS
+ * @return mixed
*/
- function setOption($optionName, $value)
+ public function getOption($optionName)
{
- if (!array_key_exists($optionName, $this->_options)) {
- return false;
- }
- $this->_options[$optionName] = $value;
+ return isset($this->_options[$optionName])
+ ? $this->_options[$optionName] : false;
}
/**
- * Returns the value of the specified option.
+ * A simple version of http_build_query in userland. The encoded string is
+ * percentage encoded according to RFC 3986.
*
- * @param string $optionName The name of the option to retrieve
+ * @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 mixed
+ * @return string
*/
- function getOption($optionName)
+ protected function buildQuery(array $data, $separator, $key = null)
{
- return isset($this->_options[$optionName])
- ? $this->_options[$optionName] : false;
+ $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;
}
}
--- /dev/null
+<?php\r
+/**\r
+ * Helper file for downloading Public Suffix List and converting it to PHP array\r
+ *\r
+ * You can run this script to update PSL to the current version instead of\r
+ * waiting for a new release of HTTP_Request2.\r
+ *\r
+ * @version SVN: $Id: generate-list.php 308480 2011-02-19 11:27:13Z avb $\r
+ */\r
+\r
+/** URL to download Public Suffix List from */\r
+define('LIST_URL', 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1');\r
+/** Name of PHP file to write */\r
+define('OUTPUT_FILE', dirname(__FILE__) . '/public-suffix-list.php');\r
+\r
+require_once 'HTTP/Request2.php';\r
+\r
+function buildSubdomain(&$node, $tldParts)\r
+{\r
+ $part = trim(array_pop($tldParts));\r
+\r
+ if (!array_key_exists($part, $node)) {\r
+ $node[$part] = array();\r
+ }\r
+\r
+ if (0 < count($tldParts)) {\r
+ buildSubdomain($node[$part], $tldParts);\r
+ }\r
+}\r
+\r
+function writeNode($fp, $valueTree, $key = null, $indent = 0)\r
+{\r
+ if (is_null($key)) {\r
+ fwrite($fp, "return ");\r
+\r
+ } else {\r
+ fwrite($fp, str_repeat(' ', $indent) . "'$key' => ");\r
+ }\r
+\r
+ if (0 == ($count = count($valueTree))) {\r
+ fwrite($fp, 'true');\r
+ } else {\r
+ fwrite($fp, "array(\n");\r
+ for ($keys = array_keys($valueTree), $i = 0; $i < $count; $i++) {\r
+ writeNode($fp, $valueTree[$keys[$i]], $keys[$i], $indent + 1);\r
+ if ($i + 1 != $count) {\r
+ fwrite($fp, ",\n");\r
+ } else {\r
+ fwrite($fp, "\n");\r
+ }\r
+ }\r
+ fwrite($fp, str_repeat(' ', $indent) . ")");\r
+ }\r
+}\r
+\r
+\r
+try {\r
+ $request = new HTTP_Request2(LIST_URL);\r
+ $response = $request->send();\r
+ if (200 != $response->getStatus()) {\r
+ throw new Exception("List download URL returned status: " .\r
+ $response->getStatus() . ' ' . $response->getReasonPhrase());\r
+ }\r
+ $list = $response->getBody();\r
+ if (false === strpos($list, 'The Original Code is the Public Suffix List.')) {\r
+ throw new Exception("List download URL does not contain expected phrase");\r
+ }\r
+ if (!($fp = @fopen(OUTPUT_FILE, 'wt'))) {\r
+ throw new Exception("Unable to open " . OUTPUT_FILE);\r
+ }\r
+\r
+} catch (Exception $e) {\r
+ die($e->getMessage());\r
+}\r
+\r
+$tldTree = array();\r
+$license = true;\r
+\r
+fwrite($fp, "<?php\n");\r
+\r
+foreach (array_filter(array_map('trim', explode("\n", $list))) as $line) {\r
+ if ('//' != substr($line, 0, 2)) {\r
+ buildSubdomain($tldTree, explode('.', $line));\r
+\r
+ } elseif ($license) {\r
+ fwrite($fp, $line . "\n");\r
+\r
+ if (0 === strpos($line, "// ***** END LICENSE BLOCK")) {\r
+ $license = false;\r
+ fwrite($fp, "\n");\r
+ }\r
+ }\r
+}\r
+\r
+writeNode($fp, $tldTree);\r
+fwrite($fp, ";\n?>");\r
+fclose($fp);\r
+?>
\ No newline at end of file
--- /dev/null
+<?php\r
+// ***** BEGIN LICENSE BLOCK *****\r
+// Version: MPL 1.1/GPL 2.0/LGPL 2.1\r
+//\r
+// The contents of this file are subject to the Mozilla Public License Version\r
+// 1.1 (the "License"); you may not use this file except in compliance with\r
+// the License. You may obtain a copy of the License at\r
+// http://www.mozilla.org/MPL/\r
+//\r
+// Software distributed under the License is distributed on an "AS IS" basis,\r
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
+// for the specific language governing rights and limitations under the\r
+// License.\r
+//\r
+// The Original Code is the Public Suffix List.\r
+//\r
+// The Initial Developer of the Original Code is\r
+// Jo Hermans <jo.hermans@gmail.com>.\r
+// Portions created by the Initial Developer are Copyright (C) 2007\r
+// the Initial Developer. All Rights Reserved.\r
+//\r
+// Contributor(s):\r
+// Ruben Arakelyan <ruben@rubenarakelyan.com>\r
+// Gervase Markham <gerv@gerv.net>\r
+// Pamela Greene <pamg.bugs@gmail.com>\r
+// David Triendl <david@triendl.name>\r
+// Jothan Frakes <jothan@gmail.com>\r
+// The kind representatives of many TLD registries\r
+//\r
+// Alternatively, the contents of this file may be used under the terms of\r
+// either the GNU General Public License Version 2 or later (the "GPL"), or\r
+// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\r
+// in which case the provisions of the GPL or the LGPL are applicable instead\r
+// of those above. If you wish to allow use of your version of this file only\r
+// under the terms of either the GPL or the LGPL, and not to allow others to\r
+// use your version of this file under the terms of the MPL, indicate your\r
+// decision by deleting the provisions above and replace them with the notice\r
+// and other provisions required by the GPL or the LGPL. If you do not delete\r
+// the provisions above, a recipient may use your version of this file under\r
+// the terms of any one of the MPL, the GPL or the LGPL.\r
+//\r
+// ***** END LICENSE BLOCK *****\r
+\r
+return array(\r
+ 'ac' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'mil' => true,\r
+ 'org' => true\r
+ ),\r
+ 'ad' => array(\r
+ 'nom' => true\r
+ ),\r
+ 'ae' => array(\r
+ 'co' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'sch' => true,\r
+ 'ac' => true,\r
+ 'gov' => true,\r
+ 'mil' => true\r
+ ),\r
+ 'aero' => array(\r
+ 'accident-investigation' => true,\r
+ 'accident-prevention' => true,\r
+ 'aerobatic' => true,\r
+ 'aeroclub' => true,\r
+ 'aerodrome' => true,\r
+ 'agents' => true,\r
+ 'aircraft' => true,\r
+ 'airline' => true,\r
+ 'airport' => true,\r
+ 'air-surveillance' => true,\r
+ 'airtraffic' => true,\r
+ 'air-traffic-control' => true,\r
+ 'ambulance' => true,\r
+ 'amusement' => true,\r
+ 'association' => true,\r
+ 'author' => true,\r
+ 'ballooning' => true,\r
+ 'broker' => true,\r
+ 'caa' => true,\r
+ 'cargo' => true,\r
+ 'catering' => true,\r
+ 'certification' => true,\r
+ 'championship' => true,\r
+ 'charter' => true,\r
+ 'civilaviation' => true,\r
+ 'club' => true,\r
+ 'conference' => true,\r
+ 'consultant' => true,\r
+ 'consulting' => true,\r
+ 'control' => true,\r
+ 'council' => true,\r
+ 'crew' => true,\r
+ 'design' => true,\r
+ 'dgca' => true,\r
+ 'educator' => true,\r
+ 'emergency' => true,\r
+ 'engine' => true,\r
+ 'engineer' => true,\r
+ 'entertainment' => true,\r
+ 'equipment' => true,\r
+ 'exchange' => true,\r
+ 'express' => true,\r
+ 'federation' => true,\r
+ 'flight' => true,\r
+ 'freight' => true,\r
+ 'fuel' => true,\r
+ 'gliding' => true,\r
+ 'government' => true,\r
+ 'groundhandling' => true,\r
+ 'group' => true,\r
+ 'hanggliding' => true,\r
+ 'homebuilt' => true,\r
+ 'insurance' => true,\r
+ 'journal' => true,\r
+ 'journalist' => true,\r
+ 'leasing' => true,\r
+ 'logistics' => true,\r
+ 'magazine' => true,\r
+ 'maintenance' => true,\r
+ 'marketplace' => true,\r
+ 'media' => true,\r
+ 'microlight' => true,\r
+ 'modelling' => true,\r
+ 'navigation' => true,\r
+ 'parachuting' => true,\r
+ 'paragliding' => true,\r
+ 'passenger-association' => true,\r
+ 'pilot' => true,\r
+ 'press' => true,\r
+ 'production' => true,\r
+ 'recreation' => true,\r
+ 'repbody' => true,\r
+ 'res' => true,\r
+ 'research' => true,\r
+ 'rotorcraft' => true,\r
+ 'safety' => true,\r
+ 'scientist' => true,\r
+ 'services' => true,\r
+ 'show' => true,\r
+ 'skydiving' => true,\r
+ 'software' => true,\r
+ 'student' => true,\r
+ 'taxi' => true,\r
+ 'trader' => true,\r
+ 'trading' => true,\r
+ 'trainer' => true,\r
+ 'union' => true,\r
+ 'workinggroup' => true,\r
+ 'works' => true\r
+ ),\r
+ 'af' => array(\r
+ 'gov' => true,\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'edu' => true\r
+ ),\r
+ 'ag' => array(\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'co' => true,\r
+ 'nom' => true\r
+ ),\r
+ 'ai' => array(\r
+ 'off' => true,\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'al' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'am' => true,\r
+ 'an' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true\r
+ ),\r
+ 'ao' => array(\r
+ 'ed' => true,\r
+ 'gv' => true,\r
+ 'og' => true,\r
+ 'co' => true,\r
+ 'pb' => true,\r
+ 'it' => true\r
+ ),\r
+ 'aq' => true,\r
+ 'ar' => array(\r
+ '*' => true,\r
+ '!congresodelalengua3' => true,\r
+ '!educ' => true,\r
+ '!gobiernoelectronico' => true,\r
+ '!mecon' => true,\r
+ '!nacion' => true,\r
+ '!nic' => true,\r
+ '!promocion' => true,\r
+ '!retina' => true,\r
+ '!uba' => true\r
+ ),\r
+ 'arpa' => array(\r
+ 'e164' => true,\r
+ 'in-addr' => true,\r
+ 'ip6' => true,\r
+ 'iris' => true,\r
+ 'uri' => true,\r
+ 'urn' => true\r
+ ),\r
+ 'as' => array(\r
+ 'gov' => true\r
+ ),\r
+ 'asia' => true,\r
+ 'at' => array(\r
+ 'ac' => true,\r
+ 'co' => true,\r
+ 'gv' => true,\r
+ 'or' => true,\r
+ 'biz' => true,\r
+ 'info' => true,\r
+ 'priv' => true\r
+ ),\r
+ 'au' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => array(\r
+ 'act' => true,\r
+ 'nsw' => true,\r
+ 'nt' => true,\r
+ 'qld' => true,\r
+ 'sa' => true,\r
+ 'tas' => true,\r
+ 'vic' => true,\r
+ 'wa' => true\r
+ ),\r
+ 'gov' => array(\r
+ 'act' => true,\r
+ 'nt' => true,\r
+ 'qld' => true,\r
+ 'sa' => true,\r
+ 'tas' => true,\r
+ 'vic' => true,\r
+ 'wa' => true\r
+ ),\r
+ 'csiro' => true,\r
+ 'asn' => true,\r
+ 'id' => true,\r
+ 'info' => true,\r
+ 'conf' => true,\r
+ 'oz' => true,\r
+ 'act' => true,\r
+ 'nsw' => true,\r
+ 'nt' => true,\r
+ 'qld' => true,\r
+ 'sa' => true,\r
+ 'tas' => true,\r
+ 'vic' => true,\r
+ 'wa' => true\r
+ ),\r
+ 'aw' => array(\r
+ 'com' => true\r
+ ),\r
+ 'ax' => true,\r
+ 'az' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'int' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'info' => true,\r
+ 'pp' => true,\r
+ 'mil' => true,\r
+ 'name' => true,\r
+ 'pro' => true,\r
+ 'biz' => true\r
+ ),\r
+ 'ba' => array(\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'unsa' => true,\r
+ 'unbi' => true,\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'rs' => true\r
+ ),\r
+ 'bb' => array(\r
+ 'biz' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'info' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'store' => true\r
+ ),\r
+ 'bd' => array(\r
+ '*' => true\r
+ ),\r
+ 'be' => array(\r
+ 'ac' => true\r
+ ),\r
+ 'bf' => array(\r
+ 'gov' => true\r
+ ),\r
+ 'bg' => array(\r
+ 'a' => true,\r
+ 'b' => true,\r
+ 'c' => true,\r
+ 'd' => true,\r
+ 'e' => true,\r
+ 'f' => true,\r
+ 'g' => true,\r
+ 'h' => true,\r
+ 'i' => true,\r
+ 'j' => true,\r
+ 'k' => true,\r
+ 'l' => true,\r
+ 'm' => true,\r
+ 'n' => true,\r
+ 'o' => true,\r
+ 'p' => true,\r
+ 'q' => true,\r
+ 'r' => true,\r
+ 's' => true,\r
+ 't' => true,\r
+ 'u' => true,\r
+ 'v' => true,\r
+ 'w' => true,\r
+ 'x' => true,\r
+ 'y' => true,\r
+ 'z' => true,\r
+ '0' => true,\r
+ '1' => true,\r
+ '2' => true,\r
+ '3' => true,\r
+ '4' => true,\r
+ '5' => true,\r
+ '6' => true,\r
+ '7' => true,\r
+ '8' => true,\r
+ '9' => true\r
+ ),\r
+ 'bh' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'bi' => array(\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'or' => true,\r
+ 'org' => true\r
+ ),\r
+ 'biz' => array(\r
+ 'dyndns' => true,\r
+ 'for-better' => true,\r
+ 'for-more' => true,\r
+ 'for-some' => true,\r
+ 'for-the' => true,\r
+ 'selfip' => true,\r
+ 'webhop' => true\r
+ ),\r
+ 'bj' => array(\r
+ 'asso' => true,\r
+ 'barreau' => true,\r
+ 'gouv' => true\r
+ ),\r
+ 'bm' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'bn' => array(\r
+ '*' => true\r
+ ),\r
+ 'bo' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'gob' => true,\r
+ 'int' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'mil' => true,\r
+ 'tv' => true\r
+ ),\r
+ 'br' => array(\r
+ 'adm' => true,\r
+ 'adv' => true,\r
+ 'agr' => true,\r
+ 'am' => true,\r
+ 'arq' => true,\r
+ 'art' => true,\r
+ 'ato' => true,\r
+ 'b' => true,\r
+ 'bio' => true,\r
+ 'blog' => true,\r
+ 'bmd' => true,\r
+ 'can' => true,\r
+ 'cim' => true,\r
+ 'cng' => true,\r
+ 'cnt' => true,\r
+ 'com' => true,\r
+ 'coop' => true,\r
+ 'ecn' => true,\r
+ 'edu' => true,\r
+ 'emp' => true,\r
+ 'eng' => true,\r
+ 'esp' => true,\r
+ 'etc' => true,\r
+ 'eti' => true,\r
+ 'far' => true,\r
+ 'flog' => true,\r
+ 'fm' => true,\r
+ 'fnd' => true,\r
+ 'fot' => true,\r
+ 'fst' => true,\r
+ 'g12' => true,\r
+ 'ggf' => true,\r
+ 'gov' => true,\r
+ 'imb' => true,\r
+ 'ind' => true,\r
+ 'inf' => true,\r
+ 'jor' => true,\r
+ 'jus' => true,\r
+ 'lel' => true,\r
+ 'mat' => true,\r
+ 'med' => true,\r
+ 'mil' => true,\r
+ 'mus' => true,\r
+ 'net' => true,\r
+ 'nom' => true,\r
+ 'not' => true,\r
+ 'ntr' => true,\r
+ 'odo' => true,\r
+ 'org' => true,\r
+ 'ppg' => true,\r
+ 'pro' => true,\r
+ 'psc' => true,\r
+ 'psi' => true,\r
+ 'qsl' => true,\r
+ 'radio' => true,\r
+ 'rec' => true,\r
+ 'slg' => true,\r
+ 'srv' => true,\r
+ 'taxi' => true,\r
+ 'teo' => true,\r
+ 'tmp' => true,\r
+ 'trd' => true,\r
+ 'tur' => true,\r
+ 'tv' => true,\r
+ 'vet' => true,\r
+ 'vlog' => true,\r
+ 'wiki' => true,\r
+ 'zlg' => true\r
+ ),\r
+ 'bs' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'bt' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'bw' => array(\r
+ 'co' => true,\r
+ 'org' => true\r
+ ),\r
+ 'by' => array(\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'com' => true,\r
+ 'of' => true\r
+ ),\r
+ 'bz' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'ca' => array(\r
+ 'ab' => true,\r
+ 'bc' => true,\r
+ 'mb' => true,\r
+ 'nb' => true,\r
+ 'nf' => true,\r
+ 'nl' => true,\r
+ 'ns' => true,\r
+ 'nt' => true,\r
+ 'nu' => true,\r
+ 'on' => true,\r
+ 'pe' => true,\r
+ 'qc' => true,\r
+ 'sk' => true,\r
+ 'yk' => true,\r
+ 'gc' => true,\r
+ 'co' => true\r
+ ),\r
+ 'cat' => true,\r
+ 'cc' => array(\r
+ 'ftpaccess' => true,\r
+ 'game-server' => true,\r
+ 'myphotos' => true,\r
+ 'scrapping' => true\r
+ ),\r
+ 'cd' => array(\r
+ 'gov' => true\r
+ ),\r
+ 'cf' => true,\r
+ 'cg' => true,\r
+ 'ch' => true,\r
+ 'ci' => array(\r
+ 'org' => true,\r
+ 'or' => true,\r
+ 'com' => true,\r
+ 'co' => true,\r
+ 'edu' => true,\r
+ 'ed' => true,\r
+ 'ac' => true,\r
+ 'net' => true,\r
+ 'go' => true,\r
+ 'asso' => true,\r
+ 'aéroport' => true,\r
+ 'int' => true,\r
+ 'presse' => true,\r
+ 'md' => true,\r
+ 'gouv' => true\r
+ ),\r
+ 'ck' => array(\r
+ '*' => true,\r
+ '!www' => true\r
+ ),\r
+ 'cl' => array(\r
+ 'gov' => true,\r
+ 'gob' => true,\r
+ 'co' => true,\r
+ 'mil' => true\r
+ ),\r
+ 'cm' => array(\r
+ 'gov' => true\r
+ ),\r
+ 'cn' => array(\r
+ 'ac' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'mil' => true,\r
+ '公司' => true,\r
+ '网络' => true,\r
+ '網絡' => true,\r
+ 'ah' => true,\r
+ 'bj' => true,\r
+ 'cq' => true,\r
+ 'fj' => true,\r
+ 'gd' => true,\r
+ 'gs' => true,\r
+ 'gz' => true,\r
+ 'gx' => true,\r
+ 'ha' => true,\r
+ 'hb' => true,\r
+ 'he' => true,\r
+ 'hi' => true,\r
+ 'hl' => true,\r
+ 'hn' => true,\r
+ 'jl' => true,\r
+ 'js' => true,\r
+ 'jx' => true,\r
+ 'ln' => true,\r
+ 'nm' => true,\r
+ 'nx' => true,\r
+ 'qh' => true,\r
+ 'sc' => true,\r
+ 'sd' => true,\r
+ 'sh' => true,\r
+ 'sn' => true,\r
+ 'sx' => true,\r
+ 'tj' => true,\r
+ 'xj' => true,\r
+ 'xz' => true,\r
+ 'yn' => true,\r
+ 'zj' => true,\r
+ 'hk' => true,\r
+ 'mo' => true,\r
+ 'tw' => true\r
+ ),\r
+ 'co' => array(\r
+ 'arts' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'firm' => true,\r
+ 'gov' => true,\r
+ 'info' => true,\r
+ 'int' => true,\r
+ 'mil' => true,\r
+ 'net' => true,\r
+ 'nom' => true,\r
+ 'org' => true,\r
+ 'rec' => true,\r
+ 'web' => true\r
+ ),\r
+ 'com' => array(\r
+ 'ar' => true,\r
+ 'br' => true,\r
+ 'cn' => true,\r
+ 'de' => true,\r
+ 'eu' => true,\r
+ 'gb' => true,\r
+ 'gr' => true,\r
+ 'hu' => true,\r
+ 'jpn' => true,\r
+ 'kr' => true,\r
+ 'no' => true,\r
+ 'qc' => true,\r
+ 'ru' => true,\r
+ 'sa' => true,\r
+ 'se' => true,\r
+ 'uk' => true,\r
+ 'us' => true,\r
+ 'uy' => true,\r
+ 'za' => true,\r
+ 'operaunite' => true,\r
+ 'appspot' => true,\r
+ 'dyndns-at-home' => true,\r
+ 'dyndns-at-work' => true,\r
+ 'dyndns-blog' => true,\r
+ 'dyndns-free' => true,\r
+ 'dyndns-home' => true,\r
+ 'dyndns-ip' => true,\r
+ 'dyndns-mail' => true,\r
+ 'dyndns-office' => true,\r
+ 'dyndns-pics' => true,\r
+ 'dyndns-remote' => true,\r
+ 'dyndns-server' => true,\r
+ 'dyndns-web' => true,\r
+ 'dyndns-wiki' => true,\r
+ 'dyndns-work' => true,\r
+ 'blogdns' => true,\r
+ 'cechire' => true,\r
+ 'dnsalias' => true,\r
+ 'dnsdojo' => true,\r
+ 'doesntexist' => true,\r
+ 'dontexist' => true,\r
+ 'doomdns' => true,\r
+ 'dyn-o-saur' => true,\r
+ 'dynalias' => true,\r
+ 'est-a-la-maison' => true,\r
+ 'est-a-la-masion' => true,\r
+ 'est-le-patron' => true,\r
+ 'est-mon-blogueur' => true,\r
+ 'from-ak' => true,\r
+ 'from-al' => true,\r
+ 'from-ar' => true,\r
+ 'from-ca' => true,\r
+ 'from-ct' => true,\r
+ 'from-dc' => true,\r
+ 'from-de' => true,\r
+ 'from-fl' => true,\r
+ 'from-ga' => true,\r
+ 'from-hi' => true,\r
+ 'from-ia' => true,\r
+ 'from-id' => true,\r
+ 'from-il' => true,\r
+ 'from-in' => true,\r
+ 'from-ks' => true,\r
+ 'from-ky' => true,\r
+ 'from-ma' => true,\r
+ 'from-md' => true,\r
+ 'from-mi' => true,\r
+ 'from-mn' => true,\r
+ 'from-mo' => true,\r
+ 'from-ms' => true,\r
+ 'from-mt' => true,\r
+ 'from-nc' => true,\r
+ 'from-nd' => true,\r
+ 'from-ne' => true,\r
+ 'from-nh' => true,\r
+ 'from-nj' => true,\r
+ 'from-nm' => true,\r
+ 'from-nv' => true,\r
+ 'from-oh' => true,\r
+ 'from-ok' => true,\r
+ 'from-or' => true,\r
+ 'from-pa' => true,\r
+ 'from-pr' => true,\r
+ 'from-ri' => true,\r
+ 'from-sc' => true,\r
+ 'from-sd' => true,\r
+ 'from-tn' => true,\r
+ 'from-tx' => true,\r
+ 'from-ut' => true,\r
+ 'from-va' => true,\r
+ 'from-vt' => true,\r
+ 'from-wa' => true,\r
+ 'from-wi' => true,\r
+ 'from-wv' => true,\r
+ 'from-wy' => true,\r
+ 'getmyip' => true,\r
+ 'gotdns' => true,\r
+ 'hobby-site' => true,\r
+ 'homelinux' => true,\r
+ 'homeunix' => true,\r
+ 'iamallama' => true,\r
+ 'is-a-anarchist' => true,\r
+ 'is-a-blogger' => true,\r
+ 'is-a-bookkeeper' => true,\r
+ 'is-a-bulls-fan' => true,\r
+ 'is-a-caterer' => true,\r
+ 'is-a-chef' => true,\r
+ 'is-a-conservative' => true,\r
+ 'is-a-cpa' => true,\r
+ 'is-a-cubicle-slave' => true,\r
+ 'is-a-democrat' => true,\r
+ 'is-a-designer' => true,\r
+ 'is-a-doctor' => true,\r
+ 'is-a-financialadvisor' => true,\r
+ 'is-a-geek' => true,\r
+ 'is-a-green' => true,\r
+ 'is-a-guru' => true,\r
+ 'is-a-hard-worker' => true,\r
+ 'is-a-hunter' => true,\r
+ 'is-a-landscaper' => true,\r
+ 'is-a-lawyer' => true,\r
+ 'is-a-liberal' => true,\r
+ 'is-a-libertarian' => true,\r
+ 'is-a-llama' => true,\r
+ 'is-a-musician' => true,\r
+ 'is-a-nascarfan' => true,\r
+ 'is-a-nurse' => true,\r
+ 'is-a-painter' => true,\r
+ 'is-a-personaltrainer' => true,\r
+ 'is-a-photographer' => true,\r
+ 'is-a-player' => true,\r
+ 'is-a-republican' => true,\r
+ 'is-a-rockstar' => true,\r
+ 'is-a-socialist' => true,\r
+ 'is-a-student' => true,\r
+ 'is-a-teacher' => true,\r
+ 'is-a-techie' => true,\r
+ 'is-a-therapist' => true,\r
+ 'is-an-accountant' => true,\r
+ 'is-an-actor' => true,\r
+ 'is-an-actress' => true,\r
+ 'is-an-anarchist' => true,\r
+ 'is-an-artist' => true,\r
+ 'is-an-engineer' => true,\r
+ 'is-an-entertainer' => true,\r
+ 'is-certified' => true,\r
+ 'is-gone' => true,\r
+ 'is-into-anime' => true,\r
+ 'is-into-cars' => true,\r
+ 'is-into-cartoons' => true,\r
+ 'is-into-games' => true,\r
+ 'is-leet' => true,\r
+ 'is-not-certified' => true,\r
+ 'is-slick' => true,\r
+ 'is-uberleet' => true,\r
+ 'is-with-theband' => true,\r
+ 'isa-geek' => true,\r
+ 'isa-hockeynut' => true,\r
+ 'issmarterthanyou' => true,\r
+ 'likes-pie' => true,\r
+ 'likescandy' => true,\r
+ 'neat-url' => true,\r
+ 'saves-the-whales' => true,\r
+ 'selfip' => true,\r
+ 'sells-for-less' => true,\r
+ 'sells-for-u' => true,\r
+ 'servebbs' => true,\r
+ 'simple-url' => true,\r
+ 'space-to-rent' => true,\r
+ 'teaches-yoga' => true,\r
+ 'writesthisblog' => true\r
+ ),\r
+ 'coop' => true,\r
+ 'cr' => array(\r
+ 'ac' => true,\r
+ 'co' => true,\r
+ 'ed' => true,\r
+ 'fi' => true,\r
+ 'go' => true,\r
+ 'or' => true,\r
+ 'sa' => true\r
+ ),\r
+ 'cu' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'gov' => true,\r
+ 'inf' => true\r
+ ),\r
+ 'cv' => true,\r
+ 'cx' => array(\r
+ 'gov' => true,\r
+ 'ath' => true\r
+ ),\r
+ 'cy' => array(\r
+ '*' => true\r
+ ),\r
+ 'cz' => true,\r
+ 'de' => array(\r
+ 'com' => true,\r
+ 'fuettertdasnetz' => true,\r
+ 'isteingeek' => true,\r
+ 'istmein' => true,\r
+ 'lebtimnetz' => true,\r
+ 'leitungsen' => true,\r
+ 'traeumtgerade' => true\r
+ ),\r
+ 'dj' => true,\r
+ 'dk' => true,\r
+ 'dm' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'do' => array(\r
+ 'art' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gob' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'sld' => true,\r
+ 'web' => true\r
+ ),\r
+ 'dz' => array(\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'asso' => true,\r
+ 'pol' => true,\r
+ 'art' => true\r
+ ),\r
+ 'ec' => array(\r
+ 'com' => true,\r
+ 'info' => true,\r
+ 'net' => true,\r
+ 'fin' => true,\r
+ 'k12' => true,\r
+ 'med' => true,\r
+ 'pro' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'gob' => true,\r
+ 'mil' => true\r
+ ),\r
+ 'edu' => true,\r
+ 'ee' => array(\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'riik' => true,\r
+ 'lib' => true,\r
+ 'med' => true,\r
+ 'com' => true,\r
+ 'pri' => true,\r
+ 'aip' => true,\r
+ 'org' => true,\r
+ 'fie' => true\r
+ ),\r
+ 'eg' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'eun' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'name' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'sci' => true\r
+ ),\r
+ 'er' => array(\r
+ '*' => true\r
+ ),\r
+ 'es' => array(\r
+ 'com' => true,\r
+ 'nom' => true,\r
+ 'org' => true,\r
+ 'gob' => true,\r
+ 'edu' => true\r
+ ),\r
+ 'et' => array(\r
+ '*' => true\r
+ ),\r
+ 'eu' => true,\r
+ 'fi' => array(\r
+ 'aland' => true,\r
+ 'iki' => true\r
+ ),\r
+ 'fj' => array(\r
+ '*' => true\r
+ ),\r
+ 'fk' => array(\r
+ '*' => true\r
+ ),\r
+ 'fm' => true,\r
+ 'fo' => true,\r
+ 'fr' => array(\r
+ 'com' => true,\r
+ 'asso' => true,\r
+ 'nom' => true,\r
+ 'prd' => true,\r
+ 'presse' => true,\r
+ 'tm' => true,\r
+ 'aeroport' => true,\r
+ 'assedic' => true,\r
+ 'avocat' => true,\r
+ 'avoues' => true,\r
+ 'cci' => true,\r
+ 'chambagri' => true,\r
+ 'chirurgiens-dentistes' => true,\r
+ 'experts-comptables' => true,\r
+ 'geometre-expert' => true,\r
+ 'gouv' => true,\r
+ 'greta' => true,\r
+ 'huissier-justice' => true,\r
+ 'medecin' => true,\r
+ 'notaires' => true,\r
+ 'pharmacien' => true,\r
+ 'port' => true,\r
+ 'veterinaire' => true\r
+ ),\r
+ 'ga' => true,\r
+ 'gd' => true,\r
+ 'ge' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'mil' => true,\r
+ 'net' => true,\r
+ 'pvt' => true\r
+ ),\r
+ 'gf' => true,\r
+ 'gg' => array(\r
+ 'co' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'sch' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'gh' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'mil' => true\r
+ ),\r
+ 'gi' => array(\r
+ 'com' => true,\r
+ 'ltd' => true,\r
+ 'gov' => true,\r
+ 'mod' => true,\r
+ 'edu' => true,\r
+ 'org' => true\r
+ ),\r
+ 'gl' => true,\r
+ 'gm' => true,\r
+ 'gn' => array(\r
+ 'ac' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'net' => true\r
+ ),\r
+ 'gov' => true,\r
+ 'gp' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'mobi' => true,\r
+ 'edu' => true,\r
+ 'org' => true,\r
+ 'asso' => true\r
+ ),\r
+ 'gq' => true,\r
+ 'gr' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'gs' => true,\r
+ 'gt' => array(\r
+ '*' => true,\r
+ '!www' => true\r
+ ),\r
+ 'gu' => array(\r
+ '*' => true\r
+ ),\r
+ 'gw' => true,\r
+ 'gy' => array(\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'net' => true\r
+ ),\r
+ 'hk' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'idv' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ '公司' => true,\r
+ '教育' => true,\r
+ '敎育' => true,\r
+ '政府' => true,\r
+ '個人' => true,\r
+ '个人' => true,\r
+ '箇人' => true,\r
+ '網络' => true,\r
+ '网络' => true,\r
+ '组織' => true,\r
+ '網絡' => true,\r
+ '网絡' => true,\r
+ '组织' => true,\r
+ '組織' => true,\r
+ '組织' => true\r
+ ),\r
+ 'hm' => true,\r
+ 'hn' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'mil' => true,\r
+ 'gob' => true\r
+ ),\r
+ 'hr' => array(\r
+ 'iz' => true,\r
+ 'from' => true,\r
+ 'name' => true,\r
+ 'com' => true\r
+ ),\r
+ 'ht' => array(\r
+ 'com' => true,\r
+ 'shop' => true,\r
+ 'firm' => true,\r
+ 'info' => true,\r
+ 'adult' => true,\r
+ 'net' => true,\r
+ 'pro' => true,\r
+ 'org' => true,\r
+ 'med' => true,\r
+ 'art' => true,\r
+ 'coop' => true,\r
+ 'pol' => true,\r
+ 'asso' => true,\r
+ 'edu' => true,\r
+ 'rel' => true,\r
+ 'gouv' => true,\r
+ 'perso' => true\r
+ ),\r
+ 'hu' => array(\r
+ 'co' => true,\r
+ 'info' => true,\r
+ 'org' => true,\r
+ 'priv' => true,\r
+ 'sport' => true,\r
+ 'tm' => true,\r
+ '2000' => true,\r
+ 'agrar' => true,\r
+ 'bolt' => true,\r
+ 'casino' => true,\r
+ 'city' => true,\r
+ 'erotica' => true,\r
+ 'erotika' => true,\r
+ 'film' => true,\r
+ 'forum' => true,\r
+ 'games' => true,\r
+ 'hotel' => true,\r
+ 'ingatlan' => true,\r
+ 'jogasz' => true,\r
+ 'konyvelo' => true,\r
+ 'lakas' => true,\r
+ 'media' => true,\r
+ 'news' => true,\r
+ 'reklam' => true,\r
+ 'sex' => true,\r
+ 'shop' => true,\r
+ 'suli' => true,\r
+ 'szex' => true,\r
+ 'tozsde' => true,\r
+ 'utazas' => true,\r
+ 'video' => true\r
+ ),\r
+ 'id' => array(\r
+ 'ac' => true,\r
+ 'co' => true,\r
+ 'go' => true,\r
+ 'mil' => true,\r
+ 'net' => true,\r
+ 'or' => true,\r
+ 'sch' => true,\r
+ 'web' => true\r
+ ),\r
+ 'ie' => array(\r
+ 'gov' => true\r
+ ),\r
+ 'il' => array(\r
+ '*' => true\r
+ ),\r
+ 'im' => array(\r
+ 'co' => array(\r
+ 'ltd' => true,\r
+ 'plc' => true\r
+ ),\r
+ 'net' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'nic' => true,\r
+ 'ac' => true\r
+ ),\r
+ 'in' => array(\r
+ 'co' => true,\r
+ 'firm' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gen' => true,\r
+ 'ind' => true,\r
+ 'nic' => true,\r
+ 'ac' => true,\r
+ 'edu' => true,\r
+ 'res' => true,\r
+ 'gov' => true,\r
+ 'mil' => true\r
+ ),\r
+ 'info' => array(\r
+ 'dyndns' => true,\r
+ 'barrel-of-knowledge' => true,\r
+ 'barrell-of-knowledge' => true,\r
+ 'for-our' => true,\r
+ 'groks-the' => true,\r
+ 'groks-this' => true,\r
+ 'here-for-more' => true,\r
+ 'knowsitall' => true,\r
+ 'selfip' => true,\r
+ 'webhop' => true\r
+ ),\r
+ 'int' => array(\r
+ 'eu' => true\r
+ ),\r
+ 'io' => array(\r
+ 'com' => true\r
+ ),\r
+ 'iq' => array(\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'mil' => true,\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true\r
+ ),\r
+ 'ir' => array(\r
+ 'ac' => true,\r
+ 'co' => true,\r
+ 'gov' => true,\r
+ 'id' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'sch' => true,\r
+ 'ایران' => true,\r
+ 'ايران' => true\r
+ ),\r
+ 'is' => array(\r
+ 'net' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'int' => true\r
+ ),\r
+ 'it' => array(\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'agrigento' => true,\r
+ 'ag' => true,\r
+ 'alessandria' => true,\r
+ 'al' => true,\r
+ 'ancona' => true,\r
+ 'an' => true,\r
+ 'aosta' => true,\r
+ 'aoste' => true,\r
+ 'ao' => true,\r
+ 'arezzo' => true,\r
+ 'ar' => true,\r
+ 'ascoli-piceno' => true,\r
+ 'ascolipiceno' => true,\r
+ 'ap' => true,\r
+ 'asti' => true,\r
+ 'at' => true,\r
+ 'avellino' => true,\r
+ 'av' => true,\r
+ 'bari' => true,\r
+ 'ba' => true,\r
+ 'andria-barletta-trani' => true,\r
+ 'andriabarlettatrani' => true,\r
+ 'trani-barletta-andria' => true,\r
+ 'tranibarlettaandria' => true,\r
+ 'barletta-trani-andria' => true,\r
+ 'barlettatraniandria' => true,\r
+ 'andria-trani-barletta' => true,\r
+ 'andriatranibarletta' => true,\r
+ 'trani-andria-barletta' => true,\r
+ 'traniandriabarletta' => true,\r
+ 'bt' => true,\r
+ 'belluno' => true,\r
+ 'bl' => true,\r
+ 'benevento' => true,\r
+ 'bn' => true,\r
+ 'bergamo' => true,\r
+ 'bg' => true,\r
+ 'biella' => true,\r
+ 'bi' => true,\r
+ 'bologna' => true,\r
+ 'bo' => true,\r
+ 'bolzano' => true,\r
+ 'bozen' => true,\r
+ 'balsan' => true,\r
+ 'alto-adige' => true,\r
+ 'altoadige' => true,\r
+ 'suedtirol' => true,\r
+ 'bz' => true,\r
+ 'brescia' => true,\r
+ 'bs' => true,\r
+ 'brindisi' => true,\r
+ 'br' => true,\r
+ 'cagliari' => true,\r
+ 'ca' => true,\r
+ 'caltanissetta' => true,\r
+ 'cl' => true,\r
+ 'campobasso' => true,\r
+ 'cb' => true,\r
+ 'carboniaiglesias' => true,\r
+ 'carbonia-iglesias' => true,\r
+ 'iglesias-carbonia' => true,\r
+ 'iglesiascarbonia' => true,\r
+ 'ci' => true,\r
+ 'caserta' => true,\r
+ 'ce' => true,\r
+ 'catania' => true,\r
+ 'ct' => true,\r
+ 'catanzaro' => true,\r
+ 'cz' => true,\r
+ 'chieti' => true,\r
+ 'ch' => true,\r
+ 'como' => true,\r
+ 'co' => true,\r
+ 'cosenza' => true,\r
+ 'cs' => true,\r
+ 'cremona' => true,\r
+ 'cr' => true,\r
+ 'crotone' => true,\r
+ 'kr' => true,\r
+ 'cuneo' => true,\r
+ 'cn' => true,\r
+ 'dell-ogliastra' => true,\r
+ 'dellogliastra' => true,\r
+ 'ogliastra' => true,\r
+ 'og' => true,\r
+ 'enna' => true,\r
+ 'en' => true,\r
+ 'ferrara' => true,\r
+ 'fe' => true,\r
+ 'fermo' => true,\r
+ 'fm' => true,\r
+ 'firenze' => true,\r
+ 'florence' => true,\r
+ 'fi' => true,\r
+ 'foggia' => true,\r
+ 'fg' => true,\r
+ 'forli-cesena' => true,\r
+ 'forlicesena' => true,\r
+ 'cesena-forli' => true,\r
+ 'cesenaforli' => true,\r
+ 'fc' => true,\r
+ 'frosinone' => true,\r
+ 'fr' => true,\r
+ 'genova' => true,\r
+ 'genoa' => true,\r
+ 'ge' => true,\r
+ 'gorizia' => true,\r
+ 'go' => true,\r
+ 'grosseto' => true,\r
+ 'gr' => true,\r
+ 'imperia' => true,\r
+ 'im' => true,\r
+ 'isernia' => true,\r
+ 'is' => true,\r
+ 'laquila' => true,\r
+ 'aquila' => true,\r
+ 'aq' => true,\r
+ 'la-spezia' => true,\r
+ 'laspezia' => true,\r
+ 'sp' => true,\r
+ 'latina' => true,\r
+ 'lt' => true,\r
+ 'lecce' => true,\r
+ 'le' => true,\r
+ 'lecco' => true,\r
+ 'lc' => true,\r
+ 'livorno' => true,\r
+ 'li' => true,\r
+ 'lodi' => true,\r
+ 'lo' => true,\r
+ 'lucca' => true,\r
+ 'lu' => true,\r
+ 'macerata' => true,\r
+ 'mc' => true,\r
+ 'mantova' => true,\r
+ 'mn' => true,\r
+ 'massa-carrara' => true,\r
+ 'massacarrara' => true,\r
+ 'carrara-massa' => true,\r
+ 'carraramassa' => true,\r
+ 'ms' => true,\r
+ 'matera' => true,\r
+ 'mt' => true,\r
+ 'medio-campidano' => true,\r
+ 'mediocampidano' => true,\r
+ 'campidano-medio' => true,\r
+ 'campidanomedio' => true,\r
+ 'vs' => true,\r
+ 'messina' => true,\r
+ 'me' => true,\r
+ 'milano' => true,\r
+ 'milan' => true,\r
+ 'mi' => true,\r
+ 'modena' => true,\r
+ 'mo' => true,\r
+ 'monza' => true,\r
+ 'monza-brianza' => true,\r
+ 'monzabrianza' => true,\r
+ 'monzaebrianza' => true,\r
+ 'monzaedellabrianza' => true,\r
+ 'monza-e-della-brianza' => true,\r
+ 'mb' => true,\r
+ 'napoli' => true,\r
+ 'naples' => true,\r
+ 'na' => true,\r
+ 'novara' => true,\r
+ 'no' => true,\r
+ 'nuoro' => true,\r
+ 'nu' => true,\r
+ 'oristano' => true,\r
+ 'or' => true,\r
+ 'padova' => true,\r
+ 'padua' => true,\r
+ 'pd' => true,\r
+ 'palermo' => true,\r
+ 'pa' => true,\r
+ 'parma' => true,\r
+ 'pr' => true,\r
+ 'pavia' => true,\r
+ 'pv' => true,\r
+ 'perugia' => true,\r
+ 'pg' => true,\r
+ 'pescara' => true,\r
+ 'pe' => true,\r
+ 'pesaro-urbino' => true,\r
+ 'pesarourbino' => true,\r
+ 'urbino-pesaro' => true,\r
+ 'urbinopesaro' => true,\r
+ 'pu' => true,\r
+ 'piacenza' => true,\r
+ 'pc' => true,\r
+ 'pisa' => true,\r
+ 'pi' => true,\r
+ 'pistoia' => true,\r
+ 'pt' => true,\r
+ 'pordenone' => true,\r
+ 'pn' => true,\r
+ 'potenza' => true,\r
+ 'pz' => true,\r
+ 'prato' => true,\r
+ 'po' => true,\r
+ 'ragusa' => true,\r
+ 'rg' => true,\r
+ 'ravenna' => true,\r
+ 'ra' => true,\r
+ 'reggio-calabria' => true,\r
+ 'reggiocalabria' => true,\r
+ 'rc' => true,\r
+ 'reggio-emilia' => true,\r
+ 'reggioemilia' => true,\r
+ 're' => true,\r
+ 'rieti' => true,\r
+ 'ri' => true,\r
+ 'rimini' => true,\r
+ 'rn' => true,\r
+ 'roma' => true,\r
+ 'rome' => true,\r
+ 'rm' => true,\r
+ 'rovigo' => true,\r
+ 'ro' => true,\r
+ 'salerno' => true,\r
+ 'sa' => true,\r
+ 'sassari' => true,\r
+ 'ss' => true,\r
+ 'savona' => true,\r
+ 'sv' => true,\r
+ 'siena' => true,\r
+ 'si' => true,\r
+ 'siracusa' => true,\r
+ 'sr' => true,\r
+ 'sondrio' => true,\r
+ 'so' => true,\r
+ 'taranto' => true,\r
+ 'ta' => true,\r
+ 'tempio-olbia' => true,\r
+ 'tempioolbia' => true,\r
+ 'olbia-tempio' => true,\r
+ 'olbiatempio' => true,\r
+ 'ot' => true,\r
+ 'teramo' => true,\r
+ 'te' => true,\r
+ 'terni' => true,\r
+ 'tr' => true,\r
+ 'torino' => true,\r
+ 'turin' => true,\r
+ 'to' => true,\r
+ 'trapani' => true,\r
+ 'tp' => true,\r
+ 'trento' => true,\r
+ 'trentino' => true,\r
+ 'tn' => true,\r
+ 'treviso' => true,\r
+ 'tv' => true,\r
+ 'trieste' => true,\r
+ 'ts' => true,\r
+ 'udine' => true,\r
+ 'ud' => true,\r
+ 'varese' => true,\r
+ 'va' => true,\r
+ 'venezia' => true,\r
+ 'venice' => true,\r
+ 've' => true,\r
+ 'verbania' => true,\r
+ 'vb' => true,\r
+ 'vercelli' => true,\r
+ 'vc' => true,\r
+ 'verona' => true,\r
+ 'vr' => true,\r
+ 'vibo-valentia' => true,\r
+ 'vibovalentia' => true,\r
+ 'vv' => true,\r
+ 'vicenza' => true,\r
+ 'vi' => true,\r
+ 'viterbo' => true,\r
+ 'vt' => true\r
+ ),\r
+ 'je' => array(\r
+ 'co' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'sch' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'jm' => array(\r
+ '*' => true\r
+ ),\r
+ 'jo' => array(\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'edu' => true,\r
+ 'sch' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'name' => true\r
+ ),\r
+ 'jobs' => true,\r
+ 'jp' => array(\r
+ 'ac' => true,\r
+ 'ad' => true,\r
+ 'co' => true,\r
+ 'ed' => true,\r
+ 'go' => true,\r
+ 'gr' => true,\r
+ 'lg' => true,\r
+ 'ne' => true,\r
+ 'or' => true,\r
+ 'aichi' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'akita' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'aomori' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'chiba' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'ehime' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'fukui' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'fukuoka' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'fukushima' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'gifu' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'gunma' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'hiroshima' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'hokkaido' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'hyogo' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'ibaraki' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'ishikawa' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'iwate' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'kagawa' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'kagoshima' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'kanagawa' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'kawasaki' => array(\r
+ '*' => true,\r
+ '!city' => true\r
+ ),\r
+ 'kitakyushu' => array(\r
+ '*' => true,\r
+ '!city' => true\r
+ ),\r
+ 'kobe' => array(\r
+ '*' => true,\r
+ '!city' => true\r
+ ),\r
+ 'kochi' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'kumamoto' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'kyoto' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'mie' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'miyagi' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'miyazaki' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'nagano' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'nagasaki' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'nagoya' => array(\r
+ '*' => true,\r
+ '!city' => true\r
+ ),\r
+ 'nara' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'niigata' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'oita' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'okayama' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'okinawa' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'osaka' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'saga' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'saitama' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'sapporo' => array(\r
+ '*' => true,\r
+ '!city' => true\r
+ ),\r
+ 'sendai' => array(\r
+ '*' => true,\r
+ '!city' => true\r
+ ),\r
+ 'shiga' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'shimane' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'shizuoka' => array(\r
+ '*' => true,\r
+ '!pref' => true,\r
+ '!city' => true\r
+ ),\r
+ 'tochigi' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'tokushima' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'tokyo' => array(\r
+ '*' => true,\r
+ '!metro' => true\r
+ ),\r
+ 'tottori' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'toyama' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'wakayama' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'yamagata' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'yamaguchi' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'yamanashi' => array(\r
+ '*' => true,\r
+ '!pref' => true\r
+ ),\r
+ 'yokohama' => array(\r
+ '*' => true,\r
+ '!city' => true\r
+ )\r
+ ),\r
+ 'ke' => array(\r
+ '*' => true\r
+ ),\r
+ 'kg' => array(\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'mil' => true\r
+ ),\r
+ 'kh' => array(\r
+ '*' => true\r
+ ),\r
+ 'ki' => array(\r
+ 'edu' => true,\r
+ 'biz' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'info' => true,\r
+ 'com' => true\r
+ ),\r
+ 'km' => array(\r
+ 'org' => true,\r
+ 'nom' => true,\r
+ 'gov' => true,\r
+ 'prd' => true,\r
+ 'tm' => true,\r
+ 'edu' => true,\r
+ 'mil' => true,\r
+ 'ass' => true,\r
+ 'com' => true,\r
+ 'coop' => true,\r
+ 'asso' => true,\r
+ 'presse' => true,\r
+ 'medecin' => true,\r
+ 'notaires' => true,\r
+ 'pharmaciens' => true,\r
+ 'veterinaire' => true,\r
+ 'gouv' => true\r
+ ),\r
+ 'kn' => array(\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'kp' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'rep' => true,\r
+ 'tra' => true\r
+ ),\r
+ 'kr' => array(\r
+ 'ac' => true,\r
+ 'co' => true,\r
+ 'es' => true,\r
+ 'go' => true,\r
+ 'hs' => true,\r
+ 'kg' => true,\r
+ 'mil' => true,\r
+ 'ms' => true,\r
+ 'ne' => true,\r
+ 'or' => true,\r
+ 'pe' => true,\r
+ 're' => true,\r
+ 'sc' => true,\r
+ 'busan' => true,\r
+ 'chungbuk' => true,\r
+ 'chungnam' => true,\r
+ 'daegu' => true,\r
+ 'daejeon' => true,\r
+ 'gangwon' => true,\r
+ 'gwangju' => true,\r
+ 'gyeongbuk' => true,\r
+ 'gyeonggi' => true,\r
+ 'gyeongnam' => true,\r
+ 'incheon' => true,\r
+ 'jeju' => true,\r
+ 'jeonbuk' => true,\r
+ 'jeonnam' => true,\r
+ 'seoul' => true,\r
+ 'ulsan' => true\r
+ ),\r
+ 'kw' => array(\r
+ '*' => true\r
+ ),\r
+ 'ky' => array(\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true\r
+ ),\r
+ 'kz' => array(\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'net' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'com' => true\r
+ ),\r
+ 'la' => array(\r
+ 'int' => true,\r
+ 'net' => true,\r
+ 'info' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'per' => true,\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'c' => true\r
+ ),\r
+ 'lb' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'lc' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'co' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'li' => true,\r
+ 'lk' => array(\r
+ 'gov' => true,\r
+ 'sch' => true,\r
+ 'net' => true,\r
+ 'int' => true,\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'ngo' => true,\r
+ 'soc' => true,\r
+ 'web' => true,\r
+ 'ltd' => true,\r
+ 'assn' => true,\r
+ 'grp' => true,\r
+ 'hotel' => true\r
+ ),\r
+ 'lr' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'net' => true\r
+ ),\r
+ 'ls' => array(\r
+ 'co' => true,\r
+ 'org' => true\r
+ ),\r
+ 'lt' => array(\r
+ 'gov' => true\r
+ ),\r
+ 'lu' => true,\r
+ 'lv' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'mil' => true,\r
+ 'id' => true,\r
+ 'net' => true,\r
+ 'asn' => true,\r
+ 'conf' => true\r
+ ),\r
+ 'ly' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'gov' => true,\r
+ 'plc' => true,\r
+ 'edu' => true,\r
+ 'sch' => true,\r
+ 'med' => true,\r
+ 'org' => true,\r
+ 'id' => true\r
+ ),\r
+ 'ma' => array(\r
+ 'co' => true,\r
+ 'net' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'ac' => true,\r
+ 'press' => true\r
+ ),\r
+ 'mc' => array(\r
+ 'tm' => true,\r
+ 'asso' => true\r
+ ),\r
+ 'md' => true,\r
+ 'me' => array(\r
+ 'co' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'ac' => true,\r
+ 'gov' => true,\r
+ 'its' => true,\r
+ 'priv' => true\r
+ ),\r
+ 'mg' => array(\r
+ 'org' => true,\r
+ 'nom' => true,\r
+ 'gov' => true,\r
+ 'prd' => true,\r
+ 'tm' => true,\r
+ 'edu' => true,\r
+ 'mil' => true,\r
+ 'com' => true\r
+ ),\r
+ 'mh' => true,\r
+ 'mil' => true,\r
+ 'mk' => array(\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'inf' => true,\r
+ 'name' => true\r
+ ),\r
+ 'ml' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gouv' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'presse' => true\r
+ ),\r
+ 'mm' => array(\r
+ '*' => true\r
+ ),\r
+ 'mn' => array(\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'org' => true\r
+ ),\r
+ 'mo' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'gov' => true\r
+ ),\r
+ 'mobi' => true,\r
+ 'mp' => true,\r
+ 'mq' => true,\r
+ 'mr' => array(\r
+ 'gov' => true\r
+ ),\r
+ 'ms' => true,\r
+ 'mt' => array(\r
+ '*' => true\r
+ ),\r
+ 'mu' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'ac' => true,\r
+ 'co' => true,\r
+ 'or' => true\r
+ ),\r
+ 'museum' => array(\r
+ 'academy' => true,\r
+ 'agriculture' => true,\r
+ 'air' => true,\r
+ 'airguard' => true,\r
+ 'alabama' => true,\r
+ 'alaska' => true,\r
+ 'amber' => true,\r
+ 'ambulance' => true,\r
+ 'american' => true,\r
+ 'americana' => true,\r
+ 'americanantiques' => true,\r
+ 'americanart' => true,\r
+ 'amsterdam' => true,\r
+ 'and' => true,\r
+ 'annefrank' => true,\r
+ 'anthro' => true,\r
+ 'anthropology' => true,\r
+ 'antiques' => true,\r
+ 'aquarium' => true,\r
+ 'arboretum' => true,\r
+ 'archaeological' => true,\r
+ 'archaeology' => true,\r
+ 'architecture' => true,\r
+ 'art' => true,\r
+ 'artanddesign' => true,\r
+ 'artcenter' => true,\r
+ 'artdeco' => true,\r
+ 'arteducation' => true,\r
+ 'artgallery' => true,\r
+ 'arts' => true,\r
+ 'artsandcrafts' => true,\r
+ 'asmatart' => true,\r
+ 'assassination' => true,\r
+ 'assisi' => true,\r
+ 'association' => true,\r
+ 'astronomy' => true,\r
+ 'atlanta' => true,\r
+ 'austin' => true,\r
+ 'australia' => true,\r
+ 'automotive' => true,\r
+ 'aviation' => true,\r
+ 'axis' => true,\r
+ 'badajoz' => true,\r
+ 'baghdad' => true,\r
+ 'bahn' => true,\r
+ 'bale' => true,\r
+ 'baltimore' => true,\r
+ 'barcelona' => true,\r
+ 'baseball' => true,\r
+ 'basel' => true,\r
+ 'baths' => true,\r
+ 'bauern' => true,\r
+ 'beauxarts' => true,\r
+ 'beeldengeluid' => true,\r
+ 'bellevue' => true,\r
+ 'bergbau' => true,\r
+ 'berkeley' => true,\r
+ 'berlin' => true,\r
+ 'bern' => true,\r
+ 'bible' => true,\r
+ 'bilbao' => true,\r
+ 'bill' => true,\r
+ 'birdart' => true,\r
+ 'birthplace' => true,\r
+ 'bonn' => true,\r
+ 'boston' => true,\r
+ 'botanical' => true,\r
+ 'botanicalgarden' => true,\r
+ 'botanicgarden' => true,\r
+ 'botany' => true,\r
+ 'brandywinevalley' => true,\r
+ 'brasil' => true,\r
+ 'bristol' => true,\r
+ 'british' => true,\r
+ 'britishcolumbia' => true,\r
+ 'broadcast' => true,\r
+ 'brunel' => true,\r
+ 'brussel' => true,\r
+ 'brussels' => true,\r
+ 'bruxelles' => true,\r
+ 'building' => true,\r
+ 'burghof' => true,\r
+ 'bus' => true,\r
+ 'bushey' => true,\r
+ 'cadaques' => true,\r
+ 'california' => true,\r
+ 'cambridge' => true,\r
+ 'can' => true,\r
+ 'canada' => true,\r
+ 'capebreton' => true,\r
+ 'carrier' => true,\r
+ 'cartoonart' => true,\r
+ 'casadelamoneda' => true,\r
+ 'castle' => true,\r
+ 'castres' => true,\r
+ 'celtic' => true,\r
+ 'center' => true,\r
+ 'chattanooga' => true,\r
+ 'cheltenham' => true,\r
+ 'chesapeakebay' => true,\r
+ 'chicago' => true,\r
+ 'children' => true,\r
+ 'childrens' => true,\r
+ 'childrensgarden' => true,\r
+ 'chiropractic' => true,\r
+ 'chocolate' => true,\r
+ 'christiansburg' => true,\r
+ 'cincinnati' => true,\r
+ 'cinema' => true,\r
+ 'circus' => true,\r
+ 'civilisation' => true,\r
+ 'civilization' => true,\r
+ 'civilwar' => true,\r
+ 'clinton' => true,\r
+ 'clock' => true,\r
+ 'coal' => true,\r
+ 'coastaldefence' => true,\r
+ 'cody' => true,\r
+ 'coldwar' => true,\r
+ 'collection' => true,\r
+ 'colonialwilliamsburg' => true,\r
+ 'coloradoplateau' => true,\r
+ 'columbia' => true,\r
+ 'columbus' => true,\r
+ 'communication' => true,\r
+ 'communications' => true,\r
+ 'community' => true,\r
+ 'computer' => true,\r
+ 'computerhistory' => true,\r
+ 'comunicações' => true,\r
+ 'contemporary' => true,\r
+ 'contemporaryart' => true,\r
+ 'convent' => true,\r
+ 'copenhagen' => true,\r
+ 'corporation' => true,\r
+ 'correios-e-telecomunicações' => true,\r
+ 'corvette' => true,\r
+ 'costume' => true,\r
+ 'countryestate' => true,\r
+ 'county' => true,\r
+ 'crafts' => true,\r
+ 'cranbrook' => true,\r
+ 'creation' => true,\r
+ 'cultural' => true,\r
+ 'culturalcenter' => true,\r
+ 'culture' => true,\r
+ 'cyber' => true,\r
+ 'cymru' => true,\r
+ 'dali' => true,\r
+ 'dallas' => true,\r
+ 'database' => true,\r
+ 'ddr' => true,\r
+ 'decorativearts' => true,\r
+ 'delaware' => true,\r
+ 'delmenhorst' => true,\r
+ 'denmark' => true,\r
+ 'depot' => true,\r
+ 'design' => true,\r
+ 'detroit' => true,\r
+ 'dinosaur' => true,\r
+ 'discovery' => true,\r
+ 'dolls' => true,\r
+ 'donostia' => true,\r
+ 'durham' => true,\r
+ 'eastafrica' => true,\r
+ 'eastcoast' => true,\r
+ 'education' => true,\r
+ 'educational' => true,\r
+ 'egyptian' => true,\r
+ 'eisenbahn' => true,\r
+ 'elburg' => true,\r
+ 'elvendrell' => true,\r
+ 'embroidery' => true,\r
+ 'encyclopedic' => true,\r
+ 'england' => true,\r
+ 'entomology' => true,\r
+ 'environment' => true,\r
+ 'environmentalconservation' => true,\r
+ 'epilepsy' => true,\r
+ 'essex' => true,\r
+ 'estate' => true,\r
+ 'ethnology' => true,\r
+ 'exeter' => true,\r
+ 'exhibition' => true,\r
+ 'family' => true,\r
+ 'farm' => true,\r
+ 'farmequipment' => true,\r
+ 'farmers' => true,\r
+ 'farmstead' => true,\r
+ 'field' => true,\r
+ 'figueres' => true,\r
+ 'filatelia' => true,\r
+ 'film' => true,\r
+ 'fineart' => true,\r
+ 'finearts' => true,\r
+ 'finland' => true,\r
+ 'flanders' => true,\r
+ 'florida' => true,\r
+ 'force' => true,\r
+ 'fortmissoula' => true,\r
+ 'fortworth' => true,\r
+ 'foundation' => true,\r
+ 'francaise' => true,\r
+ 'frankfurt' => true,\r
+ 'franziskaner' => true,\r
+ 'freemasonry' => true,\r
+ 'freiburg' => true,\r
+ 'fribourg' => true,\r
+ 'frog' => true,\r
+ 'fundacio' => true,\r
+ 'furniture' => true,\r
+ 'gallery' => true,\r
+ 'garden' => true,\r
+ 'gateway' => true,\r
+ 'geelvinck' => true,\r
+ 'gemological' => true,\r
+ 'geology' => true,\r
+ 'georgia' => true,\r
+ 'giessen' => true,\r
+ 'glas' => true,\r
+ 'glass' => true,\r
+ 'gorge' => true,\r
+ 'grandrapids' => true,\r
+ 'graz' => true,\r
+ 'guernsey' => true,\r
+ 'halloffame' => true,\r
+ 'hamburg' => true,\r
+ 'handson' => true,\r
+ 'harvestcelebration' => true,\r
+ 'hawaii' => true,\r
+ 'health' => true,\r
+ 'heimatunduhren' => true,\r
+ 'hellas' => true,\r
+ 'helsinki' => true,\r
+ 'hembygdsforbund' => true,\r
+ 'heritage' => true,\r
+ 'histoire' => true,\r
+ 'historical' => true,\r
+ 'historicalsociety' => true,\r
+ 'historichouses' => true,\r
+ 'historisch' => true,\r
+ 'historisches' => true,\r
+ 'history' => true,\r
+ 'historyofscience' => true,\r
+ 'horology' => true,\r
+ 'house' => true,\r
+ 'humanities' => true,\r
+ 'illustration' => true,\r
+ 'imageandsound' => true,\r
+ 'indian' => true,\r
+ 'indiana' => true,\r
+ 'indianapolis' => true,\r
+ 'indianmarket' => true,\r
+ 'intelligence' => true,\r
+ 'interactive' => true,\r
+ 'iraq' => true,\r
+ 'iron' => true,\r
+ 'isleofman' => true,\r
+ 'jamison' => true,\r
+ 'jefferson' => true,\r
+ 'jerusalem' => true,\r
+ 'jewelry' => true,\r
+ 'jewish' => true,\r
+ 'jewishart' => true,\r
+ 'jfk' => true,\r
+ 'journalism' => true,\r
+ 'judaica' => true,\r
+ 'judygarland' => true,\r
+ 'juedisches' => true,\r
+ 'juif' => true,\r
+ 'karate' => true,\r
+ 'karikatur' => true,\r
+ 'kids' => true,\r
+ 'koebenhavn' => true,\r
+ 'koeln' => true,\r
+ 'kunst' => true,\r
+ 'kunstsammlung' => true,\r
+ 'kunstunddesign' => true,\r
+ 'labor' => true,\r
+ 'labour' => true,\r
+ 'lajolla' => true,\r
+ 'lancashire' => true,\r
+ 'landes' => true,\r
+ 'lans' => true,\r
+ 'läns' => true,\r
+ 'larsson' => true,\r
+ 'lewismiller' => true,\r
+ 'lincoln' => true,\r
+ 'linz' => true,\r
+ 'living' => true,\r
+ 'livinghistory' => true,\r
+ 'localhistory' => true,\r
+ 'london' => true,\r
+ 'losangeles' => true,\r
+ 'louvre' => true,\r
+ 'loyalist' => true,\r
+ 'lucerne' => true,\r
+ 'luxembourg' => true,\r
+ 'luzern' => true,\r
+ 'mad' => true,\r
+ 'madrid' => true,\r
+ 'mallorca' => true,\r
+ 'manchester' => true,\r
+ 'mansion' => true,\r
+ 'mansions' => true,\r
+ 'manx' => true,\r
+ 'marburg' => true,\r
+ 'maritime' => true,\r
+ 'maritimo' => true,\r
+ 'maryland' => true,\r
+ 'marylhurst' => true,\r
+ 'media' => true,\r
+ 'medical' => true,\r
+ 'medizinhistorisches' => true,\r
+ 'meeres' => true,\r
+ 'memorial' => true,\r
+ 'mesaverde' => true,\r
+ 'michigan' => true,\r
+ 'midatlantic' => true,\r
+ 'military' => true,\r
+ 'mill' => true,\r
+ 'miners' => true,\r
+ 'mining' => true,\r
+ 'minnesota' => true,\r
+ 'missile' => true,\r
+ 'missoula' => true,\r
+ 'modern' => true,\r
+ 'moma' => true,\r
+ 'money' => true,\r
+ 'monmouth' => true,\r
+ 'monticello' => true,\r
+ 'montreal' => true,\r
+ 'moscow' => true,\r
+ 'motorcycle' => true,\r
+ 'muenchen' => true,\r
+ 'muenster' => true,\r
+ 'mulhouse' => true,\r
+ 'muncie' => true,\r
+ 'museet' => true,\r
+ 'museumcenter' => true,\r
+ 'museumvereniging' => true,\r
+ 'music' => true,\r
+ 'national' => true,\r
+ 'nationalfirearms' => true,\r
+ 'nationalheritage' => true,\r
+ 'nativeamerican' => true,\r
+ 'naturalhistory' => true,\r
+ 'naturalhistorymuseum' => true,\r
+ 'naturalsciences' => true,\r
+ 'nature' => true,\r
+ 'naturhistorisches' => true,\r
+ 'natuurwetenschappen' => true,\r
+ 'naumburg' => true,\r
+ 'naval' => true,\r
+ 'nebraska' => true,\r
+ 'neues' => true,\r
+ 'newhampshire' => true,\r
+ 'newjersey' => true,\r
+ 'newmexico' => true,\r
+ 'newport' => true,\r
+ 'newspaper' => true,\r
+ 'newyork' => true,\r
+ 'niepce' => true,\r
+ 'norfolk' => true,\r
+ 'north' => true,\r
+ 'nrw' => true,\r
+ 'nuernberg' => true,\r
+ 'nuremberg' => true,\r
+ 'nyc' => true,\r
+ 'nyny' => true,\r
+ 'oceanographic' => true,\r
+ 'oceanographique' => true,\r
+ 'omaha' => true,\r
+ 'online' => true,\r
+ 'ontario' => true,\r
+ 'openair' => true,\r
+ 'oregon' => true,\r
+ 'oregontrail' => true,\r
+ 'otago' => true,\r
+ 'oxford' => true,\r
+ 'pacific' => true,\r
+ 'paderborn' => true,\r
+ 'palace' => true,\r
+ 'paleo' => true,\r
+ 'palmsprings' => true,\r
+ 'panama' => true,\r
+ 'paris' => true,\r
+ 'pasadena' => true,\r
+ 'pharmacy' => true,\r
+ 'philadelphia' => true,\r
+ 'philadelphiaarea' => true,\r
+ 'philately' => true,\r
+ 'phoenix' => true,\r
+ 'photography' => true,\r
+ 'pilots' => true,\r
+ 'pittsburgh' => true,\r
+ 'planetarium' => true,\r
+ 'plantation' => true,\r
+ 'plants' => true,\r
+ 'plaza' => true,\r
+ 'portal' => true,\r
+ 'portland' => true,\r
+ 'portlligat' => true,\r
+ 'posts-and-telecommunications' => true,\r
+ 'preservation' => true,\r
+ 'presidio' => true,\r
+ 'press' => true,\r
+ 'project' => true,\r
+ 'public' => true,\r
+ 'pubol' => true,\r
+ 'quebec' => true,\r
+ 'railroad' => true,\r
+ 'railway' => true,\r
+ 'research' => true,\r
+ 'resistance' => true,\r
+ 'riodejaneiro' => true,\r
+ 'rochester' => true,\r
+ 'rockart' => true,\r
+ 'roma' => true,\r
+ 'russia' => true,\r
+ 'saintlouis' => true,\r
+ 'salem' => true,\r
+ 'salvadordali' => true,\r
+ 'salzburg' => true,\r
+ 'sandiego' => true,\r
+ 'sanfrancisco' => true,\r
+ 'santabarbara' => true,\r
+ 'santacruz' => true,\r
+ 'santafe' => true,\r
+ 'saskatchewan' => true,\r
+ 'satx' => true,\r
+ 'savannahga' => true,\r
+ 'schlesisches' => true,\r
+ 'schoenbrunn' => true,\r
+ 'schokoladen' => true,\r
+ 'school' => true,\r
+ 'schweiz' => true,\r
+ 'science' => true,\r
+ 'scienceandhistory' => true,\r
+ 'scienceandindustry' => true,\r
+ 'sciencecenter' => true,\r
+ 'sciencecenters' => true,\r
+ 'science-fiction' => true,\r
+ 'sciencehistory' => true,\r
+ 'sciences' => true,\r
+ 'sciencesnaturelles' => true,\r
+ 'scotland' => true,\r
+ 'seaport' => true,\r
+ 'settlement' => true,\r
+ 'settlers' => true,\r
+ 'shell' => true,\r
+ 'sherbrooke' => true,\r
+ 'sibenik' => true,\r
+ 'silk' => true,\r
+ 'ski' => true,\r
+ 'skole' => true,\r
+ 'society' => true,\r
+ 'sologne' => true,\r
+ 'soundandvision' => true,\r
+ 'southcarolina' => true,\r
+ 'southwest' => true,\r
+ 'space' => true,\r
+ 'spy' => true,\r
+ 'square' => true,\r
+ 'stadt' => true,\r
+ 'stalbans' => true,\r
+ 'starnberg' => true,\r
+ 'state' => true,\r
+ 'stateofdelaware' => true,\r
+ 'station' => true,\r
+ 'steam' => true,\r
+ 'steiermark' => true,\r
+ 'stjohn' => true,\r
+ 'stockholm' => true,\r
+ 'stpetersburg' => true,\r
+ 'stuttgart' => true,\r
+ 'suisse' => true,\r
+ 'surgeonshall' => true,\r
+ 'surrey' => true,\r
+ 'svizzera' => true,\r
+ 'sweden' => true,\r
+ 'sydney' => true,\r
+ 'tank' => true,\r
+ 'tcm' => true,\r
+ 'technology' => true,\r
+ 'telekommunikation' => true,\r
+ 'television' => true,\r
+ 'texas' => true,\r
+ 'textile' => true,\r
+ 'theater' => true,\r
+ 'time' => true,\r
+ 'timekeeping' => true,\r
+ 'topology' => true,\r
+ 'torino' => true,\r
+ 'touch' => true,\r
+ 'town' => true,\r
+ 'transport' => true,\r
+ 'tree' => true,\r
+ 'trolley' => true,\r
+ 'trust' => true,\r
+ 'trustee' => true,\r
+ 'uhren' => true,\r
+ 'ulm' => true,\r
+ 'undersea' => true,\r
+ 'university' => true,\r
+ 'usa' => true,\r
+ 'usantiques' => true,\r
+ 'usarts' => true,\r
+ 'uscountryestate' => true,\r
+ 'usculture' => true,\r
+ 'usdecorativearts' => true,\r
+ 'usgarden' => true,\r
+ 'ushistory' => true,\r
+ 'ushuaia' => true,\r
+ 'uslivinghistory' => true,\r
+ 'utah' => true,\r
+ 'uvic' => true,\r
+ 'valley' => true,\r
+ 'vantaa' => true,\r
+ 'versailles' => true,\r
+ 'viking' => true,\r
+ 'village' => true,\r
+ 'virginia' => true,\r
+ 'virtual' => true,\r
+ 'virtuel' => true,\r
+ 'vlaanderen' => true,\r
+ 'volkenkunde' => true,\r
+ 'wales' => true,\r
+ 'wallonie' => true,\r
+ 'war' => true,\r
+ 'washingtondc' => true,\r
+ 'watchandclock' => true,\r
+ 'watch-and-clock' => true,\r
+ 'western' => true,\r
+ 'westfalen' => true,\r
+ 'whaling' => true,\r
+ 'wildlife' => true,\r
+ 'williamsburg' => true,\r
+ 'windmill' => true,\r
+ 'workshop' => true,\r
+ 'york' => true,\r
+ 'yorkshire' => true,\r
+ 'yosemite' => true,\r
+ 'youth' => true,\r
+ 'zoological' => true,\r
+ 'zoology' => true,\r
+ 'ירושלים' => true,\r
+ 'иком' => true\r
+ ),\r
+ 'mv' => array(\r
+ 'aero' => true,\r
+ 'biz' => true,\r
+ 'com' => true,\r
+ 'coop' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'info' => true,\r
+ 'int' => true,\r
+ 'mil' => true,\r
+ 'museum' => true,\r
+ 'name' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'pro' => true\r
+ ),\r
+ 'mw' => array(\r
+ 'ac' => true,\r
+ 'biz' => true,\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'coop' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'int' => true,\r
+ 'museum' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'mx' => array(\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'gob' => true,\r
+ 'edu' => true,\r
+ 'net' => true\r
+ ),\r
+ 'my' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'mil' => true,\r
+ 'name' => true\r
+ ),\r
+ 'mz' => array(\r
+ '*' => true\r
+ ),\r
+ 'na' => array(\r
+ 'info' => true,\r
+ 'pro' => true,\r
+ 'name' => true,\r
+ 'school' => true,\r
+ 'or' => true,\r
+ 'dr' => true,\r
+ 'us' => true,\r
+ 'mx' => true,\r
+ 'ca' => true,\r
+ 'in' => true,\r
+ 'cc' => true,\r
+ 'tv' => true,\r
+ 'ws' => true,\r
+ 'mobi' => true,\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'org' => true\r
+ ),\r
+ 'name' => array(\r
+ 'her' => array(\r
+ 'forgot' => true\r
+ ),\r
+ 'his' => array(\r
+ 'forgot' => true\r
+ )\r
+ ),\r
+ 'nc' => array(\r
+ 'asso' => true\r
+ ),\r
+ 'ne' => true,\r
+ 'net' => array(\r
+ 'gb' => true,\r
+ 'jp' => true,\r
+ 'se' => true,\r
+ 'uk' => true,\r
+ 'za' => true,\r
+ 'at-band-camp' => true,\r
+ 'blogdns' => true,\r
+ 'broke-it' => true,\r
+ 'buyshouses' => true,\r
+ 'dnsalias' => true,\r
+ 'dnsdojo' => true,\r
+ 'does-it' => true,\r
+ 'dontexist' => true,\r
+ 'dynalias' => true,\r
+ 'dynathome' => true,\r
+ 'endofinternet' => true,\r
+ 'from-az' => true,\r
+ 'from-co' => true,\r
+ 'from-la' => true,\r
+ 'from-ny' => true,\r
+ 'gets-it' => true,\r
+ 'ham-radio-op' => true,\r
+ 'homeftp' => true,\r
+ 'homeip' => true,\r
+ 'homelinux' => true,\r
+ 'homeunix' => true,\r
+ 'in-the-band' => true,\r
+ 'is-a-chef' => true,\r
+ 'is-a-geek' => true,\r
+ 'isa-geek' => true,\r
+ 'kicks-ass' => true,\r
+ 'office-on-the' => true,\r
+ 'podzone' => true,\r
+ 'scrapper-site' => true,\r
+ 'selfip' => true,\r
+ 'sells-it' => true,\r
+ 'servebbs' => true,\r
+ 'serveftp' => true,\r
+ 'thruhere' => true,\r
+ 'webhop' => true\r
+ ),\r
+ 'nf' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'per' => true,\r
+ 'rec' => true,\r
+ 'web' => true,\r
+ 'arts' => true,\r
+ 'firm' => true,\r
+ 'info' => true,\r
+ 'other' => true,\r
+ 'store' => true\r
+ ),\r
+ 'ng' => array(\r
+ 'ac' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'ni' => array(\r
+ '*' => true\r
+ ),\r
+ 'nl' => array(\r
+ 'bv' => true,\r
+ 'co' => true\r
+ ),\r
+ 'no' => array(\r
+ 'fhs' => true,\r
+ 'vgs' => true,\r
+ 'fylkesbibl' => true,\r
+ 'folkebibl' => true,\r
+ 'museum' => true,\r
+ 'idrett' => true,\r
+ 'priv' => true,\r
+ 'mil' => true,\r
+ 'stat' => true,\r
+ 'dep' => true,\r
+ 'kommune' => true,\r
+ 'herad' => true,\r
+ 'aa' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'ah' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'bu' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'fm' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'hl' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'hm' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'jan-mayen' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'mr' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'nl' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'nt' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'of' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'ol' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'oslo' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'rl' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'sf' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'st' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'svalbard' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'tm' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'tr' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'va' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'vf' => array(\r
+ 'gs' => true\r
+ ),\r
+ 'akrehamn' => true,\r
+ 'åkrehamn' => true,\r
+ 'algard' => true,\r
+ 'ålgård' => true,\r
+ 'arna' => true,\r
+ 'brumunddal' => true,\r
+ 'bryne' => true,\r
+ 'bronnoysund' => true,\r
+ 'brønnøysund' => true,\r
+ 'drobak' => true,\r
+ 'drøbak' => true,\r
+ 'egersund' => true,\r
+ 'fetsund' => true,\r
+ 'floro' => true,\r
+ 'florø' => true,\r
+ 'fredrikstad' => true,\r
+ 'hokksund' => true,\r
+ 'honefoss' => true,\r
+ 'hønefoss' => true,\r
+ 'jessheim' => true,\r
+ 'jorpeland' => true,\r
+ 'jørpeland' => true,\r
+ 'kirkenes' => true,\r
+ 'kopervik' => true,\r
+ 'krokstadelva' => true,\r
+ 'langevag' => true,\r
+ 'langevåg' => true,\r
+ 'leirvik' => true,\r
+ 'mjondalen' => true,\r
+ 'mjøndalen' => true,\r
+ 'mo-i-rana' => true,\r
+ 'mosjoen' => true,\r
+ 'mosjøen' => true,\r
+ 'nesoddtangen' => true,\r
+ 'orkanger' => true,\r
+ 'osoyro' => true,\r
+ 'osøyro' => true,\r
+ 'raholt' => true,\r
+ 'råholt' => true,\r
+ 'sandnessjoen' => true,\r
+ 'sandnessjøen' => true,\r
+ 'skedsmokorset' => true,\r
+ 'slattum' => true,\r
+ 'spjelkavik' => true,\r
+ 'stathelle' => true,\r
+ 'stavern' => true,\r
+ 'stjordalshalsen' => true,\r
+ 'stjørdalshalsen' => true,\r
+ 'tananger' => true,\r
+ 'tranby' => true,\r
+ 'vossevangen' => true,\r
+ 'afjord' => true,\r
+ 'åfjord' => true,\r
+ 'agdenes' => true,\r
+ 'al' => true,\r
+ 'ål' => true,\r
+ 'alesund' => true,\r
+ 'ålesund' => true,\r
+ 'alstahaug' => true,\r
+ 'alta' => true,\r
+ 'áltá' => true,\r
+ 'alaheadju' => true,\r
+ 'álaheadju' => true,\r
+ 'alvdal' => true,\r
+ 'amli' => true,\r
+ 'åmli' => true,\r
+ 'amot' => true,\r
+ 'åmot' => true,\r
+ 'andebu' => true,\r
+ 'andoy' => true,\r
+ 'andøy' => true,\r
+ 'andasuolo' => true,\r
+ 'ardal' => true,\r
+ 'årdal' => true,\r
+ 'aremark' => true,\r
+ 'arendal' => true,\r
+ 'ås' => true,\r
+ 'aseral' => true,\r
+ 'åseral' => true,\r
+ 'asker' => true,\r
+ 'askim' => true,\r
+ 'askvoll' => true,\r
+ 'askoy' => true,\r
+ 'askøy' => true,\r
+ 'asnes' => true,\r
+ 'åsnes' => true,\r
+ 'audnedaln' => true,\r
+ 'aukra' => true,\r
+ 'aure' => true,\r
+ 'aurland' => true,\r
+ 'aurskog-holand' => true,\r
+ 'aurskog-høland' => true,\r
+ 'austevoll' => true,\r
+ 'austrheim' => true,\r
+ 'averoy' => true,\r
+ 'averøy' => true,\r
+ 'balestrand' => true,\r
+ 'ballangen' => true,\r
+ 'balat' => true,\r
+ 'bálát' => true,\r
+ 'balsfjord' => true,\r
+ 'bahccavuotna' => true,\r
+ 'báhccavuotna' => true,\r
+ 'bamble' => true,\r
+ 'bardu' => true,\r
+ 'beardu' => true,\r
+ 'beiarn' => true,\r
+ 'bajddar' => true,\r
+ 'bájddar' => true,\r
+ 'baidar' => true,\r
+ 'báidár' => true,\r
+ 'berg' => true,\r
+ 'bergen' => true,\r
+ 'berlevag' => true,\r
+ 'berlevåg' => true,\r
+ 'bearalvahki' => true,\r
+ 'bearalváhki' => true,\r
+ 'bindal' => true,\r
+ 'birkenes' => true,\r
+ 'bjarkoy' => true,\r
+ 'bjarkøy' => true,\r
+ 'bjerkreim' => true,\r
+ 'bjugn' => true,\r
+ 'bodo' => true,\r
+ 'bodø' => true,\r
+ 'badaddja' => true,\r
+ 'bådåddjå' => true,\r
+ 'budejju' => true,\r
+ 'bokn' => true,\r
+ 'bremanger' => true,\r
+ 'bronnoy' => true,\r
+ 'brønnøy' => true,\r
+ 'bygland' => true,\r
+ 'bykle' => true,\r
+ 'barum' => true,\r
+ 'bærum' => true,\r
+ 'telemark' => array(\r
+ 'bo' => true,\r
+ 'bø' => true\r
+ ),\r
+ 'nordland' => array(\r
+ 'bo' => true,\r
+ 'bø' => true,\r
+ 'heroy' => true,\r
+ 'herøy' => true\r
+ ),\r
+ 'bievat' => true,\r
+ 'bievát' => true,\r
+ 'bomlo' => true,\r
+ 'bømlo' => true,\r
+ 'batsfjord' => true,\r
+ 'båtsfjord' => true,\r
+ 'bahcavuotna' => true,\r
+ 'báhcavuotna' => true,\r
+ 'dovre' => true,\r
+ 'drammen' => true,\r
+ 'drangedal' => true,\r
+ 'dyroy' => true,\r
+ 'dyrøy' => true,\r
+ 'donna' => true,\r
+ 'dønna' => true,\r
+ 'eid' => true,\r
+ 'eidfjord' => true,\r
+ 'eidsberg' => true,\r
+ 'eidskog' => true,\r
+ 'eidsvoll' => true,\r
+ 'eigersund' => true,\r
+ 'elverum' => true,\r
+ 'enebakk' => true,\r
+ 'engerdal' => true,\r
+ 'etne' => true,\r
+ 'etnedal' => true,\r
+ 'evenes' => true,\r
+ 'evenassi' => true,\r
+ 'evenášši' => true,\r
+ 'evje-og-hornnes' => true,\r
+ 'farsund' => true,\r
+ 'fauske' => true,\r
+ 'fuossko' => true,\r
+ 'fuoisku' => true,\r
+ 'fedje' => true,\r
+ 'fet' => true,\r
+ 'finnoy' => true,\r
+ 'finnøy' => true,\r
+ 'fitjar' => true,\r
+ 'fjaler' => true,\r
+ 'fjell' => true,\r
+ 'flakstad' => true,\r
+ 'flatanger' => true,\r
+ 'flekkefjord' => true,\r
+ 'flesberg' => true,\r
+ 'flora' => true,\r
+ 'fla' => true,\r
+ 'flå' => true,\r
+ 'folldal' => true,\r
+ 'forsand' => true,\r
+ 'fosnes' => true,\r
+ 'frei' => true,\r
+ 'frogn' => true,\r
+ 'froland' => true,\r
+ 'frosta' => true,\r
+ 'frana' => true,\r
+ 'fræna' => true,\r
+ 'froya' => true,\r
+ 'frøya' => true,\r
+ 'fusa' => true,\r
+ 'fyresdal' => true,\r
+ 'forde' => true,\r
+ 'førde' => true,\r
+ 'gamvik' => true,\r
+ 'gangaviika' => true,\r
+ 'gáŋgaviika' => true,\r
+ 'gaular' => true,\r
+ 'gausdal' => true,\r
+ 'gildeskal' => true,\r
+ 'gildeskål' => true,\r
+ 'giske' => true,\r
+ 'gjemnes' => true,\r
+ 'gjerdrum' => true,\r
+ 'gjerstad' => true,\r
+ 'gjesdal' => true,\r
+ 'gjovik' => true,\r
+ 'gjøvik' => true,\r
+ 'gloppen' => true,\r
+ 'gol' => true,\r
+ 'gran' => true,\r
+ 'grane' => true,\r
+ 'granvin' => true,\r
+ 'gratangen' => true,\r
+ 'grimstad' => true,\r
+ 'grong' => true,\r
+ 'kraanghke' => true,\r
+ 'kråanghke' => true,\r
+ 'grue' => true,\r
+ 'gulen' => true,\r
+ 'hadsel' => true,\r
+ 'halden' => true,\r
+ 'halsa' => true,\r
+ 'hamar' => true,\r
+ 'hamaroy' => true,\r
+ 'habmer' => true,\r
+ 'hábmer' => true,\r
+ 'hapmir' => true,\r
+ 'hápmir' => true,\r
+ 'hammerfest' => true,\r
+ 'hammarfeasta' => true,\r
+ 'hámmárfeasta' => true,\r
+ 'haram' => true,\r
+ 'hareid' => true,\r
+ 'harstad' => true,\r
+ 'hasvik' => true,\r
+ 'aknoluokta' => true,\r
+ 'ákŋoluokta' => true,\r
+ 'hattfjelldal' => true,\r
+ 'aarborte' => true,\r
+ 'haugesund' => true,\r
+ 'hemne' => true,\r
+ 'hemnes' => true,\r
+ 'hemsedal' => true,\r
+ 'more-og-romsdal' => array(\r
+ 'heroy' => true,\r
+ 'sande' => true\r
+ ),\r
+ 'møre-og-romsdal' => array(\r
+ 'herøy' => true,\r
+ 'sande' => true\r
+ ),\r
+ 'hitra' => true,\r
+ 'hjartdal' => true,\r
+ 'hjelmeland' => true,\r
+ 'hobol' => true,\r
+ 'hobøl' => true,\r
+ 'hof' => true,\r
+ 'hol' => true,\r
+ 'hole' => true,\r
+ 'holmestrand' => true,\r
+ 'holtalen' => true,\r
+ 'holtålen' => true,\r
+ 'hornindal' => true,\r
+ 'horten' => true,\r
+ 'hurdal' => true,\r
+ 'hurum' => true,\r
+ 'hvaler' => true,\r
+ 'hyllestad' => true,\r
+ 'hagebostad' => true,\r
+ 'hægebostad' => true,\r
+ 'hoyanger' => true,\r
+ 'høyanger' => true,\r
+ 'hoylandet' => true,\r
+ 'høylandet' => true,\r
+ 'ha' => true,\r
+ 'hå' => true,\r
+ 'ibestad' => true,\r
+ 'inderoy' => true,\r
+ 'inderøy' => true,\r
+ 'iveland' => true,\r
+ 'jevnaker' => true,\r
+ 'jondal' => true,\r
+ 'jolster' => true,\r
+ 'jølster' => true,\r
+ 'karasjok' => true,\r
+ 'karasjohka' => true,\r
+ 'kárášjohka' => true,\r
+ 'karlsoy' => true,\r
+ 'galsa' => true,\r
+ 'gálsá' => true,\r
+ 'karmoy' => true,\r
+ 'karmøy' => true,\r
+ 'kautokeino' => true,\r
+ 'guovdageaidnu' => true,\r
+ 'klepp' => true,\r
+ 'klabu' => true,\r
+ 'klæbu' => true,\r
+ 'kongsberg' => true,\r
+ 'kongsvinger' => true,\r
+ 'kragero' => true,\r
+ 'kragerø' => true,\r
+ 'kristiansand' => true,\r
+ 'kristiansund' => true,\r
+ 'krodsherad' => true,\r
+ 'krødsherad' => true,\r
+ 'kvalsund' => true,\r
+ 'rahkkeravju' => true,\r
+ 'ráhkkerávju' => true,\r
+ 'kvam' => true,\r
+ 'kvinesdal' => true,\r
+ 'kvinnherad' => true,\r
+ 'kviteseid' => true,\r
+ 'kvitsoy' => true,\r
+ 'kvitsøy' => true,\r
+ 'kvafjord' => true,\r
+ 'kvæfjord' => true,\r
+ 'giehtavuoatna' => true,\r
+ 'kvanangen' => true,\r
+ 'kvænangen' => true,\r
+ 'navuotna' => true,\r
+ 'návuotna' => true,\r
+ 'kafjord' => true,\r
+ 'kåfjord' => true,\r
+ 'gaivuotna' => true,\r
+ 'gáivuotna' => true,\r
+ 'larvik' => true,\r
+ 'lavangen' => true,\r
+ 'lavagis' => true,\r
+ 'loabat' => true,\r
+ 'loabát' => true,\r
+ 'lebesby' => true,\r
+ 'davvesiida' => true,\r
+ 'leikanger' => true,\r
+ 'leirfjord' => true,\r
+ 'leka' => true,\r
+ 'leksvik' => true,\r
+ 'lenvik' => true,\r
+ 'leangaviika' => true,\r
+ 'leaŋgaviika' => true,\r
+ 'lesja' => true,\r
+ 'levanger' => true,\r
+ 'lier' => true,\r
+ 'lierne' => true,\r
+ 'lillehammer' => true,\r
+ 'lillesand' => true,\r
+ 'lindesnes' => true,\r
+ 'lindas' => true,\r
+ 'lindås' => true,\r
+ 'lom' => true,\r
+ 'loppa' => true,\r
+ 'lahppi' => true,\r
+ 'láhppi' => true,\r
+ 'lund' => true,\r
+ 'lunner' => true,\r
+ 'luroy' => true,\r
+ 'lurøy' => true,\r
+ 'luster' => true,\r
+ 'lyngdal' => true,\r
+ 'lyngen' => true,\r
+ 'ivgu' => true,\r
+ 'lardal' => true,\r
+ 'lerdal' => true,\r
+ 'lærdal' => true,\r
+ 'lodingen' => true,\r
+ 'lødingen' => true,\r
+ 'lorenskog' => true,\r
+ 'lørenskog' => true,\r
+ 'loten' => true,\r
+ 'løten' => true,\r
+ 'malvik' => true,\r
+ 'masoy' => true,\r
+ 'måsøy' => true,\r
+ 'muosat' => true,\r
+ 'muosát' => true,\r
+ 'mandal' => true,\r
+ 'marker' => true,\r
+ 'marnardal' => true,\r
+ 'masfjorden' => true,\r
+ 'meland' => true,\r
+ 'meldal' => true,\r
+ 'melhus' => true,\r
+ 'meloy' => true,\r
+ 'meløy' => true,\r
+ 'meraker' => true,\r
+ 'meråker' => true,\r
+ 'moareke' => true,\r
+ 'moåreke' => true,\r
+ 'midsund' => true,\r
+ 'midtre-gauldal' => true,\r
+ 'modalen' => true,\r
+ 'modum' => true,\r
+ 'molde' => true,\r
+ 'moskenes' => true,\r
+ 'moss' => true,\r
+ 'mosvik' => true,\r
+ 'malselv' => true,\r
+ 'målselv' => true,\r
+ 'malatvuopmi' => true,\r
+ 'málatvuopmi' => true,\r
+ 'namdalseid' => true,\r
+ 'aejrie' => true,\r
+ 'namsos' => true,\r
+ 'namsskogan' => true,\r
+ 'naamesjevuemie' => true,\r
+ 'nååmesjevuemie' => true,\r
+ 'laakesvuemie' => true,\r
+ 'nannestad' => true,\r
+ 'narvik' => true,\r
+ 'narviika' => true,\r
+ 'naustdal' => true,\r
+ 'nedre-eiker' => true,\r
+ 'akershus' => array(\r
+ 'nes' => true\r
+ ),\r
+ 'buskerud' => array(\r
+ 'nes' => true\r
+ ),\r
+ 'nesna' => true,\r
+ 'nesodden' => true,\r
+ 'nesseby' => true,\r
+ 'unjarga' => true,\r
+ 'unjárga' => true,\r
+ 'nesset' => true,\r
+ 'nissedal' => true,\r
+ 'nittedal' => true,\r
+ 'nord-aurdal' => true,\r
+ 'nord-fron' => true,\r
+ 'nord-odal' => true,\r
+ 'norddal' => true,\r
+ 'nordkapp' => true,\r
+ 'davvenjarga' => true,\r
+ 'davvenjárga' => true,\r
+ 'nordre-land' => true,\r
+ 'nordreisa' => true,\r
+ 'raisa' => true,\r
+ 'ráisa' => true,\r
+ 'nore-og-uvdal' => true,\r
+ 'notodden' => true,\r
+ 'naroy' => true,\r
+ 'nærøy' => true,\r
+ 'notteroy' => true,\r
+ 'nøtterøy' => true,\r
+ 'odda' => true,\r
+ 'oksnes' => true,\r
+ 'øksnes' => true,\r
+ 'oppdal' => true,\r
+ 'oppegard' => true,\r
+ 'oppegård' => true,\r
+ 'orkdal' => true,\r
+ 'orland' => true,\r
+ 'ørland' => true,\r
+ 'orskog' => true,\r
+ 'ørskog' => true,\r
+ 'orsta' => true,\r
+ 'ørsta' => true,\r
+ 'hedmark' => array(\r
+ 'os' => true,\r
+ 'valer' => true,\r
+ 'våler' => true\r
+ ),\r
+ 'hordaland' => array(\r
+ 'os' => true\r
+ ),\r
+ 'osen' => true,\r
+ 'osteroy' => true,\r
+ 'osterøy' => true,\r
+ 'ostre-toten' => true,\r
+ 'østre-toten' => true,\r
+ 'overhalla' => true,\r
+ 'ovre-eiker' => true,\r
+ 'øvre-eiker' => true,\r
+ 'oyer' => true,\r
+ 'øyer' => true,\r
+ 'oygarden' => true,\r
+ 'øygarden' => true,\r
+ 'oystre-slidre' => true,\r
+ 'øystre-slidre' => true,\r
+ 'porsanger' => true,\r
+ 'porsangu' => true,\r
+ 'porsáŋgu' => true,\r
+ 'porsgrunn' => true,\r
+ 'radoy' => true,\r
+ 'radøy' => true,\r
+ 'rakkestad' => true,\r
+ 'rana' => true,\r
+ 'ruovat' => true,\r
+ 'randaberg' => true,\r
+ 'rauma' => true,\r
+ 'rendalen' => true,\r
+ 'rennebu' => true,\r
+ 'rennesoy' => true,\r
+ 'rennesøy' => true,\r
+ 'rindal' => true,\r
+ 'ringebu' => true,\r
+ 'ringerike' => true,\r
+ 'ringsaker' => true,\r
+ 'rissa' => true,\r
+ 'risor' => true,\r
+ 'risør' => true,\r
+ 'roan' => true,\r
+ 'rollag' => true,\r
+ 'rygge' => true,\r
+ 'ralingen' => true,\r
+ 'rælingen' => true,\r
+ 'rodoy' => true,\r
+ 'rødøy' => true,\r
+ 'romskog' => true,\r
+ 'rømskog' => true,\r
+ 'roros' => true,\r
+ 'røros' => true,\r
+ 'rost' => true,\r
+ 'røst' => true,\r
+ 'royken' => true,\r
+ 'røyken' => true,\r
+ 'royrvik' => true,\r
+ 'røyrvik' => true,\r
+ 'rade' => true,\r
+ 'råde' => true,\r
+ 'salangen' => true,\r
+ 'siellak' => true,\r
+ 'saltdal' => true,\r
+ 'salat' => true,\r
+ 'sálát' => true,\r
+ 'sálat' => true,\r
+ 'samnanger' => true,\r
+ 'vestfold' => array(\r
+ 'sande' => true\r
+ ),\r
+ 'sandefjord' => true,\r
+ 'sandnes' => true,\r
+ 'sandoy' => true,\r
+ 'sandøy' => true,\r
+ 'sarpsborg' => true,\r
+ 'sauda' => true,\r
+ 'sauherad' => true,\r
+ 'sel' => true,\r
+ 'selbu' => true,\r
+ 'selje' => true,\r
+ 'seljord' => true,\r
+ 'sigdal' => true,\r
+ 'siljan' => true,\r
+ 'sirdal' => true,\r
+ 'skaun' => true,\r
+ 'skedsmo' => true,\r
+ 'ski' => true,\r
+ 'skien' => true,\r
+ 'skiptvet' => true,\r
+ 'skjervoy' => true,\r
+ 'skjervøy' => true,\r
+ 'skierva' => true,\r
+ 'skiervá' => true,\r
+ 'skjak' => true,\r
+ 'skjåk' => true,\r
+ 'skodje' => true,\r
+ 'skanland' => true,\r
+ 'skånland' => true,\r
+ 'skanit' => true,\r
+ 'skánit' => true,\r
+ 'smola' => true,\r
+ 'smøla' => true,\r
+ 'snillfjord' => true,\r
+ 'snasa' => true,\r
+ 'snåsa' => true,\r
+ 'snoasa' => true,\r
+ 'snaase' => true,\r
+ 'snåase' => true,\r
+ 'sogndal' => true,\r
+ 'sokndal' => true,\r
+ 'sola' => true,\r
+ 'solund' => true,\r
+ 'songdalen' => true,\r
+ 'sortland' => true,\r
+ 'spydeberg' => true,\r
+ 'stange' => true,\r
+ 'stavanger' => true,\r
+ 'steigen' => true,\r
+ 'steinkjer' => true,\r
+ 'stjordal' => true,\r
+ 'stjørdal' => true,\r
+ 'stokke' => true,\r
+ 'stor-elvdal' => true,\r
+ 'stord' => true,\r
+ 'stordal' => true,\r
+ 'storfjord' => true,\r
+ 'omasvuotna' => true,\r
+ 'strand' => true,\r
+ 'stranda' => true,\r
+ 'stryn' => true,\r
+ 'sula' => true,\r
+ 'suldal' => true,\r
+ 'sund' => true,\r
+ 'sunndal' => true,\r
+ 'surnadal' => true,\r
+ 'sveio' => true,\r
+ 'svelvik' => true,\r
+ 'sykkylven' => true,\r
+ 'sogne' => true,\r
+ 'søgne' => true,\r
+ 'somna' => true,\r
+ 'sømna' => true,\r
+ 'sondre-land' => true,\r
+ 'søndre-land' => true,\r
+ 'sor-aurdal' => true,\r
+ 'sør-aurdal' => true,\r
+ 'sor-fron' => true,\r
+ 'sør-fron' => true,\r
+ 'sor-odal' => true,\r
+ 'sør-odal' => true,\r
+ 'sor-varanger' => true,\r
+ 'sør-varanger' => true,\r
+ 'matta-varjjat' => true,\r
+ 'mátta-várjjat' => true,\r
+ 'sorfold' => true,\r
+ 'sørfold' => true,\r
+ 'sorreisa' => true,\r
+ 'sørreisa' => true,\r
+ 'sorum' => true,\r
+ 'sørum' => true,\r
+ 'tana' => true,\r
+ 'deatnu' => true,\r
+ 'time' => true,\r
+ 'tingvoll' => true,\r
+ 'tinn' => true,\r
+ 'tjeldsund' => true,\r
+ 'dielddanuorri' => true,\r
+ 'tjome' => true,\r
+ 'tjøme' => true,\r
+ 'tokke' => true,\r
+ 'tolga' => true,\r
+ 'torsken' => true,\r
+ 'tranoy' => true,\r
+ 'tranøy' => true,\r
+ 'tromso' => true,\r
+ 'tromsø' => true,\r
+ 'tromsa' => true,\r
+ 'romsa' => true,\r
+ 'trondheim' => true,\r
+ 'troandin' => true,\r
+ 'trysil' => true,\r
+ 'trana' => true,\r
+ 'træna' => true,\r
+ 'trogstad' => true,\r
+ 'trøgstad' => true,\r
+ 'tvedestrand' => true,\r
+ 'tydal' => true,\r
+ 'tynset' => true,\r
+ 'tysfjord' => true,\r
+ 'divtasvuodna' => true,\r
+ 'divttasvuotna' => true,\r
+ 'tysnes' => true,\r
+ 'tysvar' => true,\r
+ 'tysvær' => true,\r
+ 'tonsberg' => true,\r
+ 'tønsberg' => true,\r
+ 'ullensaker' => true,\r
+ 'ullensvang' => true,\r
+ 'ulvik' => true,\r
+ 'utsira' => true,\r
+ 'vadso' => true,\r
+ 'vadsø' => true,\r
+ 'cahcesuolo' => true,\r
+ 'čáhcesuolo' => true,\r
+ 'vaksdal' => true,\r
+ 'valle' => true,\r
+ 'vang' => true,\r
+ 'vanylven' => true,\r
+ 'vardo' => true,\r
+ 'vardø' => true,\r
+ 'varggat' => true,\r
+ 'várggát' => true,\r
+ 'vefsn' => true,\r
+ 'vaapste' => true,\r
+ 'vega' => true,\r
+ 'vegarshei' => true,\r
+ 'vegårshei' => true,\r
+ 'vennesla' => true,\r
+ 'verdal' => true,\r
+ 'verran' => true,\r
+ 'vestby' => true,\r
+ 'vestnes' => true,\r
+ 'vestre-slidre' => true,\r
+ 'vestre-toten' => true,\r
+ 'vestvagoy' => true,\r
+ 'vestvågøy' => true,\r
+ 'vevelstad' => true,\r
+ 'vik' => true,\r
+ 'vikna' => true,\r
+ 'vindafjord' => true,\r
+ 'volda' => true,\r
+ 'voss' => true,\r
+ 'varoy' => true,\r
+ 'værøy' => true,\r
+ 'vagan' => true,\r
+ 'vågan' => true,\r
+ 'voagat' => true,\r
+ 'vagsoy' => true,\r
+ 'vågsøy' => true,\r
+ 'vaga' => true,\r
+ 'vågå' => true,\r
+ 'ostfold' => array(\r
+ 'valer' => true\r
+ ),\r
+ 'østfold' => array(\r
+ 'våler' => true\r
+ ),\r
+ 'co' => true\r
+ ),\r
+ 'np' => array(\r
+ '*' => true\r
+ ),\r
+ 'nr' => array(\r
+ 'biz' => true,\r
+ 'info' => true,\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'com' => true\r
+ ),\r
+ 'nu' => array(\r
+ 'merseine' => true,\r
+ 'mine' => true,\r
+ 'shacknet' => true\r
+ ),\r
+ 'nz' => array(\r
+ '*' => true\r
+ ),\r
+ 'om' => array(\r
+ '*' => true,\r
+ '!mediaphone' => true,\r
+ '!nawrastelecom' => true,\r
+ '!nawras' => true,\r
+ '!omanmobile' => true,\r
+ '!omanpost' => true,\r
+ '!omantel' => true,\r
+ '!rakpetroleum' => true,\r
+ '!siemens' => true,\r
+ '!songfest' => true,\r
+ '!statecouncil' => true\r
+ ),\r
+ 'org' => array(\r
+ 'ae' => true,\r
+ 'us' => true,\r
+ 'za' => true,\r
+ 'dyndns' => array(\r
+ 'go' => true,\r
+ 'home' => true\r
+ ),\r
+ 'blogdns' => true,\r
+ 'blogsite' => true,\r
+ 'boldlygoingnowhere' => true,\r
+ 'dnsalias' => true,\r
+ 'dnsdojo' => true,\r
+ 'doesntexist' => true,\r
+ 'dontexist' => true,\r
+ 'doomdns' => true,\r
+ 'dvrdns' => true,\r
+ 'dynalias' => true,\r
+ 'endofinternet' => true,\r
+ 'endoftheinternet' => true,\r
+ 'from-me' => true,\r
+ 'game-host' => true,\r
+ 'gotdns' => true,\r
+ 'hobby-site' => true,\r
+ 'homedns' => true,\r
+ 'homeftp' => true,\r
+ 'homelinux' => true,\r
+ 'homeunix' => true,\r
+ 'is-a-bruinsfan' => true,\r
+ 'is-a-candidate' => true,\r
+ 'is-a-celticsfan' => true,\r
+ 'is-a-chef' => true,\r
+ 'is-a-geek' => true,\r
+ 'is-a-knight' => true,\r
+ 'is-a-linux-user' => true,\r
+ 'is-a-patsfan' => true,\r
+ 'is-a-soxfan' => true,\r
+ 'is-found' => true,\r
+ 'is-lost' => true,\r
+ 'is-saved' => true,\r
+ 'is-very-bad' => true,\r
+ 'is-very-evil' => true,\r
+ 'is-very-good' => true,\r
+ 'is-very-nice' => true,\r
+ 'is-very-sweet' => true,\r
+ 'isa-geek' => true,\r
+ 'kicks-ass' => true,\r
+ 'misconfused' => true,\r
+ 'podzone' => true,\r
+ 'readmyblog' => true,\r
+ 'selfip' => true,\r
+ 'sellsyourhome' => true,\r
+ 'servebbs' => true,\r
+ 'serveftp' => true,\r
+ 'servegame' => true,\r
+ 'stuff-4-sale' => true,\r
+ 'webhop' => true\r
+ ),\r
+ 'pa' => array(\r
+ 'ac' => true,\r
+ 'gob' => true,\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'sld' => true,\r
+ 'edu' => true,\r
+ 'net' => true,\r
+ 'ing' => true,\r
+ 'abo' => true,\r
+ 'med' => true,\r
+ 'nom' => true\r
+ ),\r
+ 'pe' => array(\r
+ 'edu' => true,\r
+ 'gob' => true,\r
+ 'nom' => true,\r
+ 'mil' => true,\r
+ 'org' => true,\r
+ 'com' => true,\r
+ 'net' => true\r
+ ),\r
+ 'pf' => array(\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'edu' => true\r
+ ),\r
+ 'pg' => array(\r
+ '*' => true\r
+ ),\r
+ 'ph' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'ngo' => true,\r
+ 'mil' => true,\r
+ 'i' => true\r
+ ),\r
+ 'pk' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'edu' => true,\r
+ 'org' => true,\r
+ 'fam' => true,\r
+ 'biz' => true,\r
+ 'web' => true,\r
+ 'gov' => true,\r
+ 'gob' => true,\r
+ 'gok' => true,\r
+ 'gon' => true,\r
+ 'gop' => true,\r
+ 'gos' => true,\r
+ 'info' => true\r
+ ),\r
+ 'pl' => array(\r
+ 'aid' => true,\r
+ 'agro' => true,\r
+ 'atm' => true,\r
+ 'auto' => true,\r
+ 'biz' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gmina' => true,\r
+ 'gsm' => true,\r
+ 'info' => true,\r
+ 'mail' => true,\r
+ 'miasta' => true,\r
+ 'media' => true,\r
+ 'mil' => true,\r
+ 'net' => true,\r
+ 'nieruchomosci' => true,\r
+ 'nom' => true,\r
+ 'org' => true,\r
+ 'pc' => true,\r
+ 'powiat' => true,\r
+ 'priv' => true,\r
+ 'realestate' => true,\r
+ 'rel' => true,\r
+ 'sex' => true,\r
+ 'shop' => true,\r
+ 'sklep' => true,\r
+ 'sos' => true,\r
+ 'szkola' => true,\r
+ 'targi' => true,\r
+ 'tm' => true,\r
+ 'tourism' => true,\r
+ 'travel' => true,\r
+ 'turystyka' => true,\r
+ '6bone' => true,\r
+ 'art' => true,\r
+ 'mbone' => true,\r
+ 'gov' => array(\r
+ 'uw' => true,\r
+ 'um' => true,\r
+ 'ug' => true,\r
+ 'upow' => true,\r
+ 'starostwo' => true,\r
+ 'so' => true,\r
+ 'sr' => true,\r
+ 'po' => true,\r
+ 'pa' => true\r
+ ),\r
+ 'ngo' => true,\r
+ 'irc' => true,\r
+ 'usenet' => true,\r
+ 'augustow' => true,\r
+ 'babia-gora' => true,\r
+ 'bedzin' => true,\r
+ 'beskidy' => true,\r
+ 'bialowieza' => true,\r
+ 'bialystok' => true,\r
+ 'bielawa' => true,\r
+ 'bieszczady' => true,\r
+ 'boleslawiec' => true,\r
+ 'bydgoszcz' => true,\r
+ 'bytom' => true,\r
+ 'cieszyn' => true,\r
+ 'czeladz' => true,\r
+ 'czest' => true,\r
+ 'dlugoleka' => true,\r
+ 'elblag' => true,\r
+ 'elk' => true,\r
+ 'glogow' => true,\r
+ 'gniezno' => true,\r
+ 'gorlice' => true,\r
+ 'grajewo' => true,\r
+ 'ilawa' => true,\r
+ 'jaworzno' => true,\r
+ 'jelenia-gora' => true,\r
+ 'jgora' => true,\r
+ 'kalisz' => true,\r
+ 'kazimierz-dolny' => true,\r
+ 'karpacz' => true,\r
+ 'kartuzy' => true,\r
+ 'kaszuby' => true,\r
+ 'katowice' => true,\r
+ 'kepno' => true,\r
+ 'ketrzyn' => true,\r
+ 'klodzko' => true,\r
+ 'kobierzyce' => true,\r
+ 'kolobrzeg' => true,\r
+ 'konin' => true,\r
+ 'konskowola' => true,\r
+ 'kutno' => true,\r
+ 'lapy' => true,\r
+ 'lebork' => true,\r
+ 'legnica' => true,\r
+ 'lezajsk' => true,\r
+ 'limanowa' => true,\r
+ 'lomza' => true,\r
+ 'lowicz' => true,\r
+ 'lubin' => true,\r
+ 'lukow' => true,\r
+ 'malbork' => true,\r
+ 'malopolska' => true,\r
+ 'mazowsze' => true,\r
+ 'mazury' => true,\r
+ 'mielec' => true,\r
+ 'mielno' => true,\r
+ 'mragowo' => true,\r
+ 'naklo' => true,\r
+ 'nowaruda' => true,\r
+ 'nysa' => true,\r
+ 'olawa' => true,\r
+ 'olecko' => true,\r
+ 'olkusz' => true,\r
+ 'olsztyn' => true,\r
+ 'opoczno' => true,\r
+ 'opole' => true,\r
+ 'ostroda' => true,\r
+ 'ostroleka' => true,\r
+ 'ostrowiec' => true,\r
+ 'ostrowwlkp' => true,\r
+ 'pila' => true,\r
+ 'pisz' => true,\r
+ 'podhale' => true,\r
+ 'podlasie' => true,\r
+ 'polkowice' => true,\r
+ 'pomorze' => true,\r
+ 'pomorskie' => true,\r
+ 'prochowice' => true,\r
+ 'pruszkow' => true,\r
+ 'przeworsk' => true,\r
+ 'pulawy' => true,\r
+ 'radom' => true,\r
+ 'rawa-maz' => true,\r
+ 'rybnik' => true,\r
+ 'rzeszow' => true,\r
+ 'sanok' => true,\r
+ 'sejny' => true,\r
+ 'siedlce' => true,\r
+ 'slask' => true,\r
+ 'slupsk' => true,\r
+ 'sosnowiec' => true,\r
+ 'stalowa-wola' => true,\r
+ 'skoczow' => true,\r
+ 'starachowice' => true,\r
+ 'stargard' => true,\r
+ 'suwalki' => true,\r
+ 'swidnica' => true,\r
+ 'swiebodzin' => true,\r
+ 'swinoujscie' => true,\r
+ 'szczecin' => true,\r
+ 'szczytno' => true,\r
+ 'tarnobrzeg' => true,\r
+ 'tgory' => true,\r
+ 'turek' => true,\r
+ 'tychy' => true,\r
+ 'ustka' => true,\r
+ 'walbrzych' => true,\r
+ 'warmia' => true,\r
+ 'warszawa' => true,\r
+ 'waw' => true,\r
+ 'wegrow' => true,\r
+ 'wielun' => true,\r
+ 'wlocl' => true,\r
+ 'wloclawek' => true,\r
+ 'wodzislaw' => true,\r
+ 'wolomin' => true,\r
+ 'wroclaw' => true,\r
+ 'zachpomor' => true,\r
+ 'zagan' => true,\r
+ 'zarow' => true,\r
+ 'zgora' => true,\r
+ 'zgorzelec' => true,\r
+ 'gda' => true,\r
+ 'gdansk' => true,\r
+ 'gdynia' => true,\r
+ 'med' => true,\r
+ 'sopot' => true,\r
+ 'gliwice' => true,\r
+ 'krakow' => true,\r
+ 'poznan' => true,\r
+ 'wroc' => true,\r
+ 'zakopane' => true,\r
+ 'co' => true\r
+ ),\r
+ 'pm' => true,\r
+ 'pn' => array(\r
+ 'gov' => true,\r
+ 'co' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'net' => true\r
+ ),\r
+ 'pr' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'isla' => true,\r
+ 'pro' => true,\r
+ 'biz' => true,\r
+ 'info' => true,\r
+ 'name' => true,\r
+ 'est' => true,\r
+ 'prof' => true,\r
+ 'ac' => true\r
+ ),\r
+ 'pro' => array(\r
+ 'aca' => true,\r
+ 'bar' => true,\r
+ 'cpa' => true,\r
+ 'jur' => true,\r
+ 'law' => true,\r
+ 'med' => true,\r
+ 'eng' => true\r
+ ),\r
+ 'ps' => array(\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'sec' => true,\r
+ 'plo' => true,\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true\r
+ ),\r
+ 'pt' => array(\r
+ 'net' => true,\r
+ 'gov' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'int' => true,\r
+ 'publ' => true,\r
+ 'com' => true,\r
+ 'nome' => true\r
+ ),\r
+ 'pw' => array(\r
+ 'co' => true,\r
+ 'ne' => true,\r
+ 'or' => true,\r
+ 'ed' => true,\r
+ 'go' => true,\r
+ 'belau' => true\r
+ ),\r
+ 'py' => array(\r
+ '*' => true\r
+ ),\r
+ 'qa' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'name' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'sch' => true\r
+ ),\r
+ 're' => array(\r
+ 'com' => true,\r
+ 'asso' => true,\r
+ 'nom' => true\r
+ ),\r
+ 'ro' => array(\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'tm' => true,\r
+ 'nt' => true,\r
+ 'nom' => true,\r
+ 'info' => true,\r
+ 'rec' => true,\r
+ 'arts' => true,\r
+ 'firm' => true,\r
+ 'store' => true,\r
+ 'www' => true\r
+ ),\r
+ 'rs' => array(\r
+ 'co' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'ac' => true,\r
+ 'gov' => true,\r
+ 'in' => true\r
+ ),\r
+ 'ru' => array(\r
+ 'ac' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'int' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'pp' => true,\r
+ 'adygeya' => true,\r
+ 'altai' => true,\r
+ 'amur' => true,\r
+ 'arkhangelsk' => true,\r
+ 'astrakhan' => true,\r
+ 'bashkiria' => true,\r
+ 'belgorod' => true,\r
+ 'bir' => true,\r
+ 'bryansk' => true,\r
+ 'buryatia' => true,\r
+ 'cbg' => true,\r
+ 'chel' => true,\r
+ 'chelyabinsk' => true,\r
+ 'chita' => true,\r
+ 'chukotka' => true,\r
+ 'chuvashia' => true,\r
+ 'dagestan' => true,\r
+ 'dudinka' => true,\r
+ 'e-burg' => true,\r
+ 'grozny' => true,\r
+ 'irkutsk' => true,\r
+ 'ivanovo' => true,\r
+ 'izhevsk' => true,\r
+ 'jar' => true,\r
+ 'joshkar-ola' => true,\r
+ 'kalmykia' => true,\r
+ 'kaluga' => true,\r
+ 'kamchatka' => true,\r
+ 'karelia' => true,\r
+ 'kazan' => true,\r
+ 'kchr' => true,\r
+ 'kemerovo' => true,\r
+ 'khabarovsk' => true,\r
+ 'khakassia' => true,\r
+ 'khv' => true,\r
+ 'kirov' => true,\r
+ 'koenig' => true,\r
+ 'komi' => true,\r
+ 'kostroma' => true,\r
+ 'krasnoyarsk' => true,\r
+ 'kuban' => true,\r
+ 'kurgan' => true,\r
+ 'kursk' => true,\r
+ 'lipetsk' => true,\r
+ 'magadan' => true,\r
+ 'mari' => true,\r
+ 'mari-el' => true,\r
+ 'marine' => true,\r
+ 'mordovia' => true,\r
+ 'mosreg' => true,\r
+ 'msk' => true,\r
+ 'murmansk' => true,\r
+ 'nalchik' => true,\r
+ 'nnov' => true,\r
+ 'nov' => true,\r
+ 'novosibirsk' => true,\r
+ 'nsk' => true,\r
+ 'omsk' => true,\r
+ 'orenburg' => true,\r
+ 'oryol' => true,\r
+ 'palana' => true,\r
+ 'penza' => true,\r
+ 'perm' => true,\r
+ 'pskov' => true,\r
+ 'ptz' => true,\r
+ 'rnd' => true,\r
+ 'ryazan' => true,\r
+ 'sakhalin' => true,\r
+ 'samara' => true,\r
+ 'saratov' => true,\r
+ 'simbirsk' => true,\r
+ 'smolensk' => true,\r
+ 'spb' => true,\r
+ 'stavropol' => true,\r
+ 'stv' => true,\r
+ 'surgut' => true,\r
+ 'tambov' => true,\r
+ 'tatarstan' => true,\r
+ 'tom' => true,\r
+ 'tomsk' => true,\r
+ 'tsaritsyn' => true,\r
+ 'tsk' => true,\r
+ 'tula' => true,\r
+ 'tuva' => true,\r
+ 'tver' => true,\r
+ 'tyumen' => true,\r
+ 'udm' => true,\r
+ 'udmurtia' => true,\r
+ 'ulan-ude' => true,\r
+ 'vladikavkaz' => true,\r
+ 'vladimir' => true,\r
+ 'vladivostok' => true,\r
+ 'volgograd' => true,\r
+ 'vologda' => true,\r
+ 'voronezh' => true,\r
+ 'vrn' => true,\r
+ 'vyatka' => true,\r
+ 'yakutia' => true,\r
+ 'yamal' => true,\r
+ 'yaroslavl' => true,\r
+ 'yekaterinburg' => true,\r
+ 'yuzhno-sakhalinsk' => true,\r
+ 'amursk' => true,\r
+ 'baikal' => true,\r
+ 'cmw' => true,\r
+ 'fareast' => true,\r
+ 'jamal' => true,\r
+ 'kms' => true,\r
+ 'k-uralsk' => true,\r
+ 'kustanai' => true,\r
+ 'kuzbass' => true,\r
+ 'magnitka' => true,\r
+ 'mytis' => true,\r
+ 'nakhodka' => true,\r
+ 'nkz' => true,\r
+ 'norilsk' => true,\r
+ 'oskol' => true,\r
+ 'pyatigorsk' => true,\r
+ 'rubtsovsk' => true,\r
+ 'snz' => true,\r
+ 'syzran' => true,\r
+ 'vdonsk' => true,\r
+ 'zgrad' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'test' => true\r
+ ),\r
+ 'rw' => array(\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'edu' => true,\r
+ 'ac' => true,\r
+ 'com' => true,\r
+ 'co' => true,\r
+ 'int' => true,\r
+ 'mil' => true,\r
+ 'gouv' => true\r
+ ),\r
+ 'sa' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'med' => true,\r
+ 'pub' => true,\r
+ 'edu' => true,\r
+ 'sch' => true\r
+ ),\r
+ 'sb' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'sc' => array(\r
+ 'com' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true\r
+ ),\r
+ 'sd' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'med' => true,\r
+ 'gov' => true,\r
+ 'info' => true\r
+ ),\r
+ 'se' => array(\r
+ 'a' => true,\r
+ 'ac' => true,\r
+ 'b' => true,\r
+ 'bd' => true,\r
+ 'brand' => true,\r
+ 'c' => true,\r
+ 'd' => true,\r
+ 'e' => true,\r
+ 'f' => true,\r
+ 'fh' => true,\r
+ 'fhsk' => true,\r
+ 'fhv' => true,\r
+ 'g' => true,\r
+ 'h' => true,\r
+ 'i' => true,\r
+ 'k' => true,\r
+ 'komforb' => true,\r
+ 'kommunalforbund' => true,\r
+ 'komvux' => true,\r
+ 'l' => true,\r
+ 'lanbib' => true,\r
+ 'm' => true,\r
+ 'n' => true,\r
+ 'naturbruksgymn' => true,\r
+ 'o' => true,\r
+ 'org' => true,\r
+ 'p' => true,\r
+ 'parti' => true,\r
+ 'pp' => true,\r
+ 'press' => true,\r
+ 'r' => true,\r
+ 's' => true,\r
+ 'sshn' => true,\r
+ 't' => true,\r
+ 'tm' => true,\r
+ 'u' => true,\r
+ 'w' => true,\r
+ 'x' => true,\r
+ 'y' => true,\r
+ 'z' => true\r
+ ),\r
+ 'sg' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'per' => true\r
+ ),\r
+ 'sh' => true,\r
+ 'si' => true,\r
+ 'sk' => true,\r
+ 'sl' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'org' => true\r
+ ),\r
+ 'sm' => true,\r
+ 'sn' => array(\r
+ 'art' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gouv' => true,\r
+ 'org' => true,\r
+ 'perso' => true,\r
+ 'univ' => true\r
+ ),\r
+ 'so' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'sr' => true,\r
+ 'st' => array(\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'consulado' => true,\r
+ 'edu' => true,\r
+ 'embaixada' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'principe' => true,\r
+ 'saotome' => true,\r
+ 'store' => true\r
+ ),\r
+ 'su' => true,\r
+ 'sv' => array(\r
+ '*' => true\r
+ ),\r
+ 'sy' => array(\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'mil' => true,\r
+ 'com' => true,\r
+ 'org' => true\r
+ ),\r
+ 'sz' => array(\r
+ 'co' => true,\r
+ 'ac' => true,\r
+ 'org' => true\r
+ ),\r
+ 'tc' => true,\r
+ 'td' => true,\r
+ 'tel' => true,\r
+ 'tf' => true,\r
+ 'tg' => true,\r
+ 'th' => array(\r
+ 'ac' => true,\r
+ 'co' => true,\r
+ 'go' => true,\r
+ 'in' => true,\r
+ 'mi' => true,\r
+ 'net' => true,\r
+ 'or' => true\r
+ ),\r
+ 'tj' => array(\r
+ 'ac' => true,\r
+ 'biz' => true,\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'go' => true,\r
+ 'gov' => true,\r
+ 'int' => true,\r
+ 'mil' => true,\r
+ 'name' => true,\r
+ 'net' => true,\r
+ 'nic' => true,\r
+ 'org' => true,\r
+ 'test' => true,\r
+ 'web' => true\r
+ ),\r
+ 'tk' => true,\r
+ 'tl' => array(\r
+ 'gov' => true\r
+ ),\r
+ 'tm' => true,\r
+ 'tn' => array(\r
+ 'com' => true,\r
+ 'ens' => true,\r
+ 'fin' => true,\r
+ 'gov' => true,\r
+ 'ind' => true,\r
+ 'intl' => true,\r
+ 'nat' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'info' => true,\r
+ 'perso' => true,\r
+ 'tourism' => true,\r
+ 'edunet' => true,\r
+ 'rnrt' => true,\r
+ 'rns' => true,\r
+ 'rnu' => true,\r
+ 'mincom' => true,\r
+ 'agrinet' => true,\r
+ 'defense' => true,\r
+ 'turen' => true\r
+ ),\r
+ 'to' => array(\r
+ 'com' => true,\r
+ 'gov' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'mil' => true\r
+ ),\r
+ 'tr' => array(\r
+ '*' => true,\r
+ '!nic' => true,\r
+ 'nc' => array(\r
+ 'gov' => true\r
+ )\r
+ ),\r
+ 'travel' => true,\r
+ 'tt' => array(\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'org' => true,\r
+ 'net' => true,\r
+ 'biz' => true,\r
+ 'info' => true,\r
+ 'pro' => true,\r
+ 'int' => true,\r
+ 'coop' => true,\r
+ 'jobs' => true,\r
+ 'mobi' => true,\r
+ 'travel' => true,\r
+ 'museum' => true,\r
+ 'aero' => true,\r
+ 'name' => true,\r
+ 'gov' => true,\r
+ 'edu' => true\r
+ ),\r
+ 'tv' => array(\r
+ 'dyndns' => true,\r
+ 'better-than' => true,\r
+ 'on-the-web' => true,\r
+ 'worse-than' => true\r
+ ),\r
+ 'tw' => array(\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'idv' => true,\r
+ 'game' => true,\r
+ 'ebiz' => true,\r
+ 'club' => true,\r
+ '網路' => true,\r
+ '組織' => true,\r
+ '商業' => true\r
+ ),\r
+ 'tz' => array(\r
+ 'ac' => true,\r
+ 'co' => true,\r
+ 'go' => true,\r
+ 'mil' => true,\r
+ 'ne' => true,\r
+ 'or' => true,\r
+ 'sc' => true\r
+ ),\r
+ 'ua' => array(\r
+ 'com' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'in' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'cherkassy' => true,\r
+ 'chernigov' => true,\r
+ 'chernovtsy' => true,\r
+ 'ck' => true,\r
+ 'cn' => true,\r
+ 'crimea' => true,\r
+ 'cv' => true,\r
+ 'dn' => true,\r
+ 'dnepropetrovsk' => true,\r
+ 'donetsk' => true,\r
+ 'dp' => true,\r
+ 'if' => true,\r
+ 'ivano-frankivsk' => true,\r
+ 'kh' => true,\r
+ 'kharkov' => true,\r
+ 'kherson' => true,\r
+ 'khmelnitskiy' => true,\r
+ 'kiev' => true,\r
+ 'kirovograd' => true,\r
+ 'km' => true,\r
+ 'kr' => true,\r
+ 'ks' => true,\r
+ 'kv' => true,\r
+ 'lg' => true,\r
+ 'lugansk' => true,\r
+ 'lutsk' => true,\r
+ 'lviv' => true,\r
+ 'mk' => true,\r
+ 'nikolaev' => true,\r
+ 'od' => true,\r
+ 'odessa' => true,\r
+ 'pl' => true,\r
+ 'poltava' => true,\r
+ 'rovno' => true,\r
+ 'rv' => true,\r
+ 'sebastopol' => true,\r
+ 'sumy' => true,\r
+ 'te' => true,\r
+ 'ternopil' => true,\r
+ 'uzhgorod' => true,\r
+ 'vinnica' => true,\r
+ 'vn' => true,\r
+ 'zaporizhzhe' => true,\r
+ 'zp' => true,\r
+ 'zhitomir' => true,\r
+ 'zt' => true,\r
+ 'co' => true,\r
+ 'pp' => true\r
+ ),\r
+ 'ug' => array(\r
+ 'co' => true,\r
+ 'ac' => true,\r
+ 'sc' => true,\r
+ 'go' => true,\r
+ 'ne' => true,\r
+ 'or' => true\r
+ ),\r
+ 'uk' => array(\r
+ '*' => true,\r
+ 'sch' => array(\r
+ '*' => true\r
+ ),\r
+ '!bl' => true,\r
+ '!british-library' => true,\r
+ '!icnet' => true,\r
+ '!jet' => true,\r
+ '!mod' => true,\r
+ '!nel' => true,\r
+ '!nhs' => true,\r
+ '!nic' => true,\r
+ '!nls' => true,\r
+ '!national-library-scotland' => true,\r
+ '!parliament' => true,\r
+ '!police' => true\r
+ ),\r
+ 'us' => array(\r
+ 'dni' => true,\r
+ 'fed' => true,\r
+ 'isa' => true,\r
+ 'kids' => true,\r
+ 'nsn' => true,\r
+ 'ak' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'al' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ar' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'as' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'az' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ca' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'co' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ct' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'dc' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'de' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'fl' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ga' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'gu' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'hi' => array(\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ia' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'id' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'il' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'in' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ks' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ky' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'la' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ma' => array(\r
+ 'k12' => array(\r
+ 'pvt' => true,\r
+ 'chtr' => true,\r
+ 'paroch' => true\r
+ ),\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'md' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'me' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'mi' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'mn' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'mo' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ms' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'mt' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'nc' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'nd' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ne' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'nh' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'nj' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'nm' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'nv' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ny' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'oh' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ok' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'or' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'pa' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'pr' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ri' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'sc' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'sd' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'tn' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'tx' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'ut' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'vi' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'vt' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'va' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'wa' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'wi' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'wv' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'wy' => array(\r
+ 'k12' => true,\r
+ 'cc' => true,\r
+ 'lib' => true\r
+ ),\r
+ 'is-by' => true,\r
+ 'land-4-sale' => true,\r
+ 'stuff-4-sale' => true\r
+ ),\r
+ 'uy' => array(\r
+ '*' => true\r
+ ),\r
+ 'uz' => array(\r
+ 'com' => true,\r
+ 'co' => true\r
+ ),\r
+ 'va' => true,\r
+ 'vc' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'mil' => true,\r
+ 'edu' => true\r
+ ),\r
+ 've' => array(\r
+ '*' => true\r
+ ),\r
+ 'vg' => true,\r
+ 'vi' => array(\r
+ 'co' => true,\r
+ 'com' => true,\r
+ 'k12' => true,\r
+ 'net' => true,\r
+ 'org' => true\r
+ ),\r
+ 'vn' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'edu' => true,\r
+ 'gov' => true,\r
+ 'int' => true,\r
+ 'ac' => true,\r
+ 'biz' => true,\r
+ 'info' => true,\r
+ 'name' => true,\r
+ 'pro' => true,\r
+ 'health' => true\r
+ ),\r
+ 'vu' => true,\r
+ 'wf' => true,\r
+ 'ws' => array(\r
+ 'com' => true,\r
+ 'net' => true,\r
+ 'org' => true,\r
+ 'gov' => true,\r
+ 'edu' => true,\r
+ 'dyndns' => true,\r
+ 'mypets' => true\r
+ ),\r
+ 'yt' => true,\r
+ 'امارات' => true,\r
+ 'বাংলা' => true,\r
+ '中国' => true,\r
+ '中國' => true,\r
+ 'الجزائر' => true,\r
+ 'مصر' => true,\r
+ 'გე' => true,\r
+ '香港' => true,\r
+ 'भारत' => true,\r
+ 'بھارت' => true,\r
+ 'భారత్' => true,\r
+ 'ભારત' => true,\r
+ 'ਭਾਰਤ' => true,\r
+ 'ভারত' => true,\r
+ 'இந்தியா' => true,\r
+ 'ایران' => true,\r
+ 'ايران' => true,\r
+ 'الاردن' => true,\r
+ '한국' => true,\r
+ 'ලංකා' => true,\r
+ 'இலங்கை' => true,\r
+ 'المغرب' => true,\r
+ 'عمان' => true,\r
+ 'فلسطين' => true,\r
+ 'срб' => true,\r
+ 'рф' => true,\r
+ 'قطر' => true,\r
+ 'السعودية' => true,\r
+ 'السعودیة' => true,\r
+ 'السعودیۃ' => true,\r
+ 'السعوديه' => true,\r
+ 'سورية' => true,\r
+ 'سوريا' => true,\r
+ '新加坡' => true,\r
+ 'சிங்கப்பூர்' => true,\r
+ 'ไทย' => true,\r
+ 'تونس' => true,\r
+ '台灣' => true,\r
+ '台湾' => true,\r
+ '臺灣' => true,\r
+ 'укр' => true,\r
+ 'اليمن' => true,\r
+ 'xxx' => true,\r
+ 'ye' => array(\r
+ '*' => true\r
+ ),\r
+ 'za' => array(\r
+ '*' => true\r
+ ),\r
+ 'zm' => array(\r
+ '*' => true\r
+ ),\r
+ 'zw' => array(\r
+ '*' => true\r
+ )\r
+);\r
+?>
\ No newline at end of file