forked from build-admin/buildadmin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommon.php
404 lines (360 loc) · 12.3 KB
/
common.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
<?php
// 应用公共文件
use think\App;
use ba\Filesystem;
use think\Response;
use think\facade\Db;
use think\facade\Lang;
use think\facade\Event;
use think\facade\Config;
use voku\helper\AntiXSS;
use app\admin\model\Config as configModel;
use think\exception\HttpResponseException;
use Symfony\Component\HttpFoundation\IpUtils;
if (!function_exists('__')) {
/**
* 语言翻译
* @param string $name 被翻译字符
* @param array $vars 替换字符数组
* @param string $lang 翻译语言
* @return mixed
*/
function __(string $name, array $vars = [], string $lang = ''): mixed
{
if (is_numeric($name) || !$name) {
return $name;
}
return Lang::get($name, $vars, $lang);
}
}
if (!function_exists('filter')) {
/**
* 输入过滤
* 富文本反XSS请使用 clean_xss,也就不需要及不能再 filter 了
* @param string $string 要过滤的字符串
* @return string
*/
function filter(string $string): string
{
// 去除字符串两端空格(对防代码注入有一定作用)
$string = trim($string);
// 过滤html和php标签
$string = strip_tags($string);
// 特殊字符转实体
return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8');
}
}
if (!function_exists('clean_xss')) {
/**
* 清理XSS
* 通常只用于富文本,比 filter 慢
* @param string $string
* @return string
*/
function clean_xss(string $string): string
{
return (new AntiXSS())->xss_clean($string);
}
}
if (!function_exists('htmlspecialchars_decode_improve')) {
/**
* html解码增强
* 被 clean_xss函数 和 filter函数 内的 htmlspecialchars 编码的字符串,需要用此函数才能完全解码
* @param string $string
* @param int $flags
* @return string
*/
function htmlspecialchars_decode_improve(string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401): string
{
return htmlspecialchars_decode($string, $flags);
}
}
if (!function_exists('get_sys_config')) {
/**
* 获取站点的系统配置,不传递参数则获取所有配置项
* @param string $name 变量名
* @param string $group 变量分组,传递此参数来获取某个分组的所有配置项
* @param bool $concise 是否开启简洁模式,简洁模式下,获取多项配置时只返回配置的键值对
* @return mixed
* @throws Throwable
*/
function get_sys_config(string $name = '', string $group = '', bool $concise = true): mixed
{
if ($name) {
// 直接使用->value('value')不能使用到模型的类型格式化
$config = configModel::cache($name, null, configModel::$cacheTag)->where('name', $name)->find();
if ($config) $config = $config['value'];
} else {
if ($group) {
$temp = configModel::cache('group' . $group, null, configModel::$cacheTag)->where('group', $group)->select()->toArray();
} else {
$temp = configModel::cache('sys_config_all', null, configModel::$cacheTag)->order('weigh desc')->select()->toArray();
}
if ($concise) {
$config = [];
foreach ($temp as $item) {
$config[$item['name']] = $item['value'];
}
} else {
$config = $temp;
}
}
return $config;
}
}
if (!function_exists('get_route_remark')) {
/**
* 获取当前路由后台菜单规则的备注信息
* @return string
*/
function get_route_remark(): string
{
$controllerName = request()->controller(true);
$actionName = request()->action(true);
$path = str_replace('.', '/', $controllerName);
$remark = Db::name('admin_rule')
->where('name', $path)
->whereOr('name', $path . '/' . $actionName)
->value('remark');
return __((string)$remark);
}
}
if (!function_exists('full_url')) {
/**
* 获取资源完整url地址;若安装了云存储或 config/buildadmin.php 配置了CdnUrl,则自动使用对应的CdnUrl
* @param string $relativeUrl 资源相对地址 不传入则获取域名
* @param boolean $domain 是否携带域名 或者直接传入域名
* @param string $default 默认值
* @return string
*/
function full_url(string $relativeUrl = '', bool $domain = true, string $default = ''): string
{
// 存储/上传资料配置
Event::trigger('uploadConfigInit', App::getInstance());
$cdnUrl = Config::get('buildadmin.cdn_url');
if (!$cdnUrl) $cdnUrl = request()->upload['cdn'] ?? request()->domain();
if ($domain === true) {
$domain = $cdnUrl;
} elseif ($domain === false) {
$domain = '';
}
$relativeUrl = $relativeUrl ?: $default;
if (!$relativeUrl) return $domain;
$regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i";
if (preg_match('/^http(s)?:\/\//', $relativeUrl) || preg_match($regex, $relativeUrl) || $domain === false) {
return $relativeUrl;
}
return $domain . $relativeUrl;
}
}
if (!function_exists('encrypt_password')) {
/**
* 加密密码
*/
function encrypt_password($password, $salt = '', $encrypt = 'md5')
{
return $encrypt($encrypt($password) . $salt);
}
}
if (!function_exists('str_attr_to_array')) {
/**
* 将字符串属性列表转为数组
* @param string $attr 属性,一行一个,无需引号,比如:class=input-class
* @return array
*/
function str_attr_to_array(string $attr): array
{
if (!$attr) return [];
$attr = explode("\n", trim(str_replace("\r\n", "\n", $attr)));
$attrTemp = [];
foreach ($attr as $item) {
$item = explode('=', $item);
if (isset($item[0]) && isset($item[1])) {
$attrVal = $item[1];
if ($item[1] === 'false' || $item[1] === 'true') {
$attrVal = !($item[1] === 'false');
} elseif (is_numeric($item[1])) {
$attrVal = (float)$item[1];
}
if (strpos($item[0], '.')) {
$attrKey = explode('.', $item[0]);
if (isset($attrKey[0]) && isset($attrKey[1])) {
$attrTemp[$attrKey[0]][$attrKey[1]] = $attrVal;
continue;
}
}
$attrTemp[$item[0]] = $attrVal;
}
}
return $attrTemp;
}
}
if (!function_exists('action_in_arr')) {
/**
* 检测一个方法是否在传递的数组内
* @param array $arr
* @return bool
*/
function action_in_arr(array $arr = []): bool
{
$arr = is_array($arr) ? $arr : explode(',', $arr);
if (!$arr) {
return false;
}
$arr = array_map('strtolower', $arr);
if (in_array(strtolower(request()->action()), $arr) || in_array('*', $arr)) {
return true;
}
return false;
}
}
if (!function_exists('build_suffix_svg')) {
/**
* 构建文件后缀的svg图片
* @param string $suffix 文件后缀
* @param ?string $background 背景颜色,如:rgb(255,255,255)
* @return string
*/
function build_suffix_svg(string $suffix = 'file', string $background = null): string
{
$suffix = mb_substr(strtoupper($suffix), 0, 4);
$total = unpack('L', hash('adler32', $suffix, true))[1];
$hue = $total % 360;
[$r, $g, $b] = hsv2rgb($hue / 360, 0.3, 0.9);
$background = $background ?: "rgb($r,$g,$b)";
return '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:' . $background . ';" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16 V416z"/>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g><text><tspan x="220" y="380" font-size="124" font-family="Verdana, Helvetica, Arial, sans-serif" fill="white" text-anchor="middle">' . $suffix . '</tspan></text></g>
</svg>';
}
}
if (!function_exists('get_area')) {
/**
* 获取省份地区数据
* @throws Throwable
*/
function get_area(): array
{
$province = request()->get('province', '');
$city = request()->get('city', '');
$where = ['pid' => 0, 'level' => 1];
if ($province !== '') {
$where['pid'] = $province;
$where['level'] = 2;
if ($city !== '') {
$where['pid'] = $city;
$where['level'] = 3;
}
}
return Db::name('area')
->where($where)
->field('id as value,name as label')
->select()
->toArray();
}
}
if (!function_exists('hsv2rgb')) {
function hsv2rgb($h, $s, $v): array
{
$r = $g = $b = 0;
$i = floor($h * 6);
$f = $h * 6 - $i;
$p = $v * (1 - $s);
$q = $v * (1 - $f * $s);
$t = $v * (1 - (1 - $f) * $s);
switch ($i % 6) {
case 0:
$r = $v;
$g = $t;
$b = $p;
break;
case 1:
$r = $q;
$g = $v;
$b = $p;
break;
case 2:
$r = $p;
$g = $v;
$b = $t;
break;
case 3:
$r = $p;
$g = $q;
$b = $v;
break;
case 4:
$r = $t;
$g = $p;
$b = $v;
break;
case 5:
$r = $v;
$g = $p;
$b = $q;
break;
}
return [
floor($r * 255),
floor($g * 255),
floor($b * 255)
];
}
}
if (!function_exists('ip_check')) {
/**
* IP检查
* @throws Throwable
*/
function ip_check($ip = null): void
{
$ip = is_null($ip) ? request()->ip() : $ip;
$noAccess = get_sys_config('no_access_ip');
$noAccess = !$noAccess ? [] : array_filter(explode("\n", str_replace("\r\n", "\n", $noAccess)));
if ($noAccess && IpUtils::checkIp($ip, $noAccess)) {
$response = Response::create(['msg' => 'No permission request'], 'json', 403);
throw new HttpResponseException($response);
}
}
}
if (!function_exists('set_timezone')) {
/**
* 设置时区
* @throws Throwable
*/
function set_timezone($timezone = null): void
{
$defaultTimezone = Config::get('app.default_timezone');
$timezone = is_null($timezone) ? get_sys_config('time_zone') : $timezone;
if ($timezone && $defaultTimezone != $timezone) {
Config::set([
'app.default_timezone' => $timezone
]);
date_default_timezone_set($timezone);
}
}
}
if (!function_exists('get_upload_config')) {
/**
* 获取上传配置
* @return array
*/
function get_upload_config(): array
{
// 存储/上传资料配置
Event::trigger('uploadConfigInit', App::getInstance());
$uploadConfig = Config::get('upload');
$uploadConfig['maxsize'] = Filesystem::fileUnitToByte($uploadConfig['maxsize']);
$upload = request()->upload;
if (!$upload) {
$uploadConfig['mode'] = 'local';
return $uploadConfig;
}
unset($upload['cdn']);
return array_merge($upload, $uploadConfig);
}
}