withCookies( # Copy cookies from default response to newly created $this->current()->getCookies() ); } /** * Create a new response. * @param int $code HTTP status code * @param string $reasonPhrase * @return ResponseInterface */ public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface { return $this->make()->withStatus($code, $reasonPhrase); } /** * Current response object * @param Closure|null $extend * @return \bff\http\Response */ public function current(?Closure $extend = null) { return bff::response($extend); } /** * Unify response object * @param ResponseInterface|PSR7Response $response * @return \bff\http\Response */ public function unify($response) { if ($response instanceof Response) { return $response; } return $this->make( $response->getBody(), $response->getStatusCode(), $response->getHeaders() ); } /** * Convert any data to response * @param mixed|null $data * @return \bff\http\Response */ public function responsify($data = null) { if ($data instanceof Closure) { $data = $data(); } if ($data instanceof Response) { return $data; } if ($data instanceof ResponseInterface) { return $this->unify($data); } if ($data instanceof BaseException) { return $data->getResponse(); } if (is_null($data)) { return $this->current(); } if (is_string($data)) { return $this->html($data); } # array, object, ... return $this->json($data); } /** * Create empty response * @param int $status * @param array $headers * @return \bff\http\Response */ public function empty(int $status = 204, array $headers = []) { return $this->make( new Stream('php://temp', 'r'), $status, $headers ); } /** * Create html text response * @param string|StreamInterface $html * @param int $status * @param array $headers * @return \bff\http\Response */ public function html($html, int $status = 200, array $headers = []) { return $this->make( $this->createBodyFromText($html), $status, $this->injectContentType('text/html; charset=utf-8', $headers) ); } /** * Create json response * @param mixed $data Data to convert to JSON. * @param int $status * @param array $headers * @param int|null $encodingOptions JSON encoding options * @return \bff\http\Response */ public function json($data, int $status = 200, array $headers = [], ?int $encodingOptions = null) { return $this->unify( new JsonResponse($data, $status, $headers, $encodingOptions ?? JsonResponse::DEFAULT_JSON_FLAGS) ); } /** * Create redirect response * @param string|UriInterface $uri * @param int $status * @param array $headers * @return \bff\http\RedirectResponse */ public function redirect($uri, int $status = 302, array $headers = []) { $headers['location'] = [ strval($uri) ]; return (new RedirectResponse( 'php://temp', $status, $headers ))->withCookies( # Copy cookies from default response to newly created $this->current()->getCookies() ); } /** * Create basic authenticate response * @param string|null $realm * @param array $headers * @return \bff\http\Response */ public function authBasic(?string $realm = null, array $headers = []) { $realm = $realm ?? Request::host(); $headers['WWW-Authenticate'] = 'Basic realm="' . $realm . '"'; return $this->make('php://temp', 401, $headers); } /** * Create text response * @param string|StreamInterface $text * @param int $status * @param array $headers * @return \bff\http\Response */ public function text($text, int $status = 200, array $headers = []) { return $this->make( $this->createBodyFromText($text), $status, $this->injectContentType('text/plain; charset=utf-8', $headers) ); } /** * Create file response * @param string $filePath file path * @param int $status * @param array $headers * @return \bff\http\Response */ public function file(string $filePath, int $status = 200, array $headers = []) { return $this->make( new Stream($filePath, 'r'), $status, $this->injectContentType('text/plain; charset=utf-8', $headers) ); } /** * Create temporary file response * @param string $filePath file path * @param int $status * @param array $headers * @return \bff\http\Response */ public function temporaryFile(string $filePath, int $status = 200, array $headers = []) { return $this->make( new StreamTemporary($filePath, 'r'), $status, $this->injectContentType('text/plain; charset=utf-8', $headers) ); } /** * Create attachment response * @param mixed $content attachment * @param string $fileName attachment file name * @param int $status * @param array $headers * @return \bff\http\Response */ public function attachment($content, string $fileName, int $status = 200, array $headers = []) { if (empty($headers)) { $headers = [ 'Content-Disposition' => 'attachment; filename="' . str_replace(';', '', $fileName) . '"', 'Content-Type' => 'application/force-download', 'Pragma' => 'private', 'Cache-control' => 'private, must-revalidate', ]; } return $this->make( $this->createBodyFromText($content), $status, $headers ); } /** * Create image file response * @param string $filePath file path * @param int $status * @param array $headers * @return \bff\http\Response */ public function image(string $filePath, int $status = 200, array $headers = []) { if (! array_key_exists('Content-Type', $headers)) { $fileExtension = Files::getExtension($filePath); if (in_array($fileExtension, ['jpg', 'png', 'gif', 'bmp'], true)) { $res = getimagesize($filePath); $headers['Content-Type'] = $res['mime']; } elseif ($fileExtension === 'svg') { $headers['Content-Type'] = 'image/svg+xml'; } } return $this->make( new Stream($filePath, 'r'), $status, $headers ); } /** * Create xml text response * @param string|StreamInterface $xml * @param int $status * @param array $headers * @return \bff\http\Response */ public function xml($xml, int $status = 200, array $headers = []) { return $this->make( $this->createBodyFromText($xml), $status, $this->injectContentType('application/xml; charset=utf-8', $headers) ); } /** * Ответ "Not Modified" * @param int|null $lastModified * @return \bff\http\Response */ public function notModified(?int $lastModified = null) { $headers = []; if ($lastModified) { $headers['Last-Modified'] = gmdate('D, d M Y H:i:s', strtotime($lastModified)) . ' GMT'; } return $this->make(null, 304, $headers); } /** * Ответ "Not Found" * @param \bff\http\Response|null $response * @return \bff\http\Response */ public function notFound($response = null) { return Errors::error404($response); } /** * Create the message body from string. * @param string|StreamInterface $text * @return StreamInterface * @throws Exception if $text is neither a string or stream. */ protected function createBodyFromText($text): StreamInterface { if ($text instanceof StreamInterface) { return $text; } if (! is_string($text)) { throw new Exception(sprintf( 'Invalid content (%s) provided to %s', (is_object($text) ? get_class($text) : gettype($text)), Response::class )); } $body = new Stream('php://temp', 'wb+'); $body->write($text); $body->rewind(); return $body; } }