1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
19:
20: 21: 22: 23: 24: 25: 26: 27:
28: class CakeResponse {
29:
30: 31: 32: 33: 34:
35: protected $_statusCodes = array(
36: 100 => 'Continue',
37: 101 => 'Switching Protocols',
38: 200 => 'OK',
39: 201 => 'Created',
40: 202 => 'Accepted',
41: 203 => 'Non-Authoritative Information',
42: 204 => 'No Content',
43: 205 => 'Reset Content',
44: 206 => 'Partial Content',
45: 300 => 'Multiple Choices',
46: 301 => 'Moved Permanently',
47: 302 => 'Found',
48: 303 => 'See Other',
49: 304 => 'Not Modified',
50: 305 => 'Use Proxy',
51: 307 => 'Temporary Redirect',
52: 400 => 'Bad Request',
53: 401 => 'Unauthorized',
54: 402 => 'Payment Required',
55: 403 => 'Forbidden',
56: 404 => 'Not Found',
57: 405 => 'Method Not Allowed',
58: 406 => 'Not Acceptable',
59: 407 => 'Proxy Authentication Required',
60: 408 => 'Request Time-out',
61: 409 => 'Conflict',
62: 410 => 'Gone',
63: 411 => 'Length Required',
64: 412 => 'Precondition Failed',
65: 413 => 'Request Entity Too Large',
66: 414 => 'Request-URI Too Large',
67: 415 => 'Unsupported Media Type',
68: 416 => 'Requested range not satisfiable',
69: 417 => 'Expectation Failed',
70: 500 => 'Internal Server Error',
71: 501 => 'Not Implemented',
72: 502 => 'Bad Gateway',
73: 503 => 'Service Unavailable',
74: 504 => 'Gateway Time-out'
75: );
76:
77: 78: 79: 80: 81:
82: protected $_mimeTypes = array(
83: 'html' => array('text/html', '*/*'),
84: 'json' => 'application/json',
85: 'xml' => array('application/xml', 'text/xml'),
86: 'rss' => 'application/rss+xml',
87: 'ai' => 'application/postscript',
88: 'bcpio' => 'application/x-bcpio',
89: 'bin' => 'application/octet-stream',
90: 'ccad' => 'application/clariscad',
91: 'cdf' => 'application/x-netcdf',
92: 'class' => 'application/octet-stream',
93: 'cpio' => 'application/x-cpio',
94: 'cpt' => 'application/mac-compactpro',
95: 'csh' => 'application/x-csh',
96: 'csv' => array('text/csv', 'application/vnd.ms-excel', 'text/plain'),
97: 'dcr' => 'application/x-director',
98: 'dir' => 'application/x-director',
99: 'dms' => 'application/octet-stream',
100: 'doc' => 'application/msword',
101: 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
102: 'drw' => 'application/drafting',
103: 'dvi' => 'application/x-dvi',
104: 'dwg' => 'application/acad',
105: 'dxf' => 'application/dxf',
106: 'dxr' => 'application/x-director',
107: 'eot' => 'application/vnd.ms-fontobject',
108: 'eps' => 'application/postscript',
109: 'exe' => 'application/octet-stream',
110: 'ez' => 'application/andrew-inset',
111: 'flv' => 'video/x-flv',
112: 'gtar' => 'application/x-gtar',
113: 'gz' => 'application/x-gzip',
114: 'bz2' => 'application/x-bzip',
115: '7z' => 'application/x-7z-compressed',
116: 'hdf' => 'application/x-hdf',
117: 'hqx' => 'application/mac-binhex40',
118: 'ico' => 'image/vnd.microsoft.icon',
119: 'ips' => 'application/x-ipscript',
120: 'ipx' => 'application/x-ipix',
121: 'js' => 'text/javascript',
122: 'latex' => 'application/x-latex',
123: 'lha' => 'application/octet-stream',
124: 'lsp' => 'application/x-lisp',
125: 'lzh' => 'application/octet-stream',
126: 'man' => 'application/x-troff-man',
127: 'me' => 'application/x-troff-me',
128: 'mif' => 'application/vnd.mif',
129: 'ms' => 'application/x-troff-ms',
130: 'nc' => 'application/x-netcdf',
131: 'oda' => 'application/oda',
132: 'otf' => 'font/otf',
133: 'pdf' => 'application/pdf',
134: 'pgn' => 'application/x-chess-pgn',
135: 'pot' => 'application/vnd.ms-powerpoint',
136: 'pps' => 'application/vnd.ms-powerpoint',
137: 'ppt' => 'application/vnd.ms-powerpoint',
138: 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
139: 'ppz' => 'application/vnd.ms-powerpoint',
140: 'pre' => 'application/x-freelance',
141: 'prt' => 'application/pro_eng',
142: 'ps' => 'application/postscript',
143: 'roff' => 'application/x-troff',
144: 'scm' => 'application/x-lotusscreencam',
145: 'set' => 'application/set',
146: 'sh' => 'application/x-sh',
147: 'shar' => 'application/x-shar',
148: 'sit' => 'application/x-stuffit',
149: 'skd' => 'application/x-koan',
150: 'skm' => 'application/x-koan',
151: 'skp' => 'application/x-koan',
152: 'skt' => 'application/x-koan',
153: 'smi' => 'application/smil',
154: 'smil' => 'application/smil',
155: 'sol' => 'application/solids',
156: 'spl' => 'application/x-futuresplash',
157: 'src' => 'application/x-wais-source',
158: 'step' => 'application/STEP',
159: 'stl' => 'application/SLA',
160: 'stp' => 'application/STEP',
161: 'sv4cpio' => 'application/x-sv4cpio',
162: 'sv4crc' => 'application/x-sv4crc',
163: 'svg' => 'image/svg+xml',
164: 'svgz' => 'image/svg+xml',
165: 'swf' => 'application/x-shockwave-flash',
166: 't' => 'application/x-troff',
167: 'tar' => 'application/x-tar',
168: 'tcl' => 'application/x-tcl',
169: 'tex' => 'application/x-tex',
170: 'texi' => 'application/x-texinfo',
171: 'texinfo' => 'application/x-texinfo',
172: 'tr' => 'application/x-troff',
173: 'tsp' => 'application/dsptype',
174: 'ttf' => 'font/ttf',
175: 'unv' => 'application/i-deas',
176: 'ustar' => 'application/x-ustar',
177: 'vcd' => 'application/x-cdlink',
178: 'vda' => 'application/vda',
179: 'xlc' => 'application/vnd.ms-excel',
180: 'xll' => 'application/vnd.ms-excel',
181: 'xlm' => 'application/vnd.ms-excel',
182: 'xls' => 'application/vnd.ms-excel',
183: 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
184: 'xlw' => 'application/vnd.ms-excel',
185: 'zip' => 'application/zip',
186: 'aif' => 'audio/x-aiff',
187: 'aifc' => 'audio/x-aiff',
188: 'aiff' => 'audio/x-aiff',
189: 'au' => 'audio/basic',
190: 'kar' => 'audio/midi',
191: 'mid' => 'audio/midi',
192: 'midi' => 'audio/midi',
193: 'mp2' => 'audio/mpeg',
194: 'mp3' => 'audio/mpeg',
195: 'mpga' => 'audio/mpeg',
196: 'ogg' => 'audio/ogg',
197: 'oga' => 'audio/ogg',
198: 'spx' => 'audio/ogg',
199: 'ra' => 'audio/x-realaudio',
200: 'ram' => 'audio/x-pn-realaudio',
201: 'rm' => 'audio/x-pn-realaudio',
202: 'rpm' => 'audio/x-pn-realaudio-plugin',
203: 'snd' => 'audio/basic',
204: 'tsi' => 'audio/TSP-audio',
205: 'wav' => 'audio/x-wav',
206: 'aac' => 'audio/aac',
207: 'asc' => 'text/plain',
208: 'c' => 'text/plain',
209: 'cc' => 'text/plain',
210: 'css' => 'text/css',
211: 'etx' => 'text/x-setext',
212: 'f' => 'text/plain',
213: 'f90' => 'text/plain',
214: 'h' => 'text/plain',
215: 'hh' => 'text/plain',
216: 'htm' => array('text/html', '*/*'),
217: 'ics' => 'text/calendar',
218: 'm' => 'text/plain',
219: 'rtf' => 'text/rtf',
220: 'rtx' => 'text/richtext',
221: 'sgm' => 'text/sgml',
222: 'sgml' => 'text/sgml',
223: 'tsv' => 'text/tab-separated-values',
224: 'tpl' => 'text/template',
225: 'txt' => 'text/plain',
226: 'text' => 'text/plain',
227: 'avi' => 'video/x-msvideo',
228: 'fli' => 'video/x-fli',
229: 'mov' => 'video/quicktime',
230: 'movie' => 'video/x-sgi-movie',
231: 'mpe' => 'video/mpeg',
232: 'mpeg' => 'video/mpeg',
233: 'mpg' => 'video/mpeg',
234: 'qt' => 'video/quicktime',
235: 'viv' => 'video/vnd.vivo',
236: 'vivo' => 'video/vnd.vivo',
237: 'ogv' => 'video/ogg',
238: 'webm' => 'video/webm',
239: 'mp4' => 'video/mp4',
240: 'gif' => 'image/gif',
241: 'ief' => 'image/ief',
242: 'jpe' => 'image/jpeg',
243: 'jpeg' => 'image/jpeg',
244: 'jpg' => 'image/jpeg',
245: 'pbm' => 'image/x-portable-bitmap',
246: 'pgm' => 'image/x-portable-graymap',
247: 'png' => 'image/png',
248: 'pnm' => 'image/x-portable-anymap',
249: 'ppm' => 'image/x-portable-pixmap',
250: 'ras' => 'image/cmu-raster',
251: 'rgb' => 'image/x-rgb',
252: 'tif' => 'image/tiff',
253: 'tiff' => 'image/tiff',
254: 'xbm' => 'image/x-xbitmap',
255: 'xpm' => 'image/x-xpixmap',
256: 'xwd' => 'image/x-xwindowdump',
257: 'ice' => 'x-conference/x-cooltalk',
258: 'iges' => 'model/iges',
259: 'igs' => 'model/iges',
260: 'mesh' => 'model/mesh',
261: 'msh' => 'model/mesh',
262: 'silo' => 'model/mesh',
263: 'vrml' => 'model/vrml',
264: 'wrl' => 'model/vrml',
265: 'mime' => 'www/mime',
266: 'pdb' => 'chemical/x-pdb',
267: 'xyz' => 'chemical/x-pdb',
268: 'javascript' => 'text/javascript',
269: 'form' => 'application/x-www-form-urlencoded',
270: 'file' => 'multipart/form-data',
271: 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'),
272: 'xhtml-mobile' => 'application/vnd.wap.xhtml+xml',
273: 'atom' => 'application/atom+xml',
274: 'amf' => 'application/x-amf',
275: 'wap' => array('text/vnd.wap.wml', 'text/vnd.wap.wmlscript', 'image/vnd.wap.wbmp'),
276: 'wml' => 'text/vnd.wap.wml',
277: 'wmlscript' => 'text/vnd.wap.wmlscript',
278: 'wbmp' => 'image/vnd.wap.wbmp',
279: );
280:
281: 282: 283: 284: 285:
286: protected $_protocol = 'HTTP/1.1';
287:
288: 289: 290: 291: 292:
293: protected $_status = 200;
294:
295: 296: 297: 298: 299: 300:
301: protected $_contentType = 'text/html';
302:
303: 304: 305: 306: 307:
308: protected $_headers = array();
309:
310: 311: 312: 313: 314:
315: protected $_body = null;
316:
317: 318: 319: 320: 321:
322: protected $_charset = 'UTF-8';
323:
324: 325: 326: 327: 328: 329:
330: protected $_cacheDirectives = array();
331:
332: 333: 334: 335: 336:
337: protected $_cookies = array();
338:
339: 340: 341: 342: 343: 344: 345: 346: 347:
348: public function __construct(array $options = array()) {
349: if (isset($options['body'])) {
350: $this->body($options['body']);
351: }
352: if (isset($options['status'])) {
353: $this->statusCode($options['status']);
354: }
355: if (isset($options['type'])) {
356: $this->type($options['type']);
357: }
358: if (isset($options['charset'])) {
359: $this->charset($options['charset']);
360: }
361: }
362:
363: 364: 365: 366: 367: 368:
369: public function send() {
370: if (isset($this->_headers['Location']) && $this->_status === 200) {
371: $this->statusCode(302);
372: }
373:
374: $codeMessage = $this->_statusCodes[$this->_status];
375: $this->_setCookies();
376: $this->_sendHeader("{$this->_protocol} {$this->_status} {$codeMessage}");
377: $this->_setContent();
378: $this->_setContentLength();
379: $this->_setContentType();
380: foreach ($this->_headers as $header => $value) {
381: $this->_sendHeader($header, $value);
382: }
383: $this->_sendContent($this->_body);
384: }
385:
386: 387: 388: 389: 390: 391: 392:
393: protected function _setCookies() {
394: foreach ($this->_cookies as $name => $c) {
395: setcookie(
396: $name, $c['value'], $c['expire'], $c['path'],
397: $c['domain'], $c['secure'], $c['httpOnly']
398: );
399: }
400: }
401:
402: 403: 404: 405: 406: 407:
408: protected function _setContentType() {
409: if (in_array($this->_status, array(304, 204))) {
410: return;
411: }
412: if (strpos($this->_contentType, 'text/') === 0) {
413: $this->header('Content-Type', "{$this->_contentType}; charset={$this->_charset}");
414: } elseif ($this->_contentType === 'application/json') {
415: $this->header('Content-Type', "{$this->_contentType}; charset=UTF-8");
416: } else {
417: $this->header('Content-Type', "{$this->_contentType}");
418: }
419: }
420:
421: 422: 423: 424: 425:
426: protected function _setContent() {
427: if (in_array($this->_status, array(304, 204))) {
428: $this->body('');
429: }
430: }
431:
432: 433: 434: 435: 436: 437:
438: protected function _setContentLength() {
439: $shouldSetLength = !isset($this->_headers['Content-Length']) && !in_array($this->_status, range(301, 307));
440: if (isset($this->_headers['Content-Length']) && $this->_headers['Content-Length'] === false) {
441: unset($this->_headers['Content-Length']);
442: return;
443: }
444: if ($shouldSetLength && !$this->outputCompressed()) {
445: $offset = ob_get_level() ? ob_get_length() : 0;
446: if (ini_get('mbstring.func_overload') & 2 && function_exists('mb_strlen')) {
447: $this->length($offset + mb_strlen($this->_body, '8bit'));
448: } else {
449: $this->length($this->_headers['Content-Length'] = $offset + strlen($this->_body));
450: }
451: }
452: }
453:
454: 455: 456: 457: 458: 459: 460:
461: protected function _sendHeader($name, $value = null) {
462: if (!headers_sent()) {
463: if (is_null($value)) {
464: header($name);
465: } else {
466: header("{$name}: {$value}");
467: }
468: }
469: }
470:
471: 472: 473: 474: 475: 476:
477: protected function _sendContent($content) {
478: echo $content;
479: }
480:
481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507:
508: public function header($header = null, $value = null) {
509: if (is_null($header)) {
510: return $this->_headers;
511: }
512: if (is_array($header)) {
513: foreach ($header as $h => $v) {
514: if (is_numeric($h)) {
515: $this->header($v);
516: continue;
517: }
518: $this->_headers[$h] = trim($v);
519: }
520: return $this->_headers;
521: }
522:
523: if (!is_null($value)) {
524: $this->_headers[$header] = $value;
525: return $this->_headers;
526: }
527:
528: list($header, $value) = explode(':', $header, 2);
529: $this->_headers[$header] = trim($value);
530: return $this->_headers;
531: }
532:
533: 534: 535: 536: 537: 538: 539:
540: public function body($content = null) {
541: if (is_null($content)) {
542: return $this->_body;
543: }
544: return $this->_body = $content;
545: }
546:
547: 548: 549: 550: 551: 552: 553: 554:
555: public function statusCode($code = null) {
556: if (is_null($code)) {
557: return $this->_status;
558: }
559: if (!isset($this->_statusCodes[$code])) {
560: throw new CakeException(__d('cake_dev', 'Unknown status code'));
561: }
562: return $this->_status = $code;
563: }
564:
565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582:
583: public function httpCodes($code = null) {
584: if (empty($code)) {
585: return $this->_statusCodes;
586: }
587:
588: if (is_array($code)) {
589: $this->_statusCodes = $code + $this->_statusCodes;
590: return true;
591: }
592:
593: if (!isset($this->_statusCodes[$code])) {
594: return null;
595: }
596: return array($code => $this->_statusCodes[$code]);
597: }
598:
599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623:
624: public function type($contentType = null) {
625: if (is_null($contentType)) {
626: return $this->_contentType;
627: }
628: if (is_array($contentType)) {
629: foreach ($contentType as $type => $definition) {
630: $this->_mimeTypes[$type] = $definition;
631: }
632: return $this->_contentType;
633: }
634: if (isset($this->_mimeTypes[$contentType])) {
635: $contentType = $this->_mimeTypes[$contentType];
636: $contentType = is_array($contentType) ? current($contentType) : $contentType;
637: }
638: if (strpos($contentType, '/') === false) {
639: return false;
640: }
641: return $this->_contentType = $contentType;
642: }
643:
644: 645: 646: 647: 648: 649: 650: 651:
652: public function getMimeType($alias) {
653: if (isset($this->_mimeTypes[$alias])) {
654: return $this->_mimeTypes[$alias];
655: }
656: return false;
657: }
658:
659: 660: 661: 662: 663: 664: 665: 666:
667: public function mapType($ctype) {
668: if (is_array($ctype)) {
669: return array_map(array($this, 'mapType'), $ctype);
670: }
671:
672: foreach ($this->_mimeTypes as $alias => $types) {
673: if (is_array($types) && in_array($ctype, $types)) {
674: return $alias;
675: } elseif (is_string($types) && $types == $ctype) {
676: return $alias;
677: }
678: }
679: return null;
680: }
681:
682: 683: 684: 685: 686: 687: 688:
689: public function charset($charset = null) {
690: if (is_null($charset)) {
691: return $this->_charset;
692: }
693: return $this->_charset = $charset;
694: }
695:
696: 697: 698: 699: 700:
701: public function disableCache() {
702: $this->header(array(
703: 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
704: 'Last-Modified' => gmdate("D, d M Y H:i:s") . " GMT",
705: 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
706: ));
707: }
708:
709: 710: 711: 712: 713: 714: 715:
716: public function cache($since, $time = '+1 day') {
717: if (!is_integer($time)) {
718: $time = strtotime($time);
719: }
720: $this->header(array(
721: 'Date' => gmdate("D, j M Y G:i:s ", time()) . 'GMT'
722: ));
723: $this->modified($since);
724: $this->expires($time);
725: $this->sharable(true);
726: $this->maxAge($time - time());
727: }
728:
729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739:
740: public function sharable($public = null, $time = null) {
741: if ($public === null) {
742: $public = array_key_exists('public', $this->_cacheDirectives);
743: $private = array_key_exists('private', $this->_cacheDirectives);
744: $noCache = array_key_exists('no-cache', $this->_cacheDirectives);
745: if (!$public && !$private && !$noCache) {
746: return null;
747: }
748: $sharable = $public || ! ($private || $noCache);
749: return $sharable;
750: }
751: if ($public) {
752: $this->_cacheDirectives['public'] = true;
753: unset($this->_cacheDirectives['private']);
754: $this->sharedMaxAge($time);
755: } else {
756: $this->_cacheDirectives['private'] = true;
757: unset($this->_cacheDirectives['public']);
758: $this->maxAge($time);
759: }
760: if ($time == null) {
761: $this->_setCacheControl();
762: }
763: return (bool)$public;
764: }
765:
766: 767: 768: 769: 770: 771: 772: 773: 774:
775: public function sharedMaxAge($seconds = null) {
776: if ($seconds !== null) {
777: $this->_cacheDirectives['s-maxage'] = $seconds;
778: $this->_setCacheControl();
779: }
780: if (isset($this->_cacheDirectives['s-maxage'])) {
781: return $this->_cacheDirectives['s-maxage'];
782: }
783: return null;
784: }
785:
786: 787: 788: 789: 790: 791: 792: 793: 794:
795: public function maxAge($seconds = null) {
796: if ($seconds !== null) {
797: $this->_cacheDirectives['max-age'] = $seconds;
798: $this->_setCacheControl();
799: }
800: if (isset($this->_cacheDirectives['max-age'])) {
801: return $this->_cacheDirectives['max-age'];
802: }
803: return null;
804: }
805:
806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816:
817: public function mustRevalidate($enable = null) {
818: if ($enable !== null) {
819: if ($enable) {
820: $this->_cacheDirectives['must-revalidate'] = true;
821: } else {
822: unset($this->_cacheDirectives['must-revalidate']);
823: }
824: $this->_setCacheControl();
825: }
826: return array_key_exists('must-revalidate', $this->_cacheDirectives);
827: }
828:
829: 830: 831: 832: 833: 834:
835: protected function _setCacheControl() {
836: $control = '';
837: foreach ($this->_cacheDirectives as $key => $val) {
838: $control .= $val === true ? $key : sprintf('%s=%s', $key, $val);
839: $control .= ', ';
840: }
841: $control = rtrim($control, ', ');
842: $this->header('Cache-Control', $control);
843: }
844:
845: 846: 847: 848: 849: 850: 851: 852: 853: 854: 855: 856: 857:
858: public function expires($time = null) {
859: if ($time !== null) {
860: $date = $this->_getUTCDate($time);
861: $this->_headers['Expires'] = $date->format('D, j M Y H:i:s') . ' GMT';
862: }
863: if (isset($this->_headers['Expires'])) {
864: return $this->_headers['Expires'];
865: }
866: return null;
867: }
868:
869: 870: 871: 872: 873: 874: 875: 876: 877: 878: 879: 880: 881:
882: public function modified($time = null) {
883: if ($time !== null) {
884: $date = $this->_getUTCDate($time);
885: $this->_headers['Last-Modified'] = $date->format('D, j M Y H:i:s') . ' GMT';
886: }
887: if (isset($this->_headers['Last-Modified'])) {
888: return $this->_headers['Last-Modified'];
889: }
890: return null;
891: }
892:
893: 894: 895: 896: 897: 898: 899:
900: public function notModified() {
901: $this->statusCode(304);
902: $this->body('');
903: $remove = array(
904: 'Allow',
905: 'Content-Encoding',
906: 'Content-Language',
907: 'Content-Length',
908: 'Content-MD5',
909: 'Content-Type',
910: 'Last-Modified'
911: );
912: foreach ($remove as $header) {
913: unset($this->_headers[$header]);
914: }
915: }
916:
917: 918: 919: 920: 921: 922: 923: 924: 925: 926:
927: public function vary($cacheVariances = null) {
928: if ($cacheVariances !== null) {
929: $cacheVariances = (array)$cacheVariances;
930: $this->_headers['Vary'] = implode(', ', $cacheVariances);
931: }
932: if (isset($this->_headers['Vary'])) {
933: return explode(', ', $this->_headers['Vary']);
934: }
935: return null;
936: }
937:
938: 939: 940: 941: 942: 943: 944: 945: 946: 947: 948: 949: 950: 951: 952: 953: 954: 955: 956: 957: 958:
959: public function etag($tag = null, $weak = false) {
960: if ($tag !== null) {
961: $this->_headers['Etag'] = sprintf('%s"%s"', ($weak) ? 'W/' : null, $tag);
962: }
963: if (isset($this->_headers['Etag'])) {
964: return $this->_headers['Etag'];
965: }
966: return null;
967: }
968:
969: 970: 971: 972: 973: 974: 975:
976: protected function _getUTCDate($time = null) {
977: if ($time instanceof DateTime) {
978: $result = clone $time;
979: } elseif (is_integer($time)) {
980: $result = new DateTime(date('Y-m-d H:i:s', $time));
981: } else {
982: $result = new DateTime($time);
983: }
984: $result->setTimeZone(new DateTimeZone('UTC'));
985: return $result;
986: }
987:
988: 989: 990: 991: 992: 993:
994: public function compress() {
995: $compressionEnabled = ini_get("zlib.output_compression") !== '1' &&
996: extension_loaded("zlib") &&
997: (strpos(env('HTTP_ACCEPT_ENCODING'), 'gzip') !== false);
998: return $compressionEnabled && ob_start('ob_gzhandler');
999: }
1000:
1001: 1002: 1003: 1004: 1005:
1006: public function outputCompressed() {
1007: return strpos(env('HTTP_ACCEPT_ENCODING'), 'gzip') !== false
1008: && (ini_get("zlib.output_compression") === '1' || in_array('ob_gzhandler', ob_list_handlers()));
1009: }
1010:
1011: 1012: 1013: 1014: 1015: 1016:
1017: public function download($filename) {
1018: $this->header('Content-Disposition', 'attachment; filename="' . $filename . '"');
1019: }
1020:
1021: 1022: 1023: 1024: 1025: 1026:
1027: public function protocol($protocol = null) {
1028: if ($protocol !== null) {
1029: $this->_protocol = $protocol;
1030: }
1031: return $this->_protocol;
1032: }
1033:
1034: 1035: 1036: 1037: 1038: 1039:
1040: public function length($bytes = null) {
1041: if ($bytes !== null ) {
1042: $this->_headers['Content-Length'] = $bytes;
1043: }
1044: if (isset($this->_headers['Content-Length'])) {
1045: return $this->_headers['Content-Length'];
1046: }
1047: return null;
1048: }
1049:
1050: 1051: 1052: 1053: 1054: 1055: 1056: 1057: 1058: 1059: 1060: 1061: 1062:
1063: public function checkNotModified(CakeRequest $request) {
1064: $etags = preg_split('/\s*,\s*/', $request->header('If-None-Match'), null, PREG_SPLIT_NO_EMPTY);
1065: $modifiedSince = $request->header('If-Modified-Since');
1066: if ($responseTag = $this->etag()) {
1067: $etagMatches = in_array('*', $etags) || in_array($responseTag, $etags);
1068: }
1069: if ($modifiedSince) {
1070: $timeMatches = strtotime($this->modified()) == strtotime($modifiedSince);
1071: }
1072: $checks = compact('etagMatches', 'timeMatches');
1073: if (empty($checks)) {
1074: return false;
1075: }
1076: $notModified = !in_array(false, $checks, true);
1077: if ($notModified) {
1078: $this->notModified();
1079: }
1080: return $notModified;
1081: }
1082:
1083: 1084: 1085: 1086: 1087: 1088:
1089: public function __toString() {
1090: return (string)$this->_body;
1091: }
1092:
1093: 1094: 1095: 1096: 1097: 1098: 1099: 1100: 1101: 1102: 1103: 1104: 1105: 1106: 1107: 1108: 1109: 1110: 1111: 1112: 1113: 1114: 1115: 1116: 1117: 1118: 1119: 1120: 1121: 1122: 1123: 1124: 1125: 1126: 1127: 1128: 1129: 1130: 1131: 1132:
1133: public function cookie($options = null) {
1134: if ($options === null) {
1135: return $this->_cookies;
1136: }
1137:
1138: if (is_string($options)) {
1139: if (!isset($this->_cookies[$options])) {
1140: return null;
1141: }
1142: return $this->_cookies[$options];
1143: }
1144:
1145: $defaults = array(
1146: 'name' => 'CakeCookie[default]',
1147: 'value' => '',
1148: 'expire' => 0,
1149: 'path' => '/',
1150: 'domain' => '',
1151: 'secure' => false,
1152: 'httpOnly' => false
1153: );
1154: $options += $defaults;
1155:
1156: $this->_cookies[$options['name']] = $options;
1157: }
1158:
1159: }
1160: