/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { ob_start(); $level = ob_get_level(); $method = Run::EXCEPTION_HANDLER; $whoops = $this->getWhoopsInstance($request); $whoops->allowQuit(false); $whoops->writeToOutput(false); $whoops->sendHttpCode(false); //Catch errors means register whoops globally if ($this->catchErrors) { $whoops->register(); } try { $response = $next($request, $response); } catch (\Throwable $exception) { $body = self::createStream($response->getBody()); $body->write($whoops->{$method}($exception)); $response = $response->withStatus(500)->withBody($body); } catch (\Exception $exception) { $body = self::createStream($response->getBody()); $body->write($whoops->{$method}($exception)); $response = $response->withStatus(500)->withBody($body); } finally { Utils\Helpers::getOutput($level); } if ($this->catchErrors) { $whoops->unregister(); } return $response; }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { if (!Middleware::hasAttribute($request, FormatNegotiator::KEY)) { throw new RuntimeException('This middleware needs FormatNegotiator executed before'); } $ajax = Utils\Helpers::isAjax($request); $debugBar = $this->debugBar ?: new StandardDebugBar(); //Redirection response if (Utils\Helpers::isRedirect($response)) { if ($debugBar->isDataPersisted() || session_status() === PHP_SESSION_ACTIVE) { $debugBar->stackData(); } //Html response } elseif (FormatNegotiator::getFormat($request) === 'html') { $renderer = $debugBar->getJavascriptRenderer(); ob_start(); echo '<style>'; $renderer->dumpCssAssets(); echo '</style>'; echo '<script>'; $renderer->dumpJsAssets(); echo '</script>'; echo $renderer->render(!$ajax); $response = $this->inject($response, ob_get_clean()); //Ajax response } elseif ($ajax && $this->captureAjax) { $headers = $debugBar->getDataAsHeaders(); foreach ($headers as $name => $value) { $response = $response->withHeader($name, $value); } } return $next($request, $response); }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { $response = $next($request, $response); if (Utils\Helpers::getMimeType($response) === 'text/html' && !Utils\Helpers::isAjax($request)) { return $this->inject($response, $this->getCode()); } return $response; }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { if (!Middleware::hasAttribute($request, FormatNegotiator::KEY)) { throw new RuntimeException('The GoogleAnalytics middleware needs FormatNegotiator executed before'); } if (FormatNegotiator::getFormat($request) === 'html' && !Utils\Helpers::isAjax($request)) { $response = $this->inject($response, $this->getCode()); } return $next($request, $response); }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { $response = $next($request, $response); $resolver = $this->resolver ?: new Transformers\Minifier(); $transformer = $resolver->resolve(Utils\Helpers::getMimeType($response)); if ($transformer) { return $response->withBody($transformer($response->getBody(), self::createStream())); } return $response; }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { if ($this->autodetect) { $this->basePath(Utils\Helpers::joinPath(self::detectBasePath($request), $this->basePath)); } $uri = $request->getUri(); $path = $this->getPath($uri->getPath()); $request = $request->withUri($uri->withPath($path)); $request = Middleware::setAttribute($request, self::KEY, $this->basePath); return $next($request, $response); }
/** * Execute the middleware. * * @param RequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(RequestInterface $request, ResponseInterface $response, callable $next) { $response = $next($request, $response); $cacheControl = $response->getHeaderLine('Cache-Control') ?: ''; if (stripos($cacheControl, 'max-age') === false) { $mime = Utils\Helpers::getMimeType($response); $expires = new DateTimeImmutable(isset($this->expires[$mime]) ? $this->expires[$mime] : $this->expiresDefault); $cacheControl .= ' max-age=' . ($expires->getTimestamp() - time()); return $response->withHeader('Cache-Control', trim($cacheControl))->withHeader('Expires', $expires->format('D, d M Y H:i:s') . ' GMT'); } return $response; }
/** * Returns the filename of the response file. * * @param RequestInterface $request * @param string $indexExt * * @return string */ private function getFilename(RequestInterface $request, $indexExt = 'html') { $path = $this->getPath($request->getUri()->getPath()); $parts = pathinfo($path); $path = isset($parts['dirname']) ? $parts['dirname'] : ''; $filename = isset($parts['basename']) ? $parts['basename'] : ''; //if it's a directory, append the index file if (empty($parts['extension'])) { $filename .= "/index.{$indexExt}"; } return Helpers::joinPath($this->directory, $path, $filename); }
/** * Returns the filename of the response file. * * @param RequestInterface $request * * @return string */ private function getFilename(RequestInterface $request) { $path = $this->getPath($request->getUri()->getPath()); $parts = pathinfo($path); $path = isset($parts['dirname']) ? $parts['dirname'] : ''; $filename = isset($parts['basename']) ? $parts['basename'] : ''; //if it's a directory, append "/index.html" if (empty($parts['extension'])) { $filename .= '/index.html'; } return Helpers::joinPath($this->storage, $path, $filename); }
/** * Decrypt the given value. * * @param string $value * * @return string */ private function decrypt($value) { $this->checkKey(); $decoded = base64_decode($value); $hmac = mb_substr($decoded, 0, 32, '8bit'); $iv = mb_substr($decoded, 32, 16, '8bit'); $cipher = mb_substr($decoded, 48, null, '8bit'); $calculated = hash_hmac('sha256', $iv . $cipher, $this->authentication, true); if (Helpers::hashEquals($hmac, $calculated)) { $value = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, $cipher, 'ctr', $iv), ""); return json_decode($value, true); } }
/** * Decrypt the given value. * * @param string $value * * @return string */ private function decrypt($value) { if (empty($this->key) || empty($this->authentication)) { throw new RuntimeException('No crypt keys provided'); } $decoded = base64_decode($value); $hmac = mb_substr($decoded, 0, 32, '8bit'); $iv = mb_substr($decoded, 32, 16, '8bit'); $cipher = mb_substr($decoded, 48, null, '8bit'); $calculated = hash_hmac('sha256', $iv . $cipher, $this->authentication, true); if (Helpers::hashEquals($hmac, $calculated)) { $value = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, $cipher, 'ctr', $iv), ""); return json_decode($value, true); } }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { if (!Middleware::hasAttribute($request, ClientIp::KEY)) { throw new RuntimeException('Recaptcha middleware needs ClientIp executed before'); } if (Utils\Helpers::isPost($request)) { $recaptcha = new GoogleRecaptcha($this->secret); $data = $request->getParsedBody(); $res = $recaptcha->verify(isset($data['g-recaptcha-response']) ? $data['g-recaptcha-response'] : '', ClientIp::getIp($request)); if (!$res->isSuccess()) { return $response->withStatus(403); } } return $next($request, $response); }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { if (!Middleware::hasAttribute($request, FormatNegotiator::KEY)) { throw new RuntimeException('Honeypot middleware needs FormatNegotiator executed before'); } if (FormatNegotiator::getFormat($request) !== 'html') { return $next($request, $response); } if (Utils\Helpers::isPost($request) && !$this->isValid($request)) { return $response->withStatus(403); } $response = $next($request, $response); return $this->insertIntoPostForms($response, function ($match) { return $match[0] . '<input type="text" name="' . $this->inputName . '" class="' . $this->inputClass . '">'; }); }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { if (!Middleware::hasAttribute($request, FormatNegotiator::KEY)) { throw new RuntimeException('This middleware needs FormatNegotiator executed before'); } $renderer = $this->debugBar->getJavascriptRenderer(); //Is an asset? $path = $request->getUri()->getPath(); $renderPath = $renderer->getBaseUrl(); if (strpos($path, $renderPath) === 0) { $file = $renderer->getBasePath() . substr($path, strlen($renderPath)); if (file_exists($file)) { $body = Middleware::createStream(); $body->write(file_get_contents($file)); return $response->withBody($body); } } $response = $next($request, $response); //Fix the render baseUrl $renderPath = Utils\Helpers::joinPath(BasePath::getBasePath($request), $renderer->getBaseUrl()); $renderer->setBaseUrl($renderPath); $ajax = Utils\Helpers::isAjax($request); //Redirection response if (Utils\Helpers::isRedirect($response)) { if ($this->debugBar->isDataPersisted() || session_status() === PHP_SESSION_ACTIVE) { $this->debugBar->stackData(); } //Html response } elseif (FormatNegotiator::getFormat($request) === 'html') { if (!$ajax) { $response = $this->inject($response, $renderer->renderHead(), 'head'); } $response = $this->inject($response, $renderer->render(!$ajax), 'body'); //Ajax response } elseif ($ajax && $this->captureAjax) { $headers = $this->debugBar->getDataAsHeaders(); foreach ($headers as $name => $value) { $response = $response->withHeader($name, $value); } } return $response; }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { ob_start(); $level = ob_get_level(); try { $response = $next($request, $response); } catch (\Exception $exception) { if (!$this->catchExceptions) { throw $exception; } $request = Middleware::setAttribute($request, self::KEY, $exception); $response = $response->withStatus(500); } finally { Utils\Helpers::getOutput($level); } if ($response->getStatusCode() >= 400 && $response->getStatusCode() < 600) { return $this->executeCallable($this->handler, $request, $response); } return $response; }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { if (Utils\Helpers::getMimeType($response) !== 'text/html') { return $next($request, $response); } if (Utils\Helpers::isPost($request) && !$this->isValid($request)) { return $response->withStatus(403); } $generator = function () { return '<input type="text" name="' . $this->inputName . '" class="' . $this->inputClass . '">'; }; if (!$this->autoInsert) { $request = self::setAttribute($request, self::KEY_GENERATOR, $generator); return $next($request, $response); } $response = $next($request, $response); return $this->insertIntoPostForms($response, function ($match) use($generator) { return $match[0] . $generator(); }); }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { $renderer = $this->debugBar->getJavascriptRenderer(); //Is an asset? $path = $request->getUri()->getPath(); $renderPath = $renderer->getBaseUrl(); if (strpos($path, $renderPath) === 0) { $file = $renderer->getBasePath() . substr($path, strlen($renderPath)); if (file_exists($file)) { return $response->withBody(self::createStream($file, 'r')); } } $response = $next($request, $response); //Fix the render baseUrl $generator = BasePath::getGenerator($request); if ($generator) { $renderer->setBaseUrl($generator($renderer->getBaseUrl())); } $ajax = Utils\Helpers::isAjax($request); //Redirection response if (Utils\Helpers::isRedirect($response)) { if ($this->debugBar->isDataPersisted() || session_status() === PHP_SESSION_ACTIVE) { $this->debugBar->stackData(); } //Html response } elseif (Utils\Helpers::getMimeType($response) === 'text/html') { if (!$ajax) { $response = $this->inject($response, $renderer->renderHead(), 'head'); } $response = $this->inject($response, $renderer->render(!$ajax), 'body'); //Ajax response } elseif ($ajax && $this->captureAjax) { $headers = $this->debugBar->getDataAsHeaders(); foreach ($headers as $name => $value) { $response = $response->withHeader($name, $value); } } return $response; }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { $file = $this->getFilename($request, 'php'); if (!is_file($file)) { if ($this->continueOnError) { return $next($request, $response); } return $response->withStatus(404); } if (strtolower(pathinfo($file, PATHINFO_EXTENSION)) === 'php') { $level = ob_get_level(); ob_start(); self::includeFile($file); $body = self::createStream(); $body->write(Utils\Helpers::getOutput($level)); foreach (headers_list() as $header) { list($name, $value) = array_map('trim', explode(':', $header, 2)); $response = $response->withHeader($name, $value); } return $response->withBody($body); } return $next($request, $response); }
/** * Execute the callable. * * @param mixed $target * @param RequestInterface $request * @param ResponseInterface $response * * @return ResponseInterface */ private function executeCallable($target, RequestInterface $request, ResponseInterface $response) { ob_start(); $level = ob_get_level(); try { $arguments = array_merge([$request, $response], $this->arguments); $target = self::getCallable($target, $arguments); $return = call_user_func_array($target, $arguments); if ($return instanceof ResponseInterface) { $response = $return; $return = ''; } $return = Utils\Helpers::getOutput($level) . $return; $body = $response->getBody(); if ($return !== '' && $body->isWritable()) { $body->write($return); } return $response; } catch (\Exception $exception) { Utils\Helpers::getOutput($level); throw $exception; } }
/** * Validate the request. * * @param ServerRequestInterface $request * @param array &$tokens * * @return bool */ private function validateRequest(ServerRequestInterface $request, array &$tokens) { $data = $request->getParsedBody(); if (!isset($data[$this->formIndex]) || !isset($data[$this->formToken])) { return false; } $index = $data[$this->formIndex]; $token = $data[$this->formToken]; if (!isset($tokens[$index])) { return false; } $stored = $tokens[$index]; unset($tokens[$index]); $lockTo = $request->getUri()->getPath(); if (!Utils\Helpers::hashEquals($lockTo, $stored['lockTo'])) { return false; } $expected = self::encode(hash_hmac('sha256', ClientIp::getIp($request), base64_decode($stored['token']), true)); return Utils\Helpers::hashEquals($token, $expected); }
/** * Parses the path and return the file and transform values. * For example, the path "/images/small.avatar.jpg" returns: * ["/images/avatar.jpg", "resizeCrop,50,50"]. * * @param string $path * * @return null|array [file, transform] */ private function parsePath($path) { $info = pathinfo($path); try { $pieces = explode('.', $info['filename'], 2); } catch (Exception $e) { return; } if (count($pieces) === 2) { list($transform, $file) = $pieces; //Check if the size is valid if (!isset($this->sizes[$transform])) { return; } return [Utils\Helpers::joinPath($info['dirname'], "{$file}." . $info['extension']), $this->sizes[$transform]]; } }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { $language = null; //Use path if ($this->usePath) { $uri = $request->getUri(); $path = ltrim($this->getPath($uri->getPath()), '/'); $dirs = explode('/', $path, 2); $first = array_shift($dirs); if (!empty($first) && in_array($first, $this->languages, true)) { $language = $first; //remove the language in the path $request = $request->withUri($uri->withPath('/' . array_shift($dirs))); } } //Use http headers if ($language === null) { $language = $this->negotiateHeader($request->getHeaderLine('Accept-Language'), new Negotiator(), $this->languages); if (empty($language)) { $language = isset($this->languages[0]) ? $this->languages[0] : null; } //Redirect to a path with the language if ($this->redirectStatus && $this->usePath) { $path = Utils\Helpers::joinPath($this->basePath, $language, $this->getPath($uri->getPath())); return self::getRedirectResponse($this->redirectStatus, $uri->withPath($path), $response); } } $request = Middleware::setAttribute($request, self::KEY, $language); if ($language !== null) { $response = $response->withHeader('Content-Language', $language); } return $next($request, $response); }
/** * Parses the path and return the file and transform values. * For example, the path "/images/small.avatar.jpg" returns: * ["/images/avatar.jpg", "resizeCrop,50,50"]. * * @param string $path * * @return false|array [file, transform] */ private function parsePath($path) { $info = pathinfo($path); $file = $info['basename']; $path = $info['dirname']; foreach ($this->sizes as $pattern => $transform) { if (strpos($pattern, '/') === false) { $patternFile = $pattern; $patternPath = ''; } else { $patternFile = pathinfo($pattern, PATHINFO_BASENAME); $patternPath = pathinfo($pattern, PATHINFO_DIRNAME); } if (substr($file, 0, strlen($patternFile)) === $patternFile && ($patternPath === '' || substr($path, -strlen($patternPath)) === $patternPath)) { return [Utils\Helpers::joinPath($path, substr($file, strlen($patternFile))), $transform]; } } return false; }
/** * Default handler. * * @param ServerRequestInterface $request * @param ResponseInterface $response * * @return string */ private function defaultHandler(ServerRequestInterface $request, ResponseInterface $response) { $statusCode = $response->getStatusCode(); $exception = self::getException($request); $message = $exception ? $exception->getMessage() : ''; switch (Utils\Helpers::getMimeType($response)) { case 'text/plain': case 'text/css': case 'text/javascript': return self::errorText($statusCode, $message); case 'image/jpeg': return self::errorImage($statusCode, $message, 'imagejpeg'); case 'image/gif': return self::errorImage($statusCode, $message, 'imagegif'); case 'image/png': return self::errorImage($statusCode, $message, 'imagepng'); case 'image/svg+xml': return self::errorSvg($statusCode, $message); case 'application/json': return self::errorJson($statusCode, $message); case 'text/xml': return self::errorXml($statusCode, $message); default: return self::errorHtml($statusCode, $message); } }
/** * Execute the middleware. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { $uri = $request->getUri(); if (strtolower($uri->getScheme()) !== 'https') { $uri = $uri->withScheme('https')->withPort(443); if ($this->redirectStatus !== false && (!$this->checkHttpsForward || $request->getHeaderLine('X-Forwarded-Proto') !== 'https' && $request->getHeaderLine('X-Forwarded-Port') !== '443')) { return $this->getRedirectResponse($request, $uri, $response); } $request = $request->withUri($uri); } if (!empty($this->maxAge)) { $response = $response->withHeader(self::HEADER, sprintf('max-age=%d%s', $this->maxAge, $this->includeSubdomains ? ';includeSubDomains' : '')); } $response = $next($request, $response); if (Utils\Helpers::isRedirect($response)) { return $response->withHeader('Location', str_replace('http://', 'https://', $response->getHeaderLine('Location'))); } return $response; }
/** * Parses the path and return the file and transform values. * For example, the path "/images/small.avatar.jpg" returns: * ["/images/avatar.jpg", "resizeCrop,50,50"]. * * @param string $path * * @return false|array [file, transform] */ private function parsePath($path) { $info = pathinfo($path); $basename = $info['basename']; $dirname = $info['dirname']; foreach ($this->sizes as $prefix => $paths) { if (strpos($basename, $prefix) !== 0) { continue; } foreach ($paths as $path => $transform) { $needle = $path === '' ? '' : substr($dirname, -strlen($path)); if ($path === $needle) { return [Utils\Helpers::joinPath($dirname, substr($basename, strlen($prefix))), $transform]; } } } return false; }