/** * Send HTTP response * * Send the specific X-Sendfile HTTP headers for internal processing by the server. For Nginx and Lighttpd 1.4 * remove the X-Sendfile header and use the specific header instead. * * If the X-Sendfile header is 1 or TRUE, the response path will be used instead of the path supplied in the * header. If X-Sendfile header is 0 or FALSE the header is ignored and removed. * * - Apache : X-Sendfile * - Nginx : X-Accel-Redirect * - Lightttpd : X-LIGHTTPD-send-file (v1.4) or X-Sendfile (v1.5) * * @param DispatcherResponseInterface $response * @return boolean */ public function send(DispatcherResponseInterface $response) { if ($response->headers->has('X-Sendfile')) { $path = $response->headers->get('X-Sendfile'); if ($path === true || $path === 1) { $path = $response->getContent()->getPathname(); } if (is_file($path)) { $server = strtolower($_SERVER['SERVER_SOFTWARE']); //Nginx uses X-Accel-Redirect header if (strpos($server, 'nginx') !== FALSE) { $path = preg_replace('/' . preg_quote(JPATH_ROOT, '/') . '/', '', $path, 1); $response->headers->set('X-Accel-Redirect', $path); $response->headers->remove('X-Sendfile'); } //Lighttpd 1.4 uses X-LIGHTTPD-send-file header if (strpos($server, 'lightttpd/1.4') !== FALSE) { $response->headers->set('X-LIGHTTPD-send-file', $path); $response->headers->remove('X-Sendfile'); } return parent::send($response); } else { $response->headers->remove('X-Sendfile'); } } }
/** * Send HTTP response * * If the format is json, add the padding by inspect the request query for a 'callback' parameter or by using * the default padding if set. * * Don't stop the transport handler chain to allow other transports handlers to continue processing the * response. * * @link http://tools.ietf.org/html/rfc2616 * * @param DispatcherResponseInterface $response * @return boolean */ public function send(DispatcherResponseInterface $response) { $request = $response->getRequest(); //Force to use the json transport if format is json if ($request->getFormat() == 'json') { //If not padding is set inspect the request query. if (empty($this->_padding)) { if ($request->query->has('callback')) { $this->setCallback($request->query->get('callback', 'cmd')); } } if (!empty($this->_padding)) { $response->setContent(sprintf('%s(%s);', $this->_padding, $response->getContent())); } } }
/** * Send response * * @param DispatcherResponseInterface $response * @return boolean Returns true if the response has been send, otherwise FALSE */ public function send(DispatcherResponseInterface $response) { //Cleanup and flush output to client if (!function_exists('fastcgi_finish_request')) { if (PHP_SAPI !== 'cli') { for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); } flush(); } } else { fastcgi_finish_request(); } //Set the exit status based on the status code. $status = 0; if (!$response->isSuccess()) { $status = (int) $response->getStatusCode(); } exit($status); return true; }
/** * Send HTTP response * * Send the specific X-Sendfile HTTP headers for internal processing by the server. * * - Apache : X-Sendfile * - Nginx : X-Accel-Redirect * * @param DispatcherResponseInterface $response * @return boolean */ public function send(DispatcherResponseInterface $response) { if ($response->isDownloadable()) { $server = strtolower($_SERVER['SERVER_SOFTWARE']); //Apache if (strpos($server, 'apache') !== FALSE) { if (in_array('mod_xsendfile', apache_get_modules())) { $path = $response->getStream()->getPath(); $response->headers->set('X-Sendfile', $path); return parent::send($response); } } //Nginx if (strpos($server, 'nginx') !== FALSE) { $path = $response->getStream()->getPath(); $path = preg_replace('/' . preg_quote(\Kodekit::getInstance()->getRootPath(), '/') . '/', '', $path, 1); $response->headers->set('X-Accel-Redirect', $path); return parent::send($response); } } }
/** * Send HTTP response * * If this is a redirect response, send the response and stop the transport handler chain. * * @link: https://en.wikipedia.org/wiki/Meta_refresh * * @param DispatcherResponseInterface $response * @return boolean */ public function send(DispatcherResponseInterface $response) { if ($response->isRedirect()) { $session = $response->getUser()->getSession(); //Set the messages into the session $messages = $response->getMessages(); if (count($messages)) { //Auto start the session if it's not active. if (!$session->isActive()) { $session->start(); } $session->getContainer('message')->add($messages); } //Set the redirect into the response $format = $response->getRequest()->getFormat(); if ($format == 'json') { array_unshift($messages, sprintf('Redirecting to %1$s', $response->getHeaders()->get('Location'))); $response->setContent(json_encode(array('messages' => $messages)), 'application/json'); } if ($format == 'html') { $response->setContent(sprintf('<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <noscript> <meta http-equiv="refresh" content="1;url=%1$s" /> </noscript> <title>Redirecting to %1$s</title> </head> <body onload="window.location = \'%1$s\'"> Redirecting to <a href="%1$s">%1$s</a>. </body> </html>', htmlspecialchars($response->getHeaders()->get('Location'), ENT_QUOTES, 'UTF-8')), 'text/html'); } return parent::send($response); } }
/** * Send HTTP response * * Prepares the Response before it is sent to the client. This method tweaks the headers to ensure that * it is compliant with RFC 2616 and calculates or modifies the cache-control header to a sensible and * conservative value * * @link http://tools.ietf.org/html/rfc2616 * * @param DispatcherResponseInterface $response * @return boolean Returns true if the response has been send, otherwise FALSE */ public function send(DispatcherResponseInterface $response) { $request = $response->getRequest(); //Make sure we do not have body content for 204, 205 and 305 status codes $codes = array(HttpResponse::NO_CONTENT, HttpResponse::NOT_MODIFIED, HttpResponse::RESET_CONTENT); if (in_array($response->getStatusCode(), $codes)) { $response->setContent(null); } //Remove location header if we are not redirecting and the status code is not 201 if (!$response->isRedirect() && $response->getStatusCode() !== HttpResponse::CREATED) { if ($response->headers->has('Location')) { $response->headers->remove('Location'); } } //Add file related information if we are serving a file if ($response->isDownloadable()) { //Last-Modified header $time = $response->getStream()->getTime(FilesystemStream::TIME_MODIFIED); $response->setLastModified($time); //Disposition header $response->headers->set('Content-Disposition', array('inline', 'filename' => '"' . basename($response->getStream()->getPath()) . '"')); //Force a download by the browser by setting the disposition to 'attachment'. if ($response->isAttachable()) { $response->setContentType('application/force-download'); $response->headers->set('Content-Disposition', array('attachment', 'filename' => '"' . basename($response->getStream()->getPath()) . '"')); } } //Add Last-Modified header if not present if (!$response->headers->has('Last-Modified')) { $response->setLastModified(new \DateTime('now')); } //Add Content-Length if not present if (!$response->headers->has('Content-Length')) { $response->headers->set('Content-Length', $response->getStream()->getSize()); } //Remove Content-Length for transfer encoded responses that do not contain a content range if ($response->headers->has('Transfer-Encoding')) { $response->headers->remove('Content-Length'); } //Modifies the response so that it conforms to the rules defined for a 304 status code. if ($response->getStatusCode() == HttpResponse::NOT_MODIFIED) { $response->setContent(null); $headers = array('Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-MD5', 'Content-Type', 'Last-Modified'); //Remove headers that MUST NOT be included with 304 Not Modified responses foreach ($headers as $header) { $response->headers->remove($header); } } //Calculates or modifies the cache-control header to a sensible, conservative value. $cache_control = (array) $response->headers->get('Cache-Control', null, false); if (empty($cache_control)) { if (!$response->isCacheable()) { $response->headers->set('Cache-Control', 'no-cache'); } else { $response->headers->set('Cache-Control', array('private', 'must-revalidate')); } } //Send headers and content $this->sendHeaders($response)->sendContent($response); return headers_sent(); }
/** * Send HTTP response * * If this is a redirect response, send the response and stop the transport handler chain. * * @param DispatcherResponseInterface $response * @return boolean */ public function send(DispatcherResponseInterface $response) { if ($response->isRedirect()) { return parent::send($response); } }
/** * Send HTTP response * * @param DispatcherResponseInterface $response * @return boolean */ public function send(DispatcherResponseInterface $response) { $request = $response->getRequest(); if ($response->isStreamable()) { //Explicitly set the Accept Ranges header to bytes to inform client we accept range requests $response->headers->set('Accept-Ranges', 'bytes'); //Set a file etag $response->headers->set('etag', $this->getFileEtag($response)); if ($request->isStreaming()) { if ($response->isSuccess()) { //Default Content-Type Header if (!$response->headers->has('Content-Type')) { $response->headers->set('Content-Type', 'application/octet-stream'); } //Transfer Encoding Headers $response->headers->set('Transfer-Encoding', 'chunked'); //Content Range Headers $offset = $this->getOffset($response); $range = $this->getRange($response); $size = $this->getFileSize($response); $response->setStatus(HttpResponse::PARTIAL_CONTENT); $response->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $offset, $range, $size)); } if ($response->isError()) { /** * A server sending a response with status code 416 (Requested range not satisfiable) SHOULD include a * Content-Range field with a byte-range- resp-spec of "*". The instance-length specifies the current * length of the selected resource. * * @see : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16 */ if ($response->getStatusCode() == HttpResponse::REQUESTED_RANGE_NOT_SATISFIED) { $size = $this->getFileSize($response); $response->headers->set('Content-Range', sprintf('bytes */%s', $size)); } } } return parent::send($response); } }
/** * Send HTTP response * * Prepares the Response before it is sent to the client. This method tweaks the headers to ensure that * it is compliant with RFC 2616 and calculates or modifies the cache-control header to a sensible and * conservative value * * @link http://tools.ietf.org/html/rfc2616 * @link http://tools.ietf.org/html/rfc7235 * * @param DispatcherResponseInterface $response * @return boolean Returns true if the response has been send, otherwise FALSE */ public function send(DispatcherResponseInterface $response) { $request = $response->getRequest(); //Make sure we do not have body content for 204, 205 and 305 status codes $codes = array(HttpResponse::NO_CONTENT, HttpResponse::NOT_MODIFIED, HttpResponse::RESET_CONTENT); if (in_array($response->getStatusCode(), $codes)) { $response->setContent(null); } //Remove location header if we are not redirecting and the status code is not 201 if (!$response->isRedirect() && $response->getStatusCode() !== HttpResponse::CREATED) { if ($response->headers->has('Location')) { $response->headers->remove('Location'); } } // IIS does not like it when you have a Location header in a non-redirect request // @link : http://stackoverflow.com/questions/12074730/w7-pro-iis-7-5-overwrites-php-location-header-solved if ($response->headers->has('Location') && !$response->isRedirect()) { $server = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : getenv('SERVER_SOFTWARE'); if ($server && strpos(strtolower($server), 'microsoft-iis') !== false) { $response->headers->remove('Location'); } } //Add file related information if we are serving a file if ($response->isDownloadable()) { //Last-Modified header if ($time = $response->getStream()->getTime(FilesystemStreamInterface::TIME_MODIFIED)) { $response->setLastModified($time); } //Allow to define a custom filename if ($response->headers->has('X-Content-Disposition-Filename')) { $filename = $response->headers->get('X-Content-Disposition-Filename'); $response->headers->remove('X-Content-Disposition-Filename'); } else { //basename does not work if the string starts with a UTF character $filename = ltrim(basename(' ' . strtr($response->getStream()->getPath(), array('/' => '/ ')))); } //Android cuts file names after # $user_agent = $response->getRequest()->getAgent(); if (stripos($user_agent, 'Android')) { $filename = str_replace('#', '_', $filename); } $disposition = array('filename' => '"' . $filename . '"'); //IE7 and 8 accepts percent encoded file names as the filename value //Other browsers (except Safari) use filename* header starting with UTF-8'' $encoded_name = rawurlencode($filename); if ($encoded_name !== $filename) { if (preg_match('/(?i)MSIE [4-8]/i', $user_agent)) { $disposition['filename'] = '"' . $encoded_name . '"'; } elseif (!stripos($user_agent, 'AppleWebkit')) { $disposition['filename*'] = 'UTF-8\'\'' . $encoded_name; } } //Disposition header $response->headers->set('Content-Disposition', array_merge(array('inline'), $disposition)); //Force a download by the browser by setting the disposition to 'attachment'. if ($response->isAttachable()) { $response->setContentType('application/octet-stream'); $response->headers->set('Content-Disposition', array_merge(array('attachment'), $disposition)); } } //Add Last-Modified header if not present if (!$response->headers->has('Last-Modified')) { $response->setLastModified(new \DateTime('now')); } //Add Content-Length if not present if (!$response->headers->has('Content-Length') && $response->getStream()->getSize()) { $response->headers->set('Content-Length', $response->getStream()->getSize()); } //Remove Content-Length for transfer encoded responses that do not contain a content range if ($response->headers->has('Transfer-Encoding')) { $response->headers->remove('Content-Length'); } //Modifies the response so that it conforms to the rules defined for a 304 status code. if ($response->getStatusCode() == HttpResponse::NOT_MODIFIED) { $response->setContent(null); $headers = array('Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-MD5', 'Content-Type', 'Last-Modified'); //Remove headers that MUST NOT be included with 304 Not Modified responses foreach ($headers as $header) { $response->headers->remove($header); } } //Modifies the response so that it conforms to the rules defined for a 401 status code. if ($response->getStatusCode() == HttpResponse::UNAUTHORIZED) { //The response MUST include a WWW-Authenticate header field, use 'unknown' scheme. //@link : http://tools.ietf.org/html/rfc7235 (updated spec) //@link : http://greenbytes.de/tech/tc/httpauth/ if (!$response->headers->has('WWW-Authenticate')) { $response->headers->set('WWW-Authenticate', 'unknown'); } } //Calculates or modifies the cache-control header to a sensible, conservative value. $cache_control = (array) $response->headers->get('Cache-Control', null, false); if (empty($cache_control)) { if (!$response->isCacheable()) { $response->headers->set('Cache-Control', 'no-cache'); } else { $response->headers->set('Cache-Control', array('private', 'must-revalidate')); } } // Prevent caching: Cache-control needs to be empty for IE on SSL. // @link : http://support.microsoft.com/default.aspx?scid=KB;EN-US;q316431 if ($request->isSecure() && preg_match('#(?:MSIE |Internet Explorer/)(?:[0-9.]+)#', $request->getAgent())) { $response->headers->set('Cache-Control', ''); } //Send headers and content $this->sendHeaders($response)->sendContent($response); return parent::send($response); }