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

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.1
      • 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
    • Network
      • Email
      • Http
    • Routing
      • Route
    • TestSuite
      • Coverage
      • Fixture
      • Reporter
    • Utility
    • View
      • Helper

Classes

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