Passed
Push — 6.0 ( 333571...1d5c1f )
by liu
02:16
created

CheckRequestCache::getRequestCache()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 8
c 2
b 0
f 0
nc 3
nop 1
dl 0
loc 14
ccs 0
cts 9
cp 0
crap 12
rs 10
1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think\middleware;
14
15
use Closure;
16
use think\Cache;
17
use think\Config;
18
use think\Request;
19
use think\Response;
20
21
/**
22
 * 请求缓存处理
23
 */
24
class CheckRequestCache
25
{
26
    /**
27
     * 缓存对象
28
     * @var Cache
29
     */
30
    protected $cache;
31
32
    /**
33
     * 配置参数
34
     * @var array
35
     */
36
    protected $config = [
37
        // 请求缓存规则 true为自动规则
38
        'request_cache_key'    => true,
39
        // 请求缓存有效期
40
        'request_cache_expire' => null,
41
        // 全局请求缓存排除规则
42
        'request_cache_except' => [],
43
        // 请求缓存的Tag
44
        'request_cache_tag'    => '',
45
    ];
46
47
    public function __construct(Cache $cache, Config $config)
48
    {
49
        $this->cache  = $cache;
50
        $this->config = array_merge($this->config, $config->get('route'));
51
    }
52
53
    /**
54
     * 设置当前地址的请求缓存
55
     * @access public
56
     * @param Request $request
57
     * @param Closure $next
58
     * @param mixed   $cache
59
     * @return Response
60
     */
61
    public function handle($request, Closure $next, $cache = null)
62
    {
63
        if ($request->isGet() && false !== $cache) {
64
            $cache = $cache ?? $this->getRequestCache($request);
65
66
            if ($cache) {
67
                if (is_array($cache)) {
68
                    [$key, $expire, $tag] = array_pad($cache, 3, null);
69
                } else {
70
                    $key    = md5($request->url(true));
71
                    $expire = $cache;
72
                    $tag    = null;
73
                }
74
75
                $key = $this->parseCacheKey($request, $key);
76
77
                if (strtotime($request->server('HTTP_IF_MODIFIED_SINCE', '')) + $expire > $request->server('REQUEST_TIME')) {
78
                    // 读取缓存
79
                    return Response::create()->code(304);
80
                } elseif (($hit = $this->cache->get($key)) !== null) {
81
                    [$content, $header, $when] = $hit;
82
                    if (null === $expire || $when + $expire > $request->server('REQUEST_TIME')) {
83
                        return Response::create($content)->header($header);
84
                    }
85
                }
86
            }
87
        }
88
89
        $response = $next($request);
90
91
        if (isset($key) && 200 == $response->getCode() && $response->isAllowCache()) {
92
            $header                  = $response->getHeader();
93
            $header['Cache-Control'] = 'max-age=' . $expire . ',must-revalidate';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $expire does not seem to be defined for all execution paths leading up to this point.
Loading history...
94
            $header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT';
95
            $header['Expires']       = gmdate('D, d M Y H:i:s', time() + $expire) . ' GMT';
96
97
            $this->cache->tag($tag)->set($key, [$response->getContent(), $header, time()], $expire);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tag does not seem to be defined for all execution paths leading up to this point.
Loading history...
98
        }
99
100
        return $response;
101
    }
102
103
    /**
104
     * 读取当前地址的请求缓存信息
105
     * @access protected
106
     * @param Request $request
107
     * @return mixed
108
     */
109
    protected function getRequestCache($request)
110
    {
111
        $key    = $this->config['request_cache_key'];
112
        $expire = $this->config['request_cache_expire'];
113
        $except = $this->config['request_cache_except'];
114
        $tag    = $this->config['request_cache_tag'];
115
116
        foreach ($except as $rule) {
117
            if (0 === stripos($request->url(), $rule)) {
118
                return;
119
            }
120
        }
121
122
        return [$key, $expire, $tag];
123
    }
124
125
    /**
126
     * 读取当前地址的请求缓存信息
127
     * @access protected
128
     * @param Request $request
129
     * @param mixed   $key
130
     * @return null|string
131
     */
132
    protected function parseCacheKey($request, $key)
133
    {
134
        if ($key instanceof \Closure) {
135
            $key = call_user_func($key, $request);
136
        }
137
138
        if (false === $key) {
139
            // 关闭当前缓存
140
            return;
141
        }
142
143
        if (true === $key) {
144
            // 自动缓存功能
145
            $key = '__URL__';
146
        } elseif (strpos($key, '|')) {
147
            [$key, $fun] = explode('|', $key);
148
        }
149
150
        // 特殊规则替换
151
        if (false !== strpos($key, '__')) {
152
            $key = str_replace(['__CONTROLLER__', '__ACTION__', '__URL__'], [$request->controller(), $request->action(), md5($request->url(true))], $key);
153
        }
154
155
        if (false !== strpos($key, ':')) {
156
            $param = $request->param();
157
158
            foreach ($param as $item => $val) {
159
                if (is_string($val) && false !== strpos($key, ':' . $item)) {
160
                    $key = str_replace(':' . $item, $val, $key);
161
                }
162
            }
163
        } elseif (strpos($key, ']')) {
164
            if ('[' . $request->ext() . ']' == $key) {
165
                // 缓存某个后缀的请求
166
                $key = md5($request->url());
167
            } else {
168
                return;
169
            }
170
        }
171
172
        if (isset($fun)) {
173
            $key = $fun($key);
174
        }
175
176
        return $key;
177
    }
178
}
179