Issues (31)

src/StringTool.php (4 issues)

1
<?php
2
namespace tinymeng\tools;
3
/**
4
 * Class 字符串类
5
 * @package tinymeng\tools
6
 * @Author: TinyMeng <[email protected]>
7
 * @Created: 2018/11/26
8
 */
9
class StringTool
10
{
11
    protected static $snakeCache = [];
12
13
    protected static $camelCache = [];
14
15
    protected static $studlyCache = [];
16
17
    /**
18
     * 检查字符串中是否包含某些字符串
19
     * @param string       $haystack
20
     * @param string|array $needles
21
     * @return bool
22
     */
23
    public static function contains(string $haystack, $needles): bool
24
    {
25
        foreach ((array) $needles as $needle) {
26
            if ('' != $needle && mb_strpos($haystack, $needle) !== false) {
27
                return true;
28
            }
29
        }
30
31
        return false;
32
    }
33
34
    /**
35
     * 检查字符串是否以某些字符串结尾
36
     *
37
     * @param  string       $haystack
38
     * @param  string|array $needles
39
     * @return bool
40
     */
41
    public static function endsWith(string $haystack, $needles): bool
42
    {
43
        foreach ((array) $needles as $needle) {
44
            if ((string) $needle === static::substr($haystack, -static::length($needle))) {
45
                return true;
46
            }
47
        }
48
49
        return false;
50
    }
51
52
    /**
53
     * 检查字符串是否以某些字符串开头
54
     *
55
     * @param  string       $haystack
56
     * @param  string|array $needles
57
     * @return bool
58
     */
59
    public static function startsWith(string $haystack, $needles): bool
60
    {
61
        foreach ((array) $needles as $needle) {
62
            if ('' != $needle && mb_strpos($haystack, $needle) === 0) {
63
                return true;
64
            }
65
        }
66
67
        return false;
68
    }
69
70
    /**
71
     * 获取指定长度的随机字母数字组合的字符串
72
     *
73
     * @param  int $length
74
     * @param  int $type
75
     * @param  string $addChars
76
     * @return string
77
     */
78
    public static function random(int $length = 6, int $type = null, string $addChars = ''): string
79
    {
80
        $str = '';
81
        switch ($type) {
82
            case 0:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $type of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
83
                $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $addChars;
84
                break;
85
            case 1:
86
                $chars = str_repeat('0123456789', 3);
87
                break;
88
            case 2:
89
                $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $addChars;
90
                break;
91
            case 3:
92
                $chars = 'abcdefghijklmnopqrstuvwxyz' . $addChars;
93
                break;
94
            case 4:
95
                $chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书" . $addChars;
96
                break;
97
            default:
98
                $chars = 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $addChars;
99
                break;
100
        }
101
        if ($length > 10) {
102
            $chars = $type == 1 ? str_repeat($chars, $length) : str_repeat($chars, 5);
103
        }
104
        if ($type != 4) {
105
            $chars = str_shuffle($chars);
106
            $str = substr($chars, 0, $length);
107
        } else {
108
            for ($i = 0; $i < $length; $i++) {
109
                $str .= mb_substr($chars, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 1);
0 ignored issues
show
floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)) of type double is incompatible with the type integer expected by parameter $start of mb_substr(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

109
                $str .= mb_substr($chars, /** @scrutinizer ignore-type */ floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 1);
Loading history...
110
            }
111
        }
112
        return $str;
113
    }
114
115
    /**
116
     * 字符串转小写
117
     *
118
     * @param  string $value
119
     * @return string
120
     */
121
    public static function lower(string $value): string
122
    {
123
        return mb_strtolower($value, 'UTF-8');
124
    }
125
126
    /**
127
     * 字符串转大写
128
     *
129
     * @param  string $value
130
     * @return string
131
     */
132
    public static function upper(string $value): string
133
    {
134
        return mb_strtoupper($value, 'UTF-8');
135
    }
136
137
    /**
138
     * 获取字符串的长度
139
     *
140
     * @param  string $value
141
     * @return int
142
     */
143
    public static function length(string $value): int
144
    {
145
        return mb_strlen($value);
146
    }
147
148
    /**
149
     * 截取字符串
150
     *
151
     * @param  string   $string
152
     * @param  int      $start
153
     * @param  int|null $length
154
     * @return string
155
     */
156
    public static function substr(string $string, int $start, int $length = null): string
157
    {
158
        return mb_substr($string, $start, $length, 'UTF-8');
159
    }
160
161
    /**
162
     * 驼峰转下划线
163
     *
164
     * @param  string $value
165
     * @param  string $delimiter
166
     * @return string
167
     */
168
    public static function snake(string $value, string $delimiter = '_'): string
169
    {
170
        $key = $value;
171
172
        if (isset(static::$snakeCache[$key][$delimiter])) {
173
            return static::$snakeCache[$key][$delimiter];
174
        }
175
176
        if (!ctype_lower($value)) {
177
            $value = preg_replace('/\s+/u', '', ucwords($value));
178
179
            $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value));
180
        }
181
182
        return static::$snakeCache[$key][$delimiter] = $value;
183
    }
184
185
    /**
186
     * 下划线转驼峰(首字母小写)
187
     *
188
     * @param  string $value
189
     * @return string
190
     */
191
    public static function camel(string $value): string
192
    {
193
        if (isset(static::$camelCache[$value])) {
194
            return static::$camelCache[$value];
195
        }
196
197
        return static::$camelCache[$value] = lcfirst(static::studly($value));
198
    }
199
200
    /**
201
     * 下划线转驼峰(首字母大写)
202
     *
203
     * @param  string $value
204
     * @return string
205
     */
206
    public static function studly(string $value): string
207
    {
208
        $key = $value;
209
210
        if (isset(static::$studlyCache[$key])) {
211
            return static::$studlyCache[$key];
212
        }
213
214
        $value = ucwords(str_replace(['-', '_'], ' ', $value));
215
216
        return static::$studlyCache[$key] = str_replace(' ', '', $value);
217
    }
218
219
    /**
220
     * 转为首字母大写的标题格式
221
     *
222
     * @param  string $value
223
     * @return string
224
     */
225
    public static function title(string $value): string
226
    {
227
        return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
228
    }
229
230
    /**
231
     * Function Name: 手写字母大写
232
     * @param $str
233
     * @return string
234
     * @author Tinymeng <[email protected]>
235
     * @date: 2019/9/26 10:19
236
     */
237
    static public function uFirst($str):string{
238
        return ucfirst(strtolower($str));
239
    }
240
241
    /**
242
     * Name: 生成随机字符串
243
     * Author: Tinymeng <[email protected]>
244
     * @param int $length 字符串长度
245
     * @return string
246
     */
247
    public static function generateRandomString($length = 10):string {
248
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
249
        return substr(str_shuffle($characters), 0, $length);
250
    }
251
252
253
    /**
254
     * 获取唯一设备号
255
     * @Author: TinyMeng <[email protected]>
256
     * @param string $namespace
257
     * @return string
258
     */
259
    static public function createChannelId($namespace = ''):string {
260
        static $guid = '';
261
        $uid = uniqid("", true);
262
        $data = $namespace. md5(time() . mt_rand(1,1000000)).uniqid();
263
        $hash = strtoupper(hash('ripemd128', $uid . $guid . md5($data)));
264
        $guid = substr($hash, 0, 8) .
265
            '-' .
266
            substr($hash, 8, 4) .
267
            '-' .
268
            substr($hash, 12, 4) .
269
            '-' .
270
            substr($hash, 16, 4) .
271
            '-' .
272
            substr($hash, 20, 12);
273
        return $guid;
274
    }
275
276
    /**
277
     * 获取md5中16位小写
278
     * 实现java的 MD516.Bit16
279
     * @Author: TinyMeng <[email protected]>
280
     * @param $str
281
     * @return string
282
     */
283
    static public function md5Bit16($str):string {
284
        return strtoupper(substr(md5($str),8,16));
285
    }
286
287
    /**
288
     * 获取时间戳(13位精确到豪妙)
289
     * @Author: TinyMeng <[email protected]>
290
     * @param null|int $time
291
     * @return int
292
     */
293
    static public function millisecond($time = null) :int{
294
        if(empty($time)){
295
            list($msec, $sec) = explode(' ', microtime());
296
            $millisecond = (int)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
297
        }elseif(is_numeric($time) && strlen((string)$time)==10){
298
            $millisecond = (string)$time."000";
299
        }else{
300
            $millisecond = strtotime($time)."000";
301
        }
302
        return (int)$millisecond;
303
    }
304
305
    /**
306
     * Name: 是否包含中文
307
     * Author: Tinymeng <[email protected]>
308
     * @param string $string
309
     * @return bool
310
     */
311
    public static function isContainChinese($string=''):bool {
312
        $result = preg_match('/[\x{4e00}-\x{9fa5}]/u', $string);
313
        return $result == 0 ? false : true;
314
    }
315
316
    /**
317
     * Name: 是否全是中文
318
     * Author: Tinymeng <[email protected]>
319
     * @param string $string
320
     * @return bool
321
     */
322
    public static function isAllChinese($string=''):bool {
323
        $result = preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', $string);
324
        return $result == 0 ? false : true;
325
    }
326
327
    /**
328
     * 判断手机号码
329
     * Author : MYL <[email protected]>
330
     * Updater:
331
     * @param string $string
332
     * @return bool
333
     */
334
    public static function isMobile($string=''):bool {
335
        if (!preg_match("/(^1[3|4|5|7|8][0-9]{9}$)/", $string)) {
336
            return false;
337
        }
338
        return true;
339
    }
340
341
    /**
342
     * Description:  科学计数法转化正常数值输出
343
     * Author: JiaMeng <[email protected]>
344
     * Updater:
345
     * @param string $num 科学计数法字符串  如 2.1E-5
346
     * @param int $double   小数点保留位数 默认3位
347
     * @return string
348
     */
349
    public static function sctonum($num, $double = 3){
350
        if(false !== stripos($num, "e")){
351
            $a = explode("e",strtolower($num));
352
            return bcmul($a[0], bcpow(10, $a[1], $double), $double);
353
        }
354
        return $num;
355
    }
356
357
    /**
358
     * Name: 自动转换字符集 支持数组转换
359
     * Author: Tinymeng <[email protected]>
360
     * @param $string
361
     * @param string $from
362
     * @param string $to
363
     * @return array|false|string|string[]|null
364
     */
365
    public static function autoCharset($string, $from='gbk', $to='utf-8') {
366
        $from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from;
367
        $to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to;
368
        if (strtoupper($from) === strtoupper($to) || empty($string) || (is_scalar($string) && !is_string($string))) {
369
            //如果编码相同或者非字符串标量则不转换
370
            return $string;
371
        }
372
        if (is_string($string)) {
373
            if (function_exists('mb_convert_encoding')) {
374
                return mb_convert_encoding($string, $to, $from);
375
            } elseif (function_exists('iconv')) {
376
                return iconv($from, $to, $string);
377
            } else {
378
                return $string;
379
            }
380
        } elseif (is_array($string)) {
381
            foreach ($string as $key => $val) {
382
                $_key = self::autoCharset($key, $from, $to);
383
                $string[$_key] = self::autoCharset($val, $from, $to);
384
                if ($key != $_key)
385
                    unset($string[$key]);
386
            }
387
            return $string;
388
        }
389
        else {
390
            return $string;
391
        }
392
    }
393
394
    /**
395
     * Description:  过滤html里a标签
396
     * Author: song <[email protected]>
397
     * Updater:
398
     * @param $html
399
     * @return string
400
     */
401
    public static function filterATag($html=''):string {
402
        return preg_replace("#<a[^>]*>(.*?)</a>#is", "$1", $html);
403
    }
404
405
    /**
406
     * Description:  删除html里a标签及内容
407
     * Author: song <[email protected]>
408
     * Updater:
409
     * @param $html
410
     * @return string
411
     */
412
    public static function deleteATag($html=''):string {
413
        return preg_replace("#<a[^>]*>(.*?)</a>#is", "", $html);
414
    }
415
416
    /**
417
     * Description:  时间转换
418
     * Author: JiaMeng <[email protected]>
419
     * Updater:
420
     * @param string $date 时间
421
     * @param bool $is_timestamp   是否是时间戳
422
     * @return string
423
     */
424
    public static function getTime($date,$is_timestamp=false):string {
425
        if($is_timestamp === true){
426
            $time = $date;
427
        }else{
428
            $time = strtotime($date);//时间转换为时间戳
429
        }
430
431
        if($time >= time()){
432
            return '刚刚';
433
        }
434
        $seconds = time() - $time;
435
        if($seconds <= 60){
436
            return '刚刚';
437
        }
438
        $minutes = intval($seconds / 60);
439
        if($minutes <= 60){
440
            return $minutes.'分钟前';
441
        }
442
        $hours = intval($minutes / 60);
443
        if($hours <= 24){
444
            return $hours.'小时前';
445
        }
446
        $days = intval($hours / 24);
447
        if($days <= 3){
448
            return $days.'天前';
449
        }
450
        if($days <= 365){
451
            return date('m-d',/** @scrutinizer ignore-type */ $time);
452
        }
453
        return date('Y-m-d',$time);
0 ignored issues
show
It seems like $time can also be of type string; however, parameter $timestamp of date() does only seem to accept integer|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

453
        return date('Y-m-d',/** @scrutinizer ignore-type */ $time);
Loading history...
454
    }
455
456
    /**
457
     * Name: 压缩html代码
458
     * Author: Tinymeng <[email protected]>
459
     * @param string $html_source
460
     * @return string
461
     */
462
    static public function compressHtml($html_source):string {
463
        $chunks   = preg_split('/(<!--<nocompress>-->.*?<!--<\/nocompress>-->|<nocompress>.*?<\/nocompress>|<pre.*?\/pre>|<textarea.*?\/textarea>|<script.*?\/script>)/msi', $html_source, -1, PREG_SPLIT_DELIM_CAPTURE);
464
        $compress = '';
465
        foreach ($chunks as $c) {
466
            if (strtolower(substr($c, 0, 19)) == '<!--<nocompress>-->') {
467
                $c        = substr($c, 19, strlen($c) - 19 - 20);
468
                $compress .= $c;
469
                continue;
470
            } elseif (strtolower(substr($c, 0, 12)) == '<nocompress>') {
471
                $c        = substr($c, 12, strlen($c) - 12 - 13);
472
                $compress .= $c;
473
                continue;
474
            } elseif (strtolower(substr($c, 0, 4)) == '<pre' || strtolower(substr($c, 0, 9)) == '<textarea') {
475
                $compress .= $c;
476
                continue;
477
            } elseif (strtolower(substr($c, 0, 7)) == '<script' && strpos($c, '//') > 0 && (strpos($c, "\r") !== false || strpos($c, "\n") !== false)) { // JS代码,包含“//”注释的,单行代码不处理
478
                $tmps = preg_split('/(\r|\n)/ms', $c, -1, PREG_SPLIT_NO_EMPTY);
479
                $c    = '';
480
                foreach ($tmps as $tmp) {
481
                    if (strpos($tmp, '//') !== false) { // 对含有“//”的行做处理
482
                        if (substr(trim($tmp), 0, 2) == '//') { // 开头是“//”的就是注释
483
                            continue;
484
                        }
485
                        $chars   = preg_split('//', $tmp, -1, PREG_SPLIT_NO_EMPTY);
486
                        $is_quot = $is_apos = false;
487
                        foreach ($chars as $key => $char) {
488
                            if ($char == '"' && !$is_apos && $key > 0 && $chars[$key - 1] != '\\') {
489
                                $is_quot = !$is_quot;
0 ignored issues
show
The condition $is_quot is always false.
Loading history...
490
                            } elseif ($char == '\'' && !$is_quot && $key > 0 && $chars[$key - 1] != '\\') {
491
                                $is_apos = !$is_apos;
492
                            } elseif ($char == '/' && $chars[$key + 1] == '/' && !$is_quot && !$is_apos) {
493
                                $tmp = substr($tmp, 0, $key); // 不是字符串内的就是注释
494
                                break;
495
                            }
496
                        }
497
                    }
498
                    $c .= $tmp;
499
                }
500
            }
501
            $c = preg_replace('/[\\n\\r\\t]+/', ' ', $c); // 清除换行符,清除制表符
502
            $c = preg_replace('/\\s{2,}/', ' ', $c); // 清除额外的空格
503
            $c = preg_replace('/>\\s</', '> <', $c); // 清除标签间的空格
504
            $c = preg_replace('/\\/\\*.*?\\*\\//i', '', $c); // 清除 CSS & JS 的注释
505
            $c = preg_replace('/<!--[^!]*-->/', '', $c); // 清除 HTML 的注释
506
            $compress .= $c;
507
        }
508
        return $compress;
509
    }
510
511
    /**
512
     * Description:  html标签替换成特定小程序标签
513
     * Author: JiaMeng <[email protected]>
514
     * Updater:
515
     * @param string $content
516
     * @return mixed
517
     */
518
    static public function htmlReplaceXcx(string $content):string {
519
        $content = str_replace("\r\n","",$content);//出除回车和换行符
520
        $content = preg_replace("/style=\".*?\"/si",'',$content);//style样式
521
        $content = preg_replace(["/<strong.*?>/si", "/<\/strong>/si"],['<text class="wx-strong">','</text>'],$content);//strong
522
        $content = preg_replace(["/<p.*?>/si", "/<\/p>/si"],['<view class="wx-p">','</view>'],$content);//p
523
        $content = preg_replace(["/<a.*?>/si", "/<\/a>/si"],['<text class="wx-a">','</text>'],$content);//a
524
        $content = preg_replace(["/<span.*?>/si", "/<\/span>/si"],['<text class="wx-span">','</text>'],$content);//span
525
        $content = preg_replace(["/<h[1-6].*?>/si", "/<\/h[1-6]>/si"],['<view class="wx-h">','</view>'],$content);//h
526
        $content = preg_replace("/<img.*?/si",'<image class="wx-img"',$content);//img
527
        return $content;
528
    }
529
530
    /**
531
     * Description:  html P标签替换成特定Span标签(安卓app使用)
532
     * Author: JiaMeng <[email protected]>
533
     * Updater:
534
     * @param string $content
535
     * @return string
536
     */
537
    static public function pReplaceSpan(string $content):string {
538
        $content = str_replace(["\r","\n","\t"],'',$content);
539
        $content = preg_replace(["/<p/si", "/<\/p>/si"],['<span','</span><br>'],$content);//p
540
        return $content;
541
    }
542
543
    /**
544
     * Description:  过滤标点符号
545
     * @author: JiaMeng <[email protected]>
546
     * Updater:
547
     * @param  string $keyword
548
     * @return string
549
     */
550
    static public function filterPunctuation($keyword){
551
        $keyword = str_replace(["\r\n", "\r", "\n"," "," "], "", trim($keyword));//删除空格
552
        $keyword = preg_replace('# #','',$keyword);
553
        $keyword = preg_replace("/[ '.,:;*?~`!@#$%^&+=)(<>{}]|\]|\[|\/|\\\|\"|\|/",'',$keyword);
554
        return $keyword;
555
    }
556
557
    /**
558
     * Description:  过滤html标签
559
     * @author: JiaMeng <[email protected]>
560
     * Updater:
561
     * @param $content
562
     * @param string $allowable_tags
563
     * @return string
564
     */
565
    static public function stripTags($content,$allowable_tags = '<font>'){
566
        $content = strip_tags($content,$allowable_tags);//替换标签
567
        $content = str_replace(["\r\n", "\r", "\n"," "], "", trim($content));//删除空格
568
        return $content;
569
    }
570
571
}