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