stringUtil.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. <?php
  2. namespace common\components;
  3. use Yii;
  4. class stringUtil
  5. {
  6. const KEY = 'Aos4eLEmqpo8dmJleG610tR1KxUVQ5OzgkzpYM23PLqwSaU3Io';
  7. /**
  8. * 随机编号,英文开头,用于鲜花商品编号
  9. * @return string
  10. */
  11. public static function buildRandNo($id)
  12. {
  13. return 'F' . $id . time();// F == flower
  14. }
  15. /**
  16. * 创建微信Token使用
  17. * @return string
  18. */
  19. public static function buildWxToken($id)
  20. {
  21. return 'wt' . $id . time();
  22. }
  23. /**
  24. * 订单号,用于购买商品生成的订单等,
  25. * @return string
  26. */
  27. public static function buildOrderNo($id = 0)
  28. {
  29. mt_srand((double)microtime() * 1000000);
  30. $no = empty($id) ? '' : $id;
  31. $no .= date('ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
  32. return $no;
  33. }
  34. /**
  35. * 判断是否手机号
  36. * @param unknown $no
  37. * @return boolean
  38. */
  39. public static function isMobieNumber($no)
  40. {
  41. return preg_match("/^1[0-9]\d{9}$/", $no) == true ? true : false;
  42. }
  43. public static function isEmail($email)
  44. {
  45. $reg = '/\w+@\w+(?:\.\w+){1,3}/i';
  46. if (preg_match($reg, $email)) {
  47. return true;
  48. }
  49. return false;
  50. }
  51. /**
  52. *
  53. * @param string $string
  54. * @param int $length 汉字字数
  55. * @param tring $ext
  56. * @return string|string
  57. */
  58. static function subStringUtf8($string, $length, $ext = '')
  59. {
  60. $num = self::getWordNum($string);
  61. //echo $num;exit();
  62. //如果截取字数大于字符长度
  63. if ($num <= $length) {
  64. return $string;
  65. }
  66. $str_length = $length * 3; //总的字节数
  67. $slen = 0;
  68. $i = 0;
  69. $count = 0;
  70. while ($i <= $str_length && $count < $length) {
  71. if (isset($string[$i])) {
  72. $c = ord($string[$i]);
  73. //第一个字节大于224的,它与它之后的2个字节一起组成一个UTF-8字符
  74. if ($c >= 224) {
  75. $bits = 3;
  76. $count++;
  77. //第一个字节大于192小于224的,它与它之后的1个字节组成一个UTF-8字符
  78. } elseif ($c >= 192) {
  79. $count++;
  80. $bits = 2;
  81. //否则第一个字节本身就是一个英文字符(包括数字和一小部分标点符号)
  82. } else {
  83. $bits = 1;
  84. $count += 0.5;
  85. }
  86. }
  87. $slen = $slen + $bits;
  88. $i = $i + $bits;
  89. }
  90. return substr($string, 0, $slen) . $ext;
  91. }
  92. /**
  93. * 计算文字字数,二个字母当一个汉字
  94. * @param unknown_type $string
  95. * @param unknown_type $code
  96. * @return number
  97. */
  98. static function getWordNum($string, $code = 'utf-8')
  99. {
  100. $i = 0; //开始字节数
  101. $count = 0; //开始字数
  102. if ($code == 'utf-8') { //utf-8编码
  103. while (isset($string[$i]) && ord($string[$i]) != 0) { //还没有到结尾
  104. $b = ord($string[$i]);
  105. //第一个字节大于224的,它与它之后的2个字节一起组成一个UTF-8字符
  106. if ($b >= 224) {
  107. $i += 3;
  108. $count++;
  109. //第一个字节大于192小于224的,它与它之后的1个字节组成一个UTF-8字符
  110. } elseif ($b >= 192) {
  111. $i += 2;
  112. $count++;
  113. //否则第一个字节本身就是一个英文字符(包括数字和一小部分标点符号)
  114. } else {
  115. $i += 1;
  116. $count += 0.5;
  117. }
  118. }
  119. return ceil($count);
  120. }
  121. //gkb编码
  122. while (isset($string[$i]) && ord($string[$i]) != 0) {
  123. $b = ord($string[$i]);
  124. //第一个字节ASCII码>129的,它与它之后的1个字节一起组成一个gbk字符。
  125. if ($b > 129) {
  126. $i += 2;
  127. $count++;
  128. //第一个字节ASCII码<=129的,一个字节组成一个gbk字符。
  129. } else {
  130. $i++;
  131. $count += 0.5;
  132. }
  133. }
  134. return ceil($count);
  135. }
  136. /*
  137. * 取汉字拼音首字母
  138. */
  139. static function getfirstchar($s0)
  140. {
  141. $fchar = ord($s0{0});
  142. if ($fchar >= ord("A") and $fchar <= ord("z")) return strtoupper($s0{0});
  143. $s1 = iconv("UTF-8", "gb2312", $s0);
  144. $s2 = iconv("gb2312", "UTF-8", $s1);
  145. if ($s2 == $s0) {
  146. $s = $s1;
  147. } else {
  148. $s = $s0;
  149. }
  150. $asc = ord($s{0}) * 256 + ord($s{1}) - 65536;
  151. if ($asc >= -20319 and $asc <= -20284) return "A";
  152. if ($asc >= -20283 and $asc <= -19776) return "B";
  153. if ($asc >= -19775 and $asc <= -19219) return "C";
  154. if ($asc >= -19218 and $asc <= -18711) return "D";
  155. if ($asc >= -18710 and $asc <= -18527) return "E";
  156. if ($asc >= -18526 and $asc <= -18240) return "F";
  157. if ($asc >= -18239 and $asc <= -17923) return "G";
  158. if ($asc >= -17922 and $asc <= -17418) return "H";
  159. if ($asc >= -17417 and $asc <= -16475) return "J";
  160. if ($asc >= -16474 and $asc <= -16213) return "K";
  161. if ($asc >= -16212 and $asc <= -15641) return "L";
  162. if ($asc >= -15640 and $asc <= -15166) return "M";
  163. if ($asc >= -15165 and $asc <= -14923) return "N";
  164. if ($asc >= -14922 and $asc <= -14915) return "O";
  165. if ($asc >= -14914 and $asc <= -14631) return "P";
  166. if ($asc >= -14630 and $asc <= -14150) return "Q";
  167. if ($asc >= -14149 and $asc <= -14091) return "R";
  168. if ($asc >= -14090 and $asc <= -13319) return "S";
  169. if ($asc >= -13318 and $asc <= -12839) return "T";
  170. if ($asc >= -12838 and $asc <= -12557) return "W";
  171. if ($asc >= -12556 and $asc <= -11848) return "X";
  172. if ($asc >= -11847 and $asc <= -11056) return "Y";
  173. if ($asc >= -11055 and $asc <= -10247) return "Z";
  174. return null;
  175. }
  176. /**
  177. * 取汉字拼音首字母
  178. * @param unknown_type $zh
  179. * @return string
  180. */
  181. function getSpelling($zh)
  182. {
  183. $zh = str_replace('圳', 'z', $zh);
  184. $ret = "";
  185. $s1 = iconv("UTF-8", "gb2312", $zh);
  186. $s2 = iconv("gb2312", "UTF-8", $s1);
  187. if ($s2 == $zh) {
  188. $zh = $s1;
  189. }
  190. for ($i = 0; $i < strlen($zh); $i++) {
  191. $s1 = substr($zh, $i, 1);
  192. $p = ord($s1);
  193. if ($p > 160) {
  194. $s2 = substr($zh, $i++, 2);
  195. $ret .= self::getfirstchar($s2);
  196. } else {
  197. $ret .= $s1;
  198. }
  199. }
  200. return strtolower($ret);
  201. }
  202. /*
  203. * 取随机数
  204. */
  205. static function charsShuffle($length)
  206. {
  207. $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  208. $key = '';
  209. for ($i = 0; $i < $length; $i++) {
  210. $pos = mt_rand(0, strlen($str) - 1);
  211. $key .= $str[$pos];
  212. }
  213. return $key;
  214. }
  215. /*
  216. * 取随机数(小写)
  217. */
  218. static function charsShuffleLowerCase($length)
  219. {
  220. $str = 'abcdefghijklmnopqrstuvwxyz0123456789';
  221. $key = '';
  222. for ($i = 0; $i < $length; $i++) {
  223. $pos = mt_rand(0, strlen($str) - 1);
  224. $key .= $str[$pos];
  225. }
  226. return $key;
  227. }
  228. /**
  229. * 随机取数字
  230. * @return unknown
  231. */
  232. static function getRandNum($num)
  233. {
  234. $shuffle = str_shuffle('1234567890');
  235. $number = substr($shuffle, 0, $num);
  236. return $number;
  237. }
  238. // $string: 明文 或 密文
  239. // $operation:DECODE表示解密,其它表示加密
  240. // $key: 密匙
  241. // $expiry:密文有效期
  242. public function authcode($string, $operation = 'DECODE', $expiry = 0)
  243. {
  244. // 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
  245. $ckey_length = 4;
  246. // 密匙
  247. $key = md5(self::KEY);
  248. // 密匙a会参与加解密
  249. $keya = md5(substr($key, 0, 16));
  250. // 密匙b会用来做数据完整性验证
  251. $keyb = md5(substr($key, 16, 16));
  252. // 密匙c用于变化生成的密文
  253. $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
  254. // 参与运算的密匙
  255. $cryptkey = $keya . md5($keya . $keyc);
  256. $key_length = strlen($cryptkey);
  257. // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性
  258. // 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
  259. $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
  260. $string_length = strlen($string);
  261. $result = '';
  262. $box = range(0, 255);
  263. $rndkey = array();
  264. // 产生密匙簿
  265. for ($i = 0; $i <= 255; $i++) {
  266. $rndkey[$i] = ord($cryptkey[$i % $key_length]);
  267. }
  268. // 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
  269. for ($j = $i = 0; $i < 256; $i++) {
  270. $j = ($j + $box[$i] + $rndkey[$i]) % 256;
  271. $tmp = $box[$i];
  272. $box[$i] = $box[$j];
  273. $box[$j] = $tmp;
  274. }
  275. // 核心加解密部分
  276. for ($a = $j = $i = 0; $i < $string_length; $i++) {
  277. $a = ($a + 1) % 256;
  278. $j = ($j + $box[$a]) % 256;
  279. $tmp = $box[$a];
  280. $box[$a] = $box[$j];
  281. $box[$j] = $tmp;
  282. // 从密匙簿得出密匙进行异或,再转成字符
  283. $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
  284. }
  285. if ($operation == 'DECODE') {
  286. // substr($result, 0, 10) == 0 验证数据有效性
  287. // substr($result, 0, 10) - time() > 0 验证数据有效性
  288. // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
  289. // 验证数据有效性,请看未加密明文的格式
  290. if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
  291. return substr($result, 26);
  292. } else {
  293. return '';
  294. }
  295. } else {
  296. // 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
  297. // 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
  298. return $keyc . str_replace('=', '', base64_encode($result));
  299. }
  300. }
  301. /**
  302. * 返回8位随机字符,重复概率较低。
  303. * @return string
  304. */
  305. public static function getRandStr($id = null)
  306. {
  307. $chars = "0123456789abcdefghijklmnopqrstuvwxyz";
  308. $res = "";
  309. for ($i = 0; $i < 8; $i++) {
  310. $res .= $chars[mt_rand(0, strlen($chars) - 1)];
  311. }
  312. $rand = empty($id) ? $res : $res . $id;
  313. return $rand;
  314. }
  315. public static function randIP()
  316. {
  317. $arr_1 = array("218", "218", "66", "66", "218", "218", "60", "60", "202", "204", "66", "66", "66", "59", "61", "60", "222", "221", "66", "59", "60", "60", "66", "218", "218", "62", "63", "64", "66", "66", "122", "211");
  318. $randarr = mt_rand(0, count($arr_1));
  319. $ip1id = $arr_1[$randarr];
  320. $ip2id = round(rand(600000, 2550000) / 10000);
  321. $ip3id = round(rand(600000, 2550000) / 10000);
  322. $ip4id = round(rand(600000, 2550000) / 10000);
  323. return $ip1id . "." . $ip2id . "." . $ip3id . "." . $ip4id;
  324. }
  325. /**
  326. * 写日志
  327. * @param unknown_type $content
  328. * @param unknown_type $file
  329. */
  330. public static function log($content, $file)
  331. {
  332. $content .= "\r\n";
  333. $fh = fopen($file, 'ab'); //打开,追加模式
  334. fwrite($fh, $content);
  335. fclose($fh);
  336. }
  337. /**
  338. * 减法
  339. */
  340. public static function calcSub($a, $b)
  341. {
  342. return ($a * 1000 - $b * 1000) / 1000;
  343. }
  344. /**
  345. * 加法
  346. */
  347. public static function calcAdd($a, $b)
  348. {
  349. return ($a * 1000 + $b * 1000) / 1000;
  350. }
  351. /**
  352. * 生成商家提现需要使用的订单号
  353. */
  354. public static function generateMerchantCashOrderNo($merchantId)
  355. {
  356. return "C" . date('ymdHis') . $merchantId . mt_rand(10000, 99999);
  357. }
  358. /**
  359. * 生成用户需要使用的订单号
  360. * shish 2019.4.20
  361. * id 不小于8位的用户id
  362. */
  363. public static function generateOrderNo($merchantId, $userId)
  364. {
  365. $userId = empty($userId) ? rand(12013120, 12536120) : $userId;
  366. if (strlen($userId) < 8) {
  367. exit('用户ID少于8位数');
  368. }
  369. $no = date('ymdHis') . $merchantId . $userId . mt_rand(10000, 99999);
  370. if (strlen($no) > 32) {
  371. exit('订单位数大于32位');
  372. }
  373. return $no;
  374. }
  375. //微信32位的场景ID shish 2019.9.4
  376. public static function generateSceneId($merchantId)
  377. {
  378. $no = 'S' . date('YmdHis') . $merchantId . mt_rand(100000, 999999);
  379. if (strlen($no) > 32) {
  380. $no = substr($no, 0, 32);
  381. }
  382. return $no;
  383. }
  384. /**
  385. * 生成微信头像文件名
  386. */
  387. public static function generateAvatarFileName($merchantId, $userId)
  388. {
  389. $userId = empty($userId) ? rand(12013120, 12536120) : $userId;
  390. if (strlen($userId) < 8) {
  391. exit('用户ID少于8位数');
  392. }
  393. $no = date('ymdHi') . $merchantId . $userId . mt_rand(1000, 9999);
  394. return $no;
  395. }
  396. //将加密窜转成可以在http上传输的字符
  397. public static function urlSafeB64Encode($string)
  398. {
  399. $data = base64_encode($string);
  400. $data = str_replace(array('+', '/', '='), array('-', '_', ''), $data);
  401. return $data;
  402. }
  403. //将url上传输的字符解密
  404. public static function urlSafeBase64Decode($string)
  405. {
  406. $data = str_replace(array('-', '_'), array('+', '/'), $string);
  407. $mod4 = strlen($data) % 4;
  408. if ($mod4) {
  409. $data .= substr('====', $mod4);
  410. }
  411. return base64_decode($data);
  412. }
  413. //中文二边保留,中间用*号代替 shish 2019.8.13
  414. public static function replaceXH($name)
  415. {
  416. //获取字符串长度
  417. $strlen = mb_strlen($name, 'utf-8');
  418. //如果字符创长度小于2,不做任何处理
  419. if ($strlen < 2) {
  420. return $name;
  421. } else {
  422. //mb_substr — 获取字符串的部分
  423. $firstStr = mb_substr($name, 0, 1, 'utf-8');
  424. $lastStr = mb_substr($name, -1, 1, 'utf-8');
  425. //str_repeat — 重复一个字符串
  426. return $strlen == 2 ? $firstStr . str_repeat('*', mb_strlen($name, 'utf-8') - 1) : $firstStr . str_repeat("*", $strlen - 2) . $lastStr;
  427. }
  428. }
  429. }