xssFilter()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
cc 4
eloc 7
c 2
b 1
f 1
nc 4
nop 1
dl 0
loc 13
rs 10
1
<?php
2
3
use Illuminate\Database\Eloquent\Model;
4
use App\Foundation\Tire;
5
use Illuminate\Support\Facades\Cache;
6
use App\Model\Admin\SensitiveWord;
7
use App\Model\Admin\Config as SiteConfig;
8
9
/**
10
 * 直接从数据库获取系统后台配置
11
 *
12
 * @param string $key key
13
 * @param mixed $default key不存在时的默认值
14
 * @return mixed key对应的value
15
 */
16
function getConfig($key, $default = null)
17
{
18
    $v = SiteConfig::where('key', $key)->value('value');
19
    return !is_null($v) ? $v : $default;
20
}
21
22
/**
23
 * 后台配置嵌套解析。支持配置值中包含其它配置:{{CONFIG_KEY}}
24
 *
25
 * @param string $value
26
 * @return string
27
 */
28
function parseConfig($value)
29
{
30
    if (preg_match_all('/\{\{(\w+)\}\}/', $value, $matches)) {
31
        foreach ($matches[1] as $key => $match) {
32
            $value = str_replace($matches[0][$key], strval(config('light_config.' . $match)), $value);
33
        }
34
    } else {
35
        return $value;
36
    }
37
38
    return parseConfig($value);
39
}
40
41
function parseEntityFieldParams($params)
42
{
43
    if (strpos($params, 'getFormItemsFrom') === 0 && function_exists($params)) {
44
        $params = call_user_func($params);
45
    }
46
47
    $items = explode("\n", $params);
48
    return array_map(function ($item) {
49
        return explode("=", $item);
50
    }, $items);
51
}
52
53
function isChecked($value, $options)
54
{
55
    return in_array($value, explode(',', $options), true);
56
}
57
58
function isCheckedByAnd($value, $options)
59
{
60
    return ($options & $value) == $value;
61
}
62
63
function xssFilter($data)
64
{
65
    if (is_string($data)) {
66
        return htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'utf-8');
67
    }
68
69
    $attributes = $data->getAttributes();
70
    foreach ($attributes as &$v) {
71
        if (is_string($v)) {
72
            $v = htmlspecialchars($v, ENT_QUOTES | ENT_SUBSTITUTE, 'utf-8');
73
        }
74
    }
75
    $data->setRawAttributes($attributes);
76
}
77
78
function initTire()
79
{
80
    return Cache::rememberForever('sensitive_words_tire', function () {
81
        $tires = [];
82
83
        foreach (['noun', 'verb', 'exclusive'] as $v) {
84
            $words = SensitiveWord::query()->select($v)->where($v, '<>', '')->get();
85
86
            $tire = new Tire();
87
            foreach ($words as $k) {
88
                $tire->add($k->$v);
89
            }
90
            $tires[$v] = $tire;
91
        }
92
93
        return $tires;
94
    });
95
}
96
97
function initTireSingle()
98
{
99
    return Cache::rememberForever('sensitive_words_tire_single', function () {
100
        $types = SensitiveWord::query()->select('type')->groupBy('type')->get();
101
        $tire = new Tire();
102
        foreach ($types as $type) {
103
            $words = SensitiveWord::query()->where('type', $type->type)->get();
104
            $nouns = [];
105
            $verbs = [];
106
            $exclusives = [];
107
            foreach ($words as $word) {
108
                if ($word->noun !== '') {
0 ignored issues
show
Bug Best Practice introduced by
The property noun does not exist on App\Model\Admin\SensitiveWord. Since you implemented __get, consider adding a @property annotation.
Loading history...
109
                    $nouns[] = $word->noun;
110
                } elseif ($word->verb !== '') {
0 ignored issues
show
Bug Best Practice introduced by
The property verb does not exist on App\Model\Admin\SensitiveWord. Since you implemented __get, consider adding a @property annotation.
Loading history...
111
                    $verbs[] = $word->verb;
112
                } elseif ($word->exclusive !== '') {
0 ignored issues
show
Bug Best Practice introduced by
The property exclusive does not exist on App\Model\Admin\SensitiveWord. Since you implemented __get, consider adding a @property annotation.
Loading history...
113
                    $exclusives[] = $word->exclusive;
114
                }
115
            }
116
117
            foreach ($exclusives as $k) {
118
                $tire->add($k);
119
            }
120
            foreach ($verbs as $vk) {
121
                foreach ($nouns as $nk) {
122
                    $tire->add($vk . $nk);
123
                }
124
            }
125
        }
126
127
        return $tire;
128
    });
129
}
130
131
function mapTypeToVerbOfSensitiveWords()
132
{
133
    return Cache::rememberForever('sensitive_verb_words', function () {
134
        $words = SensitiveWord::query()->select('verb', 'type')->where('verb', '<>', '')->get();
135
136
        $data = [];
137
        foreach ($words as $word) {
138
            $data[$word->type <> '' ? $word->type : 'others'][] = $word->verb;
139
        }
140
141
        return $data;
142
    });
143
}
144
145
/**
146
 * 敏感词检查
147
 *
148
 * @param string $text 待检查文本
149
 * @param string $type 名词、动词的检测方法。默认为 join 。join:名词和动词相连组合在一起视为违规 all:名词和动词只要同时出现即为违规
150
 * @param mixed $mode 检查模式。仅 $type 为 all 时有效。默认名词、动词、专用词都检查,显示可指定为 noun verb exclusive
151
 * @return array
152
 */
153
function checkSensitiveWords(string $text, $type = 'join', $mode = null)
154
{
155
    if (!is_null($mode) && !in_array($mode, ['noun', 'verb', 'exclusive'])) {
156
        throw new \InvalidArgumentException('mode参数无效,只能为null值、noun、exclusive');
157
    }
158
159
    if ($type === 'join') {
160
        $tire = initTireSingle();
161
        $result = $tire->seek($text);
162
        return $result;
163
    }
164
165
    $tires = initTire();
166
    if (!is_null($mode)) {
167
        return $tires[$mode]->seek($text);
168
    }
169
170
    $result = [];
171
    $return = [];
172
    foreach ($tires as $k => $tire) {
173
        $result[$k] = $tire->seek($text);
174
    }
175
    if (!empty($result['noun']) && !empty($result['verb'])) {
176
        $data = mapTypeToVerbOfSensitiveWords();
177
        foreach ($result['noun'] as $noun) {
178
            $type = Cache::rememberForever('sensitive_words_noun_type:' . $noun, function () use ($noun) {
179
                return SensitiveWord::query()->where('noun', $noun)->value('type');
180
            });
181
            $type = $type ? $type : 'others';
182
            $verbs = array_intersect($data[$type], $result['verb']);
183
            if (!empty($verbs)) {
184
                array_push($verbs, $noun);
185
                $return[] = implode(' ', $verbs);
186
            }
187
        }
188
    }
189
    return array_merge($return, $result['exclusive']);
190
}
191
192
function isWebp($data)
193
{
194
    if (strncmp(substr($data, 8, 7), "WEBPVP8", 7) === 0) {
195
        return true;
196
    }
197
198
    return false;
199
}
200