CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.8 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.8
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • ActionDispatcher
  • BaseApplication
  • Client
  • ControllerFactory
  • CorsBuilder
  • MiddlewareQueue
  • Response
  • ResponseEmitter
  • Runner
  • Server
  • ServerRequest
  • ServerRequestFactory
  • Session
  1: <?php
  2: /**
  3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5:  *
  6:  * Licensed under The MIT License
  7:  * For full copyright and license information, please see the LICENSE.txt
  8:  * Redistributions of files must retain the above copyright notice.
  9:  *
 10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 11:  * @link          https://cakephp.org CakePHP(tm) Project
 12:  * @since         3.3.5
 13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
 14:  *
 15:  * Parts of this file are derived from Zend-Diactoros
 16:  *
 17:  * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (https://www.zend.com/)
 18:  * @license   https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
 19:  */
 20: namespace Cake\Http;
 21: 
 22: use Cake\Core\Configure;
 23: use Cake\Log\Log;
 24: use Psr\Http\Message\ResponseInterface;
 25: use Zend\Diactoros\RelativeStream;
 26: use Zend\Diactoros\Response\EmitterInterface;
 27: 
 28: /**
 29:  * Emits a Response to the PHP Server API.
 30:  *
 31:  * This emitter offers a few changes from the emitters offered by
 32:  * diactoros:
 33:  *
 34:  * - It logs headers sent using CakePHP's logging tools.
 35:  * - Cookies are emitted using setcookie() to not conflict with ext/session
 36:  * - For fastcgi servers with PHP-FPM session_write_close() is called just
 37:  *   before fastcgi_finish_request() to make sure session data is saved
 38:  *   correctly (especially on slower session backends).
 39:  */
 40: class ResponseEmitter implements EmitterInterface
 41: {
 42:     /**
 43:      * {@inheritDoc}
 44:      */
 45:     public function emit(ResponseInterface $response, $maxBufferLength = 8192)
 46:     {
 47:         $file = $line = null;
 48:         if (headers_sent($file, $line)) {
 49:             $message = "Unable to emit headers. Headers sent in file=$file line=$line";
 50:             if (Configure::read('debug')) {
 51:                 trigger_error($message, E_USER_WARNING);
 52:             } else {
 53:                 Log::warning($message);
 54:             }
 55:         }
 56: 
 57:         $this->emitStatusLine($response);
 58:         $this->emitHeaders($response);
 59:         $this->flush();
 60: 
 61:         $range = $this->parseContentRange($response->getHeaderLine('Content-Range'));
 62:         if (is_array($range)) {
 63:             $this->emitBodyRange($range, $response, $maxBufferLength);
 64:         } else {
 65:             $this->emitBody($response, $maxBufferLength);
 66:         }
 67: 
 68:         if (function_exists('fastcgi_finish_request')) {
 69:             session_write_close();
 70:             fastcgi_finish_request();
 71:         }
 72:     }
 73: 
 74:     /**
 75:      * Emit the message body.
 76:      *
 77:      * @param \Psr\Http\Message\ResponseInterface $response The response to emit
 78:      * @param int $maxBufferLength The chunk size to emit
 79:      * @return void
 80:      */
 81:     protected function emitBody(ResponseInterface $response, $maxBufferLength)
 82:     {
 83:         if (in_array($response->getStatusCode(), [204, 304])) {
 84:             return;
 85:         }
 86:         $body = $response->getBody();
 87: 
 88:         if (!$body->isSeekable()) {
 89:             echo $body;
 90: 
 91:             return;
 92:         }
 93: 
 94:         $body->rewind();
 95:         while (!$body->eof()) {
 96:             echo $body->read($maxBufferLength);
 97:         }
 98:     }
 99: 
100:     /**
101:      * Emit a range of the message body.
102:      *
103:      * @param array $range The range data to emit
104:      * @param \Psr\Http\Message\ResponseInterface $response The response to emit
105:      * @param int $maxBufferLength The chunk size to emit
106:      * @return void
107:      */
108:     protected function emitBodyRange(array $range, ResponseInterface $response, $maxBufferLength)
109:     {
110:         list($unit, $first, $last, $length) = $range;
111: 
112:         $body = $response->getBody();
113: 
114:         if (!$body->isSeekable()) {
115:             $contents = $body->getContents();
116:             echo substr($contents, $first, $last - $first + 1);
117: 
118:             return;
119:         }
120: 
121:         $body = new RelativeStream($body, $first);
122:         $body->rewind();
123:         $pos = 0;
124:         $length = $last - $first + 1;
125:         while (!$body->eof() && $pos < $length) {
126:             if (($pos + $maxBufferLength) > $length) {
127:                 echo $body->read($length - $pos);
128:                 break;
129:             }
130: 
131:             echo $body->read($maxBufferLength);
132:             $pos = $body->tell();
133:         }
134:     }
135: 
136:     /**
137:      * Emit the status line.
138:      *
139:      * Emits the status line using the protocol version and status code from
140:      * the response; if a reason phrase is available, it, too, is emitted.
141:      *
142:      * @param \Psr\Http\Message\ResponseInterface $response The response to emit
143:      * @return void
144:      */
145:     protected function emitStatusLine(ResponseInterface $response)
146:     {
147:         $reasonPhrase = $response->getReasonPhrase();
148:         header(sprintf(
149:             'HTTP/%s %d%s',
150:             $response->getProtocolVersion(),
151:             $response->getStatusCode(),
152:             ($reasonPhrase ? ' ' . $reasonPhrase : '')
153:         ));
154:     }
155: 
156:     /**
157:      * Emit response headers.
158:      *
159:      * Loops through each header, emitting each; if the header value
160:      * is an array with multiple values, ensures that each is sent
161:      * in such a way as to create aggregate headers (instead of replace
162:      * the previous).
163:      *
164:      * @param \Psr\Http\Message\ResponseInterface $response The response to emit
165:      * @return void
166:      */
167:     protected function emitHeaders(ResponseInterface $response)
168:     {
169:         $cookies = [];
170:         if (method_exists($response, 'getCookies')) {
171:             $cookies = $response->getCookies();
172:         }
173: 
174:         foreach ($response->getHeaders() as $name => $values) {
175:             if (strtolower($name) === 'set-cookie') {
176:                 $cookies = array_merge($cookies, $values);
177:                 continue;
178:             }
179:             $first = true;
180:             foreach ($values as $value) {
181:                 header(sprintf(
182:                     '%s: %s',
183:                     $name,
184:                     $value
185:                 ), $first);
186:                 $first = false;
187:             }
188:         }
189: 
190:         $this->emitCookies($cookies);
191:     }
192: 
193:     /**
194:      * Emit cookies using setcookie()
195:      *
196:      * @param array $cookies An array of Set-Cookie headers.
197:      * @return void
198:      */
199:     protected function emitCookies(array $cookies)
200:     {
201:         foreach ($cookies as $cookie) {
202:             if (is_array($cookie)) {
203:                 setcookie(
204:                     $cookie['name'],
205:                     $cookie['value'],
206:                     $cookie['expire'],
207:                     $cookie['path'],
208:                     $cookie['domain'],
209:                     $cookie['secure'],
210:                     $cookie['httpOnly']
211:                 );
212:                 continue;
213:             }
214: 
215:             if (strpos($cookie, '";"') !== false) {
216:                 $cookie = str_replace('";"', '{__cookie_replace__}', $cookie);
217:                 $parts = str_replace('{__cookie_replace__}', '";"', explode(';', $cookie));
218:             } else {
219:                 $parts = preg_split('/\;[ \t]*/', $cookie);
220:             }
221: 
222:             list($name, $value) = explode('=', array_shift($parts), 2);
223:             $data = [
224:                 'name' => urldecode($name),
225:                 'value' => urldecode($value),
226:                 'expires' => 0,
227:                 'path' => '',
228:                 'domain' => '',
229:                 'secure' => false,
230:                 'httponly' => false
231:             ];
232: 
233:             foreach ($parts as $part) {
234:                 if (strpos($part, '=') !== false) {
235:                     list($key, $value) = explode('=', $part);
236:                 } else {
237:                     $key = $part;
238:                     $value = true;
239:                 }
240: 
241:                 $key = strtolower($key);
242:                 $data[$key] = $value;
243:             }
244:             if (!empty($data['expires'])) {
245:                 $data['expires'] = strtotime($data['expires']);
246:             }
247:             setcookie(
248:                 $data['name'],
249:                 $data['value'],
250:                 $data['expires'],
251:                 $data['path'],
252:                 $data['domain'],
253:                 $data['secure'],
254:                 $data['httponly']
255:             );
256:         }
257:     }
258: 
259:     /**
260:      * Loops through the output buffer, flushing each, before emitting
261:      * the response.
262:      *
263:      * @param int|null $maxBufferLevel Flush up to this buffer level.
264:      * @return void
265:      */
266:     protected function flush($maxBufferLevel = null)
267:     {
268:         if (null === $maxBufferLevel) {
269:             $maxBufferLevel = ob_get_level();
270:         }
271: 
272:         while (ob_get_level() > $maxBufferLevel) {
273:             ob_end_flush();
274:         }
275:     }
276: 
277:     /**
278:      * Parse content-range header
279:      * https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
280:      *
281:      * @param string $header The Content-Range header to parse.
282:      * @return array|false [unit, first, last, length]; returns false if no
283:      *     content range or an invalid content range is provided
284:      */
285:     protected function parseContentRange($header)
286:     {
287:         if (preg_match('/(?P<unit>[\w]+)\s+(?P<first>\d+)-(?P<last>\d+)\/(?P<length>\d+|\*)/', $header, $matches)) {
288:             return [
289:                 $matches['unit'],
290:                 (int)$matches['first'],
291:                 (int)$matches['last'],
292:                 $matches['length'] === '*' ? '*' : (int)$matches['length'],
293:             ];
294:         }
295: 
296:         return false;
297:     }
298: }
299: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs