/** * Instantiates the correct view class, hands it its data, and uses it to render the view output. * * @param string $view View to use for rendering * @param string $layout Layout to use * @return \Cake\Network\Response A response object containing the rendered view. * @link http://book.cakephp.org/3.0/en/controllers.html#rendering-a-view */ public function render($view = null, $layout = null) { $builder = $this->viewBuilder(); if (!$builder->templatePath()) { $builder->templatePath($this->_viewPath()); } if (!empty($this->request->params['bare'])) { $builder->autoLayout(false); } $builder->className($this->viewClass); $this->autoRender = false; $event = $this->dispatchEvent('Controller.beforeRender'); if ($event->result instanceof Response) { return $event->result; } if ($event->isStopped()) { return $this->response; } if ($builder->template() === null && isset($this->request->params['action'])) { $builder->template($this->request->params['action']); } $this->View = $this->createView(); $this->response->body($this->View->render($view, $layout)); return $this->response; }
public function beforeDispatch(Event $event) { $event->stopPropagation(); $response = new Response(['body' => $this->config('message')]); $response->httpCodes([429 => 'Too Many Requests']); $response->statusCode(429); return $response; }
/** * Manage redirect for specific buttons that posted. * * @param Event $event * @param array|string $url * @param Response $response * @return bool */ public function beforeRedirect(Event $event, $url, Response $response) { if ($this->request->param('prefix') == 'admin') { if (isset($this->request->data['apply'])) { $response->location(Router::url($this->request->here(false), true)); } } return true; }
/** * Apply the queued headers to the response. * * If the builder has no Origin, or if there are no allowed domains, * or if the allowed domains do not match the Origin header no headers will be applied. * * @return \Cake\Network\Response */ public function build() { if (empty($this->_origin)) { return $this->_response; } if (isset($this->_headers['Access-Control-Allow-Origin'])) { $this->_response->header($this->_headers); } return $this->_response; }
/** * Checks if the response can be considered different according to the request * headers, and the caching response headers. If it was not modified, then the * render process is skipped. And the client will get a blank response with a * "304 Not Modified" header. * * - If Router::extensions() is enabled, the layout and template type are * switched based on the parsed extension or Accept-Type header. For example, * if `controller/action.xml` is requested, the view path becomes * `app/View/Controller/xml/action.ctp`. Also if `controller/action` is * requested with `Accept-Type: application/xml` in the headers the view * path will become `app/View/Controller/xml/action.ctp`. Layout and template * types will only switch to mime-types recognized by Cake\Network\Response. * If you need to declare additional mime-types, you can do so using * Cake\Network\Response::type() in your controller's beforeFilter() method. * - If a helper with the same name as the extension exists, it is added to * the controller. * - If the extension is of a type that RequestHandler understands, it will * set that Content-type in the response header. * * @param Event $event The Controller.beforeRender event. * @return bool false if the render process should be aborted */ public function beforeRender(Event $event) { $isRecognized = !in_array($this->ext, ['html', 'htm']) && $this->response->getMimeType($this->ext); if (!empty($this->ext) && $isRecognized) { $this->renderAs($event->subject(), $this->ext); } elseif (empty($this->ext) || in_array($this->ext, ['html', 'htm'])) { $this->respondAs('html', ['charset' => Configure::read('App.encoding')]); } if ($this->_config['checkHttpCache'] && $this->response->checkNotModified($this->request)) { return false; } }
public function afterDispatch(Event $event, Request $request, Response $response) { if (Configure::read('debug') || !isset($request->params['cache']) || $request->params['cache'] !== true) { return; } unset($request->params['cache']); $cacheKey = $this->_getCacheKey($request); if ($cacheKey !== false) { $content = $response->body(); Cache::write($cacheKey, $content, 'wasabi/cms/pages'); } }
/** * Create the response. * * @param \League\Flysystem\FilesystemInterface $cache The cache file system. * @param string $path The cached file path. * * @return \Cake\Network\Response The response object. */ public function create(FilesystemInterface $cache, $path) { $stream = $cache->readStream($path); $contentType = $cache->getMimetype($path); $contentLength = (string) $cache->getSize($path); $response = new Response(); $response->type($contentType); $response->header('Content-Length', $contentLength); $response->body(function () use($stream) { rewind($stream); fpassthru($stream); fclose($stream); }); return $response; }
/** * Verify one-time code. If code not provided - redirect to verifyAction. If code provided and is not valid - * set flash message and redirect to verifyAction. Otherwise - return true. * * @param string $secret user's secret * @param string $code one-time code * @param Response $response response instance * @var AuthComponent $Auth used Auth component * @return bool * @throws Exception */ protected function _verifyCode($secret, $code, Response $response) { $Auth = $this->_registry->getController()->Auth; if (!$Auth instanceof AuthComponent) { throw new Exception('TwoFactorAuth.Auth component has to be used for authentication.'); } $verifyAction = Router::url($Auth->config('verifyAction'), true); if ($code === null) { $response->location($verifyAction); return false; } if (!$Auth->verifyCode($secret, $code)) { $Auth->flash(__d('TwoFactorAuth', 'Invalid two-step verification code.')); $response->location($verifyAction); return false; } return true; }
/** * Set the cookie in the response. * * Also sets the request->params['_csrfToken'] so the newly minted * token is available in the request data. * * @param \Cake\Network\Request $request The request object. * @param \Cake\Network\Response $response The response object. * @return void */ protected function _setCookie(Request $request, Response $response) { $expiry = new Time($this->_config['expiry']); $value = hash('sha512', Security::randomBytes(16), false); $request->params['_csrfToken'] = $value; $response->cookie(['name' => $this->_config['cookieName'], 'value' => $value, 'expire' => $expiry->format('U'), 'path' => $request->webroot, 'secure' => $this->_config['secure'], 'httpOnly' => $this->_config['httpOnly']]); }
/** * @author Gaetan SENELLE * @return Response */ public function render() { $response = new Response(); $exception = $this->error; $code = $this->_code($exception); $message = $this->_message($exception, $code); $url = $this->controller->request->here(); $isDebug = Configure::read('debug'); $response->statusCode($code); if (method_exists($exception, 'responseHeader')) { $this->controller->response->header($exception->responseHeader()); } $classname = get_class($exception); if (preg_match('@\\\\([\\w]+)$@', $classname, $matches)) { $classname = $matches[1]; } else { $classname = null; } if (!$isDebug && !$exception instanceof ApiException && !$exception instanceof HttpException) { $classname = null; } $data = ['exception' => ['type' => $classname, 'message' => $message, 'url' => h($url), 'code' => $code], 'success' => false]; $response->body(json_encode($data)); $response->type('json'); return $response; }
/** * @param \Cake\Network\Request $request Request to get authentication information from. * @param \Cake\Network\Response $response A response object that can have headers added. * @return bool|\Cake\Network\Response */ public function unauthenticated(Request $request, Response $response) { if ($this->_config['continue']) { return false; } if (isset($this->_exception)) { $response->statusCode($this->_exception->httpStatusCode); $response->header($this->_exception->getHttpHeaders()); $response->body(json_encode(['error' => $this->_exception->errorType, 'message' => $this->_exception->getMessage()])); return $response; } $message = __d('authenticate', 'You are not authenticated.'); throw new BadRequestException($message); }
/** * Asserts cookie values * * @param string $expected The expected contents. * @param string $name The cookie name. * @param string $message The failure message that will be appended to the generated message. * @return void */ public function assertCookie($expected, $name, $message = '') { if (empty($this->_response)) { $this->fail('Not response set, cannot assert cookies.'); } $result = $this->_response->cookie($name); $this->assertEquals($expected, $result['value'], 'Cookie data differs. ' . $message); }
/** * Asserts cookie values which are encrypted by the * CookieComponent. * * The difference from assertCookie() is this decrypts the cookie * value like the CookieComponent for this assertion. * * @param string $expected The expected contents. * @param string $name The cookie name. * @param string|bool $encrypt Encryption mode to use. * @param string|null $key Encryption key used. Defaults * to Security.salt. * @param string $message The failure message that will be appended to the generated message. * @return void * @see CookieCryptTrait::_encrypt */ public function assertCookieEncrypted($expected, $name, $encrypt = 'aes', $key = null, $message = '') { if (empty($this->_response)) { $this->fail('Not response set, cannot assert cookies.'); } $result = $this->_response->cookie($name); $this->_cookieEncriptionKey = $key; $result['value'] = $this->_decrypt($result['value'], $encrypt); $this->assertEquals($expected, $result['value'], 'Cookie data differs. ' . $message); }
/** * Convert a CakePHP response into a PSR7 one. * * @param CakeResponse $response The CakePHP response to convert * @return PsrResponse $response The equivalent PSR7 response. */ public static function toPsr(CakeResponse $response) { $status = $response->statusCode(); $headers = $response->header(); if (!isset($headers['Content-Type'])) { $headers['Content-Type'] = $response->type(); } $body = $response->body(); $stream = 'php://memory'; if (is_string($body)) { $stream = new Stream('php://memory', 'wb'); $stream->write($response->body()); } if (is_callable($body)) { $stream = new CallbackStream($body); } // This is horrible, but CakePHP doesn't have a getFile() method just yet. $fileProp = new \ReflectionProperty($response, '_file'); $fileProp->setAccessible(true); $file = $fileProp->getValue($response); if ($file) { $stream = new Stream($file->path, 'rb'); } return new DiactorosResponse($stream, $status, $headers); }
/** * Main functionality to trigger maintenance mode. * Will automatically set the appropriate headers. * * Tip: Check for non CLI first * * if (php_sapi_name() !== 'cli') { * App::uses('MaintenanceLib', 'Setup.Lib'); * $Maintenance = new MaintenanceLib(); * $Maintenance->checkMaintenance(); * } * * @param string|null $ipAddress * @param bool $exit If Response should be sent and exited. * @return void * @deprecated Use Maintenance DispatcherFilter */ public function checkMaintenance($ipAddress = null, $exit = true) { if ($ipAddress === null) { $ipAddress = env('REMOTE_ADDRESS'); } if (!$this->isMaintenanceMode($ipAddress)) { return; } $Response = new Response(); $Response->statusCode(503); $Response->header('Retry-After', DAY); $body = __d('setup', 'Maintenance work'); $template = APP . 'Template' . DS . 'Error' . DS . $this->template; if (file_exists($template)) { $body = file_get_contents($template); } $Response->body($body); if ($exit) { $Response->send(); exit; } }
/** * Filters the cake response to the BrowserKit one. * * @param \Cake\Network\Response $response Cake response. * @return \Symfony\Component\BrowserKit\Response BrowserKit response. */ protected function filterResponse($response) { $this->cake['response'] = $response; foreach ($response->cookie() as $cookie) { $this->getCookieJar()->set(new Cookie($cookie['name'], $cookie['value'], $cookie['expire'], $cookie['path'], $cookie['domain'], $cookie['secure'], $cookie['httpOnly'])); } $response->sendHeaders(); return new BrowserKitResponse($response->body(), $response->statusCode(), $response->header()); }
/** * @param \Cake\Network\Request $request Request to get authentication information from. * @param \Cake\Network\Response $response A response object that can have headers added. * @return bool|\Cake\Network\Response */ public function unauthenticated(Request $request, Response $response) { if ($this->_config['continue']) { return null; } if (isset($this->_exception)) { $response->statusCode($this->_exception->httpStatusCode); //add : to http code for cakephp (header method in Network/Response expects header separated with colon notation) $headers = $this->_exception->getHttpHeaders(); $code = (string) $this->_exception->httpStatusCode; $headers = array_map(function ($header) use($code) { $pos = strpos($header, $code); if ($pos !== false) { return substr($header, 0, $pos + strlen($code)) . ':' . substr($header, $pos + strlen($code) + 1); } return $header; }, $headers); $response->header($headers); $response->body(json_encode(['error' => $this->_exception->errorType, 'message' => $this->_exception->getMessage()])); return $response; } $message = __d('authenticate', 'You are not authenticated.'); throw new BadRequestException($message); }
/** * Test render with a View file specified. * * @return void */ public function testRenderWithView() { $Request = new Request(); $Response = new Response(); $Controller = new Controller($Request, $Response); $Controller->name = 'Posts'; $data = ['User' => ['username' => 'fake'], 'Item' => [['name' => 'item1'], ['name' => 'item2']]]; $Controller->set('user', $data); $Controller->viewClass = 'Json'; $View = $Controller->createView(); $View->viewPath = $Controller->name; $output = $View->render('index'); $expected = json_encode(['user' => 'fake', 'list' => ['item1', 'item2'], 'paging' => null]); $this->assertSame($expected, $output); $this->assertSame('application/json', $Response->type()); }
/** * Handles unauthenticated access attempts. Will automatically forward to the * requested provider's authorization URL to let the user grant access to the * application. * * @param \Cake\Network\Request $request Request object. * @param \Cake\Network\Response $response Response object. * @return \Cake\Network\Response|null */ public function unauthenticated(Request $request, Response $response) { $provider = $this->provider($request); if (empty($provider) || !empty($request->query['code'])) { return null; } if ($this->config('options.state')) { $request->session()->write('oauth2state', $provider->getState()); } $response->location($provider->getAuthorizationUrl()); return $response; }
/** * test setting parameters in beforeDispatch method * * @return void */ public function testQueryStringAndCustomTime() { $folder = CACHE . 'views' . DS; $file = $folder . 'posts-home-coffee-life-sleep-sissies-coffee-life-sleep-sissies.html'; $content = '<!--cachetime:' . (time() + WEEK) . ';ext:html-->Foo bar'; file_put_contents($file, $content); Router::reload(); Router::connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']); Router::connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']); Router::connect('/:controller/:action/*'); $_GET = ['coffee' => 'life', 'sleep' => 'sissies']; $filter = new CacheFilter(); $request = new Request('posts/home/?coffee=life&sleep=sissies'); $response = new Response(); $event = new Event(__CLASS__, $this, compact('request', 'response')); $filter->beforeDispatch($event); $result = $response->body(); $expected = '<!--created:'; $this->assertTextStartsWith($expected, $result); $expected = '-->Foo bar'; $this->assertTextEndsWith($expected, $result); $result = $response->type(); $expected = 'text/html'; $this->assertEquals($expected, $result); $result = $response->header(); $this->assertNotEmpty($result['Expires']); // + 1 week unlink($file); }
/** * Constructor * * @param string $code One of Types::CODE_*, or an array containing 'code' and 'data' keys * @param array $data data to return */ public function __construct($code, array $data = array()) { if (is_array($code)) { $body = \Cake\Utility\Hash::merge(array('code' => 'success', 'data' => array()), $code); } else { $body = array('code' => $code, 'data' => $data); } $options = array('type' => 'json', 'body' => json_encode($body)); parent::__construct($options); }
/** * Returns an audio/video element * * ### Usage * * Using an audio file: * * ``` * echo $this->Html->media('audio.mp3', ['fullBase' => true]); * ``` * * Outputs: * * `<video src="http://www.somehost.com/files/audio.mp3">Fallback text</video>` * * Using a video file: * * ``` * echo $this->Html->media('video.mp4', ['text' => 'Fallback text']); * ``` * * Outputs: * * `<video src="/files/video.mp4">Fallback text</video>` * * Using multiple video files: * * ``` * echo $this->Html->media( * ['video.mp4', ['src' => 'video.ogv', 'type' => "video/ogg; codecs='theora, vorbis'"]], * ['tag' => 'video', 'autoplay'] * ); * ``` * * Outputs: * * ``` * <video autoplay="autoplay"> * <source src="/files/video.mp4" type="video/mp4"/> * <source src="/files/video.ogv" type="video/ogv; codecs='theora, vorbis'"/> * </video> * ``` * * ### Options * * - `tag` Type of media element to generate, either "audio" or "video". * If tag is not provided it's guessed based on file's mime type. * - `text` Text to include inside the audio/video tag * - `pathPrefix` Path prefix to use for relative URLs, defaults to 'files/' * - `fullBase` If provided the src attribute will get a full address including domain name * * @param string|array $path Path to the video file, relative to the webroot/{$options['pathPrefix']} directory. * Or an array where each item itself can be a path string or an associate array containing keys `src` and `type` * @param array $options Array of HTML attributes, and special options above. * @return string Generated media element */ public function media($path, array $options = []) { $options += ['tag' => null, 'pathPrefix' => 'files/', 'text' => '']; if (!empty($options['tag'])) { $tag = $options['tag']; } else { $tag = null; } if (is_array($path)) { $sourceTags = ''; foreach ($path as &$source) { if (is_string($source)) { $source = ['src' => $source]; } if (!isset($source['type'])) { $ext = pathinfo($source['src'], PATHINFO_EXTENSION); $source['type'] = $this->response->getMimeType($ext); } $source['src'] = $this->Url->assetUrl($source['src'], $options); $sourceTags .= $this->formatTemplate('tagselfclosing', ['tag' => 'source', 'attrs' => $this->templater()->formatAttributes($source)]); } unset($source); $options['text'] = $sourceTags . $options['text']; unset($options['fullBase']); } else { if (empty($path) && !empty($options['src'])) { $path = $options['src']; } $options['src'] = $this->Url->assetUrl($path, $options); } if ($tag === null) { if (is_array($path)) { $mimeType = $path[0]['type']; } else { $mimeType = $this->response->getMimeType(pathinfo($path, PATHINFO_EXTENSION)); } if (preg_match('#^video/#', $mimeType)) { $tag = 'video'; } else { $tag = 'audio'; } } if (isset($options['poster'])) { $options['poster'] = $this->Url->assetUrl($options['poster'], ['pathPrefix' => Configure::read('App.imageBaseUrl')] + $options); } $text = $options['text']; $options = array_diff_key($options, ['tag' => null, 'fullBase' => null, 'pathPrefix' => null, 'text' => null]); return $this->tag($tag, $text, $options); }
/** * Sends an asset file to the client * * @param \Cake\Network\Request $request The request object to use. * @param \Cake\Network\Response $response The response object to use. * @param string $assetFile Path to the asset file in the file system * @param string $ext The extension of the file to determine its mime type * @return void */ protected function _deliverAsset(Request $request, Response $response, $assetFile, $ext) { $compressionEnabled = $response->compress(); if ($response->type($ext) === $ext) { $contentType = 'application/octet-stream'; $agent = $request->env('HTTP_USER_AGENT'); if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent) || preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) { $contentType = 'application/octetstream'; } $response->type($contentType); } if (!$compressionEnabled) { $response->header('Content-Length', filesize($assetFile)); } // $response->cache(filemtime($assetFile), $this->_cacheTime); $response->sendHeaders(); readfile($assetFile); if ($compressionEnabled) { ob_end_flush(); } }
/** * Test the location method. * * @return void */ public function testLocation() { $response = new Response(); $this->assertNull($response->location(), 'No header should be set.'); $this->assertNull($response->location('http://example.org'), 'Setting a location should return null'); $this->assertEquals('http://example.org', $response->location(), 'Reading a location should return the value.'); }
/** * RssViewTest::testSerializeWithArrayLinks() * * `'atom:link' => array('@href' => array(...)` becomes * '@rel' => 'self', '@type' => 'application/rss+xml' automatically set for atom:link * * @return void */ public function testSerializeWithArrayLinks() { $Request = new Request(); $Response = new Response(); $data = ['channel' => ['title' => 'Channel title', 'link' => 'http://channel.example.org', 'atom:link' => ['@href' => ['controller' => 'foo', 'action' => 'bar']], 'description' => 'Channel description'], 'items' => [['title' => 'Title One', 'link' => ['controller' => 'foo', 'action' => 'bar'], 'description' => 'Content one'], ['title' => 'Title Two', 'link' => ['controller' => 'foo', 'action' => 'bar'], 'description' => 'Content two']]]; $viewVars = ['channel' => $data, '_serialize' => 'channel']; $View = new RssView($Request, $Response, null, ['viewVars' => $viewVars]); $result = $View->render(false); $expected = <<<RSS <?xml version="1.0" encoding="UTF-8"?> <rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"> <channel> <title>Channel title</title> <link>http://channel.example.org</link> <atom:link href="{$this->baseUrl}/foo/bar" rel="self" type="application/rss+xml"/> <description>Channel description</description> <item> <title>Title One</title> <link>{$this->baseUrl}/foo/bar</link> <description>Content one</description> </item> <item> <title>Title Two</title> <link>{$this->baseUrl}/foo/bar</link> <description>Content two</description> </item> </channel> </rss> RSS; //debug($result); $this->assertSame('application/rss+xml', $Response->type()); $this->assertTextEquals($expected, $result); }
/** * Parses a string URL into an array. Parsed URLs will result in an automatic * redirection * * @param string $url The URL to parse * @return bool False on failure */ public function parse($url) { $params = parent::parse($url); if (!$params) { return false; } if (!$this->response) { $this->response = new Response(); } $redirect = $this->redirect; if (count($this->redirect) === 1 && !isset($this->redirect['controller'])) { $redirect = $this->redirect[0]; } if (isset($this->options['persist']) && is_array($redirect)) { $redirect += ['pass' => $params['pass'], 'url' => []]; if (is_array($this->options['persist'])) { foreach ($this->options['persist'] as $elem) { if (isset($params[$elem])) { $redirect[$elem] = $params[$elem]; } } } $redirect = Router::reverse($redirect); } $status = 301; if (isset($this->options['status']) && ($this->options['status'] >= 300 && $this->options['status'] < 400)) { $status = $this->options['status']; } $this->response->header(['Location' => Router::url($redirect, true)]); $this->response->statusCode($status); $this->response->send(); $this->response->stop(); }
public function testToPsrBodyCallable() { $cake = new CakeResponse(['status' => 200]); $cake->body(function () { return 'callback response'; }); $result = ResponseTransformer::toPsr($cake); $this->assertSame('callback response', '' . $result->getBody()); }
/** * Asserts that a file with the given name was sent in the response * * @param string $expected The file name that should be sent in the response * @param string $message The failure message that will be appended to the generated message. * @return void */ public function assertFileResponse($expected, $message = '') { if ($this->_response === null) { $this->fail('No response set, cannot assert file.'); } $actual = isset($this->_response->getFile()->path) ? $this->_response->getFile()->path : null; if ($actual === null) { $this->fail('No file was sent in this response'); } $this->assertEquals($expected, $actual, $message); }
/** * Maps a content type alias back to its mime-type(s) * * @param string|array $alias String alias to convert back into a content type. Or an array of aliases to map. * @return string Null on an undefined alias. String value of the mapped alias type. If an * alias maps to more than one content type, the first one will be returned. */ public function mapAlias($alias) { if (is_array($alias)) { return array_map(array($this, 'mapAlias'), $alias); } $type = $this->response->getMimeType($alias); if ($type) { if (is_array($type)) { return $type[0]; } return $type; } return null; }
/** * Sets a cookie expire time to remove cookie value. * * This is only done once all values in a cookie key have been * removed with delete. * * @param string $name Name of cookie * @return void */ protected function _delete($name) { $config = $this->configKey($name); $expires = new Time('now'); $this->_response->cookie(array('name' => $name, 'value' => '', 'expire' => $expires->format('U') - 42000, 'path' => $config['path'], 'domain' => $config['domain'], 'secure' => $config['secure'], 'httpOnly' => $config['httpOnly'])); }