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 2.6 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.6
      • 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

Packages

  • Cake
    • Cache
      • Engine
    • Configure
    • Console
      • Command
        • Task
    • Controller
      • Component
        • Acl
        • Auth
    • Core
    • Error
    • Event
    • I18n
    • Log
      • Engine
    • Model
      • Behavior
      • Datasource
        • Database
        • Session
      • Validator
    • Network
      • Email
      • Http
    • Routing
      • Filter
      • Route
    • TestSuite
      • Coverage
      • Fixture
      • Reporter
    • Utility
    • View
      • Helper

Classes

  • BasicAuthentication
  • DigestAuthentication
  • HttpResponse
  • HttpSocket
  • HttpSocketResponse
  1: <?php
  2: /**
  3:  * HTTP Response from HttpSocket.
  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:  * @since         CakePHP(tm) v 2.0.0
 15:  * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 16:  */
 17: 
 18: /**
 19:  * HTTP Response from HttpSocket.
 20:  *
 21:  * @package       Cake.Network.Http
 22:  */
 23: class HttpSocketResponse implements ArrayAccess {
 24: 
 25: /**
 26:  * Body content
 27:  *
 28:  * @var string
 29:  */
 30:     public $body = '';
 31: 
 32: /**
 33:  * Headers
 34:  *
 35:  * @var array
 36:  */
 37:     public $headers = array();
 38: 
 39: /**
 40:  * Cookies
 41:  *
 42:  * @var array
 43:  */
 44:     public $cookies = array();
 45: 
 46: /**
 47:  * HTTP version
 48:  *
 49:  * @var string
 50:  */
 51:     public $httpVersion = 'HTTP/1.1';
 52: 
 53: /**
 54:  * Response code
 55:  *
 56:  * @var int
 57:  */
 58:     public $code = 0;
 59: 
 60: /**
 61:  * Reason phrase
 62:  *
 63:  * @var string
 64:  */
 65:     public $reasonPhrase = '';
 66: 
 67: /**
 68:  * Pure raw content
 69:  *
 70:  * @var string
 71:  */
 72:     public $raw = '';
 73: 
 74: /**
 75:  * Context data in the response.
 76:  * Contains SSL certificates for example.
 77:  *
 78:  * @var array
 79:  */
 80:     public $context = array();
 81: 
 82: /**
 83:  * Constructor
 84:  *
 85:  * @param string $message Message to parse.
 86:  */
 87:     public function __construct($message = null) {
 88:         if ($message !== null) {
 89:             $this->parseResponse($message);
 90:         }
 91:     }
 92: 
 93: /**
 94:  * Body content
 95:  *
 96:  * @return string
 97:  */
 98:     public function body() {
 99:         return (string)$this->body;
100:     }
101: 
102: /**
103:  * Get header in case insensitive
104:  *
105:  * @param string $name Header name.
106:  * @param array $headers Headers to format.
107:  * @return mixed String if header exists or null
108:  */
109:     public function getHeader($name, $headers = null) {
110:         if (!is_array($headers)) {
111:             $headers =& $this->headers;
112:         }
113:         if (isset($headers[$name])) {
114:             return $headers[$name];
115:         }
116:         foreach ($headers as $key => $value) {
117:             if (strcasecmp($key, $name) === 0) {
118:                 return $value;
119:             }
120:         }
121:         return null;
122:     }
123: 
124: /**
125:  * If return is 200 (OK)
126:  *
127:  * @return bool
128:  */
129:     public function isOk() {
130:         return in_array($this->code, array(200, 201, 202, 203, 204, 205, 206));
131:     }
132: 
133: /**
134:  * If return is a valid 3xx (Redirection)
135:  *
136:  * @return bool
137:  */
138:     public function isRedirect() {
139:         return in_array($this->code, array(301, 302, 303, 307)) && $this->getHeader('Location') !== null;
140:     }
141: 
142: /**
143:  * Parses the given message and breaks it down in parts.
144:  *
145:  * @param string $message Message to parse
146:  * @return void
147:  * @throws SocketException
148:  */
149:     public function parseResponse($message) {
150:         if (!is_string($message)) {
151:             throw new SocketException(__d('cake_dev', 'Invalid response.'));
152:         }
153: 
154:         if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) {
155:             throw new SocketException(__d('cake_dev', 'Invalid HTTP response.'));
156:         }
157: 
158:         list(, $statusLine, $header) = $match;
159:         $this->raw = $message;
160:         $this->body = (string)substr($message, strlen($match[0]));
161: 
162:         if (preg_match("/(.+) ([0-9]{3})(?:\s+(\w.+))?\s*\r\n/DU", $statusLine, $match)) {
163:             $this->httpVersion = $match[1];
164:             $this->code = $match[2];
165:             if (isset($match[3])) {
166:                 $this->reasonPhrase = $match[3];
167:             }
168:         }
169: 
170:         $this->headers = $this->_parseHeader($header);
171:         $transferEncoding = $this->getHeader('Transfer-Encoding');
172:         $decoded = $this->_decodeBody($this->body, $transferEncoding);
173:         $this->body = $decoded['body'];
174: 
175:         if (!empty($decoded['header'])) {
176:             $this->headers = $this->_parseHeader($this->_buildHeader($this->headers) . $this->_buildHeader($decoded['header']));
177:         }
178: 
179:         if (!empty($this->headers)) {
180:             $this->cookies = $this->parseCookies($this->headers);
181:         }
182:     }
183: 
184: /**
185:  * Generic function to decode a $body with a given $encoding. Returns either an array with the keys
186:  * 'body' and 'header' or false on failure.
187:  *
188:  * @param string $body A string containing the body to decode.
189:  * @param string|bool $encoding Can be false in case no encoding is being used, or a string representing the encoding.
190:  * @return mixed Array of response headers and body or false.
191:  */
192:     protected function _decodeBody($body, $encoding = 'chunked') {
193:         if (!is_string($body)) {
194:             return false;
195:         }
196:         if (empty($encoding)) {
197:             return array('body' => $body, 'header' => false);
198:         }
199:         $decodeMethod = '_decode' . Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body';
200: 
201:         if (!is_callable(array(&$this, $decodeMethod))) {
202:             return array('body' => $body, 'header' => false);
203:         }
204:         return $this->{$decodeMethod}($body);
205:     }
206: 
207: /**
208:  * Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as
209:  * a result.
210:  *
211:  * @param string $body A string containing the chunked body to decode.
212:  * @return mixed Array of response headers and body or false.
213:  * @throws SocketException
214:  */
215:     protected function _decodeChunkedBody($body) {
216:         if (!is_string($body)) {
217:             return false;
218:         }
219: 
220:         $decodedBody = null;
221:         $chunkLength = null;
222: 
223:         while ($chunkLength !== 0) {
224:             if (!preg_match('/^([0-9a-f]+)[ ]*(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) {
225:                 // Handle remaining invalid data as one big chunk.
226:                 preg_match('/^(.*?)\r\n/', $body, $invalidMatch);
227:                 $length = isset($invalidMatch[1]) ? strlen($invalidMatch[1]) : 0;
228:                 $match = array(
229:                     0 => '',
230:                     1 => dechex($length)
231:                 );
232:             }
233:             $chunkSize = 0;
234:             $hexLength = 0;
235:             if (isset($match[0])) {
236:                 $chunkSize = $match[0];
237:             }
238:             if (isset($match[1])) {
239:                 $hexLength = $match[1];
240:             }
241: 
242:             $chunkLength = hexdec($hexLength);
243:             $body = substr($body, strlen($chunkSize));
244: 
245:             $decodedBody .= substr($body, 0, $chunkLength);
246:             if ($chunkLength) {
247:                 $body = substr($body, $chunkLength + strlen("\r\n"));
248:             }
249:         }
250: 
251:         $entityHeader = false;
252:         if (!empty($body)) {
253:             $entityHeader = $this->_parseHeader($body);
254:         }
255:         return array('body' => $decodedBody, 'header' => $entityHeader);
256:     }
257: 
258: /**
259:  * Parses an array based header.
260:  *
261:  * @param array $header Header as an indexed array (field => value)
262:  * @return array Parsed header
263:  */
264:     protected function _parseHeader($header) {
265:         if (is_array($header)) {
266:             return $header;
267:         } elseif (!is_string($header)) {
268:             return false;
269:         }
270: 
271:         preg_match_all("/(.+):(.+)(?:(?<![\t ])\r\n|\$)/Uis", $header, $matches, PREG_SET_ORDER);
272: 
273:         $header = array();
274:         foreach ($matches as $match) {
275:             list(, $field, $value) = $match;
276: 
277:             $value = trim($value);
278:             $value = preg_replace("/[\t ]\r\n/", "\r\n", $value);
279: 
280:             $field = $this->_unescapeToken($field);
281: 
282:             if (!isset($header[$field])) {
283:                 $header[$field] = $value;
284:             } else {
285:                 $header[$field] = array_merge((array)$header[$field], (array)$value);
286:             }
287:         }
288:         return $header;
289:     }
290: 
291: /**
292:  * Parses cookies in response headers.
293:  *
294:  * @param array $header Header array containing one ore more 'Set-Cookie' headers.
295:  * @return mixed Either false on no cookies, or an array of cookies received.
296:  */
297:     public function parseCookies($header) {
298:         $cookieHeader = $this->getHeader('Set-Cookie', $header);
299:         if (!$cookieHeader) {
300:             return false;
301:         }
302: 
303:         $cookies = array();
304:         foreach ((array)$cookieHeader as $cookie) {
305:             if (strpos($cookie, '";"') !== false) {
306:                 $cookie = str_replace('";"', "{__cookie_replace__}", $cookie);
307:                 $parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie));
308:             } else {
309:                 $parts = preg_split('/\;[ \t]*/', $cookie);
310:             }
311: 
312:             list($name, $value) = explode('=', array_shift($parts), 2);
313:             $cookies[$name] = compact('value');
314: 
315:             foreach ($parts as $part) {
316:                 if (strpos($part, '=') !== false) {
317:                     list($key, $value) = explode('=', $part);
318:                 } else {
319:                     $key = $part;
320:                     $value = true;
321:                 }
322: 
323:                 $key = strtolower($key);
324:                 if (!isset($cookies[$name][$key])) {
325:                     $cookies[$name][$key] = $value;
326:                 }
327:             }
328:         }
329:         return $cookies;
330:     }
331: 
332: /**
333:  * Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs)
334:  *
335:  * @param string $token Token to unescape.
336:  * @param array $chars Characters to unescape.
337:  * @return string Unescaped token
338:  */
339:     protected function _unescapeToken($token, $chars = null) {
340:         $regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/';
341:         $token = preg_replace($regex, '\\1', $token);
342:         return $token;
343:     }
344: 
345: /**
346:  * Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
347:  *
348:  * @param bool $hex True to get them as HEX values, false otherwise.
349:  * @param array $chars Characters to uescape.
350:  * @return array Escape chars
351:  */
352:     protected function _tokenEscapeChars($hex = true, $chars = null) {
353:         if (!empty($chars)) {
354:             $escape = $chars;
355:         } else {
356:             $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
357:             for ($i = 0; $i <= 31; $i++) {
358:                 $escape[] = chr($i);
359:             }
360:             $escape[] = chr(127);
361:         }
362: 
363:         if (!$hex) {
364:             return $escape;
365:         }
366:         foreach ($escape as $key => $char) {
367:             $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
368:         }
369:         return $escape;
370:     }
371: 
372: /**
373:  * ArrayAccess - Offset Exists
374:  *
375:  * @param string $offset Offset to check.
376:  * @return bool
377:  */
378:     public function offsetExists($offset) {
379:         return in_array($offset, array('raw', 'status', 'header', 'body', 'cookies'));
380:     }
381: 
382: /**
383:  * ArrayAccess - Offset Get
384:  *
385:  * @param string $offset Offset to get.
386:  * @return mixed
387:  */
388:     public function offsetGet($offset) {
389:         switch ($offset) {
390:             case 'raw':
391:                 $firstLineLength = strpos($this->raw, "\r\n") + 2;
392:                 if ($this->raw[$firstLineLength] === "\r") {
393:                     $header = null;
394:                 } else {
395:                     $header = substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength) . "\r\n";
396:                 }
397:                 return array(
398:                     'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase . "\r\n",
399:                     'header' => $header,
400:                     'body' => $this->body,
401:                     'response' => $this->raw
402:                 );
403:             case 'status':
404:                 return array(
405:                     'http-version' => $this->httpVersion,
406:                     'code' => $this->code,
407:                     'reason-phrase' => $this->reasonPhrase
408:                 );
409:             case 'header':
410:                 return $this->headers;
411:             case 'body':
412:                 return $this->body;
413:             case 'cookies':
414:                 return $this->cookies;
415:         }
416:         return null;
417:     }
418: 
419: /**
420:  * ArrayAccess - Offset Set
421:  *
422:  * @param string $offset Offset to set.
423:  * @param mixed $value Value.
424:  * @return void
425:  */
426:     public function offsetSet($offset, $value) {
427:     }
428: 
429: /**
430:  * ArrayAccess - Offset Unset
431:  *
432:  * @param string $offset Offset to unset.
433:  * @return void
434:  */
435:     public function offsetUnset($offset) {
436:     }
437: 
438: /**
439:  * Instance as string
440:  *
441:  * @return string
442:  */
443:     public function __toString() {
444:         return $this->body();
445:     }
446: 
447: }
448: 
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