<?php<liu21st@gmail.com>declare (strict_types = 1);
namespace think\middleware;
use Closure;
use think\Cache;
use think\Config;
use think\Request;
use think\Response;
class CheckRequestCache
{
protected $cache;
protected $config = [
'request_cache_key' => true,
'request_cache_expire' => null,
'request_cache_except' => [],
'request_cache_tag' => '',
];
public function __construct(Cache $cache, Config $config)
{
$this->cache = $cache;
$this->config = array_merge($this->config, $config->get('route'));
}
public function handle($request, Closure $next, $cache = null)
{
if ($request->isGet() && false !== $cache) {
$cache = $cache ?: $this->getRequestCache($request);
if ($cache) {
if (is_array($cache)) {
[$key, $expire, $tag] = $cache;
} else {
$key = str_replace('|', '/', $request->url());
$expire = $cache;
$tag = null;
}
if (strtotime($request->server('HTTP_IF_MODIFIED_SINCE', '')) + $expire > $request->server('REQUEST_TIME')) {
return Response::create()->code(304);
} elseif (($hit = $this->cache->get($key)) !== null) {
[$content, $header, $when] = $hit;
if (null === $expire || $when + $expire > $request->server('REQUEST_TIME')) {
return Response::create($content)->header($header);
}
}
}
}
$response = $next($request);
if (isset($key) && 200 == $response->getCode() && $response->isAllowCache()) {
$header = $response->getHeader();
$header['Cache-Control'] = 'max-age=' . $expire . ',must-revalidate';
$header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT';
$header['Expires'] = gmdate('D, d M Y H:i:s', time() + $expire) . ' GMT';
$this->cache->tag($tag)->set($key, [$response->getContent(), $header, time()], $expire);
}
return $response;
}
protected function getRequestCache($request)
{
$key = $this->config['request_cache_key'];
$expire = $this->config['request_cache_expire'];
$except = $this->config['request_cache_except'];
$tag = $this->config['request_cache_tag'];
if ($key instanceof \Closure) {
$key = call_user_func($key, $request);
}
if (false === $key) {
return;
}
foreach ($except as $rule) {
if (0 === stripos($request->url(), $rule)) {
return;
}
}
if (true === $key) {
$key = '__URL__';
} elseif (strpos($key, '|')) {
[$key, $fun] = explode('|', $key);
}
if (false !== strpos($key, '__')) {
$key = str_replace(['__CONTROLLER__', '__ACTION__', '__URL__'], [$request->controller(), $request->action(), md5($request->url(true))], $key);
}
if (false !== strpos($key, ':')) {
$param = $request->param();
foreach ($param as $item => $val) {
if (is_string($val) && false !== strpos($key, ':' . $item)) {
$key = str_replace(':' . $item, $val, $key);
}
}
} elseif (strpos($key, ']')) {
if ('[' . $request->ext() . ']' == $key) {
$key = md5($request->url());
} else {
return;
}
}
if (isset($fun)) {
$key = $fun($key);
}
return [$key, $expire, $tag];
}
}