pictcode / lib / Cake / Network / Http / HttpSocket.php @ 40928d1c
履歴 | 表示 | アノテート | ダウンロード (31.605 KB)
| 1 |
<?php
|
|---|---|
| 2 |
/**
|
| 3 |
* HTTP Socket connection class.
|
| 4 |
*
|
| 5 |
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
| 6 |
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
| 7 |
*
|
| 8 |
* Licensed under The MIT License
|
| 9 |
* For full copyright and license information, please see the LICENSE.txt
|
| 10 |
* Redistributions of files must retain the above copyright notice.
|
| 11 |
*
|
| 12 |
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
| 13 |
* @link http://cakephp.org CakePHP(tm) Project
|
| 14 |
* @package Cake.Network.Http
|
| 15 |
* @since CakePHP(tm) v 1.2.0
|
| 16 |
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
| 17 |
*/
|
| 18 |
|
| 19 |
App::uses('CakeSocket', 'Network'); |
| 20 |
App::uses('Router', 'Routing'); |
| 21 |
App::uses('Hash', 'Utility'); |
| 22 |
|
| 23 |
/**
|
| 24 |
* CakePHP network socket connection class.
|
| 25 |
*
|
| 26 |
* Core base class for HTTP network communication. HttpSocket can be used as an
|
| 27 |
* Object Oriented replacement for cURL in many places.
|
| 28 |
*
|
| 29 |
* @package Cake.Network.Http
|
| 30 |
*/
|
| 31 |
class HttpSocket extends CakeSocket { |
| 32 |
|
| 33 |
/**
|
| 34 |
* When one activates the $quirksMode by setting it to true, all checks meant to
|
| 35 |
* enforce RFC 2616 (HTTP/1.1 specs).
|
| 36 |
* will be disabled and additional measures to deal with non-standard responses will be enabled.
|
| 37 |
*
|
| 38 |
* @var bool
|
| 39 |
*/
|
| 40 |
public $quirksMode = false; |
| 41 |
|
| 42 |
/**
|
| 43 |
* Contain information about the last request (read only)
|
| 44 |
*
|
| 45 |
* @var array
|
| 46 |
*/
|
| 47 |
public $request = array( |
| 48 |
'method' => 'GET', |
| 49 |
'uri' => array( |
| 50 |
'scheme' => 'http', |
| 51 |
'host' => null, |
| 52 |
'port' => 80, |
| 53 |
'user' => null, |
| 54 |
'pass' => null, |
| 55 |
'path' => null, |
| 56 |
'query' => null, |
| 57 |
'fragment' => null |
| 58 |
), |
| 59 |
'version' => '1.1', |
| 60 |
'body' => '', |
| 61 |
'line' => null, |
| 62 |
'header' => array( |
| 63 |
'Connection' => 'close', |
| 64 |
'User-Agent' => 'CakePHP' |
| 65 |
), |
| 66 |
'raw' => null, |
| 67 |
'redirect' => false, |
| 68 |
'cookies' => array(), |
| 69 |
); |
| 70 |
|
| 71 |
/**
|
| 72 |
* Contain information about the last response (read only)
|
| 73 |
*
|
| 74 |
* @var array
|
| 75 |
*/
|
| 76 |
public $response = null; |
| 77 |
|
| 78 |
/**
|
| 79 |
* Response class name
|
| 80 |
*
|
| 81 |
* @var string
|
| 82 |
*/
|
| 83 |
public $responseClass = 'HttpSocketResponse'; |
| 84 |
|
| 85 |
/**
|
| 86 |
* Configuration settings for the HttpSocket and the requests
|
| 87 |
*
|
| 88 |
* @var array
|
| 89 |
*/
|
| 90 |
public $config = array( |
| 91 |
'persistent' => false, |
| 92 |
'host' => 'localhost', |
| 93 |
'protocol' => 'tcp', |
| 94 |
'port' => 80, |
| 95 |
'timeout' => 30, |
| 96 |
'ssl_verify_peer' => true, |
| 97 |
'ssl_allow_self_signed' => false, |
| 98 |
'ssl_verify_depth' => 5, |
| 99 |
'ssl_verify_host' => true, |
| 100 |
'request' => array( |
| 101 |
'uri' => array( |
| 102 |
'scheme' => array('http', 'https'), |
| 103 |
'host' => 'localhost', |
| 104 |
'port' => array(80, 443) |
| 105 |
), |
| 106 |
'redirect' => false, |
| 107 |
'cookies' => array(), |
| 108 |
) |
| 109 |
); |
| 110 |
|
| 111 |
/**
|
| 112 |
* Authentication settings
|
| 113 |
*
|
| 114 |
* @var array
|
| 115 |
*/
|
| 116 |
protected $_auth = array(); |
| 117 |
|
| 118 |
/**
|
| 119 |
* Proxy settings
|
| 120 |
*
|
| 121 |
* @var array
|
| 122 |
*/
|
| 123 |
protected $_proxy = array(); |
| 124 |
|
| 125 |
/**
|
| 126 |
* Resource to receive the content of request
|
| 127 |
*
|
| 128 |
* @var mixed
|
| 129 |
*/
|
| 130 |
protected $_contentResource = null; |
| 131 |
|
| 132 |
/**
|
| 133 |
* Build an HTTP Socket using the specified configuration.
|
| 134 |
*
|
| 135 |
* You can use a URL string to set the URL and use default configurations for
|
| 136 |
* all other options:
|
| 137 |
*
|
| 138 |
* `$http = new HttpSocket('http://cakephp.org/');`
|
| 139 |
*
|
| 140 |
* Or use an array to configure multiple options:
|
| 141 |
*
|
| 142 |
* ```
|
| 143 |
* $http = new HttpSocket(array(
|
| 144 |
* 'host' => 'cakephp.org',
|
| 145 |
* 'timeout' => 20
|
| 146 |
* ));
|
| 147 |
* ```
|
| 148 |
*
|
| 149 |
* See HttpSocket::$config for options that can be used.
|
| 150 |
*
|
| 151 |
* @param string|array $config Configuration information, either a string URL or an array of options.
|
| 152 |
*/
|
| 153 |
public function __construct($config = array()) { |
| 154 |
if (is_string($config)) { |
| 155 |
$this->_configUri($config); |
| 156 |
} elseif (is_array($config)) { |
| 157 |
if (isset($config['request']['uri']) && is_string($config['request']['uri'])) { |
| 158 |
$this->_configUri($config['request']['uri']); |
| 159 |
unset($config['request']['uri']); |
| 160 |
} |
| 161 |
$this->config = Hash::merge($this->config, $config); |
| 162 |
} |
| 163 |
parent::__construct($this->config); |
| 164 |
} |
| 165 |
|
| 166 |
/**
|
| 167 |
* Set authentication settings.
|
| 168 |
*
|
| 169 |
* Accepts two forms of parameters. If all you need is a username + password, as with
|
| 170 |
* Basic authentication you can do the following:
|
| 171 |
*
|
| 172 |
* ```
|
| 173 |
* $http->configAuth('Basic', 'mark', 'secret');
|
| 174 |
* ```
|
| 175 |
*
|
| 176 |
* If you are using an authentication strategy that requires more inputs, like Digest authentication
|
| 177 |
* you can call `configAuth()` with an array of user information.
|
| 178 |
*
|
| 179 |
* ```
|
| 180 |
* $http->configAuth('Digest', array(
|
| 181 |
* 'user' => 'mark',
|
| 182 |
* 'pass' => 'secret',
|
| 183 |
* 'realm' => 'my-realm',
|
| 184 |
* 'nonce' => 1235
|
| 185 |
* ));
|
| 186 |
* ```
|
| 187 |
*
|
| 188 |
* To remove any set authentication strategy, call `configAuth()` with no parameters:
|
| 189 |
*
|
| 190 |
* `$http->configAuth();`
|
| 191 |
*
|
| 192 |
* @param string $method Authentication method (ie. Basic, Digest). If empty, disable authentication
|
| 193 |
* @param string|array $user Username for authentication. Can be an array with settings to authentication class
|
| 194 |
* @param string $pass Password for authentication
|
| 195 |
* @return void
|
| 196 |
*/
|
| 197 |
public function configAuth($method, $user = null, $pass = null) { |
| 198 |
if (empty($method)) { |
| 199 |
$this->_auth = array(); |
| 200 |
return;
|
| 201 |
} |
| 202 |
if (is_array($user)) { |
| 203 |
$this->_auth = array($method => $user); |
| 204 |
return;
|
| 205 |
} |
| 206 |
$this->_auth = array($method => compact('user', 'pass')); |
| 207 |
} |
| 208 |
|
| 209 |
/**
|
| 210 |
* Set proxy settings
|
| 211 |
*
|
| 212 |
* @param string|array $host Proxy host. Can be an array with settings to authentication class
|
| 213 |
* @param int $port Port. Default 3128.
|
| 214 |
* @param string $method Proxy method (ie, Basic, Digest). If empty, disable proxy authentication
|
| 215 |
* @param string $user Username if your proxy need authentication
|
| 216 |
* @param string $pass Password to proxy authentication
|
| 217 |
* @return void
|
| 218 |
*/
|
| 219 |
public function configProxy($host, $port = 3128, $method = null, $user = null, $pass = null) { |
| 220 |
if (empty($host)) { |
| 221 |
$this->_proxy = array(); |
| 222 |
return;
|
| 223 |
} |
| 224 |
if (is_array($host)) { |
| 225 |
$this->_proxy = $host + array('host' => null); |
| 226 |
return;
|
| 227 |
} |
| 228 |
$this->_proxy = compact('host', 'port', 'method', 'user', 'pass'); |
| 229 |
} |
| 230 |
|
| 231 |
/**
|
| 232 |
* Set the resource to receive the request content. This resource must support fwrite.
|
| 233 |
*
|
| 234 |
* @param resource|bool $resource Resource or false to disable the resource use
|
| 235 |
* @return void
|
| 236 |
* @throws SocketException
|
| 237 |
*/
|
| 238 |
public function setContentResource($resource) { |
| 239 |
if ($resource === false) { |
| 240 |
$this->_contentResource = null; |
| 241 |
return;
|
| 242 |
} |
| 243 |
if (!is_resource($resource)) { |
| 244 |
throw new SocketException(__d('cake_dev', 'Invalid resource.')); |
| 245 |
} |
| 246 |
$this->_contentResource = $resource; |
| 247 |
} |
| 248 |
|
| 249 |
/**
|
| 250 |
* Issue the specified request. HttpSocket::get() and HttpSocket::post() wrap this
|
| 251 |
* method and provide a more granular interface.
|
| 252 |
*
|
| 253 |
* @param string|array $request Either an URI string, or an array defining host/uri
|
| 254 |
* @return mixed false on error, HttpSocketResponse on success
|
| 255 |
* @throws SocketException
|
| 256 |
*/
|
| 257 |
public function request($request = array()) { |
| 258 |
$this->reset(false); |
| 259 |
|
| 260 |
if (is_string($request)) { |
| 261 |
$request = array('uri' => $request); |
| 262 |
} elseif (!is_array($request)) { |
| 263 |
return false; |
| 264 |
} |
| 265 |
|
| 266 |
if (!isset($request['uri'])) { |
| 267 |
$request['uri'] = null; |
| 268 |
} |
| 269 |
$uri = $this->_parseUri($request['uri']); |
| 270 |
if (!isset($uri['host'])) { |
| 271 |
$host = $this->config['host']; |
| 272 |
} |
| 273 |
if (isset($request['host'])) { |
| 274 |
$host = $request['host']; |
| 275 |
unset($request['host']); |
| 276 |
} |
| 277 |
$request['uri'] = $this->url($request['uri']); |
| 278 |
$request['uri'] = $this->_parseUri($request['uri'], true); |
| 279 |
$this->request = Hash::merge($this->request, array_diff_key($this->config['request'], array('cookies' => true)), $request); |
| 280 |
|
| 281 |
$this->_configUri($this->request['uri']); |
| 282 |
|
| 283 |
$Host = $this->request['uri']['host']; |
| 284 |
if (!empty($this->config['request']['cookies'][$Host])) { |
| 285 |
if (!isset($this->request['cookies'])) { |
| 286 |
$this->request['cookies'] = array(); |
| 287 |
} |
| 288 |
if (!isset($request['cookies'])) { |
| 289 |
$request['cookies'] = array(); |
| 290 |
} |
| 291 |
$this->request['cookies'] = array_merge($this->request['cookies'], $this->config['request']['cookies'][$Host], $request['cookies']); |
| 292 |
} |
| 293 |
|
| 294 |
if (isset($host)) { |
| 295 |
$this->config['host'] = $host; |
| 296 |
} |
| 297 |
|
| 298 |
$this->_setProxy();
|
| 299 |
$this->request['proxy'] = $this->_proxy; |
| 300 |
|
| 301 |
$cookies = null; |
| 302 |
|
| 303 |
if (is_array($this->request['header'])) { |
| 304 |
if (!empty($this->request['cookies'])) { |
| 305 |
$cookies = $this->buildCookies($this->request['cookies']); |
| 306 |
} |
| 307 |
$scheme = ''; |
| 308 |
$port = 0; |
| 309 |
if (isset($this->request['uri']['scheme'])) { |
| 310 |
$scheme = $this->request['uri']['scheme']; |
| 311 |
} |
| 312 |
if (isset($this->request['uri']['port'])) { |
| 313 |
$port = $this->request['uri']['port']; |
| 314 |
} |
| 315 |
if (($scheme === 'http' && $port != 80) || |
| 316 |
($scheme === 'https' && $port != 443) || |
| 317 |
($port != 80 && $port != 443) |
| 318 |
) {
|
| 319 |
$Host .= ':' . $port; |
| 320 |
} |
| 321 |
$this->request['header'] = array_merge(compact('Host'), $this->request['header']); |
| 322 |
} |
| 323 |
|
| 324 |
if (isset($this->request['uri']['user'], $this->request['uri']['pass'])) { |
| 325 |
$this->configAuth('Basic', $this->request['uri']['user'], $this->request['uri']['pass']); |
| 326 |
} elseif (isset($this->request['auth'], $this->request['auth']['method'], $this->request['auth']['user'], $this->request['auth']['pass'])) { |
| 327 |
$this->configAuth($this->request['auth']['method'], $this->request['auth']['user'], $this->request['auth']['pass']); |
| 328 |
} |
| 329 |
$authHeader = Hash::get($this->request, 'header.Authorization'); |
| 330 |
if (empty($authHeader)) { |
| 331 |
$this->_setAuth();
|
| 332 |
$this->request['auth'] = $this->_auth; |
| 333 |
} |
| 334 |
|
| 335 |
if (is_array($this->request['body'])) { |
| 336 |
$this->request['body'] = http_build_query($this->request['body'], '', '&'); |
| 337 |
} |
| 338 |
|
| 339 |
if (!empty($this->request['body']) && !isset($this->request['header']['Content-Type'])) { |
| 340 |
$this->request['header']['Content-Type'] = 'application/x-www-form-urlencoded'; |
| 341 |
} |
| 342 |
|
| 343 |
if (!empty($this->request['body']) && !isset($this->request['header']['Content-Length'])) { |
| 344 |
$this->request['header']['Content-Length'] = strlen($this->request['body']); |
| 345 |
} |
| 346 |
if (isset($this->request['uri']['scheme']) && $this->request['uri']['scheme'] === 'https' && in_array($this->config['protocol'], array(false, 'tcp'))) { |
| 347 |
$this->config['protocol'] = 'ssl'; |
| 348 |
} |
| 349 |
|
| 350 |
$connectionType = null; |
| 351 |
if (isset($this->request['header']['Connection'])) { |
| 352 |
$connectionType = $this->request['header']['Connection']; |
| 353 |
} |
| 354 |
$this->request['header'] = $this->_buildHeader($this->request['header']) . $cookies; |
| 355 |
|
| 356 |
if (empty($this->request['line'])) { |
| 357 |
$this->request['line'] = $this->_buildRequestLine($this->request); |
| 358 |
} |
| 359 |
|
| 360 |
if ($this->quirksMode === false && $this->request['line'] === false) { |
| 361 |
return false; |
| 362 |
} |
| 363 |
|
| 364 |
$this->request['raw'] = ''; |
| 365 |
if ($this->request['line'] !== false) { |
| 366 |
$this->request['raw'] = $this->request['line']; |
| 367 |
} |
| 368 |
|
| 369 |
if ($this->request['header'] !== false) { |
| 370 |
$this->request['raw'] .= $this->request['header']; |
| 371 |
} |
| 372 |
|
| 373 |
$this->request['raw'] .= "\r\n"; |
| 374 |
$this->request['raw'] .= $this->request['body']; |
| 375 |
|
| 376 |
// SSL context is set during the connect() method.
|
| 377 |
$this->write($this->request['raw']); |
| 378 |
|
| 379 |
$response = null; |
| 380 |
$inHeader = true; |
| 381 |
while (($data = $this->read()) !== false) { |
| 382 |
if ($this->_contentResource) { |
| 383 |
if ($inHeader) { |
| 384 |
$response .= $data; |
| 385 |
$pos = strpos($response, "\r\n\r\n"); |
| 386 |
if ($pos !== false) { |
| 387 |
$pos += 4; |
| 388 |
$data = substr($response, $pos); |
| 389 |
fwrite($this->_contentResource, $data); |
| 390 |
|
| 391 |
$response = substr($response, 0, $pos); |
| 392 |
$inHeader = false; |
| 393 |
} |
| 394 |
} else {
|
| 395 |
fwrite($this->_contentResource, $data); |
| 396 |
fflush($this->_contentResource); |
| 397 |
} |
| 398 |
} else {
|
| 399 |
$response .= $data; |
| 400 |
} |
| 401 |
} |
| 402 |
|
| 403 |
if ($connectionType === 'close') { |
| 404 |
$this->disconnect();
|
| 405 |
} |
| 406 |
|
| 407 |
list($plugin, $responseClass) = pluginSplit($this->responseClass, true); |
| 408 |
App::uses($responseClass, $plugin . 'Network/Http'); |
| 409 |
if (!class_exists($responseClass)) { |
| 410 |
throw new SocketException(__d('cake_dev', 'Class %s not found.', $this->responseClass)); |
| 411 |
} |
| 412 |
$this->response = new $responseClass($response); |
| 413 |
|
| 414 |
if (!empty($this->response->cookies)) { |
| 415 |
if (!isset($this->config['request']['cookies'][$Host])) { |
| 416 |
$this->config['request']['cookies'][$Host] = array(); |
| 417 |
} |
| 418 |
$this->config['request']['cookies'][$Host] = array_merge($this->config['request']['cookies'][$Host], $this->response->cookies); |
| 419 |
} |
| 420 |
|
| 421 |
if ($this->request['redirect'] && $this->response->isRedirect()) { |
| 422 |
$location = trim($this->response->getHeader('Location'), '='); |
| 423 |
$request['uri'] = str_replace('%2F', '/', $location); |
| 424 |
$request['redirect'] = is_int($this->request['redirect']) ? $this->request['redirect'] - 1 : $this->request['redirect']; |
| 425 |
$this->response = $this->request($request); |
| 426 |
} |
| 427 |
|
| 428 |
return $this->response; |
| 429 |
} |
| 430 |
|
| 431 |
/**
|
| 432 |
* Issues a GET request to the specified URI, query, and request.
|
| 433 |
*
|
| 434 |
* Using a string uri and an array of query string parameters:
|
| 435 |
*
|
| 436 |
* `$response = $http->get('http://google.com/search', array('q' => 'cakephp', 'client' => 'safari'));`
|
| 437 |
*
|
| 438 |
* Would do a GET request to `http://google.com/search?q=cakephp&client=safari`
|
| 439 |
*
|
| 440 |
* You could express the same thing using a uri array and query string parameters:
|
| 441 |
*
|
| 442 |
* ```
|
| 443 |
* $response = $http->get(
|
| 444 |
* array('host' => 'google.com', 'path' => '/search'),
|
| 445 |
* array('q' => 'cakephp', 'client' => 'safari')
|
| 446 |
* );
|
| 447 |
* ```
|
| 448 |
*
|
| 449 |
* @param string|array $uri URI to request. Either a string uri, or a uri array, see HttpSocket::_parseUri()
|
| 450 |
* @param array $query Querystring parameters to append to URI
|
| 451 |
* @param array $request An indexed array with indexes such as 'method' or uri
|
| 452 |
* @return mixed Result of request, either false on failure or the response to the request.
|
| 453 |
*/
|
| 454 |
public function get($uri = null, $query = array(), $request = array()) { |
| 455 |
if (!empty($query)) { |
| 456 |
$uri = $this->_parseUri($uri, $this->config['request']['uri']); |
| 457 |
if (isset($uri['query'])) { |
| 458 |
$uri['query'] = array_merge($uri['query'], $query); |
| 459 |
} else {
|
| 460 |
$uri['query'] = $query; |
| 461 |
} |
| 462 |
$uri = $this->_buildUri($uri); |
| 463 |
} |
| 464 |
|
| 465 |
$request = Hash::merge(array('method' => 'GET', 'uri' => $uri), $request); |
| 466 |
return $this->request($request); |
| 467 |
} |
| 468 |
|
| 469 |
/**
|
| 470 |
* Issues a HEAD request to the specified URI, query, and request.
|
| 471 |
*
|
| 472 |
* By definition HEAD request are identical to GET request except they return no response body. This means that all
|
| 473 |
* information and examples relevant to GET also applys to HEAD.
|
| 474 |
*
|
| 475 |
* @param string|array $uri URI to request. Either a string URI, or a URI array, see HttpSocket::_parseUri()
|
| 476 |
* @param array $query Querystring parameters to append to URI
|
| 477 |
* @param array $request An indexed array with indexes such as 'method' or uri
|
| 478 |
* @return mixed Result of request, either false on failure or the response to the request.
|
| 479 |
*/
|
| 480 |
public function head($uri = null, $query = array(), $request = array()) { |
| 481 |
if (!empty($query)) { |
| 482 |
$uri = $this->_parseUri($uri, $this->config['request']['uri']); |
| 483 |
if (isset($uri['query'])) { |
| 484 |
$uri['query'] = array_merge($uri['query'], $query); |
| 485 |
} else {
|
| 486 |
$uri['query'] = $query; |
| 487 |
} |
| 488 |
$uri = $this->_buildUri($uri); |
| 489 |
} |
| 490 |
|
| 491 |
$request = Hash::merge(array('method' => 'HEAD', 'uri' => $uri), $request); |
| 492 |
return $this->request($request); |
| 493 |
} |
| 494 |
|
| 495 |
/**
|
| 496 |
* Issues a POST request to the specified URI, query, and request.
|
| 497 |
*
|
| 498 |
* `post()` can be used to post simple data arrays to a URL:
|
| 499 |
*
|
| 500 |
* ```
|
| 501 |
* $response = $http->post('http://example.com', array(
|
| 502 |
* 'username' => 'batman',
|
| 503 |
* 'password' => 'bruce_w4yne'
|
| 504 |
* ));
|
| 505 |
* ```
|
| 506 |
*
|
| 507 |
* @param string|array $uri URI to request. See HttpSocket::_parseUri()
|
| 508 |
* @param array $data Array of request body data keys and values.
|
| 509 |
* @param array $request An indexed array with indexes such as 'method' or uri
|
| 510 |
* @return mixed Result of request, either false on failure or the response to the request.
|
| 511 |
*/
|
| 512 |
public function post($uri = null, $data = array(), $request = array()) { |
| 513 |
$request = Hash::merge(array('method' => 'POST', 'uri' => $uri, 'body' => $data), $request); |
| 514 |
return $this->request($request); |
| 515 |
} |
| 516 |
|
| 517 |
/**
|
| 518 |
* Issues a PUT request to the specified URI, query, and request.
|
| 519 |
*
|
| 520 |
* @param string|array $uri URI to request, See HttpSocket::_parseUri()
|
| 521 |
* @param array $data Array of request body data keys and values.
|
| 522 |
* @param array $request An indexed array with indexes such as 'method' or uri
|
| 523 |
* @return mixed Result of request
|
| 524 |
*/
|
| 525 |
public function put($uri = null, $data = array(), $request = array()) { |
| 526 |
$request = Hash::merge(array('method' => 'PUT', 'uri' => $uri, 'body' => $data), $request); |
| 527 |
return $this->request($request); |
| 528 |
} |
| 529 |
|
| 530 |
/**
|
| 531 |
* Issues a PATCH request to the specified URI, query, and request.
|
| 532 |
*
|
| 533 |
* @param string|array $uri URI to request, See HttpSocket::_parseUri()
|
| 534 |
* @param array $data Array of request body data keys and values.
|
| 535 |
* @param array $request An indexed array with indexes such as 'method' or uri
|
| 536 |
* @return mixed Result of request
|
| 537 |
*/
|
| 538 |
public function patch($uri = null, $data = array(), $request = array()) { |
| 539 |
$request = Hash::merge(array('method' => 'PATCH', 'uri' => $uri, 'body' => $data), $request); |
| 540 |
return $this->request($request); |
| 541 |
} |
| 542 |
|
| 543 |
/**
|
| 544 |
* Issues a DELETE request to the specified URI, query, and request.
|
| 545 |
*
|
| 546 |
* @param string|array $uri URI to request (see {@link _parseUri()})
|
| 547 |
* @param array $data Array of request body data keys and values.
|
| 548 |
* @param array $request An indexed array with indexes such as 'method' or uri
|
| 549 |
* @return mixed Result of request
|
| 550 |
*/
|
| 551 |
public function delete($uri = null, $data = array(), $request = array()) { |
| 552 |
$request = Hash::merge(array('method' => 'DELETE', 'uri' => $uri, 'body' => $data), $request); |
| 553 |
return $this->request($request); |
| 554 |
} |
| 555 |
|
| 556 |
/**
|
| 557 |
* Normalizes URLs into a $uriTemplate. If no template is provided
|
| 558 |
* a default one will be used. Will generate the URL using the
|
| 559 |
* current config information.
|
| 560 |
*
|
| 561 |
* ### Usage:
|
| 562 |
*
|
| 563 |
* After configuring part of the request parameters, you can use url() to generate
|
| 564 |
* URLs.
|
| 565 |
*
|
| 566 |
* ```
|
| 567 |
* $http = new HttpSocket('http://www.cakephp.org');
|
| 568 |
* $url = $http->url('/search?q=bar');
|
| 569 |
* ```
|
| 570 |
*
|
| 571 |
* Would return `http://www.cakephp.org/search?q=bar`
|
| 572 |
*
|
| 573 |
* url() can also be used with custom templates:
|
| 574 |
*
|
| 575 |
* `$url = $http->url('http://www.cakephp/search?q=socket', '/%path?%query');`
|
| 576 |
*
|
| 577 |
* Would return `/search?q=socket`.
|
| 578 |
*
|
| 579 |
* @param string|array $url Either a string or array of URL options to create a URL with.
|
| 580 |
* @param string $uriTemplate A template string to use for URL formatting.
|
| 581 |
* @return mixed Either false on failure or a string containing the composed URL.
|
| 582 |
*/
|
| 583 |
public function url($url = null, $uriTemplate = null) { |
| 584 |
if ($url === null) { |
| 585 |
$url = '/'; |
| 586 |
} |
| 587 |
if (is_string($url)) { |
| 588 |
$scheme = $this->config['request']['uri']['scheme']; |
| 589 |
if (is_array($scheme)) { |
| 590 |
$scheme = $scheme[0]; |
| 591 |
} |
| 592 |
$port = $this->config['request']['uri']['port']; |
| 593 |
if (is_array($port)) { |
| 594 |
$port = $port[0]; |
| 595 |
} |
| 596 |
if ($url{0} === '/') { |
| 597 |
$url = $this->config['request']['uri']['host'] . ':' . $port . $url; |
| 598 |
} |
| 599 |
if (!preg_match('/^.+:\/\/|\*|^\//', $url)) { |
| 600 |
$url = $scheme . '://' . $url; |
| 601 |
} |
| 602 |
} elseif (!is_array($url) && !empty($url)) { |
| 603 |
return false; |
| 604 |
} |
| 605 |
|
| 606 |
$base = array_merge($this->config['request']['uri'], array('scheme' => array('http', 'https'), 'port' => array(80, 443))); |
| 607 |
$url = $this->_parseUri($url, $base); |
| 608 |
|
| 609 |
if (empty($url)) { |
| 610 |
$url = $this->config['request']['uri']; |
| 611 |
} |
| 612 |
|
| 613 |
if (!empty($uriTemplate)) { |
| 614 |
return $this->_buildUri($url, $uriTemplate); |
| 615 |
} |
| 616 |
return $this->_buildUri($url); |
| 617 |
} |
| 618 |
|
| 619 |
/**
|
| 620 |
* Set authentication in request
|
| 621 |
*
|
| 622 |
* @return void
|
| 623 |
* @throws SocketException
|
| 624 |
*/
|
| 625 |
protected function _setAuth() { |
| 626 |
if (empty($this->_auth)) { |
| 627 |
return;
|
| 628 |
} |
| 629 |
$method = key($this->_auth); |
| 630 |
list($plugin, $authClass) = pluginSplit($method, true); |
| 631 |
$authClass = Inflector::camelize($authClass) . 'Authentication'; |
| 632 |
App::uses($authClass, $plugin . 'Network/Http'); |
| 633 |
|
| 634 |
if (!class_exists($authClass)) { |
| 635 |
throw new SocketException(__d('cake_dev', 'Unknown authentication method.')); |
| 636 |
} |
| 637 |
if (!method_exists($authClass, 'authentication')) { |
| 638 |
throw new SocketException(__d('cake_dev', 'The %s does not support authentication.', $authClass)); |
| 639 |
} |
| 640 |
call_user_func_array("$authClass::authentication", array($this, &$this->_auth[$method])); |
| 641 |
} |
| 642 |
|
| 643 |
/**
|
| 644 |
* Set the proxy configuration and authentication
|
| 645 |
*
|
| 646 |
* @return void
|
| 647 |
* @throws SocketException
|
| 648 |
*/
|
| 649 |
protected function _setProxy() { |
| 650 |
if (empty($this->_proxy) || !isset($this->_proxy['host'], $this->_proxy['port'])) { |
| 651 |
return;
|
| 652 |
} |
| 653 |
$this->config['host'] = $this->_proxy['host']; |
| 654 |
$this->config['port'] = $this->_proxy['port']; |
| 655 |
$this->config['proxy'] = true; |
| 656 |
|
| 657 |
if (empty($this->_proxy['method']) || !isset($this->_proxy['user'], $this->_proxy['pass'])) { |
| 658 |
return;
|
| 659 |
} |
| 660 |
list($plugin, $authClass) = pluginSplit($this->_proxy['method'], true); |
| 661 |
$authClass = Inflector::camelize($authClass) . 'Authentication'; |
| 662 |
App::uses($authClass, $plugin . 'Network/Http'); |
| 663 |
|
| 664 |
if (!class_exists($authClass)) { |
| 665 |
throw new SocketException(__d('cake_dev', 'Unknown authentication method for proxy.')); |
| 666 |
} |
| 667 |
if (!method_exists($authClass, 'proxyAuthentication')) { |
| 668 |
throw new SocketException(__d('cake_dev', 'The %s does not support proxy authentication.', $authClass)); |
| 669 |
} |
| 670 |
call_user_func_array("$authClass::proxyAuthentication", array($this, &$this->_proxy)); |
| 671 |
|
| 672 |
if (!empty($this->request['header']['Proxy-Authorization'])) { |
| 673 |
$this->config['proxyauth'] = $this->request['header']['Proxy-Authorization']; |
| 674 |
if ($this->request['uri']['scheme'] === 'https') { |
| 675 |
$this->request['header'] = Hash::remove($this->request['header'], 'Proxy-Authorization'); |
| 676 |
} |
| 677 |
} |
| 678 |
} |
| 679 |
|
| 680 |
/**
|
| 681 |
* Parses and sets the specified URI into current request configuration.
|
| 682 |
*
|
| 683 |
* @param string|array $uri URI, See HttpSocket::_parseUri()
|
| 684 |
* @return bool If uri has merged in config
|
| 685 |
*/
|
| 686 |
protected function _configUri($uri = null) { |
| 687 |
if (empty($uri)) { |
| 688 |
return false; |
| 689 |
} |
| 690 |
|
| 691 |
if (is_array($uri)) { |
| 692 |
$uri = $this->_parseUri($uri); |
| 693 |
} else {
|
| 694 |
$uri = $this->_parseUri($uri, true); |
| 695 |
} |
| 696 |
|
| 697 |
if (!isset($uri['host'])) { |
| 698 |
return false; |
| 699 |
} |
| 700 |
$config = array( |
| 701 |
'request' => array( |
| 702 |
'uri' => array_intersect_key($uri, $this->config['request']['uri']) |
| 703 |
) |
| 704 |
); |
| 705 |
$this->config = Hash::merge($this->config, $config); |
| 706 |
$this->config = Hash::merge($this->config, array_intersect_key($this->config['request']['uri'], $this->config)); |
| 707 |
return true; |
| 708 |
} |
| 709 |
|
| 710 |
/**
|
| 711 |
* Takes a $uri array and turns it into a fully qualified URL string
|
| 712 |
*
|
| 713 |
* @param string|array $uri Either A $uri array, or a request string. Will use $this->config if left empty.
|
| 714 |
* @param string $uriTemplate The Uri template/format to use.
|
| 715 |
* @return mixed A fully qualified URL formatted according to $uriTemplate, or false on failure
|
| 716 |
*/
|
| 717 |
protected function _buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') { |
| 718 |
if (is_string($uri)) { |
| 719 |
$uri = array('host' => $uri); |
| 720 |
} |
| 721 |
$uri = $this->_parseUri($uri, true); |
| 722 |
|
| 723 |
if (!is_array($uri) || empty($uri)) { |
| 724 |
return false; |
| 725 |
} |
| 726 |
|
| 727 |
$uri['path'] = preg_replace('/^\//', null, $uri['path']); |
| 728 |
$uri['query'] = http_build_query($uri['query'], '', '&'); |
| 729 |
$uri['query'] = rtrim($uri['query'], '='); |
| 730 |
$stripIfEmpty = array( |
| 731 |
'query' => '?%query', |
| 732 |
'fragment' => '#%fragment', |
| 733 |
'user' => '%user:%pass@', |
| 734 |
'host' => '%host:%port/' |
| 735 |
); |
| 736 |
|
| 737 |
foreach ($stripIfEmpty as $key => $strip) { |
| 738 |
if (empty($uri[$key])) { |
| 739 |
$uriTemplate = str_replace($strip, null, $uriTemplate); |
| 740 |
} |
| 741 |
} |
| 742 |
|
| 743 |
$defaultPorts = array('http' => 80, 'https' => 443); |
| 744 |
if (array_key_exists($uri['scheme'], $defaultPorts) && $defaultPorts[$uri['scheme']] == $uri['port']) { |
| 745 |
$uriTemplate = str_replace(':%port', null, $uriTemplate); |
| 746 |
} |
| 747 |
foreach ($uri as $property => $value) { |
| 748 |
$uriTemplate = str_replace('%' . $property, $value, $uriTemplate); |
| 749 |
} |
| 750 |
|
| 751 |
if ($uriTemplate === '/*') { |
| 752 |
$uriTemplate = '*'; |
| 753 |
} |
| 754 |
return $uriTemplate; |
| 755 |
} |
| 756 |
|
| 757 |
/**
|
| 758 |
* Parses the given URI and breaks it down into pieces as an indexed array with elements
|
| 759 |
* such as 'scheme', 'port', 'query'.
|
| 760 |
*
|
| 761 |
* @param string|array $uri URI to parse
|
| 762 |
* @param bool|array $base If true use default URI config, otherwise indexed array to set 'scheme', 'host', 'port', etc.
|
| 763 |
* @return array Parsed URI
|
| 764 |
*/
|
| 765 |
protected function _parseUri($uri = null, $base = array()) { |
| 766 |
$uriBase = array( |
| 767 |
'scheme' => array('http', 'https'), |
| 768 |
'host' => null, |
| 769 |
'port' => array(80, 443), |
| 770 |
'user' => null, |
| 771 |
'pass' => null, |
| 772 |
'path' => '/', |
| 773 |
'query' => null, |
| 774 |
'fragment' => null |
| 775 |
); |
| 776 |
|
| 777 |
if (is_string($uri)) { |
| 778 |
$uri = parse_url($uri); |
| 779 |
} |
| 780 |
if (!is_array($uri) || empty($uri)) { |
| 781 |
return false; |
| 782 |
} |
| 783 |
if ($base === true) { |
| 784 |
$base = $uriBase; |
| 785 |
} |
| 786 |
|
| 787 |
if (isset($base['port'], $base['scheme']) && is_array($base['port']) && is_array($base['scheme'])) { |
| 788 |
if (isset($uri['scheme']) && !isset($uri['port'])) { |
| 789 |
$base['port'] = $base['port'][array_search($uri['scheme'], $base['scheme'])]; |
| 790 |
} elseif (isset($uri['port']) && !isset($uri['scheme'])) { |
| 791 |
$base['scheme'] = $base['scheme'][array_search($uri['port'], $base['port'])]; |
| 792 |
} |
| 793 |
} |
| 794 |
|
| 795 |
if (is_array($base) && !empty($base)) { |
| 796 |
$uri = array_merge($base, $uri); |
| 797 |
} |
| 798 |
|
| 799 |
if (isset($uri['scheme']) && is_array($uri['scheme'])) { |
| 800 |
$uri['scheme'] = array_shift($uri['scheme']); |
| 801 |
} |
| 802 |
if (isset($uri['port']) && is_array($uri['port'])) { |
| 803 |
$uri['port'] = array_shift($uri['port']); |
| 804 |
} |
| 805 |
|
| 806 |
if (array_key_exists('query', $uri)) { |
| 807 |
$uri['query'] = $this->_parseQuery($uri['query']); |
| 808 |
} |
| 809 |
|
| 810 |
if (!array_intersect_key($uriBase, $uri)) { |
| 811 |
return false; |
| 812 |
} |
| 813 |
return $uri; |
| 814 |
} |
| 815 |
|
| 816 |
/**
|
| 817 |
* This function can be thought of as a reverse to PHP5's http_build_query(). It takes a given query string and turns it into an array and
|
| 818 |
* supports nesting by using the php bracket syntax. So this means you can parse queries like:
|
| 819 |
*
|
| 820 |
* - ?key[subKey]=value
|
| 821 |
* - ?key[]=value1&key[]=value2
|
| 822 |
*
|
| 823 |
* A leading '?' mark in $query is optional and does not effect the outcome of this function.
|
| 824 |
* For the complete capabilities of this implementation take a look at HttpSocketTest::testparseQuery()
|
| 825 |
*
|
| 826 |
* @param string|array $query A query string to parse into an array or an array to return directly "as is"
|
| 827 |
* @return array The $query parsed into a possibly multi-level array. If an empty $query is
|
| 828 |
* given, an empty array is returned.
|
| 829 |
*/
|
| 830 |
protected function _parseQuery($query) { |
| 831 |
if (is_array($query)) { |
| 832 |
return $query; |
| 833 |
} |
| 834 |
|
| 835 |
$parsedQuery = array(); |
| 836 |
|
| 837 |
if (is_string($query) && !empty($query)) { |
| 838 |
$query = preg_replace('/^\?/', '', $query); |
| 839 |
$items = explode('&', $query); |
| 840 |
|
| 841 |
foreach ($items as $item) { |
| 842 |
if (strpos($item, '=') !== false) { |
| 843 |
list($key, $value) = explode('=', $item, 2); |
| 844 |
} else {
|
| 845 |
$key = $item; |
| 846 |
$value = null; |
| 847 |
} |
| 848 |
|
| 849 |
$key = urldecode($key); |
| 850 |
$value = urldecode($value); |
| 851 |
|
| 852 |
if (preg_match_all('/\[([^\[\]]*)\]/iUs', $key, $matches)) { |
| 853 |
$subKeys = $matches[1]; |
| 854 |
$rootKey = substr($key, 0, strpos($key, '[')); |
| 855 |
if (!empty($rootKey)) { |
| 856 |
array_unshift($subKeys, $rootKey); |
| 857 |
} |
| 858 |
$queryNode =& $parsedQuery; |
| 859 |
|
| 860 |
foreach ($subKeys as $subKey) { |
| 861 |
if (!is_array($queryNode)) { |
| 862 |
$queryNode = array(); |
| 863 |
} |
| 864 |
|
| 865 |
if ($subKey === '') { |
| 866 |
$queryNode[] = array(); |
| 867 |
end($queryNode); |
| 868 |
$subKey = key($queryNode); |
| 869 |
} |
| 870 |
$queryNode =& $queryNode[$subKey]; |
| 871 |
} |
| 872 |
$queryNode = $value; |
| 873 |
continue;
|
| 874 |
} |
| 875 |
if (!isset($parsedQuery[$key])) { |
| 876 |
$parsedQuery[$key] = $value; |
| 877 |
} else {
|
| 878 |
$parsedQuery[$key] = (array)$parsedQuery[$key]; |
| 879 |
$parsedQuery[$key][] = $value; |
| 880 |
} |
| 881 |
} |
| 882 |
} |
| 883 |
return $parsedQuery; |
| 884 |
} |
| 885 |
|
| 886 |
/**
|
| 887 |
* Builds a request line according to HTTP/1.1 specs. Activate quirks mode to work outside specs.
|
| 888 |
*
|
| 889 |
* @param array $request Needs to contain a 'uri' key. Should also contain a 'method' key, otherwise defaults to GET.
|
| 890 |
* @return string Request line
|
| 891 |
* @throws SocketException
|
| 892 |
*/
|
| 893 |
protected function _buildRequestLine($request = array()) { |
| 894 |
$asteriskMethods = array('OPTIONS'); |
| 895 |
|
| 896 |
if (is_string($request)) { |
| 897 |
$isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match); |
| 898 |
if (!$this->quirksMode && (!$isValid || ($match[2] === '*' && !in_array($match[3], $asteriskMethods)))) { |
| 899 |
throw new SocketException(__d('cake_dev', 'HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.')); |
| 900 |
} |
| 901 |
return $request; |
| 902 |
} elseif (!is_array($request)) { |
| 903 |
return false; |
| 904 |
} elseif (!array_key_exists('uri', $request)) { |
| 905 |
return false; |
| 906 |
} |
| 907 |
|
| 908 |
$request['uri'] = $this->_parseUri($request['uri']); |
| 909 |
$request += array('method' => 'GET'); |
| 910 |
if (!empty($this->_proxy['host']) && $request['uri']['scheme'] !== 'https') { |
| 911 |
$request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query'); |
| 912 |
} else {
|
| 913 |
$request['uri'] = $this->_buildUri($request['uri'], '/%path?%query'); |
| 914 |
} |
| 915 |
|
| 916 |
if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) { |
| 917 |
throw new SocketException(__d('cake_dev', 'HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', implode(',', $asteriskMethods))); |
| 918 |
} |
| 919 |
$version = isset($request['version']) ? $request['version'] : '1.1'; |
| 920 |
return $request['method'] . ' ' . $request['uri'] . ' HTTP/' . $version . "\r\n"; |
| 921 |
} |
| 922 |
|
| 923 |
/**
|
| 924 |
* Builds the header.
|
| 925 |
*
|
| 926 |
* @param array $header Header to build
|
| 927 |
* @param string $mode Mode
|
| 928 |
* @return string Header built from array
|
| 929 |
*/
|
| 930 |
protected function _buildHeader($header, $mode = 'standard') { |
| 931 |
if (is_string($header)) { |
| 932 |
return $header; |
| 933 |
} elseif (!is_array($header)) { |
| 934 |
return false; |
| 935 |
} |
| 936 |
|
| 937 |
$fieldsInHeader = array(); |
| 938 |
foreach ($header as $key => $value) { |
| 939 |
$lowKey = strtolower($key); |
| 940 |
if (array_key_exists($lowKey, $fieldsInHeader)) { |
| 941 |
$header[$fieldsInHeader[$lowKey]] = $value; |
| 942 |
unset($header[$key]); |
| 943 |
} else {
|
| 944 |
$fieldsInHeader[$lowKey] = $key; |
| 945 |
} |
| 946 |
} |
| 947 |
|
| 948 |
$returnHeader = ''; |
| 949 |
foreach ($header as $field => $contents) { |
| 950 |
if (is_array($contents) && $mode === 'standard') { |
| 951 |
$contents = implode(',', $contents); |
| 952 |
} |
| 953 |
foreach ((array)$contents as $content) { |
| 954 |
$contents = preg_replace("/\r\n(?![\t ])/", "\r\n ", $content); |
| 955 |
$field = $this->_escapeToken($field); |
| 956 |
|
| 957 |
$returnHeader .= $field . ': ' . $contents . "\r\n"; |
| 958 |
} |
| 959 |
} |
| 960 |
return $returnHeader; |
| 961 |
} |
| 962 |
|
| 963 |
/**
|
| 964 |
* Builds cookie headers for a request.
|
| 965 |
*
|
| 966 |
* Cookies can either be in the format returned in responses, or
|
| 967 |
* a simple key => value pair.
|
| 968 |
*
|
| 969 |
* @param array $cookies Array of cookies to send with the request.
|
| 970 |
* @return string Cookie header string to be sent with the request.
|
| 971 |
*/
|
| 972 |
public function buildCookies($cookies) { |
| 973 |
$header = array(); |
| 974 |
foreach ($cookies as $name => $cookie) { |
| 975 |
if (is_array($cookie)) { |
| 976 |
$value = $this->_escapeToken($cookie['value'], array(';')); |
| 977 |
} else {
|
| 978 |
$value = $this->_escapeToken($cookie, array(';')); |
| 979 |
} |
| 980 |
$header[] = $name . '=' . $value; |
| 981 |
} |
| 982 |
return $this->_buildHeader(array('Cookie' => implode('; ', $header)), 'pragmatic'); |
| 983 |
} |
| 984 |
|
| 985 |
/**
|
| 986 |
* Escapes a given $token according to RFC 2616 (HTTP 1.1 specs)
|
| 987 |
*
|
| 988 |
* @param string $token Token to escape
|
| 989 |
* @param array $chars Characters to escape
|
| 990 |
* @return string Escaped token
|
| 991 |
*/
|
| 992 |
protected function _escapeToken($token, $chars = null) { |
| 993 |
$regex = '/([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])/'; |
| 994 |
$token = preg_replace($regex, '"\\1"', $token); |
| 995 |
return $token; |
| 996 |
} |
| 997 |
|
| 998 |
/**
|
| 999 |
* Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
|
| 1000 |
*
|
| 1001 |
* @param bool $hex true to get them as HEX values, false otherwise
|
| 1002 |
* @param array $chars Characters to escape
|
| 1003 |
* @return array Escape chars
|
| 1004 |
*/
|
| 1005 |
protected function _tokenEscapeChars($hex = true, $chars = null) { |
| 1006 |
if (!empty($chars)) { |
| 1007 |
$escape = $chars; |
| 1008 |
} else {
|
| 1009 |
$escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " "); |
| 1010 |
for ($i = 0; $i <= 31; $i++) { |
| 1011 |
$escape[] = chr($i); |
| 1012 |
} |
| 1013 |
$escape[] = chr(127); |
| 1014 |
} |
| 1015 |
|
| 1016 |
if (!$hex) { |
| 1017 |
return $escape; |
| 1018 |
} |
| 1019 |
foreach ($escape as $key => $char) { |
| 1020 |
$escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT); |
| 1021 |
} |
| 1022 |
return $escape; |
| 1023 |
} |
| 1024 |
|
| 1025 |
/**
|
| 1026 |
* Resets the state of this HttpSocket instance to it's initial state (before Object::__construct got executed) or does
|
| 1027 |
* the same thing partially for the request and the response property only.
|
| 1028 |
*
|
| 1029 |
* @param bool $full If set to false only HttpSocket::response and HttpSocket::request are reset
|
| 1030 |
* @return bool True on success
|
| 1031 |
*/
|
| 1032 |
public function reset($full = true) { |
| 1033 |
static $initalState = array(); |
| 1034 |
if (empty($initalState)) { |
| 1035 |
$initalState = get_class_vars(__CLASS__); |
| 1036 |
} |
| 1037 |
if (!$full) { |
| 1038 |
$this->request = $initalState['request']; |
| 1039 |
$this->response = $initalState['response']; |
| 1040 |
return true; |
| 1041 |
} |
| 1042 |
parent::reset($initalState); |
| 1043 |
return true; |
| 1044 |
} |
| 1045 |
|
| 1046 |
} |
| 1047 |
|