/** * Attempts to cache the sent entity by its last modification date. * @param string|int|DateTime last modified time * @param string strong entity tag validator * @return bool */ public function isModified($lastModified = NULL, $etag = NULL) { if ($lastModified) { $this->response->setHeader('Last-Modified', $this->response->date($lastModified)); } if ($etag) { $this->response->setHeader('ETag', '"' . addslashes($etag) . '"'); } $ifNoneMatch = $this->request->getHeader('If-None-Match'); if ($ifNoneMatch === '*') { $match = TRUE; // match, check if-modified-since } elseif ($ifNoneMatch !== NULL) { $etag = $this->response->getHeader('ETag'); if ($etag == NULL || strpos(' ' . strtr($ifNoneMatch, ",\t", ' '), ' ' . $etag) === FALSE) { return TRUE; } else { $match = TRUE; // match, check if-modified-since } } $ifModifiedSince = $this->request->getHeader('If-Modified-Since'); if ($ifModifiedSince !== NULL) { $lastModified = $this->response->getHeader('Last-Modified'); if ($lastModified != NULL && strtotime($lastModified) <= strtotime($ifModifiedSince)) { $match = TRUE; } else { return TRUE; } } if (empty($match)) { return TRUE; } $this->response->setCode(IHttpResponse::S304_NOT_MODIFIED); return FALSE; }
/** * Sends response to output. * @return void */ public function send(IHttpRequest $httpRequest, IHttpResponse $httpResponse) { $httpResponse->setContentType($this->contentType); $httpResponse->setHeader('Content-Disposition', 'attachment; filename="' . $this->name . '"'); $filesize = $length = filesize($this->file); $handle = fopen($this->file, 'r'); if ($this->resuming) { $httpResponse->setHeader('Accept-Ranges', 'bytes'); if (preg_match('#^bytes=(\\d*)-(\\d*)$#', $httpRequest->getHeader('Range'), $matches)) { list(, $start, $end) = $matches; if ($start === '') { $start = max(0, $filesize - $end); $end = $filesize - 1; } elseif ($end === '' || $end > $filesize - 1) { $end = $filesize - 1; } if ($end < $start) { $httpResponse->setCode(416); // requested range not satisfiable return; } $httpResponse->setCode(206); $httpResponse->setHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $filesize); $length = $end - $start + 1; fseek($handle, $start); } else { $httpResponse->setHeader('Content-Range', 'bytes 0-' . ($filesize - 1) . '/' . $filesize); } } $httpResponse->setHeader('Content-Length', $length); while (!feof($handle) && $length > 0) { echo $s = fread($handle, min(4000000.0, $length)); $length -= strlen($s); } fclose($handle); }
/** * Sends response to output. * @return void */ public function send(IHttpRequest $httpRequest, IHttpResponse $httpResponse) { $httpResponse->setContentType($this->contentType); $httpResponse->setHeader('Content-Disposition', 'attachment; filename="' . $this->name . '"'); $filesize = $length = filesize($this->file); $handle = fopen($this->file, 'r'); if ($this->resuming) { $httpResponse->setHeader('Accept-Ranges', 'bytes'); $range = $httpRequest->getHeader('Range'); if ($range !== NULL) { $range = substr($range, 6); // 6 == strlen('bytes=') list($start, $end) = explode('-', $range); if ($start == NULL) { $start = 0; } if ($end == NULL) { $end = $filesize - 1; } if ($start < 0 || $end <= $start || $end > $filesize -1) { $httpResponse->setCode(416); // requested range not satisfiable return; } $httpResponse->setCode(206); $httpResponse->setHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $filesize); $length = $end - $start + 1; fseek($handle, $start); } else { $httpResponse->setHeader('Content-Range', 'bytes 0-' . ($filesize - 1) . '/' . $filesize); } } $httpResponse->setHeader('Content-Length', $length); while (!feof($handle)) { echo fread($handle, 4e6); } fclose($handle); }
/** * Dispatch a HTTP request to a front controller. * @return void */ public function run() { $request = NULL; $repeatedError = FALSE; do { try { if (count($this->requests) > self::$maxLoop) { throw new NApplicationException('Too many loops detected in application life cycle.'); } if (!$request) { $this->onStartup($this); $request = $this->router->match($this->httpRequest); if (!$request instanceof NPresenterRequest) { $request = NULL; throw new NBadRequestException('No route for HTTP request.'); } if (strcasecmp($request->getPresenterName(), $this->errorPresenter) === 0) { throw new NBadRequestException('Invalid request. Presenter is not achievable.'); } } $this->requests[] = $request; $this->onRequest($this, $request); // Instantiate presenter $presenterName = $request->getPresenterName(); try { $this->presenter = $this->presenterFactory->createPresenter($presenterName); } catch (NInvalidPresenterException $e) { throw new NBadRequestException($e->getMessage(), 404, $e); } $this->presenterFactory->getPresenterClass($presenterName); $request->setPresenterName($presenterName); $request->freeze(); // Execute presenter $response = $this->presenter->run($request); if ($response) { $this->onResponse($this, $response); } // Send response if ($response instanceof NForwardResponse) { $request = $response->getRequest(); continue; } elseif ($response instanceof IPresenterResponse) { $response->send($this->httpRequest, $this->httpResponse); } break; } catch (Exception $e) { // fault barrier $this->onError($this, $e); if (!$this->catchExceptions) { $this->onShutdown($this, $e); throw $e; } if ($repeatedError) { $e = new NApplicationException('An error occurred while executing error-presenter', 0, $e); } if (!$this->httpResponse->isSent()) { $this->httpResponse->setCode($e instanceof NBadRequestException ? $e->getCode() : 500); } if (!$repeatedError && $this->errorPresenter) { $repeatedError = TRUE; if ($this->presenter instanceof NPresenter) { try { $this->presenter->forward(":$this->errorPresenter:", array('exception' => $e)); } catch (NAbortException $foo) { $request = $this->presenter->getLastCreatedRequest(); } } else { $request = new NPresenterRequest( $this->errorPresenter, NPresenterRequest::FORWARD, array('exception' => $e) ); } // continue } else { // default error handler if ($e instanceof NBadRequestException) { $code = $e->getCode(); } else { $code = 500; NDebugger::log($e, NDebugger::ERROR); } require dirname(__FILE__) . '/templates/error.phtml'; break; } } } while (1); $this->onShutdown($this, isset($e) ? $e : NULL); }