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: if (!empty($query)) {
456: $uri = $this->_parseUri($uri, $this->config['request']['uri']);
457: if (isset($uri['query'])) {
458: $uri['query'] = array_merge($uri['query'], $query);
459: } else {
460: $uri['query'] = $query;
461: }
462: $uri = $this->_buildUri($uri);
463: }
464:
465: $request = Hash::merge(array('method' => 'GET', 'uri' => $uri), $request);
466: return $this->request($request);
467: }
468:
469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479:
480: public function head($uri = null, $query = array(), $request = array()) {
481: if (!empty($query)) {
482: $uri = $this->_parseUri($uri, $this->config['request']['uri']);
483: if (isset($uri['query'])) {
484: $uri['query'] = array_merge($uri['query'], $query);
485: } else {
486: $uri['query'] = $query;
487: }
488: $uri = $this->_buildUri($uri);
489: }
490:
491: $request = Hash::merge(array('method' => 'HEAD', 'uri' => $uri), $request);
492: return $this->request($request);
493: }
494:
495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511:
512: public function post($uri = null, $data = array(), $request = array()) {
513: $request = Hash::merge(array('method' => 'POST', 'uri' => $uri, 'body' => $data), $request);
514: return $this->request($request);
515: }
516:
517: 518: 519: 520: 521: 522: 523: 524:
525: public function put($uri = null, $data = array(), $request = array()) {
526: $request = Hash::merge(array('method' => 'PUT', 'uri' => $uri, 'body' => $data), $request);
527: return $this->request($request);
528: }
529:
530: 531: 532: 533: 534: 535: 536: 537:
538: public function patch($uri = null, $data = array(), $request = array()) {
539: $request = Hash::merge(array('method' => 'PATCH', 'uri' => $uri, 'body' => $data), $request);
540: return $this->request($request);
541: }
542:
543: 544: 545: 546: 547: 548: 549: 550:
551: public function delete($uri = null, $data = array(), $request = array()) {
552: $request = Hash::merge(array('method' => 'DELETE', 'uri' => $uri, 'body' => $data), $request);
553: return $this->request($request);
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: 580: 581: 582:
583: public function url($url = null, $uriTemplate = null) {
584: if ($url === null) {
585: $url = '/';
586: }
587: if (is_string($url)) {
588: $scheme = $this->config['request']['uri']['scheme'];
589: if (is_array($scheme)) {
590: $scheme = $scheme[0];
591: }
592: $port = $this->config['request']['uri']['port'];
593: if (is_array($port)) {
594: $port = $port[0];
595: }
596: if ($url{0} === '/') {
597: $url = $this->config['request']['uri']['host'] . ':' . $port . $url;
598: }
599: if (!preg_match('/^.+:\/\/|\*|^\//', $url)) {
600: $url = $scheme . '://' . $url;
601: }
602: } elseif (!is_array($url) && !empty($url)) {
603: return false;
604: }
605:
606: $base = array_merge($this->config['request']['uri'], array('scheme' => array('http', 'https'), 'port' => array(80, 443)));
607: $url = $this->_parseUri($url, $base);
608:
609: if (empty($url)) {
610: $url = $this->config['request']['uri'];
611: }
612:
613: if (!empty($uriTemplate)) {
614: return $this->_buildUri($url, $uriTemplate);
615: }
616: return $this->_buildUri($url);
617: }
618:
619: 620: 621: 622: 623: 624:
625: protected function _setAuth() {
626: if (empty($this->_auth)) {
627: return;
628: }
629: $method = key($this->_auth);
630: list($plugin, $authClass) = pluginSplit($method, true);
631: $authClass = Inflector::camelize($authClass) . 'Authentication';
632: App::uses($authClass, $plugin . 'Network/Http');
633:
634: if (!class_exists($authClass)) {
635: throw new SocketException(__d('cake_dev', 'Unknown authentication method.'));
636: }
637: if (!method_exists($authClass, 'authentication')) {
638: throw new SocketException(__d('cake_dev', 'The %s does not support authentication.', $authClass));
639: }
640: call_user_func_array("$authClass::authentication", array($this, &$this->_auth[$method]));
641: }
642:
643: 644: 645: 646: 647: 648:
649: protected function _setProxy() {
650: if (empty($this->_proxy) || !isset($this->_proxy['host'], $this->_proxy['port'])) {
651: return;
652: }
653: $this->config['host'] = $this->_proxy['host'];
654: $this->config['port'] = $this->_proxy['port'];
655: $this->config['proxy'] = true;
656:
657: if (empty($this->_proxy['method']) || !isset($this->_proxy['user'], $this->_proxy['pass'])) {
658: return;
659: }
660: list($plugin, $authClass) = pluginSplit($this->_proxy['method'], true);
661: $authClass = Inflector::camelize($authClass) . 'Authentication';
662: App::uses($authClass, $plugin . 'Network/Http');
663:
664: if (!class_exists($authClass)) {
665: throw new SocketException(__d('cake_dev', 'Unknown authentication method for proxy.'));
666: }
667: if (!method_exists($authClass, 'proxyAuthentication')) {
668: throw new SocketException(__d('cake_dev', 'The %s does not support proxy authentication.', $authClass));
669: }
670: call_user_func_array("$authClass::proxyAuthentication", array($this, &$this->_proxy));
671:
672: if (!empty($this->request['header']['Proxy-Authorization'])) {
673: $this->config['proxyauth'] = $this->request['header']['Proxy-Authorization'];
674: if ($this->request['uri']['scheme'] === 'https') {
675: $this->request['header'] = Hash::remove($this->request['header'], 'Proxy-Authorization');
676: }
677: }
678: }
679:
680: 681: 682: 683: 684: 685:
686: protected function _configUri($uri = null) {
687: if (empty($uri)) {
688: return false;
689: }
690:
691: if (is_array($uri)) {
692: $uri = $this->_parseUri($uri);
693: } else {
694: $uri = $this->_parseUri($uri, true);
695: }
696:
697: if (!isset($uri['host'])) {
698: return false;
699: }
700: $config = array(
701: 'request' => array(
702: 'uri' => array_intersect_key($uri, $this->config['request']['uri'])
703: )
704: );
705: $this->config = Hash::merge($this->config, $config);
706: $this->config = Hash::merge($this->config, array_intersect_key($this->config['request']['uri'], $this->config));
707: return true;
708: }
709:
710: 711: 712: 713: 714: 715: 716:
717: protected function _buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') {
718: if (is_string($uri)) {
719: $uri = array('host' => $uri);
720: }
721: $uri = $this->_parseUri($uri, true);
722:
723: if (!is_array($uri) || empty($uri)) {
724: return false;
725: }
726:
727: $uri['path'] = preg_replace('/^\//', null, $uri['path']);
728: $uri['query'] = http_build_query($uri['query'], '', '&');
729: $uri['query'] = rtrim($uri['query'], '=');
730: $stripIfEmpty = array(
731: 'query' => '?%query',
732: 'fragment' => '#%fragment',
733: 'user' => '%user:%pass@',
734: 'host' => '%host:%port/'
735: );
736:
737: foreach ($stripIfEmpty as $key => $strip) {
738: if (empty($uri[$key])) {
739: $uriTemplate = str_replace($strip, null, $uriTemplate);
740: }
741: }
742:
743: $defaultPorts = array('http' => 80, 'https' => 443);
744: if (array_key_exists($uri['scheme'], $defaultPorts) && $defaultPorts[$uri['scheme']] == $uri['port']) {
745: $uriTemplate = str_replace(':%port', null, $uriTemplate);
746: }
747: foreach ($uri as $property => $value) {
748: $uriTemplate = str_replace('%' . $property, $value, $uriTemplate);
749: }
750:
751: if ($uriTemplate === '/*') {
752: $uriTemplate = '*';
753: }
754: return $uriTemplate;
755: }
756:
757: 758: 759: 760: 761: 762: 763: 764:
765: protected function _parseUri($uri = null, $base = array()) {
766: $uriBase = array(
767: 'scheme' => array('http', 'https'),
768: 'host' => null,
769: 'port' => array(80, 443),
770: 'user' => null,
771: 'pass' => null,
772: 'path' => '/',
773: 'query' => null,
774: 'fragment' => null
775: );
776:
777: if (is_string($uri)) {
778: $uri = parse_url($uri);
779: }
780: if (!is_array($uri) || empty($uri)) {
781: return false;
782: }
783: if ($base === true) {
784: $base = $uriBase;
785: }
786:
787: if (isset($base['port'], $base['scheme']) && is_array($base['port']) && is_array($base['scheme'])) {
788: if (isset($uri['scheme']) && !isset($uri['port'])) {
789: $base['port'] = $base['port'][array_search($uri['scheme'], $base['scheme'])];
790: } elseif (isset($uri['port']) && !isset($uri['scheme'])) {
791: $base['scheme'] = $base['scheme'][array_search($uri['port'], $base['port'])];
792: }
793: }
794:
795: if (is_array($base) && !empty($base)) {
796: $uri = array_merge($base, $uri);
797: }
798:
799: if (isset($uri['scheme']) && is_array($uri['scheme'])) {
800: $uri['scheme'] = array_shift($uri['scheme']);
801: }
802: if (isset($uri['port']) && is_array($uri['port'])) {
803: $uri['port'] = array_shift($uri['port']);
804: }
805:
806: if (array_key_exists('query', $uri)) {
807: $uri['query'] = $this->_parseQuery($uri['query']);
808: }
809:
810: if (!array_intersect_key($uriBase, $uri)) {
811: return false;
812: }
813: return $uri;
814: }
815:
816: 817: 818: 819: 820: 821: 822: 823: 824: 825: 826: 827: 828: 829:
830: protected function _parseQuery($query) {
831: if (is_array($query)) {
832: return $query;
833: }
834:
835: $parsedQuery = array();
836:
837: if (is_string($query) && !empty($query)) {
838: $query = preg_replace('/^\?/', '', $query);
839: $items = explode('&', $query);
840:
841: foreach ($items as $item) {
842: if (strpos($item, '=') !== false) {
843: list($key, $value) = explode('=', $item, 2);
844: } else {
845: $key = $item;
846: $value = null;
847: }
848:
849: $key = urldecode($key);
850: $value = urldecode($value);
851:
852: if (preg_match_all('/\[([^\[\]]*)\]/iUs', $key, $matches)) {
853: $subKeys = $matches[1];
854: $rootKey = substr($key, 0, strpos($key, '['));
855: if (!empty($rootKey)) {
856: array_unshift($subKeys, $rootKey);
857: }
858: $queryNode =& $parsedQuery;
859:
860: foreach ($subKeys as $subKey) {
861: if (!is_array($queryNode)) {
862: $queryNode = array();
863: }
864:
865: if ($subKey === '') {
866: $queryNode[] = array();
867: end($queryNode);
868: $subKey = key($queryNode);
869: }
870: $queryNode =& $queryNode[$subKey];
871: }
872: $queryNode = $value;
873: continue;
874: }
875: if (!isset($parsedQuery[$key])) {
876: $parsedQuery[$key] = $value;
877: } else {
878: $parsedQuery[$key] = (array)$parsedQuery[$key];
879: $parsedQuery[$key][] = $value;
880: }
881: }
882: }
883: return $parsedQuery;
884: }
885:
886: 887: 888: 889: 890: 891: 892:
893: protected function _buildRequestLine($request = array()) {
894: $asteriskMethods = array('OPTIONS');
895:
896: if (is_string($request)) {
897: $isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match);
898: if (!$this->quirksMode && (!$isValid || ($match[2] === '*' && !in_array($match[3], $asteriskMethods)))) {
899: throw new SocketException(__d('cake_dev', 'HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.'));
900: }
901: return $request;
902: } elseif (!is_array($request)) {
903: return false;
904: } elseif (!array_key_exists('uri', $request)) {
905: return false;
906: }
907:
908: $request['uri'] = $this->_parseUri($request['uri']);
909: $request += array('method' => 'GET');
910: if (!empty($this->_proxy['host']) && $request['uri']['scheme'] !== 'https') {
911: $request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query');
912: } else {
913: $request['uri'] = $this->_buildUri($request['uri'], '/%path?%query');
914: }
915:
916: if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) {
917: 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)));
918: }
919: $version = isset($request['version']) ? $request['version'] : '1.1';
920: return $request['method'] . ' ' . $request['uri'] . ' HTTP/' . $version . "\r\n";
921: }
922:
923: 924: 925: 926: 927: 928: 929:
930: protected function _buildHeader($header, $mode = 'standard') {
931: if (is_string($header)) {
932: return $header;
933: } elseif (!is_array($header)) {
934: return false;
935: }
936:
937: $fieldsInHeader = array();
938: foreach ($header as $key => $value) {
939: $lowKey = strtolower($key);
940: if (array_key_exists($lowKey, $fieldsInHeader)) {
941: $header[$fieldsInHeader[$lowKey]] = $value;
942: unset($header[$key]);
943: } else {
944: $fieldsInHeader[$lowKey] = $key;
945: }
946: }
947:
948: $returnHeader = '';
949: foreach ($header as $field => $contents) {
950: if (is_array($contents) && $mode === 'standard') {
951: $contents = implode(',', $contents);
952: }
953: foreach ((array)$contents as $content) {
954: $contents = preg_replace("/\r\n(?![\t ])/", "\r\n ", $content);
955: $field = $this->_escapeToken($field);
956:
957: $returnHeader .= $field . ': ' . $contents . "\r\n";
958: }
959: }
960: return $returnHeader;
961: }
962:
963: 964: 965: 966: 967: 968: 969: 970: 971:
972: public function buildCookies($cookies) {
973: $header = array();
974: foreach ($cookies as $name => $cookie) {
975: if (is_array($cookie)) {
976: $value = $this->_escapeToken($cookie['value'], array(';'));
977: } else {
978: $value = $this->_escapeToken($cookie, array(';'));
979: }
980: $header[] = $name . '=' . $value;
981: }
982: return $this->_buildHeader(array('Cookie' => implode('; ', $header)), 'pragmatic');
983: }
984:
985: 986: 987: 988: 989: 990: 991:
992: protected function _escapeToken($token, $chars = null) {
993: $regex = '/([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])/';
994: $token = preg_replace($regex, '"\\1"', $token);
995: return $token;
996: }
997:
998: 999: 1000: 1001: 1002: 1003: 1004:
1005: protected function _tokenEscapeChars($hex = true, $chars = null) {
1006: if (!empty($chars)) {
1007: $escape = $chars;
1008: } else {
1009: $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
1010: for ($i = 0; $i <= 31; $i++) {
1011: $escape[] = chr($i);
1012: }
1013: $escape[] = chr(127);
1014: }
1015:
1016: if (!$hex) {
1017: return $escape;
1018: }
1019: foreach ($escape as $key => $char) {
1020: $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
1021: }
1022: return $escape;
1023: }
1024:
1025: 1026: 1027: 1028: 1029: 1030: 1031:
1032: public function reset($full = true) {
1033: static $initalState = array();
1034: if (empty($initalState)) {
1035: $initalState = get_class_vars(__CLASS__);
1036: }
1037: if (!$full) {
1038: $this->request = $initalState['request'];
1039: $this->response = $initalState['response'];
1040: return true;
1041: }
1042: parent::reset($initalState);
1043: return true;
1044: }
1045:
1046: }
1047:
1048: