Helper.php 16 KB

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