1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
18:
19: App::uses('CakeSocket', 'Network');
20: App::uses('Router', 'Routing');
21: App::uses('Hash', 'Utility');
22:
23: 24: 25: 26: 27: 28: 29: 30:
31: class HttpSocket extends CakeSocket {
32:
33: 34: 35: 36: 37: 38: 39:
40: public $quirksMode = false;
41:
42: 43: 44: 45: 46:
47: public $request = array(
48: 'method' => 'GET',
49: 'uri' => array(
50: 'scheme' => 'http',
51: 'host' => null,
52: 'port' => 80,
53: 'user' => null,
54: 'pass' => null,
55: 'path' => null,
56: 'query' => null,
57: 'fragment' => null
58: ),
59: 'version' => '1.1',
60: 'body' => '',
61: 'line' => null,
62: 'header' => array(
63: 'Connection' => 'close',
64: 'User-Agent' => 'CakePHP'
65: ),
66: 'raw' => null,
67: 'redirect' => false,
68: 'cookies' => array(),
69: );
70:
71: 72: 73: 74: 75:
76: public $response = null;
77:
78: 79: 80: 81: 82:
83: public $responseClass = 'HttpSocketResponse';
84:
85: 86: 87: 88: 89:
90: public $config = array(
91: 'persistent' => false,
92: 'host' => 'localhost',
93: 'protocol' => 'tcp',
94: 'port' => 80,
95: 'timeout' => 30,
96: 'ssl_verify_peer' => true,
97: 'ssl_allow_self_signed' => false,
98: 'ssl_verify_depth' => 5,
99: 'ssl_verify_host' => true,
100: 'request' => array(
101: 'uri' => array(
102: 'scheme' => array('http', 'https'),
103: 'host' => 'localhost',
104: 'port' => array(80, 443)
105: ),
106: 'redirect' => false,
107: 'cookies' => array(),
108: )
109: );
110:
111: 112: 113: 114: 115:
116: protected $_auth = array();
117:
118: 119: 120: 121: 122:
123: protected $_proxy = array();
124:
125: 126: 127: 128: 129:
130: protected $_contentResource = null;
131:
132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152:
153: public function __construct($config = array()) {
154: if (is_string($config)) {
155: $this->_configUri($config);
156: } elseif (is_array($config)) {
157: if (isset($config['request']['uri']) && is_string($config['request']['uri'])) {
158: $this->_configUri($config['request']['uri']);
159: unset($config['request']['uri']);
160: }
161: $this->config = Hash::merge($this->config, $config);
162: }
163: parent::__construct($this->config);
164: }
165:
166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196:
197: public function configAuth($method, $user = null, $pass = null) {
198: if (empty($method)) {
199: $this->_auth = array();
200: return;
201: }
202: if (is_array($user)) {
203: $this->_auth = array($method => $user);
204: return;
205: }
206: $this->_auth = array($method => compact('user', 'pass'));
207: }
208:
209: 210: 211: 212: 213: 214: 215: 216: 217: 218:
219: public function configProxy($host, $port = 3128, $method = null, $user = null, $pass = null) {
220: if (empty($host)) {
221: $this->_proxy = array();
222: return;
223: }
224: if (is_array($host)) {
225: $this->_proxy = $host + array('host' => null);
226: return;
227: }
228: $this->_proxy = compact('host', 'port', 'method', 'user', 'pass');
229: }
230:
231: 232: 233: 234: 235: 236: 237:
238: public function setContentResource($resource) {
239: if ($resource === false) {
240: $this->_contentResource = null;
241: return;
242: }
243: if (!is_resource($resource)) {
244: throw new SocketException(__d('cake_dev', 'Invalid resource.'));
245: }
246: $this->_contentResource = $resource;
247: }
248:
249: 250: 251: 252: 253: 254: 255: 256:
257: public function request($request = array()) {
258: $this->reset(false);
259:
260: if (is_string($request)) {
261: $request = array('uri' => $request);
262: } elseif (!is_array($request)) {
263: return false;
264: }
265:
266: if (!isset($request['uri'])) {
267: $request['uri'] = null;
268: }
269: $uri = $this->_parseUri($request['uri']);
270: if (!isset($uri['host'])) {
271: $host = $this->config['host'];
272: }
273: if (isset($request['host'])) {
274: $host = $request['host'];
275: unset($request['host']);
276: }
277: $request['uri'] = $this->url($request['uri']);
278: $request['uri'] = $this->_parseUri($request['uri'], true);
279: $this->request = Hash::merge($this->request, array_diff_key($this->config['request'], array('cookies' => true)), $request);
280:
281: $this->_configUri($this->request['uri']);
282:
283: $Host = $this->request['uri']['host'];
284: if (!empty($this->config['request']['cookies'][$Host])) {
285: if (!isset($this->request['cookies'])) {
286: $this->request['cookies'] = array();
287: }
288: if (!isset($request['cookies'])) {
289: $request['cookies'] = array();
290: }
291: $this->request['cookies'] = array_merge($this->request['cookies'], $this->config['request']['cookies'][$Host], $request['cookies']);
292: }
293:
294: if (isset($host)) {
295: $this->config['host'] = $host;
296: }
297:
298: $this->_setProxy();
299: $this->request['proxy'] = $this->_proxy;
300:
301: $cookies = null;
302:
303: if (is_array($this->request['header'])) {
304: if (!empty($this->request['cookies'])) {
305: $cookies = $this->buildCookies($this->request['cookies']);
306: }
307: $scheme = '';
308: $port = 0;
309: if (isset($this->request['uri']['scheme'])) {
310: $scheme = $this->request['uri']['scheme'];
311: }
312: if (isset($this->request['uri']['port'])) {
313: $port = $this->request['uri']['port'];
314: }
315: if (($scheme === 'http' && $port != 80) ||
316: ($scheme === 'https' && $port != 443) ||
317: ($port != 80 && $port != 443)
318: ) {
319: $Host .= ':' . $port;
320: }
321: $this->request['header'] = array_merge(compact('Host'), $this->request['header']);
322: }
323:
324: if (isset($this->request['uri']['user'], $this->request['uri']['pass'])) {
325: $this->configAuth('Basic', $this->request['uri']['user'], $this->request['uri']['pass']);
326: } elseif (isset($this->request['auth'], $this->request['auth']['method'], $this->request['auth']['user'], $this->request['auth']['pass'])) {
327: $this->configAuth($this->request['auth']['method'], $this->request['auth']['user'], $this->request['auth']['pass']);
328: }
329: $authHeader = Hash::get($this->request, 'header.Authorization');
330: if (empty($authHeader)) {
331: $this->_setAuth();
332: $this->request['auth'] = $this->_auth;
333: }
334:
335: if (is_array($this->request['body'])) {
336: $this->request['body'] = http_build_query($this->request['body'], '', '&');
337: }
338:
339: if (!empty($this->request['body']) && !isset($this->request['header']['Content-Type'])) {
340: $this->request['header']['Content-Type'] = 'application/x-www-form-urlencoded';
341: }
342:
343: if (!empty($this->request['body']) && !isset($this->request['header']['Content-Length'])) {
344: $this->request['header']['Content-Length'] = strlen($this->request['body']);
345: }
346: if (isset($this->request['uri']['scheme']) && $this->request['uri']['scheme'] === 'https' && in_array($this->config['protocol'], array(false, 'tcp'))) {
347: $this->config['protocol'] = 'ssl';
348: }
349:
350: $connectionType = null;
351: if (isset($this->request['header']['Connection'])) {
352: $connectionType = $this->request['header']['Connection'];
353: }
354: $this->request['header'] = $this->_buildHeader($this->request['header']) . $cookies;
355:
356: if (empty($this->request['line'])) {
357: $this->request['line'] = $this->_buildRequestLine($this->request);
358: }
359:
360: if ($this->quirksMode === false && $this->request['line'] === false) {
361: return false;
362: }
363:
364: $this->request['raw'] = '';
365: if ($this->request['line'] !== false) {
366: $this->request['raw'] = $this->request['line'];
367: }
368:
369: if ($this->request['header'] !== false) {
370: $this->request['raw'] .= $this->request['header'];
371: }
372:
373: $this->request['raw'] .= "\r\n";
374: $this->request['raw'] .= $this->request['body'];
375:
376:
377: $this->write($this->request['raw']);
378:
379: $response = null;
380: $inHeader = true;
381: while (($data = $this->read()) !== false) {
382: if ($this->_contentResource) {
383: if ($inHeader) {
384: $response .= $data;
385: $pos = strpos($response, "\r\n\r\n");
386: if ($pos !== false) {
387: $pos += 4;
388: $data = substr($response, $pos);
389: fwrite($this->_contentResource, $data);
390:
391: $response = substr($response, 0, $pos);
392: $inHeader = false;
393: }
394: } else {
395: fwrite($this->_contentResource, $data);
396: fflush($this->_contentResource);
397: }
398: } else {
399: $response .= $data;
400: }
401: }
402:
403: if ($connectionType === 'close') {
404: $this->disconnect();
405: }
406:
407: list($plugin, $responseClass) = pluginSplit($this->responseClass, true);
408: App::uses($responseClass, $plugin . 'Network/Http');
409: if (!class_exists($responseClass)) {
410: throw new SocketException(__d('cake_dev', 'Class %s not found.', $this->responseClass));
411: }
412: $this->response = new $responseClass($response);
413:
414: if (!empty($this->response->cookies)) {
415: if (!isset($this->config['request']['cookies'][$Host])) {
416: $this->config['request']['cookies'][$Host] = array();
417: }
418: $this->config['request']['cookies'][$Host] = array_merge($this->config['request']['cookies'][$Host], $this->response->cookies);
419: }
420:
421: if ($this->request['redirect'] && $this->response->isRedirect()) {
422: $location = trim($this->response->getHeader('Location'), '=');
423: $request['uri'] = str_replace('%2F', '/', $location);
424: $request['redirect'] = is_int($this->request['redirect']) ? $this->request['redirect'] - 1 : $this->request['redirect'];
425: $this->response = $this->request($request);
426: }
427:
428: return $this->response;
429: }
430:
431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453:
454: public function get($uri = null, $query = array(), $request = array()) {
455: $uri = $this->_parseUri($uri, $this->config['request']['uri']);
456: if (isset($uri['query'])) {
457: $uri['query'] = array_merge($uri['query'], $query);
458: } else {
459: $uri['query'] = $query;
460: }
461: $uri = $this->_buildUri($uri);
462:
463: $request = Hash::merge(array('method' => 'GET', 'uri' => $uri), $request);
464: return $this->request($request);
465: }
466:
467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477:
478: public function head($uri = null, $query = array(), $request = array()) {
479: $uri = $this->_parseUri($uri, $this->config['request']['uri']);
480: if (isset($uri['query'])) {
481: $uri['query'] = array_merge($uri['query'], $query);
482: } else {
483: $uri['query'] = $query;
484: }
485: $uri = $this->_buildUri($uri);
486:
487: $request = Hash::merge(array('method' => 'HEAD', 'uri' => $uri), $request);
488: return $this->request($request);
489: }
490:
491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507:
508: public function post($uri = null, $data = array(), $request = array()) {
509: $request = Hash::merge(array('method' => 'POST', 'uri' => $uri, 'body' => $data), $request);
510: return $this->request($request);
511: }
512:
513: 514: 515: 516: 517: 518: 519: 520:
521: public function put($uri = null, $data = array(), $request = array()) {
522: $request = Hash::merge(array('method' => 'PUT', 'uri' => $uri, 'body' => $data), $request);
523: return $this->request($request);
524: }
525:
526: 527: 528: 529: 530: 531: 532: 533:
534: public function patch($uri = null, $data = array(), $request = array()) {
535: $request = Hash::merge(array('method' => 'PATCH', 'uri' => $uri, 'body' => $data), $request);
536: return $this->request($request);
537: }
538:
539: 540: 541: 542: 543: 544: 545: 546:
547: public function delete($uri = null, $data = array(), $request = array()) {
548: $request = Hash::merge(array('method' => 'DELETE', 'uri' => $uri, 'body' => $data), $request);
549: return $this->request($request);
550: }
551:
552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578:
579: public function url($url = null, $uriTemplate = null) {
580: if ($url === null) {
581: $url = '/';
582: }
583: if (is_string($url)) {
584: $scheme = $this->config['request']['uri']['scheme'];
585: if (is_array($scheme)) {
586: $scheme = $scheme[0];
587: }
588: $port = $this->config['request']['uri']['port'];
589: if (is_array($port)) {
590: $port = $port[0];
591: }
592: if ($url[0] === '/') {
593: $url = $this->config['request']['uri']['host'] . ':' . $port . $url;
594: }
595: if (!preg_match('/^.+:\/\/|\*|^\//', $url)) {
596: $url = $scheme . '://' . $url;
597: }
598: } elseif (!is_array($url) && !empty($url)) {
599: return false;
600: }
601:
602: $base = array_merge($this->config['request']['uri'], array('scheme' => array('http', 'https'), 'port' => array(80, 443)));
603: $url = $this->_parseUri($url, $base);
604:
605: if (empty($url)) {
606: $url = $this->config['request']['uri'];
607: }
608:
609: if (!empty($uriTemplate)) {
610: return $this->_buildUri($url, $uriTemplate);
611: }
612: return $this->_buildUri($url);
613: }
614:
615: 616: 617: 618: 619: 620:
621: protected function _setAuth() {
622: if (empty($this->_auth)) {
623: return;
624: }
625: $method = key($this->_auth);
626: list($plugin, $authClass) = pluginSplit($method, true);
627: $authClass = Inflector::camelize($authClass) . 'Authentication';
628: App::uses($authClass, $plugin . 'Network/Http');
629:
630: if (!class_exists($authClass)) {
631: throw new SocketException(__d('cake_dev', 'Unknown authentication method.'));
632: }
633: if (!method_exists($authClass, 'authentication')) {
634: throw new SocketException(__d('cake_dev', 'The %s does not support authentication.', $authClass));
635: }
636: call_user_func_array("$authClass::authentication", array($this, &$this->_auth[$method]));
637: }
638:
639: 640: 641: 642: 643: 644:
645: protected function _setProxy() {
646: if (empty($this->_proxy) || !isset($this->_proxy['host'], $this->_proxy['port'])) {
647: return;
648: }
649: $this->config['host'] = $this->_proxy['host'];
650: $this->config['port'] = $this->_proxy['port'];
651: $this->config['proxy'] = true;
652:
653: if (empty($this->_proxy['method']) || !isset($this->_proxy['user'], $this->_proxy['pass'])) {
654: return;
655: }
656: list($plugin, $authClass) = pluginSplit($this->_proxy['method'], true);
657: $authClass = Inflector::camelize($authClass) . 'Authentication';
658: App::uses($authClass, $plugin . 'Network/Http');
659:
660: if (!class_exists($authClass)) {
661: throw new SocketException(__d('cake_dev', 'Unknown authentication method for proxy.'));
662: }
663: if (!method_exists($authClass, 'proxyAuthentication')) {
664: throw new SocketException(__d('cake_dev', 'The %s does not support proxy authentication.', $authClass));
665: }
666: call_user_func_array("$authClass::proxyAuthentication", array($this, &$this->_proxy));
667:
668: if (!empty($this->request['header']['Proxy-Authorization'])) {
669: $this->config['proxyauth'] = $this->request['header']['Proxy-Authorization'];
670: if ($this->request['uri']['scheme'] === 'https') {
671: $this->request['header'] = Hash::remove($this->request['header'], 'Proxy-Authorization');
672: }
673: }
674: }
675:
676: 677: 678: 679: 680: 681:
682: protected function _configUri($uri = null) {
683: if (empty($uri)) {
684: return false;
685: }
686:
687: if (is_array($uri)) {
688: $uri = $this->_parseUri($uri);
689: } else {
690: $uri = $this->_parseUri($uri, true);
691: }
692:
693: if (!isset($uri['host'])) {
694: return false;
695: }
696: $config = array(
697: 'request' => array(
698: 'uri' => array_intersect_key($uri, $this->config['request']['uri'])
699: )
700: );
701: $this->config = Hash::merge($this->config, $config);
702: $this->config = Hash::merge($this->config, array_intersect_key($this->config['request']['uri'], $this->config));
703: return true;
704: }
705:
706: 707: 708: 709: 710: 711: 712:
713: protected function _buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') {
714: if (is_string($uri)) {
715: $uri = array('host' => $uri);
716: }
717: $uri = $this->_parseUri($uri, true);
718:
719: if (!is_array($uri) || empty($uri)) {
720: return false;
721: }
722:
723: $uri['path'] = preg_replace('/^\//', null, $uri['path']);
724: $uri['query'] = http_build_query($uri['query'], '', '&');
725: $uri['query'] = rtrim($uri['query'], '=');
726: $stripIfEmpty = array(
727: 'query' => '?%query',
728: 'fragment' => '#%fragment',
729: 'user' => '%user:%pass@',
730: 'host' => '%host:%port/'
731: );
732:
733: foreach ($stripIfEmpty as $key => $strip) {
734: if (empty($uri[$key])) {
735: $uriTemplate = str_replace($strip, null, $uriTemplate);
736: }
737: }
738:
739: $defaultPorts = array('http' => 80, 'https' => 443);
740: if (array_key_exists($uri['scheme'], $defaultPorts) && $defaultPorts[$uri['scheme']] == $uri['port']) {
741: $uriTemplate = str_replace(':%port', null, $uriTemplate);
742: }
743: foreach ($uri as $property => $value) {
744: $uriTemplate = str_replace('%' . $property, $value, $uriTemplate);
745: }
746:
747: if ($uriTemplate === '/*') {
748: $uriTemplate = '*';
749: }
750: return $uriTemplate;
751: }
752:
753: 754: 755: 756: 757: 758: 759: 760:
761: protected function _parseUri($uri = null, $base = array()) {
762: $uriBase = array(
763: 'scheme' => array('http', 'https'),
764: 'host' => null,
765: 'port' => array(80, 443),
766: 'user' => null,
767: 'pass' => null,
768: 'path' => '/',
769: 'query' => null,
770: 'fragment' => null
771: );
772:
773: if (is_string($uri)) {
774: $uri = parse_url($uri);
775: }
776: if (!is_array($uri) || empty($uri)) {
777: return false;
778: }
779: if ($base === true) {
780: $base = $uriBase;
781: }
782:
783: if (isset($base['port'], $base['scheme']) && is_array($base['port']) && is_array($base['scheme'])) {
784: if (isset($uri['scheme']) && !isset($uri['port'])) {
785: $base['port'] = $base['port'][array_search($uri['scheme'], $base['scheme'])];
786: } elseif (isset($uri['port']) && !isset($uri['scheme'])) {
787: $base['scheme'] = $base['scheme'][array_search($uri['port'], $base['port'])];
788: }
789: }
790:
791: if (is_array($base) && !empty($base)) {
792: $uri = array_merge($base, $uri);
793: }
794:
795: if (isset($uri['scheme']) && is_array($uri['scheme'])) {
796: $uri['scheme'] = array_shift($uri['scheme']);
797: }
798: if (isset($uri['port']) && is_array($uri['port'])) {
799: $uri['port'] = array_shift($uri['port']);
800: }
801:
802: if (array_key_exists('query', $uri)) {
803: $uri['query'] = $this->_parseQuery($uri['query']);
804: }
805:
806: if (!array_intersect_key($uriBase, $uri)) {
807: return false;
808: }
809: return $uri;
810: }
811:
812: 813: 814: 815: 816: 817: 818: 819: 820: 821: 822: 823: 824: 825:
826: protected function _parseQuery($query) {
827: if (is_array($query)) {
828: return $query;
829: }
830:
831: $parsedQuery = array();
832:
833: if (is_string($query) && !empty($query)) {
834: $query = preg_replace('/^\?/', '', $query);
835: $items = explode('&', $query);
836:
837: foreach ($items as $item) {
838: if (strpos($item, '=') !== false) {
839: list($key, $value) = explode('=', $item, 2);
840: } else {
841: $key = $item;
842: $value = null;
843: }
844:
845: $key = urldecode($key);
846: $value = urldecode($value);
847:
848: if (preg_match_all('/\[([^\[\]]*)\]/iUs', $key, $matches)) {
849: $subKeys = $matches[1];
850: $rootKey = substr($key, 0, strpos($key, '['));
851: if (!empty($rootKey)) {
852: array_unshift($subKeys, $rootKey);
853: }
854: $queryNode =& $parsedQuery;
855:
856: foreach ($subKeys as $subKey) {
857: if (!is_array($queryNode)) {
858: $queryNode = array();
859: }
860:
861: if ($subKey === '') {
862: $queryNode[] = array();
863: end($queryNode);
864: $subKey = key($queryNode);
865: }
866: $queryNode =& $queryNode[$subKey];
867: }
868: $queryNode = $value;
869: continue;
870: }
871: if (!isset($parsedQuery[$key])) {
872: $parsedQuery[$key] = $value;
873: } else {
874: $parsedQuery[$key] = (array)$parsedQuery[$key];
875: $parsedQuery[$key][] = $value;
876: }
877: }
878: }
879: return $parsedQuery;
880: }
881:
882: 883: 884: 885: 886: 887: 888:
889: protected function _buildRequestLine($request = array()) {
890: $asteriskMethods = array('OPTIONS');
891:
892: if (is_string($request)) {
893: $isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match);
894: if (!$this->quirksMode && (!$isValid || ($match[2] === '*' && !in_array($match[3], $asteriskMethods)))) {
895: throw new SocketException(__d('cake_dev', 'HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.'));
896: }
897: return $request;
898: } elseif (!is_array($request)) {
899: return false;
900: } elseif (!array_key_exists('uri', $request)) {
901: return false;
902: }
903:
904: $request['uri'] = $this->_parseUri($request['uri']);
905: $request += array('method' => 'GET');
906: if (!empty($this->_proxy['host']) && $request['uri']['scheme'] !== 'https') {
907: $request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query');
908: } else {
909: $request['uri'] = $this->_buildUri($request['uri'], '/%path?%query');
910: }
911:
912: if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) {
913: 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)));
914: }
915: $version = isset($request['version']) ? $request['version'] : '1.1';
916: return $request['method'] . ' ' . $request['uri'] . ' HTTP/' . $version . "\r\n";
917: }
918:
919: 920: 921: 922: 923: 924: 925:
926: protected function _buildHeader($header, $mode = 'standard') {
927: if (is_string($header)) {
928: return $header;
929: } elseif (!is_array($header)) {
930: return false;
931: }
932:
933: $fieldsInHeader = array();
934: foreach ($header as $key => $value) {
935: $lowKey = strtolower($key);
936: if (array_key_exists($lowKey, $fieldsInHeader)) {
937: $header[$fieldsInHeader[$lowKey]] = $value;
938: unset($header[$key]);
939: } else {
940: $fieldsInHeader[$lowKey] = $key;
941: }
942: }
943:
944: $returnHeader = '';
945: foreach ($header as $field => $contents) {
946: if (is_array($contents) && $mode === 'standard') {
947: $contents = implode(',', $contents);
948: }
949: foreach ((array)$contents as $content) {
950: $contents = preg_replace("/\r\n(?![\t ])/", "\r\n ", $content);
951: $field = $this->_escapeToken($field);
952:
953: $returnHeader .= $field . ': ' . $contents . "\r\n";
954: }
955: }
956: return $returnHeader;
957: }
958:
959: 960: 961: 962: 963: 964: 965: 966: 967:
968: public function buildCookies($cookies) {
969: $header = array();
970: foreach ($cookies as $name => $cookie) {
971: if (is_array($cookie)) {
972: $value = $this->_escapeToken($cookie['value'], array(';'));
973: } else {
974: $value = $this->_escapeToken($cookie, array(';'));
975: }
976: $header[] = $name . '=' . $value;
977: }
978: return $this->_buildHeader(array('Cookie' => implode('; ', $header)), 'pragmatic');
979: }
980:
981: 982: 983: 984: 985: 986: 987:
988: protected function _escapeToken($token, $chars = null) {
989: $regex = '/([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])/';
990: $token = preg_replace($regex, '"\\1"', $token);
991: return $token;
992: }
993:
994: 995: 996: 997: 998: 999: 1000:
1001: protected function _tokenEscapeChars($hex = true, $chars = null) {
1002: if (!empty($chars)) {
1003: $escape = $chars;
1004: } else {
1005: $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
1006: for ($i = 0; $i <= 31; $i++) {
1007: $escape[] = chr($i);
1008: }
1009: $escape[] = chr(127);
1010: }
1011:
1012: if (!$hex) {
1013: return $escape;
1014: }
1015: foreach ($escape as $key => $char) {
1016: $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
1017: }
1018: return $escape;
1019: }
1020:
1021: 1022: 1023: 1024: 1025: 1026: 1027:
1028: public function reset($full = true) {
1029: static $initalState = array();
1030: if (empty($initalState)) {
1031: $initalState = get_class_vars(__CLASS__);
1032: }
1033: if (!$full) {
1034: $this->request = $initalState['request'];
1035: $this->response = $initalState['response'];
1036: return true;
1037: }
1038: parent::reset($initalState);
1039: return true;
1040: }
1041:
1042: }
1043:
1044: