| 1 |
<?php |
| 2 |
if(!function_exists('base64_urlencode')){ |
| 3 |
function base64_urlencode($str){ |
| 4 |
return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); |
| 5 |
} |
| 6 |
} |
| 7 |
|
| 8 |
if(!function_exists('base64_urldecode')){ |
| 9 |
function base64_urldecode($str){ |
| 10 |
return base64_decode(str_pad(strtr($str, '-_', '+/'), strlen($str) % 4, '=')); |
| 11 |
} |
| 12 |
} |
| 13 |
|
| 14 |
// JWT |
| 15 |
function wpjam_generate_jwt($payload, $header=[]){ |
| 16 |
if(is_array($payload)){ |
| 17 |
$jwt = implode('.', array_map(fn($v)=> base64_urlencode(wpjam_json_encode($v)), [$header+['typ'=>'JWT'], $payload])); |
| 18 |
|
| 19 |
return $jwt.'.'.wpjam_generate_signature('hmac-sha256', $jwt); // 'alg'=>'HS256' |
| 20 |
} |
| 21 |
} |
| 22 |
|
| 23 |
function wpjam_verify_jwt($token){ |
| 24 |
[$header, $payload, $sign] = explode('.', $token)+['', '', '']; |
| 25 |
|
| 26 |
//iat 签发时间不能大于当前时间 |
| 27 |
//nbf 时间之前不接收处理该Token |
| 28 |
//exp 过期时间不能小于当前时间 |
| 29 |
return hash_equals(wpjam_generate_signature('hmac-sha256', $header.'.'.$payload), $sign) |
| 30 |
&& ($data = wpjam_json_decode(base64_urldecode($payload))) |
| 31 |
&& !array_any(['iat'=>'>', 'nbf'=>'>', 'exp'=>'<'], fn($v, $k)=> isset($data[$k]) && wpjam_compare($data[$k], $v, time())) |
| 32 |
? $data |
| 33 |
: false; |
| 34 |
} |
| 35 |
|
| 36 |
function wpjam_get_jwt($key='access_token', $required=false){ |
| 37 |
return ($header = $_SERVER['HTTP_AUTHORIZATION'] ?? '') && try_prefix($header, '-', 'Bearer') |
| 38 |
? trim($header) |
| 39 |
: wpjam_param($key, ['required'=>$required]); |
| 40 |
} |
| 41 |
|
| 42 |
// Crypt |
| 43 |
function wpjam_encrypt($text, $args){ |
| 44 |
$de = $args['de'] ?? false; |
| 45 |
$params = [$args['method'] ?? '', $args['key'] ?? '', $args['options'] ?? '', $args['iv'] ?? '']; |
| 46 |
$text = $de ? openssl_decrypt($text, ...$params) : $text; |
| 47 |
|
| 48 |
foreach($de ? ['pkcs7', 'weixin'] : ['weixin', 'pkcs7'] as $pad){ |
| 49 |
if($arg = $pad == 'pkcs7' |
| 50 |
? (($args['options'] ?? '') == OPENSSL_ZERO_PADDING ? ($args['block_size'] ?? '') : '') |
| 51 |
: (($args['pad'] ?? '') == 'weixin' ? trim($args['appid'] ?? '') : '') |
| 52 |
){ |
| 53 |
$text = wpjam_pad($text, ($de ? '-' : '').$pad, $arg); |
| 54 |
} |
| 55 |
} |
| 56 |
|
| 57 |
return $de ? $text : openssl_encrypt($text, ...$params); |
| 58 |
} |
| 59 |
|
| 60 |
function wpjam_decrypt($text, $args){ |
| 61 |
return wpjam_encrypt($text, $args+['de'=>true]); |
| 62 |
} |
| 63 |
|
| 64 |
function wpjam_pad($text, $type, ...$args){ |
| 65 |
if($type == 'pkcs7'){ |
| 66 |
$pad = $args[0] - (strlen($text) % $args[0]); |
| 67 |
$text .= str_repeat(chr($pad), $pad); |
| 68 |
}elseif($type == '-pkcs7'){ |
| 69 |
$pad = ord(substr($text, -1)); |
| 70 |
$text = ($pad > 0 && $pad < $args[0]) ? substr($text, 0, -1 * $pad) : $text; |
| 71 |
}elseif($type == 'weixin'){ |
| 72 |
$text = wp_generate_password(16, false).pack("N", strlen($text)).$text.$args[0]; |
| 73 |
}elseif($type == '-weixin'){ |
| 74 |
$length = (unpack("N", substr($text, 16, 4)))[1]; |
| 75 |
|
| 76 |
return (($appid = substr($text, $length + 20)) != $args[0]) |
| 77 |
? new WP_Error('invalid_appid', 'Appid 校验「'.$appid.'」「'.$args[0].'」错误') |
| 78 |
: substr($text, 20, $length); |
| 79 |
} |
| 80 |
|
| 81 |
return $text; |
| 82 |
} |
| 83 |
|
| 84 |
function wpjam_generate_signature($algo='sha1', ...$args){ |
| 85 |
if($algo == 'sha1'){ |
| 86 |
return sha1(implode(wpjam_sort($args, SORT_STRING))); |
| 87 |
}elseif($algo == 'hmac-sha256'){ |
| 88 |
return base64_urlencode(hash_hmac('sha256', $args[0], wp_salt(), true)); |
| 89 |
} |
| 90 |
} |
| 91 |
|
| 92 |
// JSON |
| 93 |
function wpjam_json_encode($data){ |
| 94 |
return wp_json_encode($data, JSON_UNESCAPED_UNICODE); |
| 95 |
} |
| 96 |
|
| 97 |
function wpjam_json_decode($json, $assoc=true){ |
| 98 |
$result = ($json = wpjam_strip_control_chars($json)) ? json_decode($json, $assoc) : new WP_Error('empty_json', 'JSON � |
| 99 |
容不能为空!'); |
| 100 |
$result ??= str_contains($json, '\\') ? json_decode(stripslashes($json), $assoc) : $result; |
| 101 |
|
| 102 |
if(is_null($result)){ |
| 103 |
trigger_error('json_decode_error['.json_last_error().']:'.($msg = json_last_error_msg())."\n".var_export($json, true)); |
| 104 |
|
| 105 |
return new WP_Error('json_decode_error', $msg); |
| 106 |
} |
| 107 |
|
| 108 |
return $result; |
| 109 |
} |
| 110 |
|
| 111 |
function wpjam_send_json($data=[], $code=null){ |
| 112 |
if($data === true || $data === []){ |
| 113 |
$data = ['errcode'=>0]; |
| 114 |
}elseif($data === false || is_null($data)){ |
| 115 |
$data = ['errcode'=>'-1', 'errmsg'=>'error']; |
| 116 |
}elseif(is_wp_error($data) || wpjam_is_assoc_array($data)){ |
| 117 |
$data = wpjam_error($data); |
| 118 |
} |
| 119 |
|
| 120 |
$data = wpjam_json_encode($data); |
| 121 |
$jsonp = wp_is_jsonp_request(); |
| 122 |
|
| 123 |
if(!headers_sent()){ |
| 124 |
isset($code) && status_header($code); |
| 125 |
|
| 126 |
wpjam_doing_debug() || @header('Content-Type: application/'.($jsonp ? 'javascript' : 'json').'; charset='.get_option('blog_charset')); |
| 127 |
} |
| 128 |
|
| 129 |
echo $jsonp ? '/**/'.$_GET['_jsonp'].'('.$data.')' : $data; exit; |
| 130 |
} |
| 131 |
|
| 132 |
function wpjam_import($file, $columns=[]){ |
| 133 |
$dir = wp_get_upload_dir()['basedir']; |
| 134 |
$file = ($file && !str_starts_with($file, $dir) ? $dir : '').$file; |
| 135 |
|
| 136 |
if(!$file || !file_exists($file)){ |
| 137 |
return new WP_Error('file_not_exists', '文件不存在'); |
| 138 |
} |
| 139 |
|
| 140 |
$ext = wpjam_at($file, '.', -1); |
| 141 |
|
| 142 |
if($ext == 'csv'){ |
| 143 |
$columns = wpjam_reduce($columns, fn($c, $v, $k)=> $c+[trim($v)=>$k, $k=>$k], []); |
| 144 |
|
| 145 |
if(($handle = fopen($file, 'r')) !== false){ |
| 146 |
while(($row = fgetcsv($handle)) !== false){ |
| 147 |
if(!array_filter($row)){ |
| 148 |
continue; |
| 149 |
} |
| 150 |
|
| 151 |
if(($encoding ??= mb_detect_encoding(implode('', $row), mb_list_encodings(), true)) != 'UTF-8'){ |
| 152 |
$row = array_map(fn($v) => mb_convert_encoding($v, 'UTF-8', 'GBK'), $row); |
| 153 |
} |
| 154 |
|
| 155 |
if(isset($map)){ |
| 156 |
$data[] = array_map(fn($i)=> preg_replace('/="([^"]*)"/', '$1', $row[$i]), $map); |
| 157 |
}else{ |
| 158 |
$row = array_map(fn($v)=> trim(trim($v), "\xEF\xBB\xBF"), $row); |
| 159 |
$map = $columns ? wpjam_array($row, fn($i, $k)=> isset($columns[$k]) ? [$columns[$k], $i] : null) : array_flip($row); |
| 160 |
} |
| 161 |
} |
| 162 |
|
| 163 |
fclose($handle); |
| 164 |
} |
| 165 |
}else{ |
| 166 |
$data = file_get_contents($file); |
| 167 |
$data = ($ext == 'txt' && is_serialized($data)) ? maybe_unserialize($data) : $data; |
| 168 |
} |
| 169 |
|
| 170 |
unlink($file); |
| 171 |
|
| 172 |
return $data ?? []; |
| 173 |
} |
| 174 |
|
| 175 |
function wpjam_export($file, $data, $columns=[]){ |
| 176 |
$handle = fopen('php://output', 'w'); |
| 177 |
$ext = wpjam_at($file, '.', -1); |
| 178 |
|
| 179 |
header('Content-Disposition: attachment;filename='.$file); |
| 180 |
header('Content-Type: text/'.($ext == 'txt' ? 'plain' : $ext)); |
| 181 |
header('Pragma: no-cache'); |
| 182 |
header('Expires: 0'); |
| 183 |
|
| 184 |
if($ext == 'csv'){ |
| 185 |
fwrite($handle, chr(0xEF).chr(0xBB).chr(0xBF)); |
| 186 |
|
| 187 |
$columns && fputcsv($handle, $columns); |
| 188 |
|
| 189 |
array_walk($data, fn($item)=> fputcsv($handle, $columns ? wpjam_map($columns, fn($k)=> $item[$k] ?? '', 'k') : $item)); |
| 190 |
}elseif($ext == 'txt'){ |
| 191 |
fputs($handle, is_scalar($data) ? $data : maybe_serialize($data)); |
| 192 |
} |
| 193 |
|
| 194 |
fclose($handle); |
| 195 |
|
| 196 |
exit; |
| 197 |
} |
| 198 |
|
| 199 |
function wpjam_columnar($items, $columns=[], $dict=[]){ |
| 200 |
if(!$items){ |
| 201 |
return []; |
| 202 |
} |
| 203 |
|
| 204 |
$columns= $columns ?: array_keys(array_first($items)); |
| 205 |
$dict = $dict ? wpjam_fill(array_intersect($dict, $columns), fn($k)=> array_values(array_unique(array_column($items, $k)))) : []; |
| 206 |
$rows = []; |
| 207 |
|
| 208 |
foreach($items as $id => $item){ |
| 209 |
if($dict){ |
| 210 |
foreach(array_intersect_key($item, $dict) as $k => $v){ |
| 211 |
$item[$k] = array_search($v, $dict[$k]); |
| 212 |
} |
| 213 |
} |
| 214 |
|
| 215 |
$rows[$id] = array_map(fn($k)=> $item[$k] ?? null, $columns); |
| 216 |
} |
| 217 |
|
| 218 |
return ['columns'=>$columns, 'rows'=>$rows]+($dict ? ['dict'=>$dict] : []); |
| 219 |
} |
| 220 |
|
| 221 |
function wpjam_records($data){ |
| 222 |
if(!$data || empty($data['columns']) || empty($data['rows'])){ |
| 223 |
return []; |
| 224 |
} |
| 225 |
|
| 226 |
$dict = $data['dict'] ?? []; |
| 227 |
$items = []; |
| 228 |
|
| 229 |
foreach($data['rows'] as $id => $row){ |
| 230 |
$row = array_combine($data['columns'], $row); |
| 231 |
|
| 232 |
if($dict){ |
| 233 |
foreach(array_intersect_key($row, $dict) as $k => $v){ |
| 234 |
$row[$k] = $dict[$k][$v]; |
| 235 |
} |
| 236 |
} |
| 237 |
|
| 238 |
$items[$id] = $row; |
| 239 |
} |
| 240 |
|
| 241 |
return $items; |
| 242 |
} |
| 243 |
|
| 244 |
function wpjam_compress($data, $base64=true, $level=6){ |
| 245 |
$text = gzcompress(wpjam_json_encode($data), $level); |
| 246 |
|
| 247 |
return $base64 ? base64_encode($text) : $text; |
| 248 |
} |
| 249 |
|
| 250 |
function wpjam_uncompress($text, $base64=true){ |
| 251 |
return wpjam_json_decode(gzuncompress($base64 ? base64_decode($text) : $text)); |
| 252 |
} |
| 253 |
|
| 254 |
// User agent |
| 255 |
function wpjam_get_user_agent(){ |
| 256 |
return $_SERVER['HTTP_USER_AGENT'] ?? ''; |
| 257 |
} |
| 258 |
|
| 259 |
function wpjam_get_ip(){ |
| 260 |
return $_SERVER['REMOTE_ADDR'] ?? ''; |
| 261 |
} |
| 262 |
|
| 263 |
function wpjam_parse_user_agent($agent=null, $referer=null){ |
| 264 |
$agent ??= wpjam_get_user_agent(); |
| 265 |
$rule = array_find([ |
| 266 |
['iPhone', 'iOS'], |
| 267 |
['iPad', 'iOS'], |
| 268 |
['iPod', 'iOS'], |
| 269 |
['Android'], |
| 270 |
['Windows NT', 'Windows'], |
| 271 |
['Macintosh'], |
| 272 |
['Windows Phone'], |
| 273 |
['BlackBerry'], |
| 274 |
['BB10', 'BlackBerry'], |
| 275 |
['Symbian'], |
| 276 |
], fn($v)=> stripos($agent, $v[0])); |
| 277 |
|
| 278 |
$os = $rule ? ($rule[1] ?? $rule[0]) : 'unknown'; |
| 279 |
|
| 280 |
if($os == 'iOS'){ |
| 281 |
if(preg_match('/OS (.*?) like Mac OS X[\)]{1}/i', $agent, $m)){ |
| 282 |
$ua = [(float)trim(str_replace('_', '.', $m[1])), $rule[0]]; |
| 283 |
} |
| 284 |
}elseif($os == 'Android'){ |
| 285 |
if(preg_match('/Android ([0-9\.]{1,}?); (.*?) Build\/(.*?)[\)\s;]{1}/i', $agent, $m) && !empty($m[1]) && !empty($m[2])){ |
| 286 |
$ua = [trim($m[1]), str_contains($m[2], ';') ? wpjam_at(trim($m[2]), ';', 1) : trim($m[2])]; |
| 287 |
} |
| 288 |
} |
| 289 |
|
| 290 |
$rule = array_find([ |
| 291 |
['lynx'], |
| 292 |
['safari', '/version\/([\d\.]+).*safari/i'], |
| 293 |
['edge', '/edge\/([\d\.]+)/i'], |
| 294 |
['chrome', '/chrome\/([\d\.]+)/i'], |
| 295 |
['firefox', '/firefox\/([\d\.]+)/i'], |
| 296 |
['opera', '/(?:opera).([\d\.]+)/i'], |
| 297 |
['opr/', '/(?:opr).([\d\.]+)/i', 'opera'], |
| 298 |
['msie', '', 'ie'], |
| 299 |
['trident', '', 'ie'], |
| 300 |
['gecko'], |
| 301 |
['nav'] |
| 302 |
], fn($v)=> stripos($agent, $v[0])); |
| 303 |
|
| 304 |
return ['os'=>$os, 'os_version'=>$ua[0] ?? 0, 'device'=>$ua[1] ?? '']+array_combine( |
| 305 |
['browser', 'browser_version'], |
| 306 |
$rule ? [($rule[2] ?? '') ?: $rule[0], !empty($rule[1]) && preg_match($rule[1], $agent, $m) ? (float)(trim($m[1])) : 0] : ['', 0] |
| 307 |
)+array_combine( |
| 308 |
['app', 'app_version'], |
| 309 |
preg_match('/MicroMessenger\/(.*?)\s/', $agent, $m) ? [str_contains($referer ?? ($_SERVER['HTTP_REFERER'] ?? ''), 'https://servicewechat.com') ? 'weapp' : 'weixin', (float)$m[1]] : ['', 0] |
| 310 |
); |
| 311 |
} |
| 312 |
|
| 313 |
function wpjam_parse_ip($ip=''){ |
| 314 |
$ip = $ip ?: ($_SERVER['REMOTE_ADDR'] ?? ''); |
| 315 |
|
| 316 |
if($ip == 'unknown' || !$ip){ |
| 317 |
return false; |
| 318 |
} |
| 319 |
|
| 320 |
$default = ['ip'=>$ip]+array_fill_keys(['country', 'region', 'city'], ''); |
| 321 |
|
| 322 |
if(!file_exists(WP_CONTENT_DIR.'/uploads/17monipdb.dat')){ |
| 323 |
return $default; |
| 324 |
} |
| 325 |
|
| 326 |
$nip = gethostbyname($ip); |
| 327 |
$ipdot = explode('.', $nip); |
| 328 |
|
| 329 |
if($ipdot[0] < 0 || $ipdot[0] > 255 || count($ipdot) !== 4){ |
| 330 |
return $default; |
| 331 |
} |
| 332 |
|
| 333 |
static $cache = []; |
| 334 |
|
| 335 |
if(!$cache){ |
| 336 |
$fp = fopen(WP_CONTENT_DIR.'/uploads/17monipdb.dat', 'rb'); |
| 337 |
$offset = unpack('Nlen', fread($fp, 4)); |
| 338 |
$index = fread($fp, $offset['len'] - 4); |
| 339 |
$cache = ['fp'=>$fp, 'offset'=>$offset, 'index'=>$index]; |
| 340 |
|
| 341 |
register_shutdown_function(fn()=> fclose($fp)); |
| 342 |
} |
| 343 |
|
| 344 |
$fp = $cache['fp']; |
| 345 |
$offset = $cache['offset']; |
| 346 |
$index = $cache['index']; |
| 347 |
$nip2 = pack('N', ip2long($nip)); |
| 348 |
$start = (int)$ipdot[0]*4; |
| 349 |
$start = unpack('Vlen', $index[$start].$index[$start+1].$index[$start+2].$index[$start+3]); |
| 350 |
|
| 351 |
for($start = $start['len']*8+1024; $start < $offset['len']-1024-4; $start+=8){ |
| 352 |
if($index[$start].$index[$start+1].$index[$start+2].$index[$start+3] >= $nip2){ |
| 353 |
$index_offset = unpack('Vlen', $index[$start+4].$index[$start+5].$index[$start+6]."\x0"); |
| 354 |
$index_length = unpack('Clen', $index[$start+7]); |
| 355 |
|
| 356 |
fseek($fp, $offset['len']+$index_offset['len']-1024); |
| 357 |
|
| 358 |
$data = explode("\t", fread($fp, $index_length['len'])); |
| 359 |
$data = array_slice(array_pad($data, 3, ''), 0, 3); |
| 360 |
|
| 361 |
return ['ip'=>$ip]+array_combine(['country', 'region', 'city'], $data); |
| 362 |
} |
| 363 |
} |
| 364 |
|
| 365 |
return $default; |
| 366 |
} |
| 367 |
|
| 368 |
// $a, $args |
| 369 |
// $a, $b |
| 370 |
// $a, $op, $b, $strict=false |
| 371 |
function wpjam_compare($a, $op, ...$args){ |
| 372 |
if(wpjam_is_assoc_array($op)){ |
| 373 |
return wpjam_is_assoc_array($a) && isset($op['key']) |
| 374 |
? wpjam_match($a, $op) |
| 375 |
: wpjam_compare($a, $op['compare'] ?? '', $op['value'] ?? null, (bool)($args['strict'] ?? false)); |
| 376 |
} |
| 377 |
|
| 378 |
$is = is_array($op) || !$args; |
| 379 |
$b = $is ? $op : array_shift($args); |
| 380 |
$op = $is ? '' : $op; |
| 381 |
$strict = in_array($op, ['!==', '===']) ? true : (bool)array_shift($args); |
| 382 |
$op = $op ? strtoupper(['!=='=>'!=', '==='=>'=', '=='=>'='][$op] ?? $op) : (is_array($b) ? 'IN' : '='); |
| 383 |
$inv = ['!='=>'=', '<='=>'>', '>='=>'<', 'NOT IN'=>'IN', 'NOT BETWEEN'=>'BETWEEN', 'NOT LIKE'=>'LIKE', 'NOT REGEXP'=>'REGEXP'][$op] ?? ''; |
| 384 |
|
| 385 |
if($inv){ |
| 386 |
return !wpjam_compare($a, $inv, $b, $strict); |
| 387 |
} |
| 388 |
|
| 389 |
$b = in_array($op, ['IN', 'BETWEEN']) ? wp_parse_list($b) : (is_string($b) ? trim($b) : $b); |
| 390 |
|
| 391 |
switch($op){ |
| 392 |
case '=': return $strict ? $a === $b : $a == $b; |
| 393 |
case '>': return $a > $b; |
| 394 |
case '<': return $a < $b; |
| 395 |
case '<=>': return $a <=> $b; |
| 396 |
case 'IN': return is_array($a) ? array_all($a , fn($v)=> in_array($v, $b, $strict)) : in_array($a, $b, $strict); |
| 397 |
case 'LIKE': return str_contains((string)$a, str_replace('%', '', (string)$b)); |
| 398 |
case 'BETWEEN': return $a >= $b[0] && $a <= ($b[1] ?? $b[0]); |
| 399 |
case 'REGEXP': return (bool)preg_match('/'.str_replace('/', '\/', (string)$b).'/', (string)$a); |
| 400 |
} |
| 401 |
} |
| 402 |
|
| 403 |
function wpjam_operate($a, $op, $b){ |
| 404 |
if(is_array($a)){ |
| 405 |
switch($op){ |
| 406 |
case '+': return array_merge($a, $b); |
| 407 |
case '-': return wpjam_is_assoc_array($a) && wp_is_numeric_array($b) ? wpjam_except($a, $b) : array_diff($a, $b); |
| 408 |
} |
| 409 |
}else{ |
| 410 |
switch($op){ |
| 411 |
case '+': return $a + $b; |
| 412 |
case '-': return $a - $b; |
| 413 |
case '*': return $a * $b; |
| 414 |
case '/': return $a / $b; |
| 415 |
case '%': return $a % $b; |
| 416 |
case '**': return $a ** $b; |
| 417 |
case '.': return $a.$b; |
| 418 |
default: return wpjam_compare($a, $op, $b); |
| 419 |
} |
| 420 |
} |
| 421 |
} |
| 422 |
|
| 423 |
function wpjam_calc(...$args){ |
| 424 |
if(wpjam_is_assoc_array($args[0])){ |
| 425 |
$item = $args[0]; |
| 426 |
$formulas = $args[1]; |
| 427 |
$if_errors = $args[2] ?? []; |
| 428 |
$item = array_diff_key($item, $formulas); |
| 429 |
|
| 430 |
foreach($formulas as $key => $formula){ |
| 431 |
foreach($formula as &$t){ |
| 432 |
if(str_starts_with($t, '$')){ |
| 433 |
$k = substr($t, 1); |
| 434 |
$v = $item[$k] ?? null; |
| 435 |
$t = $v === null || $v === '' ? 0 : (is_numeric($v) ? $v : wpjam_format($v, '-,', false)); |
| 436 |
$t = $t === false ? ($if_errors[$k] ?? false) : $t; |
| 437 |
|
| 438 |
if($t === false){ |
| 439 |
$item[$key] = $if_errors[$key] ?? '!无法计算'; |
| 440 |
goto calced; |
| 441 |
} |
| 442 |
} |
| 443 |
} |
| 444 |
|
| 445 |
try{ |
| 446 |
$item[$key] = wpjam_calc($formula); |
| 447 |
}catch(Throwable $e){ |
| 448 |
$item[$key] = $if_errors[$key] ?? ($e instanceof DivisionByZeroError ? '!除零错误' : '!'.$e->getMessage()); |
| 449 |
} |
| 450 |
|
| 451 |
calced:; |
| 452 |
|
| 453 |
if(!$item[$key]){ |
| 454 |
unset($item[$key]); |
| 455 |
} |
| 456 |
} |
| 457 |
|
| 458 |
return $item; |
| 459 |
} |
| 460 |
|
| 461 |
$exp = $args[0]; |
| 462 |
$item = $args[1] ?? []; |
| 463 |
$calc = []; |
| 464 |
|
| 465 |
foreach(is_array($exp) ? $exp : wpjam_formula(...$args) as $t){ |
| 466 |
if(is_numeric($t) || $t === '|'){ |
| 467 |
$calc[] = $t; |
| 468 |
}elseif(try_prefix($t, '-', '$')){ |
| 469 |
$calc[] = $item[$t] ?? 0; |
| 470 |
}elseif(in_array($t, ['sin', 'cos', 'abs', 'max', 'min', 'sqrt', 'pow', 'round', 'floor', 'ceil', 'fmod'])){ |
| 471 |
$calc[] = $t(...(array_slice(array_splice($calc, array_last(array_keys($calc, '|'))), 1) ?: wpjam_throw('invalid_calc', '函数「'.$t.'」无有效参数'))); |
| 472 |
}else{ |
| 473 |
$v = array_pop($calc); |
| 474 |
|
| 475 |
if(in_array($t, ['/', '%']) && in_array((string)$v, ['0', '0.0', ''])){ |
| 476 |
throw new DivisionByZeroError('Division by zero'); |
| 477 |
} |
| 478 |
|
| 479 |
$calc[] = wpjam_operate(array_pop($calc), $t, $v); |
| 480 |
} |
| 481 |
} |
| 482 |
|
| 483 |
return count($calc) === 1 ? $calc[0] : wpjam_throw('invalid_calc', '计算栈剩余� |
| 484 |
�素数还有'.count($calc).'个'); |
| 485 |
} |
| 486 |
|
| 487 |
function wpjam_formula(...$args){ |
| 488 |
if(is_array($args[0])){ |
| 489 |
$fields = array_shift($args); |
| 490 |
|
| 491 |
if($args){ |
| 492 |
$render = fn($key)=> '字段'.($fields[$key]['title'] ?? '').'「'.$key.'」'.'� |
| 493 |
�式「'.$fields[$key]['formula'].'」'; |
| 494 |
$key = $args[0]; |
| 495 |
$parsed = $args[1]; |
| 496 |
$path = $args[2] ?? []; |
| 497 |
|
| 498 |
if(isset($parsed[$key])){ |
| 499 |
return $parsed; |
| 500 |
} |
| 501 |
|
| 502 |
if(in_array($key, $path)){ |
| 503 |
wpjam_throw('invalid_formula', '� |
| 504 |
�式嵌套:'.implode(' → ', wpjam_map(array_slice($path, array_search($key, $path)), fn($k)=> $render($k)))); |
| 505 |
} |
| 506 |
|
| 507 |
$path[] = $key; |
| 508 |
$formula = wpjam_formula($fields[$key]['formula'], $fields, $render($key).'错误'); |
| 509 |
$parsed = array_reduce($formula, fn($c, $t)=> try_prefix($t, '-', '$') && !empty($fields[$t]['formula']) ? wpjam_formula($fields, $t, $c, $path) : $c, $parsed); |
| 510 |
|
| 511 |
return $parsed+[$key => $formula]; |
| 512 |
} |
| 513 |
|
| 514 |
return wpjam_reduce($fields, fn($c, $v, $k)=> empty($v['formula']) ? $c : wpjam_formula($fields, $k, $c), []); |
| 515 |
} |
| 516 |
|
| 517 |
$formula = trim(str_replace("\xc2\xa0", ' ', $args[0])); |
| 518 |
$fields = $args[1] ?? []; |
| 519 |
$error = $args[2] ?? ''; |
| 520 |
$throw = fn($msg)=> wpjam_throw('invalid_formula', $error.':'.$msg); |
| 521 |
$functions = ['sin', 'cos', 'abs', 'ceil', 'pow', 'sqrt', 'pi', 'max', 'min', 'fmod', 'round']; |
| 522 |
$precedence = ['+'=>1, '-'=>1, '**'=>2, '*'=>2, '/'=>2, '%'=>2, '>='=>3, '<='=>3, '!='=>3, '=='=>3, '>'=>3, '<'=>3,]; |
| 523 |
$signs = implode('|', array_map(fn($v)=> preg_quote($v, '/'), [...array_keys($precedence), '(', ')', ','])); |
| 524 |
$formula = preg_split('/\s*('.$signs.')\s*/', $formula, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); |
| 525 |
$output = $stack = []; |
| 526 |
$pt = null; |
| 527 |
|
| 528 |
foreach($formula as $i => $t){ |
| 529 |
$nt = $formula[$i+1] ?? null; |
| 530 |
|
| 531 |
if(is_numeric($t)){ |
| 532 |
$output[] = str_ends_with($t, '.') ? $throw('无效的数字「'.$t.'」') : (float)$t; |
| 533 |
}elseif($t[0] === '$'){ |
| 534 |
$output[] = isset($fields[substr($t, 1)]) ? $t : $throw('「'.$t.'」未定义'); |
| 535 |
}elseif(in_array($t, $functions, true)){ |
| 536 |
$stack[] = $t; |
| 537 |
$output[] = '|'; |
| 538 |
}elseif($t === '('){ |
| 539 |
$stack[] = $t; |
| 540 |
}elseif($t === ')' || $t === ','){ |
| 541 |
if(!in_array('(', $stack, true) || ($t === ',' && ($pt === '(' || !$nt || $nt === ','))){ |
| 542 |
$throw(($t === ')' ? '未匹� |
| 543 |
�' : '无效').'的「'.$t.'」'); |
| 544 |
} |
| 545 |
|
| 546 |
while(array_last($stack) !== '('){ |
| 547 |
$output[] = array_pop($stack); |
| 548 |
} |
| 549 |
|
| 550 |
if($t === ')'){ |
| 551 |
array_pop($stack); |
| 552 |
|
| 553 |
in_array(array_last($stack), $functions) && array_push($output, array_pop($stack)); |
| 554 |
} |
| 555 |
}elseif(isset($precedence[$t])){ |
| 556 |
$r = ((!$pt || in_array($pt, ['(', ','], true)) ? 1 : 0)+((!$nt || in_array($nt, [')', ','], true) || isset($precedence[$nt])) ? 2 : 0); |
| 557 |
|
| 558 |
if(in_array($t, ['+', '-'], true) && $r == 1){ |
| 559 |
$output[] = 0; |
| 560 |
}elseif($r){ |
| 561 |
$throw('操作符「'.$t.'」缺少操作数'); |
| 562 |
} |
| 563 |
|
| 564 |
while($stack && ($v = array_last($stack)) !== '('){ |
| 565 |
if(in_array($v, $functions) || $precedence[$t] <= $precedence[$v]){ |
| 566 |
$output[] = array_pop($stack); |
| 567 |
}else{ |
| 568 |
break; |
| 569 |
} |
| 570 |
} |
| 571 |
|
| 572 |
$stack[] = $t; |
| 573 |
}else{ |
| 574 |
$throw('无效的符号「'.$t.'」'); |
| 575 |
} |
| 576 |
|
| 577 |
$pt = $t; |
| 578 |
} |
| 579 |
|
| 580 |
return array_merge($output, array_reverse(in_array('(', $stack, true) ? $throw('未匹� |
| 581 |
�的「(」') : $stack)); |
| 582 |
} |
| 583 |
|
| 584 |
function wpjam_format($value, $format, ...$args){ |
| 585 |
if(is_array($value) && is_array($format)){ |
| 586 |
return wpjam_reduce($format ?: [], fn($c, $v, $k)=> isset($c[$k]) ? wpjam_set($c, $k, wpjam_format($c[$k], ...$v)) : $c, $value); |
| 587 |
} |
| 588 |
|
| 589 |
if(is_numeric($value)){ |
| 590 |
if($format == ','){ |
| 591 |
return number_format(trim($value), (int)($args[0] ?? 2)); |
| 592 |
}elseif($format == '%'){ |
| 593 |
return round($value * 100, ($args[0] ?? 2) ?: 2).'%'; |
| 594 |
}elseif(!$format && $args && is_numeric($args[0])){ |
| 595 |
return round($value, $args[0]); |
| 596 |
} |
| 597 |
|
| 598 |
return $value / 1; |
| 599 |
}elseif(in_array($format, ['-,', '-%'])){ |
| 600 |
if(is_string($value)){ |
| 601 |
$value = str_replace(',', '', trim($value)); |
| 602 |
|
| 603 |
if($format == '-%' && try_suffix($value, '-', '%')){ |
| 604 |
$value = is_numeric($value) ? $value / 100 : $value; |
| 605 |
} |
| 606 |
} |
| 607 |
|
| 608 |
return is_numeric($value) ? $value / 1 : ($args ? $args[0] : $value); |
| 609 |
} |
| 610 |
|
| 611 |
return $value; |
| 612 |
} |
| 613 |
|
| 614 |
function wpjam_match($item, ...$args){ |
| 615 |
if(!$args || is_null($args[0])){ |
| 616 |
return true; |
| 617 |
} |
| 618 |
|
| 619 |
$args = wpjam_parse_show_if(is_string($args[0]) ? $args : $args[0]); |
| 620 |
$value = wpjam_get($item, $args['key']); |
| 621 |
$value2 = $args['value'] ?? null; |
| 622 |
|
| 623 |
if(!isset($args['compare'])){ |
| 624 |
if(!empty($args['callable']) && (is_closure($value) || (is_callable($value) && is_array($value)))){ |
| 625 |
return $value($value2, $item); |
| 626 |
} |
| 627 |
|
| 628 |
if(isset($args['if_null']) && is_null($value)){ |
| 629 |
return $args['if_null']; |
| 630 |
} |
| 631 |
} |
| 632 |
|
| 633 |
if(is_array($value) || !empty($args['swap'])){ |
| 634 |
[$value, $value2] = [$value2, $value]; |
| 635 |
} |
| 636 |
|
| 637 |
return wpjam_compare($value, $args['compare'] ?? null, $value2, (bool)($args['strict'] ?? false)); |
| 638 |
} |
| 639 |
|
| 640 |
function wpjam_matches($arr, $args, $op='AND'){ |
| 641 |
$op = strtoupper($op); |
| 642 |
|
| 643 |
if(!in_array($op, ['AND', 'ALL', 'OR', 'ANY', 'NOT'])){ |
| 644 |
return false; |
| 645 |
} |
| 646 |
|
| 647 |
if(!is_callable($args)){ |
| 648 |
return wpjam_matches($args, fn($v, $k)=> wpjam_match($arr, ...(wpjam_is_assoc_array($v) ? [$v+['key'=>$k]] : [$k, $v])), $op); |
| 649 |
} |
| 650 |
|
| 651 |
if(in_array($op, ['AND', 'ALL'], true)){ |
| 652 |
return array_all($arr, $args); |
| 653 |
}elseif(in_array($op, ['OR', 'ANY'], true)){ |
| 654 |
return array_any($arr, $args); |
| 655 |
}else{ |
| 656 |
return !array_all($arr, $args); |
| 657 |
} |
| 658 |
} |
| 659 |
|
| 660 |
// Array |
| 661 |
function wpjam_is_assoc_array($arr){ |
| 662 |
return is_array($arr) && !wp_is_numeric_array($arr); |
| 663 |
} |
| 664 |
|
| 665 |
function wpjam_array($arr=null, $cb=null, $skip_null=false){ |
| 666 |
if(!$cb){ |
| 667 |
if(is_object($arr)){ |
| 668 |
if(method_exists($arr, 'to_array')){ |
| 669 |
return $arr->to_array(); |
| 670 |
}elseif($arr instanceof Traversable){ |
| 671 |
return iterator_to_array($arr); |
| 672 |
}else{ |
| 673 |
return ($arr instanceof JsonSerializable) && is_array($data = $arr->jsonSerialize()) ? $data : []; |
| 674 |
} |
| 675 |
} |
| 676 |
|
| 677 |
return (array)$arr; |
| 678 |
} |
| 679 |
|
| 680 |
$data = []; |
| 681 |
|
| 682 |
foreach($arr as $k => $v){ |
| 683 |
$r = $cb($k, $v); |
| 684 |
|
| 685 |
if(is_scalar($r)){ |
| 686 |
$k = $r; |
| 687 |
}elseif(is_array($r) && count($r) >= 2 && !($skip_null && is_null($r[1]))){ |
| 688 |
[$k, $v] = $r; |
| 689 |
}else{ |
| 690 |
continue; |
| 691 |
} |
| 692 |
|
| 693 |
$data = wpjam_set($data, $k, $v, '[]'); |
| 694 |
} |
| 695 |
|
| 696 |
return $data; |
| 697 |
} |
| 698 |
|
| 699 |
function wpjam_fill($keys, $cb){ |
| 700 |
return wpjam_array($keys, fn($i, $k)=> [$k, $cb($k, $i)], true); |
| 701 |
} |
| 702 |
|
| 703 |
function wpjam_pick($arr, $args){ |
| 704 |
return wpjam_array($args, fn($i, $k)=> [$k, wpjam_get($arr, $k)], true); |
| 705 |
} |
| 706 |
|
| 707 |
function wpjam_entries($items, $key=null, $value=null){ |
| 708 |
$key ??= 0; |
| 709 |
$value ??= (int)($key === 0); |
| 710 |
|
| 711 |
return wpjam_array($items, fn($k, $v)=> [null, [$key=>$k, $value=>$v]]); |
| 712 |
} |
| 713 |
|
| 714 |
function wpjam_column($items, $key=null, $index=null){ |
| 715 |
return wpjam_array($items, fn($k, $v)=> [ |
| 716 |
is_null($index) || $index === false ? null : ($index === true ? $k : $v[$index]), |
| 717 |
is_array($key) ? wpjam_array($key, fn($i, $j)=> [wpjam_is_assoc_array($key) ? $i : $j, wpjam_get($v, $j)], true) : wpjam_get($v, $key) |
| 718 |
]); |
| 719 |
} |
| 720 |
|
| 721 |
function wpjam_map($arr, $cb, $args=[]){ |
| 722 |
if($arr){ |
| 723 |
$args = is_bool($args) || $args === 'deep' ? ['deep'=>(bool)$args] : (is_string($args) ? ['mode'=>$args] : $args); |
| 724 |
$mode = str_split(in_array($args['mode'] ?? '', ['vk', 'kv', 'k', 'v']) ? $args['mode'] : 'vk'); |
| 725 |
$deep = $args['deep'] ?? false; |
| 726 |
$all = in_array($deep, [true, '*'], true); |
| 727 |
|
| 728 |
foreach($arr as $k => &$v){ |
| 729 |
$d = is_array($v) && ($all || (is_string($deep) && is_array($v[$deep] ?? ''))); |
| 730 |
$v = (!$d || $deep === '*') ? $cb(...array_map(fn($c) => $c === 'k' ? $k : $v, $mode)) : $v; |
| 731 |
$v = $d ? ($all ? wpjam_map($v, $cb, $args) : [$deep => wpjam_map($v[$deep], $cb, $args)]+$v) : $v; |
| 732 |
} |
| 733 |
|
| 734 |
unset($v); |
| 735 |
} |
| 736 |
|
| 737 |
return $arr; |
| 738 |
} |
| 739 |
|
| 740 |
function wpjam_reduce($arr, $cb, $carry=null, $key='', $args=[]){ |
| 741 |
$depth = $args['depth'] ??= 0; |
| 742 |
|
| 743 |
foreach(wpjam_array($arr) as $k => $v){ |
| 744 |
$carry = $cb($carry, $v, $k, $args); |
| 745 |
|
| 746 |
if($key && (empty($args['max_depth']) || $args['max_depth'] > $depth+1) && is_array($v)){ |
| 747 |
$sub = $key === true ? $v : wpjam_get($v, $key); |
| 748 |
$carry = is_array($sub) ? wpjam_reduce($sub, $cb, $carry, $key, ['depth'=>$depth+1]+$args) : $carry; |
| 749 |
} |
| 750 |
} |
| 751 |
|
| 752 |
return $carry; |
| 753 |
} |
| 754 |
|
| 755 |
function wpjam_nest($items, $options=[], $parent=null, $depth=0){ |
| 756 |
if(!$items){ |
| 757 |
return []; |
| 758 |
} |
| 759 |
|
| 760 |
$fields = array_filter($options['fields'] ?? [])+['id'=>'id', 'name'=>'name', 'parent'=>'parent', 'children'=>'children']; |
| 761 |
|
| 762 |
if($parent === null){ |
| 763 |
$group = wpjam_group($items, $fields['parent']); |
| 764 |
$group[0] = array_filter([$options['top'] ?? '']) ?: ($group[0] ?? array_first($group)); |
| 765 |
|
| 766 |
return wpjam_nest($group, $options, 0, 0); |
| 767 |
} |
| 768 |
|
| 769 |
$cb = $options['item_callback'] ?? ''; |
| 770 |
$max = $options['max_depth'] ?? 0; |
| 771 |
$format = $options['format'] ?? ''; |
| 772 |
$parsed = []; |
| 773 |
|
| 774 |
foreach(wpjam_pull($items, $parent) ?: [] as $item){ |
| 775 |
$item = $cb ? $cb($item) : $item; |
| 776 |
$children = (!$max || $max > $depth+1) ? wpjam_nest($items, $options, wpjam_get($item, $fields['id']), $depth+1) : []; |
| 777 |
$parsed[] = wpjam_set($item, ...($format == 'flat' |
| 778 |
? [$fields['name'], str_repeat(' ', $depth).wpjam_get($item, $fields['name'])] |
| 779 |
: [$fields['children'], $children] |
| 780 |
)); |
| 781 |
|
| 782 |
if($format == 'flat'){ |
| 783 |
$parsed = array_merge($parsed, $children); |
| 784 |
} |
| 785 |
} |
| 786 |
|
| 787 |
return $parsed; |
| 788 |
} |
| 789 |
|
| 790 |
function wpjam_at($arr, $index, ...$args){ |
| 791 |
if(is_string($arr)){ |
| 792 |
[$sep, $index] = is_int($index) ? [$args[0] ?? '', $index] : [$index, $args[0] ?? 0]; |
| 793 |
|
| 794 |
$sep && ($arr = explode($sep, $arr)); |
| 795 |
} |
| 796 |
|
| 797 |
if(is_array($arr) || is_string($arr)){ |
| 798 |
$count = is_array($arr) ? count($arr) : strlen($arr); |
| 799 |
$index = $index >= 0 ? $index : $count + $index; |
| 800 |
|
| 801 |
if($index >= 0 && $index < $count){ |
| 802 |
return is_string($arr) ? $arr[$index] : $arr[array_keys($arr)[$index]]; |
| 803 |
} |
| 804 |
} |
| 805 |
} |
| 806 |
|
| 807 |
function wpjam_add_at($arr, $index, $key, ...$args){ |
| 808 |
if(!$args && !is_array($key)){ |
| 809 |
$args = [$key]; |
| 810 |
$key = null; |
| 811 |
} |
| 812 |
|
| 813 |
if(is_null($key)){ |
| 814 |
array_splice($arr, $index, 0, $args); |
| 815 |
|
| 816 |
return $arr; |
| 817 |
} |
| 818 |
|
| 819 |
return array_replace(array_slice($arr, 0, $index, true), (is_array($key) ? $key : [$key=>$args[0] ?? '']))+array_slice($arr, $index, null, true); |
| 820 |
} |
| 821 |
|
| 822 |
function wpjam_rotate($arr, $step=1){ |
| 823 |
if(($count = count($arr)) <= 1 || ($step %= $count) === 0){ |
| 824 |
return $arr; |
| 825 |
} |
| 826 |
|
| 827 |
$step = $step < 0 ? $count + $step : $step; |
| 828 |
|
| 829 |
return [...array_slice($arr, $step), ...array_slice($arr, 0, $step)]; |
| 830 |
} |
| 831 |
|
| 832 |
function wpjam_find($arr, $cb, ...$args){ |
| 833 |
$output = 'value'; |
| 834 |
|
| 835 |
if($args){ |
| 836 |
if(is_callable($args[0])){ |
| 837 |
$output = 'result'; |
| 838 |
$mapper = $args[0]; |
| 839 |
}else{ |
| 840 |
$output = $args[0]; |
| 841 |
} |
| 842 |
} |
| 843 |
|
| 844 |
$cb = wpjam_is_assoc_array($cb) ? fn($v)=> wpjam_matches($v, $cb) : ($cb ?: fn()=> true); |
| 845 |
$cb = $cb === true ? fn($v)=> $v : $cb; |
| 846 |
|
| 847 |
if(!$cb){ |
| 848 |
return; |
| 849 |
} |
| 850 |
|
| 851 |
if($output == 'value'){ |
| 852 |
return array_find($arr, $cb); |
| 853 |
} |
| 854 |
|
| 855 |
if($output == 'key'){ |
| 856 |
return array_find_key($arr, $cb); |
| 857 |
} |
| 858 |
|
| 859 |
if($output == 'index'){ |
| 860 |
return array_search(array_find_key($arr, $cb), array_keys($arr)); |
| 861 |
} |
| 862 |
|
| 863 |
if($output == 'result'){ |
| 864 |
foreach($arr as $k => $v){ |
| 865 |
$v = $mapper($v, $k); |
| 866 |
|
| 867 |
if($cb($v)){ |
| 868 |
return $v; |
| 869 |
} |
| 870 |
} |
| 871 |
} |
| 872 |
} |
| 873 |
|
| 874 |
function wpjam_group($arr, $field){ |
| 875 |
$cb = is_closure($field) ? $field : fn($v) => wpjam_get($v, $field); |
| 876 |
|
| 877 |
return wpjam_reduce($arr, fn($c, $v, $k)=> wpjam_set($c, [$cb($v, $k), $k], $v), []); |
| 878 |
} |
| 879 |
|
| 880 |
function wpjam_pull(&$arr, $key, ...$args){ |
| 881 |
$value = (is_array($key) ? 'wpjam_pick' : 'wpjam_get')($arr, $key, ...$args); |
| 882 |
$arr = wpjam_except($arr, $key); |
| 883 |
|
| 884 |
return $value; |
| 885 |
} |
| 886 |
|
| 887 |
function wpjam_assoc($arr){ |
| 888 |
if(!wp_is_numeric_array($arr) && (!($sub = wpjam_filter($arr, fn($v, $k) => is_int($k))) || !array_is_list($sub))){ |
| 889 |
return $arr; |
| 890 |
} |
| 891 |
|
| 892 |
return wpjam_array($arr, fn($k, $v)=> is_int($k) ? $v : $k); |
| 893 |
} |
| 894 |
|
| 895 |
function wpjam_except($arr, $key, ...$args){ |
| 896 |
if(is_object($arr)){ |
| 897 |
foreach((array)$key as $k){ |
| 898 |
unset($arr->$k); |
| 899 |
} |
| 900 |
|
| 901 |
return $arr; |
| 902 |
} |
| 903 |
|
| 904 |
if(!is_array($arr)){ |
| 905 |
trigger_error(var_export($arr, true)); |
| 906 |
return $arr; |
| 907 |
} |
| 908 |
|
| 909 |
if(is_array($key) || wpjam_exists($arr, $key)){ |
| 910 |
return array_diff_key($arr, is_array($key) ? array_flip($key) : [$key=>'']); |
| 911 |
} |
| 912 |
|
| 913 |
if(str_ends_with($key, '[]') && $args){ |
| 914 |
return wpjam_set($arr, substr($key, 0, -2), array_diff(wpjam_get($arr, $key, [], '[]'), $args), '[]'); |
| 915 |
} |
| 916 |
|
| 917 |
$key = wpjam_keys($key, ...$args); |
| 918 |
$sub = &$arr; |
| 919 |
|
| 920 |
while($key){ |
| 921 |
$k = array_shift($key); |
| 922 |
|
| 923 |
if(empty($key)){ |
| 924 |
unset($sub[$k]); |
| 925 |
}elseif(wpjam_exists($sub, $k)){ |
| 926 |
$sub = &$sub[$k]; |
| 927 |
}else{ |
| 928 |
break; |
| 929 |
} |
| 930 |
} |
| 931 |
|
| 932 |
return $arr; |
| 933 |
} |
| 934 |
|
| 935 |
function wpjam_merge($arr, $data){ |
| 936 |
foreach($data as $k => $v){ |
| 937 |
$arr[$k] = ((wpjam_is_assoc_array($v) || $v === []) && isset($arr[$k]) && wpjam_is_assoc_array($arr[$k])) ? wpjam_merge($arr[$k], $v) : $v; |
| 938 |
} |
| 939 |
|
| 940 |
return $arr; |
| 941 |
} |
| 942 |
|
| 943 |
function wpjam_diff($arr, $data, $compare='value'){ |
| 944 |
if($compare == 'value' && array_is_list($arr) && array_is_list($data)){ |
| 945 |
return array_values(array_diff($arr, $data)); |
| 946 |
} |
| 947 |
|
| 948 |
foreach($data as $k => $v){ |
| 949 |
if(isset($arr[$k])){ |
| 950 |
if(wpjam_is_assoc_array($v) && wpjam_is_assoc_array($arr[$k])){ |
| 951 |
$arr[$k] = wpjam_diff($arr[$k], $v, $compare); |
| 952 |
|
| 953 |
if(!$arr[$k]){ |
| 954 |
unset($arr[$k]); |
| 955 |
} |
| 956 |
}else{ |
| 957 |
if($compare == 'key' || $arr[$k] == $v){ |
| 958 |
unset($arr[$k]); |
| 959 |
} |
| 960 |
} |
| 961 |
} |
| 962 |
} |
| 963 |
|
| 964 |
return $arr; |
| 965 |
} |
| 966 |
|
| 967 |
function wpjam_toggle($arr, $data){ |
| 968 |
return array_merge(array_diff($arr, $data), array_diff($data, $arr)); |
| 969 |
} |
| 970 |
|
| 971 |
function wpjam_filter($arr, $cb=null, ...$args){ |
| 972 |
$list = array_is_list($arr); |
| 973 |
|
| 974 |
if($cb === 'unique'){ |
| 975 |
$arr = array_unique($arr); |
| 976 |
}elseif($cb && is_array($cb) && !is_callable($cb)){ |
| 977 |
$arr = wpjam_is_assoc_array($cb) ? array_filter($arr, fn($v)=> wpjam_matches($v, $cb, ...$args)) : array_intersect_key($arr, array_flip($cb)); |
| 978 |
}elseif($cb){ |
| 979 |
$arr = ($args[0] ?? ($cb == 'isset')) ? array_map(fn($v)=> is_array($v) ? wpjam_filter($v, $cb, true) : $v, $arr) : $arr; |
| 980 |
$arr = array_filter($arr, $cb === 'isset' ? fn($v)=> !is_null($v) : $cb, ARRAY_FILTER_USE_BOTH); |
| 981 |
}else{ |
| 982 |
$arr = array_filter($arr); |
| 983 |
} |
| 984 |
|
| 985 |
return $list ? array_values($arr) : $arr; |
| 986 |
} |
| 987 |
|
| 988 |
function wpjam_sort($arr, ...$args){ |
| 989 |
if(count($arr) <= 1){ |
| 990 |
return $arr; |
| 991 |
} |
| 992 |
|
| 993 |
if(!$args || is_int($args[0])){ |
| 994 |
sort($arr, ...$args); |
| 995 |
|
| 996 |
return $arr; |
| 997 |
} |
| 998 |
|
| 999 |
if(in_array($args[0], ['', 'k', 'a', 'kr', 'ar', 'r'], true)){ |
| 1000 |
(array_shift($args).'sort')($arr, ...$args); |
| 1001 |
|
| 1002 |
return $arr; |
| 1003 |
} |
| 1004 |
|
| 1005 |
$is_asc = fn($v)=> is_int($v) ? $v === SORT_ASC : strtolower($v) === 'asc'; |
| 1006 |
|
| 1007 |
if(wpjam_is_assoc_array($args[0])){ |
| 1008 |
$args = wpjam_reduce($args[0], fn($carry, $order, $field)=>[ |
| 1009 |
...$carry, |
| 1010 |
($column = array_column($arr, $field)), |
| 1011 |
$is_asc($order) ? SORT_ASC : SORT_DESC, |
| 1012 |
is_numeric(array_first($column)) ? SORT_NUMERIC : SORT_REGULAR |
| 1013 |
], []); |
| 1014 |
}elseif(is_callable($args[0]) || is_string($args[0])){ |
| 1015 |
$field = $args[0]; |
| 1016 |
$order = $args[1] ?? ''; |
| 1017 |
|
| 1018 |
if(is_callable($field)){ |
| 1019 |
$column = array_map($field, ($order === 'key' ? array_keys($arr) : $arr)); |
| 1020 |
$flag = $args[2] ?? SORT_NUMERIC; |
| 1021 |
}else{ |
| 1022 |
$default= $args[2] ?? 0; |
| 1023 |
$column = array_map(fn($item)=> wpjam_get($item, $field, $default), $arr); |
| 1024 |
$flag = is_numeric($default) ? SORT_NUMERIC : SORT_REGULAR; |
| 1025 |
} |
| 1026 |
|
| 1027 |
$args = [$column, ($is_asc($order) ? SORT_ASC : SORT_DESC), $flag]; |
| 1028 |
} |
| 1029 |
|
| 1030 |
array_push($args, range(1, count($arr)), SORT_ASC, SORT_NUMERIC); |
| 1031 |
|
| 1032 |
if(wp_is_numeric_array($arr)){ |
| 1033 |
$keys = array_keys($arr); |
| 1034 |
$args[] = &$keys; |
| 1035 |
} |
| 1036 |
|
| 1037 |
$args[] = &$arr; |
| 1038 |
|
| 1039 |
array_multisort(...$args); |
| 1040 |
|
| 1041 |
return isset($keys) ? array_combine($keys, $arr) : $arr; |
| 1042 |
} |
| 1043 |
|
| 1044 |
function wpjam_exists($arr, $key){ |
| 1045 |
return is_array($arr) ? array_key_exists($key, $arr) : (is_object($arr) ? isset($arr->$key) : false); |
| 1046 |
} |
| 1047 |
|
| 1048 |
function wpjam_keys($key, ...$args){ |
| 1049 |
if(!$args){ |
| 1050 |
return wpjam_keys($key, '[]') ?: (wpjam_keys($key, '.') ?: []); |
| 1051 |
} |
| 1052 |
|
| 1053 |
$keys = []; |
| 1054 |
|
| 1055 |
if($args[0] == '.'){ |
| 1056 |
if(str_contains($key, '.')){ |
| 1057 |
return explode('.', $key); |
| 1058 |
} |
| 1059 |
}elseif($args[0] == '[]'){ |
| 1060 |
$total = strlen($key); |
| 1061 |
$cursor = 0; |
| 1062 |
|
| 1063 |
while($cursor < $total){ |
| 1064 |
$offset = $keys ? 1 : 0; |
| 1065 |
$len = $offset && $key[$cursor] !== '[' ? 0 : strcspn($key, $offset ? ']' : '[', $cursor); |
| 1066 |
$sub = ($len > $offset && $len < $total-$cursor) ? substr($key, $cursor+$offset, $len-$offset) : ''; |
| 1067 |
|
| 1068 |
if($sub === '' || str_contains($sub, $offset ? '[' : ']')){ |
| 1069 |
return []; |
| 1070 |
} |
| 1071 |
|
| 1072 |
$keys[] = $sub; |
| 1073 |
$cursor += $len + $offset; |
| 1074 |
} |
| 1075 |
} |
| 1076 |
|
| 1077 |
return $keys; |
| 1078 |
} |
| 1079 |
|
| 1080 |
function wpjam_names($name){ |
| 1081 |
return is_array($name) |
| 1082 |
? array_shift($name).($name ? '['.implode('][', $name).']' : '') |
| 1083 |
: ($name ? (wpjam_keys($name, '[]') ?: [$name]) : []); |
| 1084 |
} |
| 1085 |
|
| 1086 |
function wpjam_get($arr, $key, $default=null, ...$args){ |
| 1087 |
if(is_object($arr)){ |
| 1088 |
return $arr->$key ?? $default; |
| 1089 |
} |
| 1090 |
|
| 1091 |
if(!is_array($arr)){ |
| 1092 |
trigger_error(var_export($arr, true)); |
| 1093 |
return $default; |
| 1094 |
} |
| 1095 |
|
| 1096 |
if(!is_array($key)){ |
| 1097 |
if(isset($key) && wpjam_exists($arr, $key)){ |
| 1098 |
return $arr[$key]; |
| 1099 |
} |
| 1100 |
|
| 1101 |
if(is_null($key)){ |
| 1102 |
return $arr; |
| 1103 |
} |
| 1104 |
|
| 1105 |
if(!$args || $args[0] === '[]'){ |
| 1106 |
if($key === '[]'){ |
| 1107 |
return $arr; |
| 1108 |
} |
| 1109 |
|
| 1110 |
if(str_ends_with($key, '[]')){ |
| 1111 |
$value = wpjam_get($arr, substr($key, 0, -2), $default, '[]'); |
| 1112 |
|
| 1113 |
return is_object($value) ? [$value] : (array)$value; |
| 1114 |
} |
| 1115 |
} |
| 1116 |
|
| 1117 |
$key = wpjam_keys($key, ...$args); |
| 1118 |
} |
| 1119 |
|
| 1120 |
return _wp_array_get($arr, $key, $default); |
| 1121 |
} |
| 1122 |
|
| 1123 |
function wpjam_set($arr, $key, ...$args){ |
| 1124 |
if(wpjam_is_assoc_array($key)){ |
| 1125 |
if(!$args){ // del 2026-12-31 |
| 1126 |
return wpjam_reduce($key, fn($c, $v, $k)=> wpjam_set($c, $k, $v, ...$args), $arr); |
| 1127 |
} |
| 1128 |
|
| 1129 |
trigger_error(var_export($key, true)); |
| 1130 |
} |
| 1131 |
|
| 1132 |
$value = array_shift($args); |
| 1133 |
|
| 1134 |
if(is_object($arr)){ |
| 1135 |
$arr->$key = $value; |
| 1136 |
|
| 1137 |
return $arr; |
| 1138 |
} |
| 1139 |
|
| 1140 |
if(!is_array($arr)){ |
| 1141 |
trigger_error(var_export($arr, true)); |
| 1142 |
return $arr; |
| 1143 |
} |
| 1144 |
|
| 1145 |
if(!is_array($key)){ |
| 1146 |
if(isset($key) && wpjam_exists($arr, $key)){ |
| 1147 |
$arr[$key] = $value; |
| 1148 |
|
| 1149 |
return $arr; |
| 1150 |
} |
| 1151 |
|
| 1152 |
if(is_null($key)){ |
| 1153 |
$arr[] = $value; |
| 1154 |
|
| 1155 |
return $arr; |
| 1156 |
} |
| 1157 |
|
| 1158 |
if(!$args || $args[0] === '[]'){ |
| 1159 |
if($key === '[]'){ |
| 1160 |
$arr[] = $value; |
| 1161 |
|
| 1162 |
return $arr; |
| 1163 |
} |
| 1164 |
|
| 1165 |
if(str_ends_with($key, '[]')){ |
| 1166 |
$items = wpjam_get($arr, $key, [], '[]'); |
| 1167 |
$items[] = $value; |
| 1168 |
|
| 1169 |
return wpjam_set($arr, substr($key, 0, -2), $items, '[]'); |
| 1170 |
} |
| 1171 |
} |
| 1172 |
|
| 1173 |
$key = wpjam_keys($key, ...$args) ?: [$key]; |
| 1174 |
} |
| 1175 |
|
| 1176 |
_wp_array_set($arr, $key, $value); |
| 1177 |
|
| 1178 |
return $arr; |
| 1179 |
} |
| 1180 |
|
| 1181 |
function wpjam_pack($value, $key){ |
| 1182 |
return is_null($key) ? $value : wpjam_set([], $key, $value); |
| 1183 |
} |
| 1184 |
|
| 1185 |
function wpjam_some($arr, $cb){ |
| 1186 |
foreach($arr as $k => $v){ |
| 1187 |
if($cb($v, $k)){ |
| 1188 |
return true; |
| 1189 |
} |
| 1190 |
} |
| 1191 |
|
| 1192 |
return false; |
| 1193 |
} |
| 1194 |
|
| 1195 |
function wpjam_every($arr, $cb){ |
| 1196 |
foreach($arr as $k => $v){ |
| 1197 |
if(!$cb($v, $k)){ |
| 1198 |
return false; |
| 1199 |
} |
| 1200 |
} |
| 1201 |
|
| 1202 |
return true; |
| 1203 |
} |
| 1204 |
|
| 1205 |
function wpjam_lines($str, ...$args){ |
| 1206 |
$sep = ($args && is_closure($args[0]) ? '' : array_shift($args)) ?: "\n"; |
| 1207 |
$cb = array_shift($args); |
| 1208 |
$lines = []; |
| 1209 |
|
| 1210 |
foreach(explode($sep, (string)$str) as $v){ |
| 1211 |
$v = trim($v); |
| 1212 |
$v = $cb ? $cb($v) : $v; |
| 1213 |
|
| 1214 |
if(!is_blank($v)){ |
| 1215 |
$lines[] = $v; |
| 1216 |
} |
| 1217 |
} |
| 1218 |
|
| 1219 |
return $lines; |
| 1220 |
} |
| 1221 |
|
| 1222 |
if(!function_exists('array_pull')){ |
| 1223 |
function array_pull(&$arr, $key, ...$args){ |
| 1224 |
return wpjam_pull($arr, $key, ...$args); |
| 1225 |
} |
| 1226 |
} |
| 1227 |
|
| 1228 |
if(!function_exists('array_except')){ |
| 1229 |
function array_except($array, ...$keys){ |
| 1230 |
return wpjam_except($array, (($keys && is_array($keys[0])) ? $keys[0] : $keys)); |
| 1231 |
} |
| 1232 |
} |
| 1233 |
|
| 1234 |
if(!function_exists('array_first')){ |
| 1235 |
function array_first($array){ |
| 1236 |
return $array === [] ? null : $array[array_key_first($array)]; |
| 1237 |
} |
| 1238 |
} |
| 1239 |
|
| 1240 |
if(!function_exists('array_last')){ |
| 1241 |
function array_last($array){ |
| 1242 |
return $array === [] ? null : $array[array_key_last($array)]; |
| 1243 |
} |
| 1244 |
} |
| 1245 |
|
| 1246 |
function wpjam_move($arr, $id, $data){ |
| 1247 |
$arr = array_values($arr); |
| 1248 |
$index = array_search($id, $arr); |
| 1249 |
$arr = wpjam_diff($arr, [$id]); |
| 1250 |
|
| 1251 |
$index === false && wpjam_throw('invalid_id', '无效的 ID'); |
| 1252 |
|
| 1253 |
if(isset($data['pos'])){ |
| 1254 |
$index = $data['pos']; |
| 1255 |
}elseif(!empty($data['up'])){ |
| 1256 |
$index == 0 && wpjam_throw('invalid_position', '已经是第一个了,不可上移了!'); |
| 1257 |
|
| 1258 |
$index--; |
| 1259 |
}elseif(!empty($data['down'])){ |
| 1260 |
$index == count($arr) && wpjam_throw('invalid_position', '已经最后一个了,不可下移了!'); |
| 1261 |
|
| 1262 |
$index++; |
| 1263 |
}else{ |
| 1264 |
$k = array_find(['next', 'prev'], fn($k)=> isset($data[$k])); |
| 1265 |
$index = ($k && isset($data[$k])) ? array_search($data[$k], $arr) : false; |
| 1266 |
|
| 1267 |
$index === false && wpjam_throw('invalid_position', '无效的移动位置'); |
| 1268 |
|
| 1269 |
$index += $k == 'prev' ? 1 : 0; |
| 1270 |
} |
| 1271 |
|
| 1272 |
return wpjam_add_at($arr, $index, null, $id); |
| 1273 |
} |
| 1274 |
|
| 1275 |
// Bit |
| 1276 |
function wpjam_has_bit($value, $bit){ |
| 1277 |
return ((int)$value & (int)$bit) == $bit; |
| 1278 |
} |
| 1279 |
|
| 1280 |
function wpjam_add_bit($value, $bit){ |
| 1281 |
return (int)$value | (int)$bit; |
| 1282 |
} |
| 1283 |
|
| 1284 |
function wpjam_remove_bit($value, $bit){ |
| 1285 |
return (int)$value & (~(int)$bit); |
| 1286 |
} |
| 1287 |
|
| 1288 |
// UUID |
| 1289 |
function wpjam_create_uuid(){ |
| 1290 |
$chars = md5(uniqid(mt_rand(), true)); |
| 1291 |
|
| 1292 |
return implode('-', array_map(fn($v)=> substr($chars, ...$v), [[0, 8], [8, 4], [12, 4], [16, 4], [20, 12]])); |
| 1293 |
} |
| 1294 |
|
| 1295 |
// Str |
| 1296 |
if(!function_exists('explode_last')){ |
| 1297 |
function explode_last($sep, $str, $limit=2){ |
| 1298 |
$parts = explode($sep, $str); |
| 1299 |
$count = count($parts); |
| 1300 |
|
| 1301 |
return $limit >= $count ? $parts : [implode($sep, array_splice($parts, 0, $count - $limit + 1)), ...$parts]; |
| 1302 |
} |
| 1303 |
} |
| 1304 |
|
| 1305 |
if(!function_exists('try_fix')){ |
| 1306 |
function try_fix($type, &$str, ...$args){ |
| 1307 |
$action = count($args) > 1 && in_array($args[0], ['+', '-']) ? array_shift($args) : '+'; |
| 1308 |
$fix = array_shift($args); |
| 1309 |
$has = $type == 'prefix' ? str_starts_with($str, $fix) : str_ends_with($str, $fix); |
| 1310 |
$res = $has !== ($action == '+'); |
| 1311 |
|
| 1312 |
if($res){ |
| 1313 |
$str = $type == 'prefix' |
| 1314 |
? ($has ? substr($str, strlen($fix)) : $fix.$str) |
| 1315 |
: ($has ? substr($str, 0, -strlen($fix)) : $str.$fix); |
| 1316 |
} |
| 1317 |
|
| 1318 |
return $res; |
| 1319 |
} |
| 1320 |
} |
| 1321 |
|
| 1322 |
if(!function_exists('try_prefix')){ |
| 1323 |
function try_prefix(&$str, ...$args){ |
| 1324 |
return try_fix('prefix', $str, ...$args); |
| 1325 |
} |
| 1326 |
} |
| 1327 |
|
| 1328 |
if(!function_exists('try_suffix')){ |
| 1329 |
function try_suffix(&$str, ...$args){ |
| 1330 |
return try_fix('suffix', $str, ...$args); |
| 1331 |
} |
| 1332 |
} |
| 1333 |
|
| 1334 |
function wpjam_prefix($str, ...$args){ |
| 1335 |
try_prefix($str, ...$args); |
| 1336 |
|
| 1337 |
return $str; |
| 1338 |
} |
| 1339 |
|
| 1340 |
function wpjam_suffix($str, ...$args){ |
| 1341 |
try_suffix($str, ...$args); |
| 1342 |
|
| 1343 |
return $str; |
| 1344 |
} |
| 1345 |
|
| 1346 |
function wpjam_join($sep, ...$args){ |
| 1347 |
return join($sep, array_filter(($args && is_array($args[0])) ? $args[0] : $args)); |
| 1348 |
} |
| 1349 |
|
| 1350 |
function wpjam_remove_pre_tab($str, $times=1){ |
| 1351 |
return preg_replace('/^\t{'.$times.'}/m', '', $str); |
| 1352 |
} |
| 1353 |
|
| 1354 |
function wpjam_preg_replace($pattern, $replace, $subject, $limit=-1, &$count=null, $flags=0){ |
| 1355 |
$result = is_closure($replace) ? preg_replace_callback($pattern, $replace, $subject, $limit, $count, $flags) : preg_replace($pattern, $replace, $subject, $limit, $count); |
| 1356 |
|
| 1357 |
if(is_null($result)){ |
| 1358 |
trigger_error(preg_last_error_msg()); |
| 1359 |
return $subject; |
| 1360 |
} |
| 1361 |
|
| 1362 |
return $result; |
| 1363 |
} |
| 1364 |
|
| 1365 |
function wpjam_serialize($data){ |
| 1366 |
return maybe_serialize(wpjam_sort(wpjam_map($data, fn($v)=> is_closure($v) ? spl_object_hash($v) : $v, true), 'k')); |
| 1367 |
} |
| 1368 |
|
| 1369 |
function wpjam_unserialize($serialized, $cb=null){ |
| 1370 |
if($serialized){ |
| 1371 |
$result = @unserialize($serialized, ['allowed_classes'=>false]); |
| 1372 |
|
| 1373 |
if(!$result){ |
| 1374 |
$fixed = preg_replace_callback('!s:(\d+):"(.*?)";!', fn($m)=> 's:'.strlen($m[2]).':"'.$m[2].'";', $serialized); |
| 1375 |
$result = @unserialize($fixed, ['allowed_classes'=>false]); |
| 1376 |
|
| 1377 |
$result && $cb && $cb($fixed); |
| 1378 |
} |
| 1379 |
|
| 1380 |
return $result; |
| 1381 |
} |
| 1382 |
} |
| 1383 |
|
| 1384 |
// 去掉非 utf8mb4 字符 |
| 1385 |
function wpjam_strip_invalid_text($text){ |
| 1386 |
return $text ? iconv('UTF-8', 'UTF-8//IGNORE', $text) : ''; |
| 1387 |
} |
| 1388 |
|
| 1389 |
// 去掉 4字节 字符 |
| 1390 |
function wpjam_strip_4_byte_chars($text){ |
| 1391 |
return $text ? preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $text) : ''; |
| 1392 |
// \xEF\xBF\xBD 常用来表示未知、未识别或不可表示的字符 |
| 1393 |
} |
| 1394 |
|
| 1395 |
// 移除 除了 line feeds 和 carriage returns 所有控制字符 |
| 1396 |
function wpjam_strip_control_chars($text){ |
| 1397 |
return $text ? preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F]/u', '', $text) : ''; |
| 1398 |
// /[\x00-\x09\x0B\x0C\x0E-\x1F\x80-\x9F]/u |
| 1399 |
} |
| 1400 |
|
| 1401 |
//获取第一段 |
| 1402 |
function wpjam_get_first_p($text){ |
| 1403 |
$text = wp_strip_all_tags($text); |
| 1404 |
$line = strtok($text, "\n"); |
| 1405 |
|
| 1406 |
while($line !== false){ |
| 1407 |
if($line = trim($line)){ |
| 1408 |
return $line; |
| 1409 |
} |
| 1410 |
|
| 1411 |
$line = strtok("\n"); |
| 1412 |
} |
| 1413 |
|
| 1414 |
return ''; |
| 1415 |
} |
| 1416 |
|
| 1417 |
function wpjam_unicode_decode($text){ |
| 1418 |
return wpjam_preg_replace('/\\\\u(?!00[0-7][0-9A-F])[0-9a-fA-F]{4}/i', fn($m)=> json_decode('"'.$m[0].'"') ?: $m[0], $text); |
| 1419 |
} |
| 1420 |
|
| 1421 |
function wpjam_zh_urlencode($url){ |
| 1422 |
return $url ? wpjam_preg_replace('/[\x{4e00}-\x{9fa5}]+/u', fn($m)=> urlencode($m[0]), $url) : ''; |
| 1423 |
} |
| 1424 |
|
| 1425 |
// 检查非法字符 |
| 1426 |
function wpjam_blacklist_check($text, $name='� |
| 1427 |
容'){ |
| 1428 |
$pre = $text ? apply_filters('wpjam_pre_blacklist_check', null, $text, $name) : false; |
| 1429 |
|
| 1430 |
if(isset($pre)){ |
| 1431 |
return $pre; |
| 1432 |
} |
| 1433 |
|
| 1434 |
$key = strtok(get_option('disallowed_keys'), "\n"); |
| 1435 |
|
| 1436 |
while($key !== false){ |
| 1437 |
if(($key = trim($key)) && stripos($text, $key) !== false){ |
| 1438 |
return true; |
| 1439 |
} |
| 1440 |
|
| 1441 |
$key = strtok("\n"); |
| 1442 |
} |
| 1443 |
|
| 1444 |
return false; |
| 1445 |
} |
| 1446 |
|
| 1447 |
function wpjam_expandable($str, $num=10, $name=null){ |
| 1448 |
if(is_a($str, 'WPJAM_Tag') || count(explode("\n", $str)) > $num){ |
| 1449 |
static $index = 0; |
| 1450 |
|
| 1451 |
$name = 'expandable_'.($name ?? (++$index)); |
| 1452 |
|
| 1453 |
return '<div class="expandable-container"><input type="checkbox" class="button" id="'.esc_attr($name).'" /><div class="inner">'.$str.'</div></div>'; |
| 1454 |
} |
| 1455 |
|
| 1456 |
return $str; |
| 1457 |
} |
| 1458 |
|
| 1459 |
function wpjam_get_current_page_url(){ |
| 1460 |
return set_url_scheme('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); |
| 1461 |
} |
| 1462 |
|
| 1463 |
// Date |
| 1464 |
function wpjam_date($format, $ts=null){ |
| 1465 |
$ts ??= time(); |
| 1466 |
$dt = $ts ? date_create('@'.$ts) : null; |
| 1467 |
|
| 1468 |
return $dt ? $dt->setTimezone(wp_timezone())->format($format) : ''; |
| 1469 |
} |
| 1470 |
|
| 1471 |
function wpjam_strtotime($str){ |
| 1472 |
$dt = $str ? date_create($str, wp_timezone()) : null; |
| 1473 |
|
| 1474 |
return $dt ? $dt->getTimestamp() : 0; |
| 1475 |
} |
| 1476 |
|
| 1477 |
function wpjam_human_time_diff($from, $to=0){ |
| 1478 |
return sprintf(__('%s '.(($to ?: time()) > $from ? 'ago' : 'from now'), 'wpjam'), human_time_diff($from, $to)); |
| 1479 |
} |
| 1480 |
|
| 1481 |
function wpjam_human_date_diff($from, $to=0){ |
| 1482 |
$zone = wp_timezone(); |
| 1483 |
$to = $to ? date_create($to, $zone) : current_datetime(); |
| 1484 |
$from = date_create($from, $zone); |
| 1485 |
$day = [ |
| 1486 |
0 => __('Today', 'wpjam'), |
| 1487 |
-1 => __('Yesterday', 'wpjam'), |
| 1488 |
-2 => __('The day before yesterday', 'wpjam'), |
| 1489 |
1 => __('Tomorrow', 'wpjam'), |
| 1490 |
2 => __('The day after tomorrow', 'wpjam') |
| 1491 |
][(int)$to->diff($from)->format('%R%a')] ?? ''; |
| 1492 |
|
| 1493 |
return $day ?: ($from->format('W') == $to->format('W') ? __($from->format('l'), 'wpjam') : $from->format(__('F, Y', 'wpjam'))); |
| 1494 |
} |
| 1495 |
|
| 1496 |
// Video |
| 1497 |
function wpjam_get_video_mp4($id_or_url){ |
| 1498 |
if(filter_var($id_or_url, FILTER_VALIDATE_URL)){ |
| 1499 |
if(preg_match('#http://www.miaopai.com/show/(.*?).htm#i',$id_or_url, $matches)){ |
| 1500 |
return 'http://gslb.miaopai.com/stream/'.esc_attr($matches[1]).'.mp4'; |
| 1501 |
} |
| 1502 |
|
| 1503 |
return ($id = wpjam_get_qqv_id($id_or_url)) ? wpjam_get_qqv_mp4($id) : wpjam_zh_urlencode($id_or_url); |
| 1504 |
} |
| 1505 |
|
| 1506 |
return wpjam_get_qqv_mp4($id_or_url); |
| 1507 |
} |
| 1508 |
|
| 1509 |
function wpjam_get_qqv_mp4($vid, $cache=true){ |
| 1510 |
strlen($vid) > 20 && wpjam_throw('error', '无效的� |
| 1511 |
�讯视频'); |
| 1512 |
|
| 1513 |
if($cache){ |
| 1514 |
return wpjam_transient('qqv_mp4:'.$vid, fn()=> wpjam_get_qqv_mp4($vid, false), HOUR_IN_SECONDS*6); |
| 1515 |
} |
| 1516 |
|
| 1517 |
$resp = wpjam_remote_request('http://vv.video.qq.com/getinfo?otype=json&platform=11001&vid='.$vid, ['timeout'=>4, 'throw'=>true]); |
| 1518 |
$resp = trim(substr($resp, strpos($resp, '{')),';'); |
| 1519 |
$resp = wpjam_try('wpjam_json_decode', $resp); |
| 1520 |
|
| 1521 |
empty($resp['vl']) && wpjam_throw('error', '� |
| 1522 |
�讯视频不存在或� |
| 1523 |
为收费视频!'); |
| 1524 |
|
| 1525 |
$u = $resp['vl']['vi'][0]; |
| 1526 |
|
| 1527 |
return $u['ul']['ui'][0]['url'].$u['fn'].'?vkey='.$u['fvkey']; |
| 1528 |
} |
| 1529 |
|
| 1530 |
function wpjam_get_qqv_id($id_or_url){ |
| 1531 |
if(filter_var($id_or_url, FILTER_VALIDATE_URL)){ |
| 1532 |
return wpjam_find(['page', 'cover/.*'], true, fn($v)=> preg_match('#https://v.qq.com/x/'.$v.'/(.*?).html#i', $id_or_url, $m) ? $m[1] : '') ?: ''; |
| 1533 |
} |
| 1534 |
|
| 1535 |
return $id_or_url; |
| 1536 |
} |
| 1537 |
|
| 1538 |
function wpjam_is_mobile_number($number){ |
| 1539 |
return preg_match('/^0{0,1}(1[3,5,8][0-9]|14[5,7]|166|17[0,1,3,6,7,8]|19[8,9])[0-9]{8}$/', $number); |
| 1540 |
} |
| 1541 |
|
| 1542 |
function wpjam_set_cookie($key, $value, $expire=DAY_IN_SECONDS){ |
| 1543 |
if(is_null($value)){ |
| 1544 |
unset($_COOKIE[$key]); |
| 1545 |
|
| 1546 |
$expire = time()-YEAR_IN_SECONDS; |
| 1547 |
}else{ |
| 1548 |
$_COOKIE[$key] = $value; |
| 1549 |
|
| 1550 |
$expire += $expire < time() ? time() : 0; |
| 1551 |
} |
| 1552 |
|
| 1553 |
setcookie($key, $value ?? '', $expire, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true); |
| 1554 |
|
| 1555 |
COOKIEPATH != SITECOOKIEPATH && setcookie($key, $value ?? '', $expire, SITECOOKIEPATH, COOKIE_DOMAIN, is_ssl(), true); |
| 1556 |
} |
| 1557 |
|
| 1558 |
function wpjam_clear_cookie($key){ |
| 1559 |
wpjam_set_cookie($key, null); |
| 1560 |
} |
| 1561 |
|
| 1562 |
function wpjam_get_filter_name($name, $type){ |
| 1563 |
return (str_starts_with($name, 'wpjam') ? '' : 'wpjam_').str_replace('-', '_', $name).'_'.$type; |
| 1564 |
} |
| 1565 |
|