CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 1.2 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 1.2
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Classes

  • AclBase
  • AclBehavior
  • AclComponent
  • AclNode
  • AclShell
  • Aco
  • AcoAction
  • AjaxHelper
  • ApcEngine
  • ApiShell
  • App
  • AppController
  • AppHelper
  • AppModel
  • Aro
  • AuthComponent
  • BakeShell
  • BehaviorCollection
  • Cache
  • CacheEngine
  • CacheHelper
  • CakeErrorController
  • CakeLog
  • CakeSchema
  • CakeSession
  • CakeSocket
  • ClassRegistry
  • Component
  • Configure
  • ConnectionManager
  • ConsoleShell
  • ContainableBehavior
  • Controller
  • ControllerTask
  • CookieComponent
  • DataSource
  • DbAcl
  • DbAclSchema
  • DbConfigTask
  • DboAdodb
  • DboDb2
  • DboFirebird
  • DboMssql
  • DboMysql
  • DboMysqlBase
  • DboMysqli
  • DboOdbc
  • DboOracle
  • DboPostgres
  • DboSource
  • DboSqlite
  • DboSybase
  • Debugger
  • EmailComponent
  • ErrorHandler
  • ExtractTask
  • File
  • FileEngine
  • Flay
  • Folder
  • FormHelper
  • Helper
  • HtmlHelper
  • HttpSocket
  • I18n
  • I18nModel
  • i18nSchema
  • I18nShell
  • Inflector
  • IniAcl
  • JavascriptHelper
  • JsHelper
  • JsHelperObject
  • L10n
  • MagicDb
  • MagicFileResource
  • MediaView
  • MemcacheEngine
  • Model
  • ModelBehavior
  • ModelTask
  • Multibyte
  • NumberHelper
  • Object
  • Overloadable
  • Overloadable2
  • PagesController
  • PaginatorHelper
  • Permission
  • PluginTask
  • ProjectTask
  • RequestHandlerComponent
  • Router
  • RssHelper
  • Sanitize
  • Scaffold
  • ScaffoldView
  • SchemaShell
  • Security
  • SecurityComponent
  • SessionComponent
  • SessionHelper
  • SessionsSchema
  • Set
  • Shell
  • String
  • TestSuiteShell
  • TestTask
  • TextHelper
  • ThemeView
  • TimeHelper
  • TranslateBehavior
  • TreeBehavior
  • Validation
  • View
  • ViewTask
  • XcacheEngine
  • Xml
  • XmlElement
  • XmlHelper
  • XmlManager
  • XmlNode
  • XmlTextNode

Functions

  • __enclose
  • make_clean_css
  • mb_encode_mimeheader
  • mb_stripos
  • mb_stristr
  • mb_strlen
  • mb_strpos
  • mb_strrchr
  • mb_strrichr
  • mb_strripos
  • mb_strrpos
  • mb_strstr
  • mb_strtolower
  • mb_strtoupper
  • mb_substr
  • mb_substr_count
  • write_css_cache
   1: <?php
   2: /* SVN FILE: $Id$ */
   3: /**
   4:  * HTTP Socket connection class.
   5:  *
   6:  * PHP versions 4 and 5
   7:  *
   8:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
   9:  * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  10:  *
  11:  * Licensed under The MIT License
  12:  * Redistributions of files must retain the above copyright notice.
  13:  *
  14:  * @copyright     Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  15:  * @link          http://cakephp.org CakePHP(tm) Project
  16:  * @package       cake
  17:  * @subpackage    cake.cake.libs
  18:  * @since         CakePHP(tm) v 1.2.0
  19:  * @version       $Revision$
  20:  * @modifiedby    $LastChangedBy$
  21:  * @lastmodified  $Date$
  22:  * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
  23:  */
  24: App::import('Core', array('Socket', 'Set', 'Router'));
  25: /**
  26:  * Cake network socket connection class.
  27:  *
  28:  * Core base class for HTTP network communication.
  29:  *
  30:  * @package       cake
  31:  * @subpackage    cake.cake.libs
  32:  */
  33: class HttpSocket extends CakeSocket {
  34: /**
  35:  * Object description
  36:  *
  37:  * @var string
  38:  * @access public
  39:  */
  40:     var $description = 'HTTP-based DataSource Interface';
  41: /**
  42:  * When one activates the $quirksMode by setting it to true, all checks meant to enforce RFC 2616 (HTTP/1.1 specs)
  43:  * will be disabled and additional measures to deal with non-standard responses will be enabled.
  44:  *
  45:  * @var boolean
  46:  * @access public
  47:  */
  48:     var $quirksMode = false;
  49: /**
  50:  * The default values to use for a request
  51:  *
  52:  * @var array
  53:  * @access public
  54:  */
  55:     var $request = array(
  56:         'method' => 'GET',
  57:         'uri' => array(
  58:             'scheme' => 'http',
  59:             'host' => null,
  60:             'port' => 80,
  61:             'user' => null,
  62:             'pass' => null,
  63:             'path' => null,
  64:             'query' => null,
  65:             'fragment' => null
  66:         ),
  67:         'auth' => array(
  68:             'method' => 'Basic',
  69:             'user' => null,
  70:             'pass' => null
  71:         ),
  72:         'version' => '1.1',
  73:         'body' => '',
  74:         'line' => null,
  75:         'header' => array(
  76:             'Connection' => 'close',
  77:             'User-Agent' => 'CakePHP'
  78:         ),
  79:         'raw' => null,
  80:         'cookies' => array()
  81:     );
  82: /**
  83: * The default structure for storing the response
  84: *
  85: * @var array
  86: * @access public
  87: */
  88:     var $response = array(
  89:         'raw' => array(
  90:             'status-line' => null,
  91:             'header' => null,
  92:             'body' => null,
  93:             'response' => null
  94:         ),
  95:         'status' => array(
  96:             'http-version' => null,
  97:             'code' => null,
  98:             'reason-phrase' => null
  99:         ),
 100:         'header' => array(),
 101:         'body' => '',
 102:         'cookies' => array()
 103:     );
 104: /**
 105:  * Default configuration settings for the HttpSocket
 106:  *
 107:  * @var array
 108:  * @access public
 109:  */
 110:     var $config = array(
 111:         'persistent' => false,
 112:         'host'       => 'localhost',
 113:         'protocol'   => 'tcp',
 114:         'port'       => 80,
 115:         'timeout'    => 30,
 116:         'request' => array(
 117:             'uri' => array(
 118:                 'scheme' => 'http',
 119:                 'host' => 'localhost',
 120:                 'port' => 80
 121:             ),
 122:             'auth' => array(
 123:                 'method' => 'Basic',
 124:                 'user' => null,
 125:                 'pass' => null
 126:             ),
 127:             'cookies' => array()
 128:         )
 129:     );
 130: /**
 131:  * String that represents a line break.
 132:  *
 133:  * @var string
 134:  * @access public
 135:  */
 136:     var $lineBreak = "\r\n";
 137: 
 138: /**
 139:  * Build an HTTP Socket using the specified configuration.
 140:  *
 141:  * @param array $config Configuration
 142:  */
 143:     function __construct($config = array()) {
 144:         if (is_string($config)) {
 145:             $this->configUri($config);
 146:         } elseif (is_array($config)) {
 147:             if (isset($config['request']['uri']) && is_string($config['request']['uri'])) {
 148:                 $this->configUri($config['request']['uri']);
 149:                 unset($config['request']['uri']);
 150:             }
 151:             $this->config = Set::merge($this->config, $config);
 152:         }
 153:         parent::__construct($this->config);
 154:     }
 155: /**
 156:  * Issue the specified request.
 157:  *
 158:  * @param mixed $request Either an URI string, or an array defining host/uri
 159:  * @return mixed false on error, request body on success
 160:  * @access public
 161:  */
 162:     function request($request = array()) {
 163:         $this->reset(false);
 164: 
 165:         if (is_string($request)) {
 166:             $request = array('uri' => $request);
 167:         } elseif (!is_array($request)) {
 168:             return false;
 169:         }
 170: 
 171:         if (!isset($request['uri'])) {
 172:             $request['uri'] = null;
 173:         }
 174: 
 175:         $uri = $this->parseUri($request['uri']);
 176:         $hadAuth = false;
 177:         if (is_array($uri) && array_key_exists('user', $uri)) {
 178:             $hadAuth = true;
 179:         }
 180: 
 181:         if (!isset($uri['host'])) {
 182:             $host = $this->config['host'];
 183:         }
 184:         if (isset($request['host'])) {
 185:             $host = $request['host'];
 186:             unset($request['host']);
 187:         }
 188:         $request['uri'] = $this->url($request['uri']);
 189:         $request['uri'] = $this->parseUri($request['uri'], true);
 190:         $this->request = Set::merge($this->request, $this->config['request'], $request);
 191: 
 192:         if (!$hadAuth && !empty($this->config['request']['auth']['user'])) {
 193:             $this->request['uri']['user'] = $this->config['request']['auth']['user'];
 194:             $this->request['uri']['pass'] = $this->config['request']['auth']['pass'];
 195:         }
 196:         $this->configUri($this->request['uri']);
 197: 
 198:         if (isset($host)) {
 199:             $this->config['host'] = $host;
 200:         }
 201:         $cookies = null;
 202: 
 203:         if (is_array($this->request['header'])) {
 204:             $this->request['header'] = $this->parseHeader($this->request['header']);
 205:             if (!empty($this->request['cookies'])) {
 206:                 $cookies = $this->buildCookies($this->request['cookies']);
 207:             }
 208:             $Host = $this->request['uri']['host'];
 209:             $schema = '';
 210:             $port = 0;
 211:             if (isset($this->request['uri']['schema'])) {
 212:                 $schema = $this->request['uri']['schema'];
 213:             }
 214:             if (isset($this->request['uri']['port'])) {
 215:                 $port = $this->request['uri']['port'];
 216:             }
 217:             if (
 218:                 ($schema === 'http' && $port != 80) ||
 219:                 ($schema === 'https' && $port != 443) ||
 220:                 ($port != 80 && $port != 443)
 221:             ) {
 222:                 $Host .= ':' . $port;
 223:             }
 224:             $this->request['header'] = array_merge(compact('Host'), $this->request['header']);
 225:         }
 226: 
 227:         if (isset($this->request['auth']['user']) && isset($this->request['auth']['pass'])) {
 228:             $this->request['header']['Authorization'] = $this->request['auth']['method'] . " " . base64_encode($this->request['auth']['user'] . ":" . $this->request['auth']['pass']);
 229:         }
 230:         if (isset($this->request['uri']['user']) && isset($this->request['uri']['pass'])) {
 231:             $this->request['header']['Authorization'] = $this->request['auth']['method'] . " " . base64_encode($this->request['uri']['user'] . ":" . $this->request['uri']['pass']);
 232:         }
 233: 
 234:         if (is_array($this->request['body'])) {
 235:             $this->request['body'] = $this->httpSerialize($this->request['body']);
 236:         }
 237: 
 238:         if (!empty($this->request['body']) && !isset($this->request['header']['Content-Type'])) {
 239:             $this->request['header']['Content-Type'] = 'application/x-www-form-urlencoded';
 240:         }
 241: 
 242:         if (!empty($this->request['body']) && !isset($this->request['header']['Content-Length'])) {
 243:             $this->request['header']['Content-Length'] = strlen($this->request['body']);
 244:         }
 245: 
 246:         $connectionType = null;
 247:         if (isset($this->request['header']['Connection'])) {
 248:             $connectionType = $this->request['header']['Connection'];
 249:         }
 250:         $this->request['header'] = $this->buildHeader($this->request['header']).$cookies;
 251: 
 252:         if (empty($this->request['line'])) {
 253:             $this->request['line'] = $this->buildRequestLine($this->request);
 254:         }
 255: 
 256:         if ($this->quirksMode === false && $this->request['line'] === false) {
 257:             return $this->response = false;
 258:         }
 259: 
 260:         if ($this->request['line'] !== false) {
 261:             $this->request['raw'] = $this->request['line'];
 262:         }
 263: 
 264:         if ($this->request['header'] !== false) {
 265:             $this->request['raw'] .= $this->request['header'];
 266:         }
 267: 
 268:         $this->request['raw'] .= "\r\n";
 269:         $this->request['raw'] .= $this->request['body'];
 270:         $this->write($this->request['raw']);
 271: 
 272:         $response = null;
 273:         while ($data = $this->read()) {
 274:             $response .= $data;
 275:         }
 276: 
 277:         if ($connectionType == 'close') {
 278:             $this->disconnect();
 279:         }
 280: 
 281:         $this->response = $this->parseResponse($response);
 282:         if (!empty($this->response['cookies'])) {
 283:             $this->config['request']['cookies'] = array_merge($this->config['request']['cookies'], $this->response['cookies']);
 284:         }
 285: 
 286:         return $this->response['body'];
 287:     }
 288: /**
 289:  * Issues a GET request to the specified URI, query, and request.
 290:  *
 291:  * @param mixed $uri URI to request (see {@link parseUri()})
 292:  * @param array $query Query to append to URI
 293:  * @param array $request An indexed array with indexes such as 'method' or uri
 294:  * @return mixed Result of request
 295:  * @access public
 296:  */
 297:     function get($uri = null, $query = array(), $request = array()) {
 298:         if (!empty($query)) {
 299:             $uri =$this->parseUri($uri);
 300:             if (isset($uri['query'])) {
 301:                 $uri['query'] = array_merge($uri['query'], $query);
 302:             } else {
 303:                 $uri['query'] = $query;
 304:             }
 305:             $uri = $this->buildUri($uri);
 306:         }
 307: 
 308:         $request = Set::merge(array('method' => 'GET', 'uri' => $uri), $request);
 309:         return $this->request($request);
 310:     }
 311: 
 312: /**
 313:  * Issues a POST request to the specified URI, query, and request.
 314:  *
 315:  * @param mixed $uri URI to request (see {@link parseUri()})
 316:  * @param array $query Query to append to URI
 317:  * @param array $request An indexed array with indexes such as 'method' or uri
 318:  * @return mixed Result of request
 319:  * @access public
 320:  */
 321:     function post($uri = null, $data = array(), $request = array()) {
 322:         $request = Set::merge(array('method' => 'POST', 'uri' => $uri, 'body' => $data), $request);
 323:         return $this->request($request);
 324:     }
 325: /**
 326:  * Issues a PUT request to the specified URI, query, and request.
 327:  *
 328:  * @param mixed $uri URI to request (see {@link parseUri()})
 329:  * @param array $query Query to append to URI
 330:  * @param array $request An indexed array with indexes such as 'method' or uri
 331:  * @return mixed Result of request
 332:  * @access public
 333:  */
 334:     function put($uri = null, $data = array(), $request = array()) {
 335:         $request = Set::merge(array('method' => 'PUT', 'uri' => $uri, 'body' => $data), $request);
 336:         return $this->request($request);
 337:     }
 338: /**
 339:  * Issues a DELETE request to the specified URI, query, and request.
 340:  *
 341:  * @param mixed $uri URI to request (see {@link parseUri()})
 342:  * @param array $query Query to append to URI
 343:  * @param array $request An indexed array with indexes such as 'method' or uri
 344:  * @return mixed Result of request
 345:  * @access public
 346:  */
 347:     function delete($uri = null, $data = array(), $request = array()) {
 348:         $request = Set::merge(array('method' => 'DELETE', 'uri' => $uri, 'body' => $data), $request);
 349:         return $this->request($request);
 350:     }
 351: /**
 352:  * undocumented function
 353:  *
 354:  * @param unknown $url
 355:  * @param unknown $uriTemplate
 356:  * @return void
 357:  * @access public
 358:  */
 359:     function url($url = null, $uriTemplate = null) {
 360:         if (is_null($url)) {
 361:             $url = '/';
 362:         }
 363:         if (is_string($url)) {
 364:             if ($url{0} == '/') {
 365:                 $url = $this->config['request']['uri']['host'].':'.$this->config['request']['uri']['port'] . $url;
 366:             }
 367:             if (!preg_match('/^.+:\/\/|\*|^\//', $url)) {
 368:                 $url = $this->config['request']['uri']['scheme'].'://'.$url;
 369:             }
 370:         } elseif (!is_array($url) && !empty($url)) {
 371:             return false;
 372:         }
 373: 
 374:         $base = array_merge($this->config['request']['uri'], array('scheme' => array('http', 'https'), 'port' => array(80, 443)));
 375:         $url = $this->parseUri($url, $base);
 376: 
 377:         if (empty($url)) {
 378:             $url = $this->config['request']['uri'];
 379:         }
 380: 
 381:         if (!empty($uriTemplate)) {
 382:             return $this->buildUri($url, $uriTemplate);
 383:         }
 384:         return $this->buildUri($url);
 385:     }
 386: /**
 387:  * Parses the given message and breaks it down in parts.
 388:  *
 389:  * @param string $message Message to parse
 390:  * @return array Parsed message (with indexed elements such as raw, status, header, body)
 391:  * @access protected
 392:  */
 393:     function parseResponse($message) {
 394:         if (is_array($message)) {
 395:             return $message;
 396:         } elseif (!is_string($message)) {
 397:             return false;
 398:         }
 399: 
 400:         static $responseTemplate;
 401: 
 402:         if (empty($responseTemplate)) {
 403:             $classVars = get_class_vars(__CLASS__);
 404:             $responseTemplate = $classVars['response'];
 405:         }
 406: 
 407:         $response = $responseTemplate;
 408: 
 409:         if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) {
 410:             return false;
 411:         }
 412: 
 413:         list($null, $response['raw']['status-line'], $response['raw']['header']) = $match;
 414:         $response['raw']['response'] = $message;
 415:         $response['raw']['body'] = substr($message, strlen($match[0]));
 416: 
 417:         if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $response['raw']['status-line'], $match)) {
 418:             $response['status']['http-version'] = $match[1];
 419:             $response['status']['code'] = (int)$match[2];
 420:             $response['status']['reason-phrase'] = $match[3];
 421:         }
 422: 
 423:         $response['header'] = $this->parseHeader($response['raw']['header']);
 424:         $transferEncoding = null;
 425:         if (isset($response['header']['Transfer-Encoding'])) {
 426:             $transferEncoding = $response['header']['Transfer-Encoding'];
 427:         }
 428:         $decoded = $this->decodeBody($response['raw']['body'], $transferEncoding);
 429:         $response['body'] = $decoded['body'];
 430: 
 431:         if (!empty($decoded['header'])) {
 432:             $response['header'] = $this->parseHeader($this->buildHeader($response['header']).$this->buildHeader($decoded['header']));
 433:         }
 434: 
 435:         if (!empty($response['header'])) {
 436:             $response['cookies'] = $this->parseCookies($response['header']);
 437:         }
 438: 
 439:         foreach ($response['raw'] as $field => $val) {
 440:             if ($val === '') {
 441:                 $response['raw'][$field] = null;
 442:             }
 443:         }
 444: 
 445:         return $response;
 446:     }
 447: /**
 448:  * Generic function to decode a $body with a given $encoding. Returns either an array with the keys
 449:  * 'body' and 'header' or false on failure.
 450:  *
 451:  * @param string $body A string continaing the body to decode
 452:  * @param mixed $encoding Can be false in case no encoding is being used, or a string representing the encoding
 453:  * @return mixed Array or false
 454:  * @access protected
 455:  */
 456:     function decodeBody($body, $encoding = 'chunked') {
 457:         if (!is_string($body)) {
 458:             return false;
 459:         }
 460:         if (empty($encoding)) {
 461:             return array('body' => $body, 'header' => false);
 462:         }
 463:         $decodeMethod = 'decode'.Inflector::camelize(str_replace('-', '_', $encoding)).'Body';
 464: 
 465:         if (!is_callable(array(&$this, $decodeMethod))) {
 466:             if (!$this->quirksMode) {
 467:                 trigger_error(sprintf(__('HttpSocket::decodeBody - Unknown encoding: %s. Activate quirks mode to surpress error.', true), h($encoding)), E_USER_WARNING);
 468:             }
 469:             return array('body' => $body, 'header' => false);
 470:         }
 471:         return $this->{$decodeMethod}($body);
 472:     }
 473: /**
 474:  * Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as
 475:  * a result.
 476:  *
 477:  * @param string $body A string continaing the chunked body to decode
 478:  * @return mixed Array or false
 479:  * @access protected
 480:  */
 481:     function decodeChunkedBody($body) {
 482:         if (!is_string($body)) {
 483:             return false;
 484:         }
 485: 
 486:         $decodedBody = null;
 487:         $chunkLength = null;
 488: 
 489:         while ($chunkLength !== 0) {
 490:             if (!preg_match("/^([0-9a-f]+) *(?:;(.+)=(.+))?\r\n/iU", $body, $match)) {
 491:                 if (!$this->quirksMode) {
 492:                     trigger_error(__('HttpSocket::decodeChunkedBody - Could not parse malformed chunk. Activate quirks mode to do this.', true), E_USER_WARNING);
 493:                     return false;
 494:                 }
 495:                 break;
 496:             }
 497: 
 498:             $chunkSize = 0;
 499:             $hexLength = 0;
 500:             $chunkExtensionName = '';
 501:             $chunkExtensionValue = '';
 502:             if (isset($match[0])) {
 503:                 $chunkSize = $match[0];
 504:             }
 505:             if (isset($match[1])) {
 506:                 $hexLength = $match[1];
 507:             }
 508:             if (isset($match[2])) {
 509:                 $chunkExtensionName = $match[2];
 510:             }
 511:             if (isset($match[3])) {
 512:                 $chunkExtensionValue = $match[3];
 513:             }
 514: 
 515:             $body = substr($body, strlen($chunkSize));
 516:             $chunkLength = hexdec($hexLength);
 517:             $chunk = substr($body, 0, $chunkLength);
 518:             if (!empty($chunkExtensionName)) {
 519:                 /**
 520:                  * @todo See if there are popular chunk extensions we should implement
 521:                  */
 522:             }
 523:             $decodedBody .= $chunk;
 524:             if ($chunkLength !== 0) {
 525:                 $body = substr($body, $chunkLength+strlen("\r\n"));
 526:             }
 527:         }
 528: 
 529:         $entityHeader = false;
 530:         if (!empty($body)) {
 531:             $entityHeader = $this->parseHeader($body);
 532:         }
 533:         return array('body' => $decodedBody, 'header' => $entityHeader);
 534:     }
 535: /**
 536:  * Parses and sets the specified URI into current request configuration.
 537:  *
 538:  * @param mixed $uri URI (see {@link parseUri()})
 539:  * @return array Current configuration settings
 540:  * @access protected
 541:  */
 542:     function configUri($uri = null) {
 543:         if (empty($uri)) {
 544:             return false;
 545:         }
 546: 
 547:         if (is_array($uri)) {
 548:             $uri = $this->parseUri($uri);
 549:         } else {
 550:             $uri = $this->parseUri($uri, true);
 551:         }
 552: 
 553:         if (!isset($uri['host'])) {
 554:             return false;
 555:         }
 556:         $config = array(
 557:             'request' => array(
 558:                 'uri' => array_intersect_key($uri, $this->config['request']['uri']),
 559:                 'auth' => array_intersect_key($uri, $this->config['request']['auth'])
 560:             )
 561:         );
 562:         $this->config = Set::merge($this->config, $config);
 563:         $this->config = Set::merge($this->config, array_intersect_key($this->config['request']['uri'], $this->config));
 564:         return $this->config;
 565:     }
 566: /**
 567:  * Takes a $uri array and turns it into a fully qualified URL string
 568:  *
 569:  * @param array $uri A $uri array, or uses $this->config if left empty
 570:  * @param string $uriTemplate The Uri template/format to use
 571:  * @return string A fully qualified URL formated according to $uriTemplate
 572:  * @access protected
 573:  */
 574:     function buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') {
 575:         if (is_string($uri)) {
 576:             $uri = array('host' => $uri);
 577:         }
 578:         $uri = $this->parseUri($uri, true);
 579: 
 580:         if (!is_array($uri) || empty($uri)) {
 581:             return false;
 582:         }
 583: 
 584:         $uri['path'] = preg_replace('/^\//', null, $uri['path']);
 585:         $uri['query'] = $this->httpSerialize($uri['query']);
 586:         $stripIfEmpty = array(
 587:             'query' => '?%query',
 588:             'fragment' => '#%fragment',
 589:             'user' => '%user:%pass@',
 590:             'host' => '%host:%port/'
 591:         );
 592: 
 593:         foreach ($stripIfEmpty as $key => $strip) {
 594:             if (empty($uri[$key])) {
 595:                 $uriTemplate = str_replace($strip, null, $uriTemplate);
 596:             }
 597:         }
 598: 
 599:         $defaultPorts = array('http' => 80, 'https' => 443);
 600:         if (array_key_exists($uri['scheme'], $defaultPorts) && $defaultPorts[$uri['scheme']] == $uri['port']) {
 601:             $uriTemplate = str_replace(':%port', null, $uriTemplate);
 602:         }
 603:         foreach ($uri as $property => $value) {
 604:             $uriTemplate = str_replace('%'.$property, $value, $uriTemplate);
 605:         }
 606: 
 607:         if ($uriTemplate === '/*') {
 608:             $uriTemplate = '*';
 609:         }
 610:         return $uriTemplate;
 611:     }
 612: /**
 613:  * Parses the given URI and breaks it down into pieces as an indexed array with elements
 614:  * such as 'scheme', 'port', 'query'.
 615:  *
 616:  * @param string $uri URI to parse
 617:  * @param mixed $base If true use default URI config, otherwise indexed array to set 'scheme', 'host', 'port', etc.
 618:  * @return array Parsed URI
 619:  * @access protected
 620:  */
 621:     function parseUri($uri = null, $base = array()) {
 622:         $uriBase = array(
 623:             'scheme' => array('http', 'https'),
 624:             'host' => null,
 625:             'port' => array(80, 443),
 626:             'user' => null,
 627:             'pass' => null,
 628:             'path' => '/',
 629:             'query' => null,
 630:             'fragment' => null
 631:         );
 632: 
 633:         if (is_string($uri)) {
 634:             $uri = parse_url($uri);
 635:         }
 636:         if (!is_array($uri) || empty($uri)) {
 637:             return false;
 638:         }
 639:         if ($base === true) {
 640:             $base = $uriBase;
 641:         }
 642: 
 643:         if (isset($base['port'], $base['scheme']) && is_array($base['port']) && is_array($base['scheme'])) {
 644:             if (isset($uri['scheme']) && !isset($uri['port'])) {
 645:                 $base['port'] = $base['port'][array_search($uri['scheme'], $base['scheme'])];
 646:             } elseif (isset($uri['port']) && !isset($uri['scheme'])) {
 647:                 $base['scheme'] = $base['scheme'][array_search($uri['port'], $base['port'])];
 648:             }
 649:         }
 650: 
 651:         if (is_array($base) && !empty($base)) {
 652:             $uri = array_merge($base, $uri);
 653:         }
 654: 
 655:         if (isset($uri['scheme']) && is_array($uri['scheme'])) {
 656:             $uri['scheme'] = array_shift($uri['scheme']);
 657:         }
 658:         if (isset($uri['port']) && is_array($uri['port'])) {
 659:             $uri['port'] = array_shift($uri['port']);
 660:         }
 661: 
 662:         if (array_key_exists('query', $uri)) {
 663:             $uri['query'] = $this->parseQuery($uri['query']);
 664:         }
 665: 
 666:         if (!array_intersect_key($uriBase, $uri)) {
 667:             return false;
 668:         }
 669:         return $uri;
 670:     }
 671: /**
 672:  * 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
 673:  * supports nesting by using the php bracket syntax. So this menas you can parse queries like:
 674:  *
 675:  * - ?key[subKey]=value
 676:  * - ?key[]=value1&key[]=value2
 677:  *
 678:  * A leading '?' mark in $query is optional and does not effect the outcome of this function. For the complete capabilities of this implementation
 679:  * take a look at HttpSocketTest::testParseQuery()
 680:  *
 681:  * @param mixed $query A query string to parse into an array or an array to return directly "as is"
 682:  * @return array The $query parsed into a possibly multi-level array. If an empty $query is given, an empty array is returned.
 683:  * @access protected
 684:  */
 685:     function parseQuery($query) {
 686:         if (is_array($query)) {
 687:             return $query;
 688:         }
 689:         $parsedQuery = array();
 690: 
 691:         if (is_string($query) && !empty($query)) {
 692:             $query = preg_replace('/^\?/', '', $query);
 693:             $items = explode('&', $query);
 694: 
 695:             foreach ($items as $item) {
 696:                 if (strpos($item, '=') !== false) {
 697:                     list($key, $value) = explode('=', $item, 2);
 698:                 } else {
 699:                     $key = $item;
 700:                     $value = null;
 701:                 }
 702: 
 703:                 $key = urldecode($key);
 704:                 $value = urldecode($value);
 705: 
 706:                 if (preg_match_all('/\[([^\[\]]*)\]/iUs', $key, $matches)) {
 707:                     $subKeys = $matches[1];
 708:                     $rootKey = substr($key, 0, strpos($key, '['));
 709:                     if (!empty($rootKey)) {
 710:                         array_unshift($subKeys, $rootKey);
 711:                     }
 712:                     $queryNode =& $parsedQuery;
 713: 
 714:                     foreach ($subKeys as $subKey) {
 715:                         if (!is_array($queryNode)) {
 716:                             $queryNode = array();
 717:                         }
 718: 
 719:                         if ($subKey === '') {
 720:                             $queryNode[] = array();
 721:                             end($queryNode);
 722:                             $subKey = key($queryNode);
 723:                         }
 724:                         $queryNode =& $queryNode[$subKey];
 725:                     }
 726:                     $queryNode = $value;
 727:                 } else {
 728:                     $parsedQuery[$key] = $value;
 729:                 }
 730:             }
 731:         }
 732:         return $parsedQuery;
 733:     }
 734: /**
 735:  * Builds a request line according to HTTP/1.1 specs. Activate quirks mode to work outside specs.
 736:  *
 737:  * @param array $request Needs to contain a 'uri' key. Should also contain a 'method' key, otherwise defaults to GET.
 738:  * @param string $versionToken The version token to use, defaults to HTTP/1.1
 739:  * @return string Request line
 740:  * @access protected
 741:  */
 742:     function buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') {
 743:         $asteriskMethods = array('OPTIONS');
 744: 
 745:         if (is_string($request)) {
 746:             $isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match);
 747:             if (!$this->quirksMode && (!$isValid || ($match[2] == '*' && !in_array($match[3], $asteriskMethods)))) {
 748:                 trigger_error(__('HttpSocket::buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.', true), E_USER_WARNING);
 749:                 return false;
 750:             }
 751:             return $request;
 752:         } elseif (!is_array($request)) {
 753:             return false;
 754:         } elseif (!array_key_exists('uri', $request)) {
 755:             return false;
 756:         }
 757: 
 758:         $request['uri'] = $this->parseUri($request['uri']);
 759:         $request = array_merge(array('method' => 'GET'), $request);
 760:         $request['uri'] = $this->buildUri($request['uri'], '/%path?%query');
 761: 
 762:         if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) {
 763:             trigger_error(sprintf(__('HttpSocket::buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', true), implode(',', $asteriskMethods)), E_USER_WARNING);
 764:             return false;
 765:         }
 766:         return $request['method'].' '.$request['uri'].' '.$versionToken.$this->lineBreak;
 767:     }
 768: /**
 769:  * Serializes an array for transport.
 770:  *
 771:  * @param array $data Data to serialize
 772:  * @return string Serialized variable
 773:  * @access protected
 774:  */
 775:     function httpSerialize($data = array()) {
 776:         if (is_string($data)) {
 777:             return $data;
 778:         }
 779:         if (empty($data) || !is_array($data)) {
 780:             return false;
 781:         }
 782:         return substr(Router::queryString($data), 1);
 783:     }
 784: /**
 785:  * Builds the header.
 786:  *
 787:  * @param array $header Header to build
 788:  * @return string Header built from array
 789:  * @access protected
 790:  */
 791:     function buildHeader($header, $mode = 'standard') {
 792:         if (is_string($header)) {
 793:             return $header;
 794:         } elseif (!is_array($header)) {
 795:             return false;
 796:         }
 797: 
 798:         $returnHeader = '';
 799:         foreach ($header as $field => $contents) {
 800:             if (is_array($contents) && $mode == 'standard') {
 801:                 $contents = implode(',', $contents);
 802:             }
 803:             foreach ((array)$contents as $content) {
 804:                 $contents = preg_replace("/\r\n(?![\t ])/", "\r\n ", $content);
 805:                 $field = $this->escapeToken($field);
 806: 
 807:                 $returnHeader .= $field.': '.$contents.$this->lineBreak;
 808:             }
 809:         }
 810:         return $returnHeader;
 811:     }
 812: 
 813: /**
 814:  * Parses an array based header.
 815:  *
 816:  * @param array $header Header as an indexed array (field => value)
 817:  * @return array Parsed header
 818:  * @access protected
 819:  */
 820:     function parseHeader($header) {
 821:         if (is_array($header)) {
 822:             foreach ($header as $field => $value) {
 823:                 unset($header[$field]);
 824:                 $field = strtolower($field);
 825:                 preg_match_all('/(?:^|(?<=-))[a-z]/U', $field, $offsets, PREG_OFFSET_CAPTURE);
 826: 
 827:                 foreach ($offsets[0] as $offset) {
 828:                     $field = substr_replace($field, strtoupper($offset[0]), $offset[1], 1);
 829:                 }
 830:                 $header[$field] = $value;
 831:             }
 832:             return $header;
 833:         } elseif (!is_string($header)) {
 834:             return false;
 835:         }
 836: 
 837:         preg_match_all("/(.+):(.+)(?:(?<![\t ])" . $this->lineBreak . "|\$)/Uis", $header, $matches, PREG_SET_ORDER);
 838: 
 839:         $header = array();
 840:         foreach ($matches as $match) {
 841:             list(, $field, $value) = $match;
 842: 
 843:             $value = trim($value);
 844:             $value = preg_replace("/[\t ]\r\n/", "\r\n", $value);
 845: 
 846:             $field = $this->unescapeToken($field);
 847: 
 848:             $field = strtolower($field);
 849:             preg_match_all('/(?:^|(?<=-))[a-z]/U', $field, $offsets, PREG_OFFSET_CAPTURE);
 850:             foreach ($offsets[0] as $offset) {
 851:                 $field = substr_replace($field, strtoupper($offset[0]), $offset[1], 1);
 852:             }
 853: 
 854:             if (!isset($header[$field])) {
 855:                 $header[$field] = $value;
 856:             } else {
 857:                 $header[$field] = array_merge((array)$header[$field], (array)$value);
 858:             }
 859:         }
 860:         return $header;
 861:     }
 862: /**
 863:  * undocumented function
 864:  *
 865:  * @param unknown $header
 866:  * @return void
 867:  * @access public
 868:  * @todo Make this 100% RFC 2965 confirm
 869:  */
 870:     function parseCookies($header) {
 871:         if (!isset($header['Set-Cookie'])) {
 872:             return false;
 873:         }
 874: 
 875:         $cookies = array();
 876:         foreach ((array)$header['Set-Cookie'] as $cookie) {
 877:             if (strpos($cookie, '";"') !== false) {
 878:                 $cookie = str_replace('";"', "{__cookie_replace__}", $cookie);
 879:                 $parts  = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie));
 880:             } else {
 881:                 $parts = preg_split('/\;[ \t]*/', $cookie);
 882:             }
 883: 
 884:             list($name, $value) = explode('=', array_shift($parts), 2);
 885:             $cookies[$name] = compact('value');
 886: 
 887:             foreach ($parts as $part) {
 888:                 if (strpos($part, '=') !== false) {
 889:                     list($key, $value) = explode('=', $part);
 890:                 } else {
 891:                     $key = $part;
 892:                     $value = true;
 893:                 }
 894: 
 895:                 $key = strtolower($key);
 896:                 if (!isset($cookies[$name][$key])) {
 897:                     $cookies[$name][$key] = $value;
 898:                 }
 899:             }
 900:         }
 901:         return $cookies;
 902:     }
 903: /**
 904:  * undocumented function
 905:  *
 906:  * @param unknown $cookies
 907:  * @return void
 908:  * @access public
 909:  * @todo Refactor token escape mechanism to be configurable
 910:  */
 911:     function buildCookies($cookies) {
 912:         $header = array();
 913:         foreach ($cookies as $name => $cookie) {
 914:             $header[] = $name.'='.$this->escapeToken($cookie['value'], array(';'));
 915:         }
 916:         $header = $this->buildHeader(array('Cookie' => implode('; ', $header)), 'pragmatic');
 917:         return $header;
 918:     }
 919: /**
 920:  * undocumented function
 921:  *
 922:  * @return void
 923:  * @access public
 924:  */
 925:     function saveCookies() {
 926: 
 927:     }
 928: /**
 929:  * undocumented function
 930:  *
 931:  * @return void
 932:  * @access public
 933:  */
 934:     function loadCookies() {
 935: 
 936:     }
 937: /**
 938:  * Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs)
 939:  *
 940:  * @param string $token Token to unescape
 941:  * @return string Unescaped token
 942:  * @access protected
 943:  * @todo Test $chars parameter
 944:  */
 945:     function unescapeToken($token, $chars = null) {
 946:         $regex = '/"(['.implode('', $this->__tokenEscapeChars(true, $chars)).'])"/';
 947:         $token = preg_replace($regex, '\\1', $token);
 948:         return $token;
 949:     }
 950: /**
 951:  * Escapes a given $token according to RFC 2616 (HTTP 1.1 specs)
 952:  *
 953:  * @param string $token Token to escape
 954:  * @return string Escaped token
 955:  * @access protected
 956:  * @todo Test $chars parameter
 957:  */
 958:     function escapeToken($token, $chars = null) {
 959:         $regex = '/(['.implode('', $this->__tokenEscapeChars(true, $chars)).'])/';
 960:         $token = preg_replace($regex, '"\\1"', $token);
 961:         return $token;
 962:     }
 963: /**
 964:  * Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
 965:  *
 966:  * @param boolean $hex true to get them as HEX values, false otherwise
 967:  * @return array Escape chars
 968:  * @access private
 969:  * @todo Test $chars parameter
 970:  */
 971:     function __tokenEscapeChars($hex = true, $chars = null) {
 972:         if (!empty($chars)) {
 973:             $escape = $chars;
 974:         } else {
 975:             $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
 976:             for ($i = 0; $i <= 31; $i++) {
 977:                 $escape[] = chr($i);
 978:             }
 979:             $escape[] = chr(127);
 980:         }
 981: 
 982:         if ($hex == false) {
 983:             return $escape;
 984:         }
 985:         $regexChars = '';
 986:         foreach ($escape as $key => $char) {
 987:             $escape[$key] = '\\x'.str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
 988:         }
 989:         return $escape;
 990:     }
 991: /**
 992:  * Resets the state of this HttpSocket instance to it's initial state (before Object::__construct got executed) or does
 993:  * the same thing partially for the request and the response property only.
 994:  *
 995:  * @param boolean $full If set to false only HttpSocket::response and HttpSocket::request are reseted
 996:  * @return boolean True on success
 997:  * @access public
 998:  */
 999:     function reset($full = true) {
1000:         static $initalState = array();
1001:         if (empty($initalState)) {
1002:             $initalState = get_class_vars(__CLASS__);
1003:         }
1004:         if ($full == false) {
1005:             $this->request = $initalState['request'];
1006:             $this->response = $initalState['response'];
1007:             return true;
1008:         }
1009:         parent::reset($initalState);
1010:         return true;
1011:     }
1012: }
1013: ?>
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs