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.3 API

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