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