Helper.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. <?php
  2. use lwmf\base\Logger;
  3. class Helper
  4. {
  5. const PARAM_KEY_TYPE = [
  6. 'string' => 'string', // 字符串
  7. 'int' => 'int', // 数字
  8. 'float' => 'float', // float数字
  9. 'date' => 'date', // 日期
  10. 'datetime' => 'datetime', // 日期时间
  11. 'array_string' => 'array_string', // 包含字符串的数组
  12. 'array_float' => 'array_float', // 包含float的数组
  13. 'array_int' => 'array_int', // 包含int的数组
  14. ];
  15. /**
  16. * 检查字符串中是否含有任何一个子串
  17. * @param $str
  18. * @param array $arr
  19. * @param bool $case 是否区分大小写 0-否
  20. * @return bool
  21. */
  22. public static function hasAnyString($str, array $arr, bool $case = false): bool
  23. {
  24. foreach ($arr as $v) {
  25. if (!$case && stripos($str, $v) !== false) {
  26. return true;
  27. } elseif ($case && str_contains($str, $v)) {
  28. return true;
  29. }
  30. }
  31. return false;
  32. }
  33. /**
  34. * 获取图片完整路径
  35. * @param $imageUrl
  36. * @param string $default
  37. *
  38. * @return string
  39. * @author lizhi <1458705589@qq.com>
  40. * @date 2021/5/11
  41. */
  42. public static function getImageUrl($imageUrl, string $default = '', $params = []): string
  43. {
  44. if (empty($imageUrl)) {
  45. return $default;
  46. }
  47. if (str_contains($imageUrl, 'http')) {
  48. return $imageUrl;
  49. }
  50. $imageUrl = IMAGEDOMAIN . '/' . ltrim($imageUrl, '/');
  51. if (self::getArrParam($params, 'from_type', 'string') == 'console') {
  52. // 把后端用到图片的地方,加个后缀,类似!max200 !width600这种
  53. $imageUrl .= '!max200';
  54. }
  55. return $imageUrl;
  56. }
  57. public static function time_tran($time)
  58. {
  59. $text = '请选择正确的时间!';
  60. if(!$time){
  61. return $text;
  62. }
  63. $current = time();
  64. $t = $current - $time;
  65. $retArr = array('刚刚','秒前','分钟前','小时前','天前','月前','年前');
  66. switch($t){
  67. case $t < 0://时间大于当前时间,返回格式化时间
  68. $text = date('Y-m-d',$time);
  69. break;
  70. case $t == 0://刚刚
  71. $text = $retArr[0];
  72. break;
  73. case $t < 60:// 几秒前
  74. $text = $t.$retArr[1];
  75. break;
  76. case $t < 3600://几分钟前
  77. $text = floor($t / 60).$retArr[2];
  78. break;
  79. case $t < 86400://几小时前
  80. $text = floor($t / 3600).$retArr[3];
  81. break;
  82. case $t < 2592000: //几天前
  83. $text = floor($t / 86400).$retArr[4];
  84. break;
  85. case $t < 31536000: //几个月前
  86. $text = floor($t / 2592000).$retArr[5];
  87. break;
  88. default : //几年前
  89. $text = floor($t / 31536000).$retArr[6];
  90. }
  91. return $text;
  92. }
  93. /**
  94. * 检查数组是否指定键都存在 true-都在
  95. * - checkEmptyKey(['num' => 1], ['num']) => true
  96. * - checkEmptyKey(['num' => 1], ['id']) => false
  97. * - checkEmptyKey(['num' => 0], ['num']) => false
  98. * - checkEmptyKey(['num' => 0], ['num'], ['num') => true
  99. *
  100. * @param array $data
  101. * @param $keys
  102. * @param array $allowEmpty 允许为空的字段
  103. *
  104. * @return bool true-通过检查
  105. * @author lizhi <1458705589@qq.com>
  106. * @date 2021/6/18
  107. */
  108. public static function checkEmptyKey($data, $keys, array $allowEmpty = [])
  109. {
  110. if (is_array($keys)) {
  111. foreach ($keys as $item) {
  112. if (!isset($data[$item]) || (!in_array($item, $allowEmpty) && empty($data[$item]))) {
  113. return false;
  114. }
  115. }
  116. } elseif (!isset($data[$keys]) || (!in_array($keys, $allowEmpty) && empty($data[$keys]))) {
  117. return false;
  118. }
  119. return true;
  120. }
  121. public static function getPostString($key, $default = null)
  122. {
  123. return self::getArrParam($_POST, $key, 'string', $default);
  124. }
  125. public static function getPostFloat($key, $default = null)
  126. {
  127. return self::getArrParam($_POST, $key, 'float', $default);
  128. }
  129. public static function getGetFloat($key, $default = null)
  130. {
  131. return self::getArrParam($_GET, $key, 'float', $default);
  132. }
  133. public static function isPhone(?string $phone)
  134. {
  135. return $phone && preg_match('/^1[3456789]\d{9}$/', $phone);
  136. }
  137. public static function getPostInt($key, $default = 0)
  138. {
  139. return self::getArrParam($_POST, $key, 'int', $default);
  140. }
  141. public static function getGetString($key, $default = null)
  142. {
  143. return self::getArrParam($_GET, $key, 'string', $default);
  144. }
  145. public static function getGetDate($key, $default = null)
  146. {
  147. return self::getArrParam($_GET, $key, 'date', $default);
  148. }
  149. public static function getPostDatetime($key, $default = null)
  150. {
  151. return self::getArrParam($_POST, $key, 'datetime', $default);
  152. }
  153. public static function getGetDatetime($key, $default = null)
  154. {
  155. return self::getArrParam($_GET, $key, 'datetime', $default);
  156. }
  157. public static function getPostDate($key, $default = null)
  158. {
  159. return self::getArrParam($_POST, $key, 'date', $default);
  160. }
  161. public static function getGetInt($key, $default = 0)
  162. {
  163. return self::getArrParam($_GET, $key, 'int', $default);
  164. }
  165. /**
  166. * 从数组中获取字段
  167. */
  168. public static function getArrParam($arr, $name, $type = 'string', $default = null)
  169. {
  170. if (isset($arr[$name])) {
  171. $param = $arr[$name];
  172. return self::formatByType($param, $type, $default);
  173. }
  174. return $default;
  175. }
  176. /**
  177. * @param string $name 从数组中获取字段,并进行安全处理 多维数组示例 area.name
  178. * @see self::formatByType()
  179. */
  180. public static function getByKey($arr, $name, $type = '', $default = null)
  181. {
  182. $nameArr = array_filter(explode('.', $name));
  183. if (count($nameArr) == 1) {
  184. if (!isset($arr[$name])) {
  185. return $default;
  186. } else {
  187. $param = $arr[$name];
  188. }
  189. } else if (count($nameArr) == 2) {
  190. if (!isset($arr[$nameArr[0]][$nameArr[1]])) {
  191. return $default;
  192. } else {
  193. $param = $arr[$nameArr[0]][$nameArr[1]];
  194. }
  195. } else {
  196. return $default;
  197. }
  198. return self::formatByType($param, $type, $default);
  199. }
  200. /**
  201. * 格式化数据
  202. * @param mixed $param
  203. * @param string $type 数据类型,将元素处理成这样的数据类型
  204. - string 字符串
  205. - int 数字
  206. - float float数字
  207. - date 日期
  208. - datetime 日期时间
  209. - array_string 包含字符串的数组
  210. - array_float 包含float的数组
  211. - array_int 包含int的数组
  212. * @param mixed $default
  213. * @return mixed
  214. */
  215. public static function formatByType($param, $type, $default)
  216. {
  217. if ($type == 'string') {
  218. $param = addslashes(trim($param));
  219. }
  220. elseif ($type == 'int') {
  221. $param = intval($param);
  222. }
  223. elseif ($type == 'float') {
  224. $param = floatval($param);
  225. }
  226. elseif ($type == 'date') {
  227. if (!empty($param)) {
  228. $param = date('Y-m-d', strtotime($param));
  229. } else {
  230. $param = $default;
  231. }
  232. }
  233. elseif ($type == 'datetime') {
  234. if (!empty($param)) {
  235. $param = date('Y-m-d H:i:s', strtotime($param));
  236. } else {
  237. $param = $default;
  238. }
  239. }
  240. elseif ($type == 'array_string') {
  241. if (!empty($param)) {
  242. foreach ($param as $key => &$item) {
  243. $item = addslashes(trim($item));
  244. }
  245. }
  246. }
  247. elseif ($type == 'array_float') {
  248. if (!empty($param)) {
  249. foreach ($param as $key => &$item) {
  250. $item = floatval($item);
  251. }
  252. }
  253. }
  254. elseif ($type == 'array_int') {
  255. if (!empty($param)) {
  256. foreach ($param as $key => &$item) {
  257. $item = intval($item);
  258. }
  259. }
  260. }
  261. return $param;
  262. }
  263. /**
  264. * 获取date格式的日期间隔
  265. */
  266. public static function intervalDays($date1, $date2)
  267. {
  268. $d = @(strtotime($date2) - strtotime($date1)) / (3600 * 24);
  269. return $d;
  270. }
  271. /**
  272. * 获取一个对象中的某个字段,返回数组
  273. * @param array $arr 通过查询返回的数组
  274. * @param string $column 字段名
  275. */
  276. public static function getObjectColumn(array $arr, $column = 'id')
  277. {
  278. $ret = [];
  279. if (!empty($arr)) {
  280. foreach ($arr as $key => $item) {
  281. $attributes = $item->attributes;
  282. isset($attributes[$column]) && $ret[] = $attributes[$column];
  283. }
  284. }
  285. return $ret;
  286. }
  287. public static function concatArray($arr1, $arr2)
  288. {
  289. foreach ($arr2 as $item) {
  290. if (!in_array($item, $arr1)) {
  291. $arr1[] = $item;
  292. }
  293. }
  294. return $arr1;
  295. }
  296. public static function toJson($code = 200, $data = [], $msg = '请求成功')
  297. {
  298. @header("Content-Type: text/json; charset=UTF-8");
  299. echo json_encode([
  300. 'code' => $code,
  301. 'msg' => $msg,
  302. 'data' => $data
  303. ]);
  304. \Yii::app()->end();
  305. }
  306. public static function imageUpload($imagepath, $uploadpath)
  307. {
  308. try {
  309. // 腾讯云
  310. $region = 'ap-shanghai'; // 用户的 region,已创建桶归属的 region 可以在控制台查看,https://console.cloud.tencent.com/cos5/bucket
  311. $cosClient = new \Qcloud\Cos\Client(
  312. array(
  313. 'region' => $region,
  314. // 'scheme' => 'https', //协议头部,默认为 http
  315. 'credentials'=> array(
  316. 'secretId' => 'AKIDviIeLyQluythLAykSJ6oXH91upgR6iT8' ,
  317. 'secretKey' => 'tobSCsOn7yc6ToBSWegaM9rVGyiR6f95'
  318. )
  319. )
  320. );
  321. $bucket = 'lewaimai-image-1251685925';
  322. $file = fopen($imagepath, "rb");
  323. if ($file) {
  324. $result = $cosClient->putObject(['Bucket' => $bucket, 'Key' => $uploadpath, 'Body' => $file]);
  325. }
  326. } catch(Exception $e) {
  327. throw $e;
  328. }
  329. }
  330. public static function error($msg, $code = 400, $data = [])
  331. {
  332. self::toJson($code, $data, $msg);
  333. }
  334. public static function ok($data = [], $msg = '操作成功', $code = 200)
  335. {
  336. self::toJson($code, $data, $msg);
  337. }
  338. public static function commonError($_msg = '', $_code = 500, $_data = [])
  339. {
  340. return self::commonReturn($_data, $_msg, $_code);
  341. }
  342. public static function commonReturn($_data = [], $_msg = '', $_code = 200)
  343. {
  344. return [
  345. 'code' => $_code,
  346. 'msg' => $_msg,
  347. 'data' => $_data
  348. ];
  349. }
  350. public static function dealCommonResult($res, $exit = true)
  351. {
  352. if ($exit || $res['code'] != 200) {
  353. Helper::toJson($res['code'], $res['data'], $res['msg']);
  354. }
  355. }
  356. //php防注入和XSS攻击通用过滤
  357. public static function safeFilter (&$arr)
  358. {
  359. $ra=Array('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','/script/','/javascript/','/vbscript/','/expression/','/applet/'
  360. ,'/meta/','/xml/','/blink/','/link/','/style/','/embed/','/object/','/frame/','/layer/','/title/','/bgsound/'
  361. ,'/base/','/onload/','/onunload/','/onchange/','/onsubmit/','/onreset/','/onselect/','/onblur/','/onfocus/',
  362. '/onabort/','/onkeydown/','/onkeypress/','/onkeyup/','/onclick/','/ondblclick/','/onmousedown/','/onmousemove/'
  363. ,'/onmouseout/','/onmouseover/','/onmouseup/','/onunload/');
  364. if (is_array($arr))
  365. {
  366. foreach ($arr as $key => $value)
  367. {
  368. if (!is_array($value))
  369. {
  370. if (!get_magic_quotes_gpc()) //不对magic_quotes_gpc转义过的字符使用addslashes(),避免双重转义。
  371. {
  372. $value = addslashes($value); //给单引号(')、双引号(")、反斜线(\)与 NUL(NULL 字符)
  373. #加上反斜线转义
  374. }
  375. $value = preg_replace($ra,'',$value); //删除非打印字符,粗暴式过滤xss可疑字符串
  376. // $arr[$key] = htmlentities(strip_tags($value)); //去除 HTML 和 PHP 标记并转换为 HTML 实体
  377. }
  378. else
  379. {
  380. self::SafeFilter($arr[$key]);
  381. }
  382. }
  383. }
  384. return $arr;
  385. }
  386. public static function getSign($data)
  387. {
  388. return md5($data . "145709480B89EE59E3F4D43A56C355F2");
  389. }
  390. /**
  391. * 将二维数组转化为对象数组
  392. * @param array $arr
  393. * @return array
  394. */
  395. public static function arrayToObjects(array $arr)
  396. {
  397. $ret = [];
  398. foreach ($arr as $item) {
  399. $ret[] = (object)$item;
  400. }
  401. return $ret;
  402. }
  403. /**
  404. * 异步批量get请求
  405. *
  406. * @param array $nodes 格式: 'key' => ['url', 'data'] key是标识key,url是请求host,data是post传递的数据
  407. * @param integer $timeOut 超时时间
  408. * @return void
  409. */
  410. public static function multiGet($nodes, $options = [] ,$timeOut = 5)
  411. {
  412. $mh = curl_multi_init();
  413. $curl_arr = [];
  414. // 将请求放入curl中
  415. foreach ($nodes as $key => $node) {
  416. if (!is_array($node)) {
  417. continue;
  418. }
  419. $ch = curl_init();
  420. $url = $node['url'] . (strpos($node['url'], '?') === FALSE ? '?' : '');
  421. if (isset($node['data'])) {
  422. $url .= http_build_query($node['data']);
  423. }
  424. curl_setopt($ch, CURLOPT_URL, $url);
  425. // 其他的参数按照 function GET($url, $get = array(), array $options = array()) 来
  426. curl_setopt($ch, CURLOPT_HEADER, 0);
  427. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
  428. curl_setopt($ch, CURLOPT_TIMEOUT, 15);
  429. curl_setopt($ch, CURLOPT_SSLVERSION, 1);
  430. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  431. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  432. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  433. // 超时时间
  434. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeOut);
  435. foreach ($options as $k => $v) {
  436. curl_setopt($ch, $k, $v);
  437. }
  438. $curl_arr[$key] = $ch;
  439. curl_multi_add_handle($mh, $curl_arr[$key]);
  440. }
  441. // 发送请求
  442. $running = null;
  443. do {
  444. usleep(10000);
  445. curl_multi_exec($mh, $running);
  446. } while ($running > 0);
  447. // 获取请求数据,并删除请求
  448. $ret = [];
  449. foreach ($nodes as $key => $node) {
  450. $ret[$key] = curl_multi_getcontent($curl_arr[$key]);
  451. curl_multi_remove_handle($mh, $curl_arr[$key]);
  452. }
  453. curl_multi_close($mh);
  454. return $ret;
  455. }
  456. /**
  457. * array_column 一样用法
  458. */
  459. public static function arrayColumn($array, $column_key, $index_key = null): array
  460. {
  461. return $array && $array['datas'] ? array_column($array['datas'], $column_key, $index_key) : [];
  462. }
  463. /**
  464. * @param int $ipNum 每日ip次数限制
  465. * @param string $phone 手机号
  466. * @param int $phoneNum 每日单个手机号次数限制
  467. * @return array
  468. */
  469. public static function limitSmsSend(int $ipNum = 10, string $phone = '', int $phoneNum = 3):array
  470. {
  471. if ($ipNum > 0) {
  472. $ip = self::getUserHostIp();
  473. $key = 'limit_ip:' . date('Ymd') . '_' . $ip;
  474. if (RedisInstance::getInstance()->incr($key, 1, 86400) > $ipNum) {
  475. return Helper::commonError('今日短信次数超过限制i');
  476. }
  477. }
  478. if ($phone && $phoneNum > 0) {
  479. $key = 'limit_phone:' . date('Ymd') . '_' . $phone;
  480. if (RedisInstance::getInstance()->incr($key, 1, 86400) > $phoneNum) {
  481. return Helper::commonError('今日短信次数超过限制p');
  482. }
  483. }
  484. return Helper::commonReturn();
  485. }
  486. /**
  487. * 获取代理模式用户真实访问IP
  488. * 获取阿里云用户真实访问IP
  489. */
  490. public static function getUserHostIp()
  491. {
  492. if (isset($_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR']))
  493. {
  494. $ips = isset($_SERVER["HTTP_X_ORIGINAL_FORWARDED_FOR"]) ? explode(',', $_SERVER["HTTP_X_ORIGINAL_FORWARDED_FOR"]) : '';
  495. }
  496. else
  497. {
  498. $ips = isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ? explode(',', $_SERVER["HTTP_X_FORWARDED_FOR"]) : '';
  499. }
  500. if (isset($ips[0]))
  501. {
  502. $ip = $ips[0];
  503. }
  504. else
  505. {
  506. $ip = isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : '';
  507. }
  508. return $ip ? $ip : '127.0.0.1';
  509. }
  510. }