common.php 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com
  8. * =========================================================
  9. */
  10. // 应用公共文件
  11. // 除了 E_NOTICE,报告其他所有错误
  12. //error_reporting(E_ALL ^ E_NOTICE);
  13. //error_reporting(E_ERROR | E_WARNING | E_PARSE);
  14. error_reporting(E_NOTICE);
  15. use extend\QRcode as QRcode;
  16. use think\facade\Session;
  17. use think\facade\Event;
  18. use app\model\system\Addon;
  19. use extend\Barcode;
  20. /*****************************************************基础函数*********************************************************/
  21. /**
  22. * 把返回的数据集转换成Tree
  23. *
  24. * @param array $list
  25. * 要转换的数据集
  26. * @param string $pid
  27. * parent标记字段
  28. * @param string $level
  29. * level标记字段
  30. * @return array
  31. */
  32. function list_to_tree($list, $pk = 'id', $pid = 'pid', $child = '_child', $root = 0)
  33. {
  34. // 创建Tree
  35. $tree = [];
  36. if (!is_array($list)) :
  37. return false;
  38. endif;
  39. // 创建基于主键的数组引用
  40. $refer = [];
  41. foreach ($list as $key => $data) {
  42. $refer[ $data[ $pk ] ] = &$list[ $key ];
  43. $refer[ $data[ $pk ] ][ $child ] = [];
  44. $refer[ $data[ $pk ] ][ 'child_num' ] = 0;
  45. }
  46. foreach ($refer as $key => $data) {
  47. // 判断是否存在parent
  48. $parentId = $data[ $pid ];
  49. if ($root == $parentId) {
  50. $tree[ $key ] = &$refer[ $key ];
  51. } else if (isset($refer[ $parentId ])) {
  52. is_object($refer[ $parentId ]) && $refer[ $parentId ] = $refer[ $parentId ]->toArray();
  53. $parent = &$refer[ $parentId ];
  54. $parent[ $child ][ $key ] = &$refer[ $key ];
  55. $parent[ 'child_num' ]++;
  56. }
  57. }
  58. return $tree;
  59. }
  60. /**
  61. * 读取csv的内容到数组
  62. * @param string $uploadfile
  63. * @return array|mixed
  64. */
  65. function readCsv($uploadfile)
  66. {
  67. $file = fopen($uploadfile, "r");
  68. while (!feof($file)) {
  69. $data[] = fgetcsv($file);
  70. }
  71. $data = eval('return ' . iconv('gbk', 'utf-8', var_export($data, true)) . ';');
  72. foreach ($data as $key => $value) {
  73. if (!$value) {
  74. unset($data[ $key ]);
  75. }
  76. }
  77. fclose($file);
  78. return $data;
  79. }
  80. /**
  81. * 将list_to_tree的树还原成列表
  82. *
  83. * @param array $tree
  84. * 原来的树
  85. * @param string $child
  86. * 孩子节点的键
  87. * @param string $order
  88. * 排序显示的键,一般是主键 升序排列
  89. * @param array $list
  90. * 过渡用的中间数组,
  91. * @return array 返回排过序的列表数组
  92. */
  93. function tree_to_list($tree, $child = '_child', $order = 'id', &$list = array ())
  94. {
  95. if (is_array($tree)) {
  96. foreach ($tree as $key => $value) {
  97. $reffer = $value;
  98. if (isset($reffer[ $child ])) {
  99. unset($reffer[ $child ]);
  100. tree_to_list($value[ $child ], $child, $order, $list);
  101. }
  102. $list[] = $reffer;
  103. }
  104. $list = list_sort_by($list, $order, $sortby = 'asc');
  105. }
  106. return $list;
  107. }
  108. /**
  109. * 对查询结果集进行排序
  110. *
  111. * @access public
  112. * @param array $list
  113. * 查询结果
  114. * @param string $field
  115. * 排序的字段名
  116. * @param array $sortby
  117. * 排序类型
  118. * asc正向排序 desc逆向排序 nat自然排序
  119. * @return array
  120. */
  121. function list_sort_by($list, $field, $sortby = 'asc')
  122. {
  123. if (is_array($list)) {
  124. $refer = $resultSet = array ();
  125. foreach ($list as $i => $data)
  126. $refer[ $i ] = &$data[ $field ];
  127. switch ( $sortby ) {
  128. case 'asc': // 正向排序
  129. asort($refer);
  130. break;
  131. case 'desc': // 逆向排序
  132. arsort($refer);
  133. break;
  134. case 'nat': // 自然排序
  135. natcasesort($refer);
  136. break;
  137. }
  138. foreach ($refer as $key => $val)
  139. $resultSet[] = &$list[ $key ];
  140. return $resultSet;
  141. }
  142. return false;
  143. }
  144. /**
  145. * 对象转化为数组
  146. * @param object $obj
  147. */
  148. function object_to_array($obj)
  149. {
  150. if (is_object($obj)) {
  151. $obj = (array) $obj;
  152. }
  153. if (is_array($obj)) {
  154. foreach ($obj as $key => $value) {
  155. $obj[ $key ] = object_to_array($value);
  156. }
  157. }
  158. return $obj;
  159. }
  160. /**
  161. * 系统加密方法
  162. *
  163. * @param string $data
  164. * 要加密的字符串
  165. * @param string $key
  166. * 加密密钥
  167. * @param int $expire
  168. * 过期时间 单位 秒
  169. * @return string
  170. */
  171. function encrypt($data, $key = '', $expire = 0)
  172. {
  173. $key = md5(empty ($key) ? 'niucloud098)(*' : $key);
  174. $data = base64_encode($data);
  175. $x = 0;
  176. $len = strlen($data);
  177. $l = strlen($key);
  178. $char = '';
  179. for ($i = 0; $i < $len; $i++) {
  180. if ($x == $l)
  181. $x = 0;
  182. $char .= substr($key, $x, 1);
  183. $x++;
  184. }
  185. $str = sprintf('%010d', $expire ? $expire + time() : 0);
  186. for ($i = 0; $i < $len; $i++) {
  187. $str .= chr(ord(substr($data, $i, 1)) + ( ord(substr($char, $i, 1)) ) % 256);
  188. }
  189. return str_replace(array (
  190. '+',
  191. '/',
  192. '='
  193. ), array (
  194. '-',
  195. '_',
  196. ''
  197. ), base64_encode($str));
  198. }
  199. /**
  200. * 系统解密方法
  201. *
  202. * @param string $data
  203. * 要解密的字符串 (必须是encrypt方法加密的字符串)
  204. * @param string $key
  205. * 加密密钥
  206. * @return string
  207. */
  208. function decrypt($data, $key = '')
  209. {
  210. $key = md5(empty ($key) ? 'niucloud098)(*' : $key);
  211. $data = str_replace(array (
  212. '-',
  213. '_'
  214. ), array (
  215. '+',
  216. '/'
  217. ), $data);
  218. $mod4 = strlen($data) % 4;
  219. if ($mod4) {
  220. $data .= substr('====', $mod4);
  221. }
  222. $data = base64_decode($data);
  223. $expire = substr($data, 0, 10);
  224. $data = substr($data, 10);
  225. if ($expire > 0 && $expire < time()) {
  226. return '';
  227. }
  228. $x = 0;
  229. $len = strlen($data);
  230. $l = strlen($key);
  231. $char = $str = '';
  232. for ($i = 0; $i < $len; $i++) {
  233. if ($x == $l)
  234. $x = 0;
  235. $char .= substr($key, $x, 1);
  236. $x++;
  237. }
  238. for ($i = 0; $i < $len; $i++) {
  239. if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1))) {
  240. $str .= chr(( ord(substr($data, $i, 1)) + 256 ) - ord(substr($char, $i, 1)));
  241. } else {
  242. $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
  243. }
  244. }
  245. return base64_decode($str);
  246. }
  247. /**
  248. * 数据签名认证
  249. */
  250. function data_auth_sign($data)
  251. {
  252. // 数据类型检测
  253. if (!is_array($data)) {
  254. $data = (array) $data;
  255. }
  256. ksort($data); // 排序
  257. $code = http_build_query($data); // url编码并生成query字符串
  258. $sign = sha1($code); // 生成签名
  259. return $sign;
  260. }
  261. /**
  262. * 重写md5加密方式
  263. *
  264. * @param string $str
  265. * @return string
  266. */
  267. function data_md5($str)
  268. {
  269. return '' === $str ? '' : md5(md5($str) . 'NiuCloud');
  270. }
  271. /**
  272. * 时间戳转时间
  273. */
  274. function time_to_date($time_stamp, $format = 'Y-m-d H:i:s')
  275. {
  276. if ($time_stamp > 0) {
  277. $time = date($format, $time_stamp);
  278. } else {
  279. $time = "";
  280. }
  281. return $time;
  282. }
  283. /**
  284. * 时间转时间戳
  285. */
  286. function date_to_time($date)
  287. {
  288. $time_stamp = strtotime($date);
  289. return $time_stamp;
  290. }
  291. /**
  292. * 获取唯一随机字符串
  293. * 创建时间:2018年8月7日15:54:16
  294. */
  295. function unique_random($len = 10)
  296. {
  297. $str = 'qwertyuiopasdfghjklzxcvbnm';
  298. str_shuffle($str);
  299. $res = 'nc_' . substr(str_shuffle($str), 0, $len) . date('is');
  300. return $res;
  301. }
  302. /**
  303. * 生成随机数
  304. * @param int $length
  305. * @return string
  306. */
  307. function random_keys($length)
  308. {
  309. // $pattern = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ';
  310. $pattern = array (
  311. '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
  312. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  313. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
  314. );
  315. $keys = array_rand($pattern, $length);
  316. $key = '';
  317. for ($i = 0; $i < $length; $i++) {
  318. $key .= $pattern[ $keys[ $i ] ]; //生成php随机数
  319. }
  320. return $key;
  321. }
  322. /**
  323. * 发送HTTP请求方法,目前只支持CURL发送请求
  324. *
  325. * @param string $url
  326. * 请求URL
  327. * @param array $params
  328. * 请求参数
  329. * @param string $method
  330. * 请求方法GET/POST
  331. * @return array $data 响应数据
  332. */
  333. function http($url, $timeout = 30, $header = array ())
  334. {
  335. if (!function_exists('curl_init')) {
  336. throw new Exception('server not install curl');
  337. }
  338. $ch = curl_init();
  339. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  340. curl_setopt($ch, CURLOPT_HEADER, true);
  341. curl_setopt($ch, CURLOPT_URL, $url);
  342. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  343. curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727;)');
  344. if (!empty($header)) {
  345. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  346. }
  347. $data = curl_exec($ch);
  348. if ($data && is_array(explode("\r\n\r\n", $data))) {
  349. list ($header, $data) = explode("\r\n\r\n", $data);
  350. } else {
  351. $header = explode("\r\n\r\n", $data)[ 0 ];
  352. $data = [];
  353. }
  354. $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  355. if ($http_code == 301 || $http_code == 302) {
  356. $matches = array ();
  357. preg_match('/Location:(.*?)\n/', $header, $matches);
  358. $url = trim(array_pop($matches));
  359. curl_setopt($ch, CURLOPT_URL, $url);
  360. curl_setopt($ch, CURLOPT_HEADER, false);
  361. $data = curl_exec($ch);
  362. }
  363. if ($data == false) {
  364. curl_close($ch);
  365. }
  366. @curl_close($ch);
  367. return $data;
  368. }
  369. /**
  370. * 替换数组元素
  371. * @param array $array 数组
  372. * @param array $replace 替换元素['key' => 'value', 'key' => 'value']
  373. */
  374. function replace_array_element($array, $replace)
  375. {
  376. foreach ($replace as $k => $v) {
  377. if ($v == "unset" || $v == "") {
  378. unset($array[ $k ]);
  379. } else {
  380. $array[ $k ] = $v;
  381. }
  382. }
  383. return $array;
  384. }
  385. /**
  386. * 过滤特殊符号
  387. * 创建时间:2018年1月30日15:39:32
  388. * @param unknown $string
  389. * @return mixed
  390. */
  391. function ihtmlspecialchars($string)
  392. {
  393. if (is_array($string)) {
  394. foreach ($string as $key => $val) {
  395. $string[ $key ] = ihtmlspecialchars($val);
  396. }
  397. } else {
  398. $string = preg_replace('/&amp;((#(d{3,5}|x[a-fa-f0-9]{4})|[a-za-z][a-z0-9]{2,5});)/', '&\1',
  399. str_replace(array ( '&', '"', '<', '>' ), array ( '&amp;', '&quot;', '&lt;', '&gt;' ), $string));
  400. }
  401. return $string;
  402. }
  403. /********************************************* 插件,站点相关函数 ************************************************************************************
  404. *
  405. * /**
  406. * 插件显示内容里生成访问插件的url
  407. *
  408. * @param string $url
  409. * url
  410. * @param array $param
  411. * 参数
  412. * 格式:addon_url('HelloWorld://sitehome/Game/index', [])
  413. */
  414. function addon_url($url, $param = array ())
  415. {
  416. if (strpos($url, 'http://') === 0 || strpos($url, 'https://') === 0) {
  417. return $url;
  418. }
  419. $parse_url = parse_url($url);
  420. $addon = isset($parse_url[ 'scheme' ]) ? $parse_url[ 'scheme' ] : '';
  421. $controller = isset($parse_url[ 'host' ]) ? $parse_url[ 'host' ] : '';
  422. $action = trim($parse_url[ 'path' ], '/');
  423. /* 解析URL带的参数 */
  424. if (isset($parse_url[ 'query' ])) {
  425. parse_str($parse_url[ 'query' ], $query);
  426. $param = array_merge($query, $param);
  427. }
  428. $url = $addon . '/' . $controller . '/' . $action;
  429. if (empty($addon)) {
  430. $url = $controller . '/' . $action;
  431. if (empty($controller)) {
  432. $url = $action;
  433. }
  434. }
  435. return url($url, $param);
  436. }
  437. /**
  438. * Url生成(重写url函数)
  439. * @param string $url 路由地址
  440. */
  441. function url(string $url = '', $vars = [])
  442. {
  443. if (!empty($vars)) {
  444. if (is_array($vars)) {
  445. $vars = http_build_query($vars);
  446. }
  447. $tag = REWRITE_MODULE ? '?' : '&';
  448. $var_url = $tag . $vars;
  449. } else {
  450. $var_url = '';
  451. }
  452. $url = $url . '.html';
  453. $url_arr = explode("/", $url);
  454. foreach ($url_arr as $key => $val) {
  455. if ($val == "shop") {
  456. $url_arr[ $key ] = SHOP_MODULE;
  457. break;
  458. }
  459. }
  460. $url = implode("/", $url_arr);
  461. // $url = str_replace("shop", SHOP_MODULE, $url); //针对输入
  462. return ROOT_URL . '/' . $url . $var_url;
  463. }
  464. /**
  465. * Url生成(重写url函数) 获取不含html的url
  466. * @param string $url 路由地址
  467. */
  468. function getUrl(string $url = '', $vars = [])
  469. {
  470. if (!empty($vars)) {
  471. if (is_array($vars)) {
  472. $vars = http_build_query($vars);
  473. }
  474. $tag = REWRITE_MODULE ? '?' : '&';
  475. $var_url = $tag . $vars;
  476. } else {
  477. $var_url = '';
  478. }
  479. // $url = $url . '.html';
  480. $url_arr = explode("/", $url);
  481. foreach ($url_arr as $key => $val) {
  482. if ($val == "shop") {
  483. $url_arr[ $key ] = SHOP_MODULE;
  484. break;
  485. }
  486. }
  487. $url = implode("/", $url_arr);
  488. // $url = str_replace("shop", SHOP_MODULE, $url); //针对输入
  489. return ROOT_URL . '/' . $url . $var_url;
  490. }
  491. /**
  492. * 解析url的插件,模块,控制器,方法
  493. * @param unknown $url
  494. */
  495. function url_action($url)
  496. {
  497. if (empty($url)) {
  498. return [
  499. 'addon' => '',
  500. 'model' => 'index',
  501. 'controller' => 'index',
  502. 'action' => 'index'
  503. ];
  504. }
  505. if (!strstr($url, '://')) {
  506. $url_array = explode('/', $url);
  507. return [
  508. 'addon' => '',
  509. 'model' => $url_array[ 0 ],
  510. 'controller' => $url_array[ 1 ],
  511. 'action' => $url_array[ 2 ]
  512. ];
  513. } else {
  514. $url_addon_array = explode('://', $url);
  515. $addon = $url_addon_array[ 0 ];
  516. $url_array = explode('/', $url_addon_array[ 1 ]);
  517. return [
  518. 'addon' => $addon,
  519. 'model' => $url_array[ 0 ],
  520. 'controller' => $url_array[ 1 ],
  521. 'action' => $url_array[ 2 ]
  522. ];
  523. }
  524. }
  525. /**
  526. * 检测插件是否存在
  527. * @param string $name
  528. * @return number
  529. */
  530. function addon_is_exit($name, $site_id = 0)
  531. {
  532. $addon_model = new Addon();
  533. $addon_data = $addon_model->getAddonList([], 'name');
  534. $addons = array_column($addon_data[ 'data' ], 'name');
  535. if (in_array($name, $addons)) {
  536. return 1;
  537. } else {
  538. return 0;
  539. }
  540. }
  541. /***************************************************niucloud系统函数***************************************************/
  542. /**
  543. * 处理事件
  544. *
  545. * @param string $event
  546. * 钩子名称
  547. * @param mixed $args
  548. * 传入参数
  549. * @param bool $once
  550. * 只获取一个有效返回值
  551. * @return void
  552. */
  553. function event($event, $args = [], $once = false)
  554. {
  555. $res = Event::trigger($event, $args);
  556. if (is_array($res)) {
  557. $res = array_filter($res);
  558. sort($res);
  559. }
  560. //只返回一个结果集
  561. if ($once) {
  562. return isset($res[ 0 ]) ? $res[ 0 ] : '';
  563. }
  564. return $res;
  565. }
  566. /**
  567. * 错误返回值函数
  568. * @param int $code
  569. * @param string $message
  570. * @param string $data
  571. * @return array
  572. */
  573. function error($code = -1, $message = '', $data = '')
  574. {
  575. return [
  576. 'code' => $code,
  577. 'message' => $message,
  578. 'data' => $data
  579. ];
  580. }
  581. /**
  582. * 返回值函数
  583. * @param int $code
  584. * @param string $message
  585. * @param string $data
  586. * @return array
  587. */
  588. function success($code = 0, $message = '', $data = '')
  589. {
  590. return [
  591. 'code' => $code,
  592. 'message' => $message,
  593. 'data' => $data
  594. ];
  595. }
  596. /**
  597. * 实例化Model
  598. *
  599. * @param string $name
  600. * Model名称
  601. */
  602. function model($table = '')
  603. {
  604. return new \app\model\Model($table);
  605. }
  606. /**
  607. * 获取带有表前缀的表名
  608. * @param string $table
  609. */
  610. function table($table = '')
  611. {
  612. return config('database.connections.prefix') . $table;
  613. }
  614. /**
  615. * 获取图片的真实路径
  616. *
  617. * @param string $path 图片初始路径
  618. * @param string $type 类型 big、mid、small
  619. * @return string 图片的真实路径
  620. */
  621. function img($path, $type = '')
  622. {
  623. $start = strripos($path, '.');
  624. $type = $type ? '_' . strtoupper($type) : '';
  625. $first = explode("/", $path);
  626. $path = substr_replace($path, $type, $start, 0);
  627. // 处理商品助手的图片路径
  628. $path = str_replace('addons/NsGoodsAssist/', '', $path);
  629. $path = str_replace('shop/goods/', '', $path);
  630. if (stristr($path, "http://") === false && stristr($path, "https://") === false) {
  631. if (is_numeric($first[ 0 ])) {
  632. $true_path = __ROOT__ . '/upload/' . $path;
  633. } else {
  634. $true_path = __ROOT__ . '/' . $path;
  635. }
  636. } else {
  637. $true_path = $path;
  638. }
  639. return $true_path;
  640. }
  641. /**
  642. * 获取标准二维码格式
  643. *
  644. * @param string $url
  645. * @param string $path
  646. * @param string $ext
  647. */
  648. function qrcode($url, $path, $qrcode_name, $size = 4)
  649. {
  650. if (!is_dir($path)) {
  651. $mode = intval('0777', 8);
  652. mkdir($path, $mode, true);
  653. chmod($path, $mode);
  654. }
  655. $path = $path . '/' . $qrcode_name . '.png';
  656. if (file_exists($path)) {
  657. unlink($path);
  658. }
  659. QRcode::png($url, $path, '', $size, 1);
  660. return $path;
  661. }
  662. /**
  663. * 前端页面api请求(通过api接口实现)
  664. * @param string $method
  665. * @param array $params
  666. * @return mixed
  667. */
  668. function api($method, $params = [])
  669. {
  670. //本地访问
  671. $data = get_api_data($method, $params);
  672. return $data;
  673. }
  674. /**
  675. * 获取Api类
  676. *
  677. * @param string $method
  678. */
  679. function get_api_data($method, $params)
  680. {
  681. $method_array = explode('.', $method);
  682. if ($method_array[ 0 ] == 'System') {
  683. $class_name = 'app\\api\\controller\\' . $method_array[ 1 ];
  684. if (!class_exists($class_name)) {
  685. return error();
  686. }
  687. $api_model = new $class_name($params);
  688. } else {
  689. $class_name = "addon\\{$method_array[0]}\\api\\controller\\" . $method_array[ 1 ];
  690. if (!class_exists($class_name)) {
  691. return error();
  692. }
  693. $api_model = new $class_name($params);
  694. }
  695. $function = $method_array[ 2 ];
  696. $data = $api_model->$function($params);
  697. return $data;
  698. }
  699. /**
  700. * 根据年份计算生肖
  701. * @param unknown $year
  702. */
  703. function get_zodiac($year)
  704. {
  705. $animals = array (
  706. '鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'
  707. );
  708. $key = ( $year - 1900 ) % 12;
  709. return $animals[ $key ];
  710. }
  711. /**
  712. * 计算.星座
  713. * @param int $month 月份
  714. * @param int $day 日期
  715. * @return str
  716. */
  717. function get_constellation($month, $day)
  718. {
  719. $constellations = array (
  720. '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座', '巨蟹座',
  721. '狮子座', '处女座', '天秤座', '天蝎座', '射手座', '摩羯座'
  722. );
  723. if ($day <= 22) {
  724. if (1 != $month) {
  725. $constellation = $constellations[ $month - 2 ];
  726. } else {
  727. $constellation = $constellations[ 11 ];
  728. }
  729. } else {
  730. $constellation = $constellations[ $month - 1 ];
  731. }
  732. return $constellation;
  733. }
  734. /**
  735. * 数组键名转化为数字
  736. * @param $data
  737. */
  738. function arr_key_to_int($data, $clild_name)
  739. {
  740. $temp_data = array_values($data);
  741. foreach ($temp_data as $k => $v) {
  742. if (!empty($v[ $clild_name ])) {
  743. $temp_data[ $k ][ $clild_name ] = arr_key_to_int($v[ $clild_name ], $clild_name);
  744. }
  745. }
  746. return $temp_data;
  747. }
  748. /**
  749. * 以天为单位 计算间隔内的日期数组
  750. * @param $start_time
  751. * @param $end_time
  752. * @return array
  753. */
  754. function period_group($start_time, $end_time, $format = 'Ymd')
  755. {
  756. $type_time = 3600 * 24;
  757. $data = [];
  758. for ($i = $start_time; $i <= $end_time; $i += $type_time) {
  759. $data[] = date($format, $i);
  760. }
  761. return $data;
  762. }
  763. /**
  764. * 数组删除另一个数组
  765. * @param $arr
  766. * @param $del_arr
  767. * @return mixed
  768. */
  769. function arr_del_arr($arr, $del_arr)
  770. {
  771. foreach ($arr as $k => $v) {
  772. if (in_array($v, $del_arr)) {
  773. unset($arr[ $k ]);
  774. }
  775. }
  776. sort($arr);
  777. return $arr;
  778. }
  779. /**
  780. * 检测登录(应用于h5网页检测登录)
  781. * @param unknown $url
  782. */
  783. function check_auth($url = '')
  784. {
  785. $access_token = Session::get("access_token_" . request()->siteid());
  786. if (empty($access_token)) {
  787. if (!empty($url)) {
  788. Session::set("redirect_login_url", $url);
  789. }
  790. //尚未登录(直接跳转)
  791. return error(url('wap/login/login'));
  792. }
  793. $member_info = cache("member_info_" . request()->siteid() . $access_token);
  794. if (empty($member_info)) {
  795. $member_info = api("System.Member.memberInfo", [ 'access_token' => $access_token ]);
  796. if ($member_info[ 'code' ] == 0) {
  797. $member_info = $member_info[ 'data' ];
  798. cache("member_info_" . request()->siteid() . $access_token, $member_info);
  799. }
  800. }
  801. $member_info[ 'access_token' ] = $access_token;
  802. return success($member_info);
  803. }
  804. /**
  805. * 分割sql语句
  806. * @param string $content sql内容
  807. * @param bool $string 如果为真,则只返回一条sql语句,默认以数组形式返回
  808. * @param array $replace 替换前缀,如:['my_' => 'me_'],表示将表前缀my_替换成me_
  809. * @return array|string 除去注释之后的sql语句数组或一条语句
  810. */
  811. function parse_sql($content = '', $string = false, $replace = [])
  812. {
  813. // 纯sql内容
  814. $pure_sql = [];
  815. // 被替换的前缀
  816. $from = '';
  817. // 要替换的前缀
  818. $to = '';
  819. // 替换表前缀
  820. if (!empty($replace)) {
  821. $to = current($replace);
  822. $from = current(array_flip($replace));
  823. }
  824. if ($content != '') {
  825. // 多行注释标记
  826. $comment = false;
  827. // 按行分割,兼容多个平台
  828. $content = str_replace([ "\r\n", "\r" ], "\n", $content);
  829. $content = explode("\n", trim($content));
  830. // 循环处理每一行
  831. foreach ($content as $key => $line) {
  832. // 跳过空行
  833. if ($line == '') {
  834. continue;
  835. }
  836. // 跳过以#或者--开头的单行注释
  837. if (preg_match("/^(#|--)/", $line)) {
  838. continue;
  839. }
  840. // 跳过以/**/包裹起来的单行注释
  841. if (preg_match("/^\/\*(.*?)\*\//", $line)) {
  842. continue;
  843. }
  844. // 多行注释开始
  845. if (substr($line, 0, 2) == '/*') {
  846. $comment = true;
  847. continue;
  848. }
  849. // 多行注释结束
  850. if (substr($line, -2) == '*/') {
  851. $comment = false;
  852. continue;
  853. }
  854. // 多行注释没有结束,继续跳过
  855. if ($comment) {
  856. continue;
  857. }
  858. // 替换表前缀
  859. if ($from != '') {
  860. $line = str_replace('`' . $from, '`' . $to, $line);
  861. }
  862. // sql语句
  863. $pure_sql[] = $line;
  864. }
  865. // 只返回一条语句
  866. if ($string) {
  867. return implode("", $pure_sql);
  868. }
  869. // 以数组形式返回sql语句
  870. $pure_sql = implode("\n", $pure_sql);
  871. $pure_sql = explode(";\n", $pure_sql);
  872. }
  873. return $pure_sql;
  874. }
  875. /**
  876. * 执行sql
  877. * @param string $sql_name
  878. */
  879. function execute_sql($sql_name)
  880. {
  881. $sql_string = file_get_contents($sql_name);
  882. $sql_string = str_replace("{{prefix}}", config("database.connections.mysql.prefix"), $sql_string);
  883. if ($sql_string) {
  884. $sql = explode(";\n", str_replace("\r", "\n", $sql_string));
  885. foreach ($sql as $value) {
  886. $value = trim($value);
  887. if (!empty($value)) {
  888. \think\facade\Db::execute($value);
  889. }
  890. }
  891. }
  892. }
  893. /**
  894. * 检测目录读写权限
  895. */
  896. function check_dir_iswritable($dir)
  897. {
  898. $testDir = $dir;
  899. sp_dir_create($testDir);
  900. if (sp_testwrite($testDir)) {
  901. return true;
  902. } else {
  903. return false;
  904. }
  905. }
  906. /**
  907. * 检查测试文件是否可写入
  908. */
  909. function sp_testwrite($d)
  910. {
  911. $tfile = "_test.txt";
  912. $fp = @fopen($d . "/" . $tfile, "w");
  913. if (!$fp) {
  914. return false;
  915. }
  916. fclose($fp);
  917. $rs = @unlink($d . "/" . $tfile);
  918. if ($rs) {
  919. return true;
  920. }
  921. return false;
  922. }
  923. /**
  924. * 检查文件是否创建
  925. */
  926. function sp_dir_create($path, $mode = 0777)
  927. {
  928. if (is_dir($path))
  929. return true;
  930. $ftp_enable = 0;
  931. $path = sp_dir_path($path);
  932. $temp = explode('/', $path);
  933. $cur_dir = '';
  934. $max = count($temp) - 1;
  935. for ($i = 0; $i < $max; $i++) {
  936. $cur_dir .= $temp[ $i ] . '/';
  937. if (@is_dir($cur_dir))
  938. continue;
  939. @mkdir($cur_dir, 0777, true);
  940. @chmod($cur_dir, 0777);
  941. }
  942. return is_dir($path);
  943. }
  944. /**
  945. * 判断目录是否为空
  946. * @param $dir
  947. * @return bool
  948. */
  949. function dir_is_empty($dir)
  950. {
  951. $handle = opendir($dir);
  952. while (false !== ( $entry = readdir($handle) )) {
  953. if ($entry != "." && $entry != "..") {
  954. return FALSE;
  955. }
  956. }
  957. return TRUE;
  958. }
  959. /**
  960. * 创建文件夹
  961. *
  962. * @param string $path 文件夹路径
  963. * @param int $mode 访问权限
  964. * @param bool $recursive 是否递归创建
  965. * @return bool
  966. */
  967. function dir_mkdir($path = '', $mode = 0777, $recursive = true)
  968. {
  969. clearstatcache();
  970. if (!is_dir($path)) {
  971. mkdir($path, $mode, $recursive);
  972. return chmod($path, $mode);
  973. }
  974. return true;
  975. }
  976. /**
  977. * 文件夹文件拷贝
  978. *
  979. * @param string $src 来源文件夹
  980. * @param string $dst 目的地文件夹
  981. * @return bool
  982. */
  983. function dir_copy($src = '', $dst = '', $ignore_files = [])
  984. {
  985. if (empty($src) || empty($dst)) {
  986. return false;
  987. }
  988. $dir = opendir($src);
  989. dir_mkdir($dst);
  990. while (false !== ( $file = readdir($dir) )) {
  991. if (( $file != '.' ) && ( $file != '..' )) {
  992. if (is_dir($src . '/' . $file)) {
  993. dir_copy($src . '/' . $file, $dst . '/' . $file);
  994. } else {
  995. if (!in_array($file, $ignore_files)) {
  996. copy($src . '/' . $file, $dst . '/' . $file);
  997. }
  998. }
  999. }
  1000. }
  1001. closedir($dir);
  1002. return true;
  1003. }
  1004. /**查询存在目录
  1005. * @param $dir
  1006. */
  1007. function sp_exist_dir($dir)
  1008. {
  1009. $is_exist = false;
  1010. $is_write = false;
  1011. while (!$is_exist) {
  1012. $dir = dirname($dir);
  1013. if (is_dir($dir) || $dir == ".") {
  1014. $is_exist = true;
  1015. if (is_writeable($dir)) {
  1016. $is_write = true;
  1017. }
  1018. }
  1019. }
  1020. return $is_write;
  1021. }
  1022. /**
  1023. * 拼接字符串
  1024. * @param $string
  1025. * @param $delimiter 分割字符
  1026. * @param $value
  1027. */
  1028. function string_split($string, $delimiter, $value)
  1029. {
  1030. return empty($string) ? $value : $string . $delimiter . $value;
  1031. }
  1032. /**
  1033. * $str为要进行截取的字符串,$length为截取长度(汉字算一个字,字母算半个字
  1034. * @param $str
  1035. * @param $length
  1036. * @return string
  1037. */
  1038. function str_sub($str, $length = 10)
  1039. {
  1040. return mb_substr($str, 0, $length, 'UTF-8') . "...";
  1041. }
  1042. /**
  1043. * 删除缓存文件使用
  1044. * @param $dir
  1045. */
  1046. function rmdirs($dir)
  1047. {
  1048. $dir = 'runtime/' . $dir;
  1049. $dh = opendir($dir);
  1050. while ($file = readdir($dh)) {
  1051. if ($file != "." && $file != "..") {
  1052. $fullpath = $dir . "/" . $file;
  1053. if (is_dir($fullpath)) {
  1054. rmdirs($fullpath);
  1055. } else {
  1056. unlink($fullpath);
  1057. }
  1058. }
  1059. }
  1060. closedir($dh);
  1061. }
  1062. /**
  1063. * 删除指定目录所有文件和目录
  1064. * @param $path
  1065. */
  1066. function deleteDir($path)
  1067. {
  1068. if (is_dir($path)) {
  1069. //扫描一个目录内的所有目录和文件并返回数组
  1070. $dirs = scandir($path);
  1071. foreach ($dirs as $dir) {
  1072. //排除目录中的当前目录(.)和上一级目录(..)
  1073. if ($dir != '.' && $dir != '..') {
  1074. //如果是目录则递归子目录,继续操作
  1075. $sonDir = $path . '/' . $dir;
  1076. if (is_dir($sonDir)) {
  1077. //递归删除
  1078. deleteDir($sonDir);
  1079. //目录内的子目录和文件删除后删除空目录
  1080. @rmdir($sonDir);
  1081. } else {
  1082. //如果是文件直接删除
  1083. @unlink($sonDir);
  1084. }
  1085. }
  1086. }
  1087. }
  1088. }
  1089. /**
  1090. * 以天为单位 计算间隔内的日期数组
  1091. * @param $srart_time
  1092. * @param $end_time
  1093. * @return array
  1094. */
  1095. function periodGroup($srart_time, $end_time, $format = 'Ymd')
  1096. {
  1097. $type_time = 3600 * 24;
  1098. $data = [];
  1099. for ($i = $srart_time; $i <= $end_time; $i += $type_time) {
  1100. $data[] = date($format, $i);
  1101. }
  1102. return $data;
  1103. }
  1104. /*
  1105. * 导出数据到日志文件
  1106. * */
  1107. function outFileLog($data,$filename='log',$title='data'){
  1108. file_put_contents($_SERVER['DOCUMENT_ROOT'] . '/lic/'.$filename.'.txt', PHP_EOL .date('Y-m-d h:i:s', time()).'~'.$title.':' . json_encode($data,JSON_UNESCAPED_UNICODE), FILE_APPEND);
  1109. }
  1110. //解决个别中文乱码
  1111. function mbStrreplace($content, $to_encoding = "UTF-8", $from_encoding = "GBK")
  1112. {
  1113. $content = mb_convert_encoding($content, $to_encoding, $from_encoding);
  1114. $str = mb_convert_encoding(" ", $to_encoding, $from_encoding);
  1115. $content = mb_eregi_replace($str, " ", $content);
  1116. $content = mb_convert_encoding($content, $from_encoding, $to_encoding);
  1117. $content = trim($content);
  1118. return $content;
  1119. }
  1120. /**
  1121. * 将非UTF-8字符集的编码转为UTF-8
  1122. *
  1123. * @param mixed $mixed 源数据
  1124. *
  1125. * @return mixed utf-8格式数据
  1126. */
  1127. function charset2utf8($mixed)
  1128. {
  1129. if (is_array($mixed)) {
  1130. foreach ($mixed as $k => $v) {
  1131. if (is_array($v)) {
  1132. $mixed[ $k ] = charsetToUTF8($v);
  1133. } else {
  1134. $encode = mb_detect_encoding($v, array ( 'ASCII', 'UTF-8', 'GB2312', 'GBK', 'BIG5' ));
  1135. if ($encode == 'EUC-CN') {
  1136. $mixed[ $k ] = iconv('GBK', 'UTF-8', $v);
  1137. }
  1138. }
  1139. }
  1140. } else {
  1141. $encode = mb_detect_encoding($mixed, array ( 'ASCII', 'UTF-8', 'GB2312', 'GBK', 'BIG5' ));
  1142. if ($encode == 'EUC-CN') {
  1143. $mixed = iconv('GBK', 'UTF-8', $mixed);
  1144. }
  1145. }
  1146. return $mixed;
  1147. }
  1148. /**
  1149. * 过滤bom
  1150. * @param $filename
  1151. */
  1152. function check_bom($filename)
  1153. {
  1154. $contents = file_get_contents($filename);
  1155. $charset[ 1 ] = substr($contents, 0, 1);
  1156. $charset[ 2 ] = substr($contents, 1, 1);
  1157. $charset[ 3 ] = substr($contents, 2, 1);
  1158. if (ord($charset[ 1 ]) == 239 && ord($charset[ 2 ]) == 187 && ord($charset[ 3 ]) == 191) {
  1159. $rest = substr($contents, 3);
  1160. return $rest;
  1161. } else {
  1162. return $contents;
  1163. }
  1164. }
  1165. /**
  1166. * 判断 文件/目录 是否可写(取代系统自带的 is_writeable 函数)
  1167. *
  1168. * @param string $file 文件/目录
  1169. * @return boolean
  1170. */
  1171. function is_write($file)
  1172. {
  1173. if (is_dir($file)) {
  1174. $dir = $file;
  1175. if ($fp = @fopen("$dir/test.txt", 'w')) {
  1176. @fclose($fp);
  1177. @unlink("$dir/test.txt");
  1178. $writeable = true;
  1179. } else {
  1180. $writeable = false;
  1181. }
  1182. } else {
  1183. if ($fp = @fopen($file, 'a+')) {
  1184. @fclose($fp);
  1185. $writeable = true;
  1186. } else {
  1187. $writeable = false;
  1188. }
  1189. }
  1190. return $writeable;
  1191. }
  1192. /**
  1193. * 是否是url链接
  1194. * @param unknown $string
  1195. * @return boolean
  1196. */
  1197. function is_url($string)
  1198. {
  1199. if (strstr($string, 'http://') === false && strstr($string, 'https://') === false) {
  1200. return false;
  1201. } else {
  1202. return true;
  1203. }
  1204. }
  1205. /**
  1206. * 计算两点之间的距离
  1207. * @param double $lng1 经度1
  1208. * @param double $lat1 纬度1
  1209. * @param double $lng2 经度2
  1210. * @param double $lat2 纬度2
  1211. * @param int $unit m,km
  1212. * @param int $decimal 位数
  1213. * @return float 米
  1214. */
  1215. function getDistance($lng1, $lat1, $lng2, $lat2, $unit = 1, $decimal = 0)
  1216. {
  1217. $EARTH_RADIUS = 6370.996; // 地球半径系数
  1218. $PI = 3.1415926535898;
  1219. $radLat1 = $lat1 * $PI / 180.0;
  1220. $radLat2 = $lat2 * $PI / 180.0;
  1221. $radLng1 = $lng1 * $PI / 180.0;
  1222. $radLng2 = $lng2 * $PI / 180.0;
  1223. $a = $radLat1 - $radLat2;
  1224. $b = $radLng1 - $radLng2;
  1225. $distance = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2)));
  1226. $distance = $distance * $EARTH_RADIUS * 1000;
  1227. if ($unit === 2) {
  1228. $distance /= 1000;
  1229. }
  1230. return round($distance, $decimal);
  1231. }
  1232. /**
  1233. *
  1234. * @param unknown $string
  1235. * @return boolean
  1236. */
  1237. function is_json($string)
  1238. {
  1239. json_decode($string);
  1240. return ( json_last_error() == JSON_ERROR_NONE );
  1241. }
  1242. /**
  1243. * 获取站点h5域名
  1244. * @param $site_id
  1245. * @return string
  1246. */
  1247. function getH5Domain()
  1248. {
  1249. $config = new \app\model\web\Config();
  1250. $info = $config->getH5DomainName();
  1251. $h5_name = $info[ 'data' ][ 'value' ][ 'domain_name_h5' ];
  1252. if ($h5_name) {
  1253. return $h5_name;
  1254. }
  1255. return ROOT_URL . '/h5';
  1256. }
  1257. function get_http_type()
  1258. {
  1259. $http_type = ( ( isset($_SERVER[ 'HTTPS' ]) && $_SERVER[ 'HTTPS' ] == 'on' ) || ( isset($_SERVER[ 'HTTP_X_FORWARDED_PROTO' ]) && $_SERVER[ 'HTTP_X_FORWARDED_PROTO' ] == 'https' ) ) ? 'https' : 'http';
  1260. return $http_type;
  1261. }
  1262. /**
  1263. * 获取文件地图
  1264. * @param $path
  1265. * @param array $arr
  1266. * @return array
  1267. */
  1268. function getFileMap($path, $arr = [])
  1269. {
  1270. if (is_dir($path)) {
  1271. $dir = scandir($path);
  1272. foreach ($dir as $file_path) {
  1273. if ($file_path != '.' && $file_path != '..') {
  1274. $temp_path = $path . '/' . $file_path;
  1275. if (is_dir($temp_path)) {
  1276. $arr[ $temp_path ] = $file_path;
  1277. $arr = getFileMap($temp_path, $arr);
  1278. } else {
  1279. $arr[ $temp_path ] = $file_path;
  1280. }
  1281. }
  1282. }
  1283. return $arr;
  1284. }
  1285. }
  1286. /**
  1287. * 判断一个坐标是否在一个多边形内(由多个坐标围成的)
  1288. * 基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
  1289. * 在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。
  1290. * @param array $point 指定点坐标 $point=['longitude'=>121.427417,'latitude'=>31.20357];
  1291. * @param array $pts 多边形坐标 顺时针方向 $arr=[['longitude'=>121.23036,'latitude'=>31.218609],['longitude'=>121.233666,'latitude'=>31.210579].............];
  1292. */
  1293. function is_point_in_polygon($point, $pts)
  1294. {
  1295. $N = count($pts);
  1296. $boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
  1297. $intersectCount = 0;//cross points count of x
  1298. $precision = 2e-10; //浮点类型计算时候与0比较时候的容差
  1299. $p1 = 0;//neighbour bound vertices
  1300. $p2 = 0;
  1301. $p = $point; //测试点
  1302. $p1 = $pts[ 0 ];//left vertex
  1303. for ($i = 1; $i <= $N; ++$i) {//check all rays
  1304. // dump($p1);
  1305. if ($p[ 'longitude' ] == $p1[ 'longitude' ] && $p[ 'latitude' ] == $p1[ 'latitude' ]) {
  1306. return $boundOrVertex;//p is an vertex
  1307. }
  1308. $p2 = $pts[ $i % $N ];//right vertex
  1309. if ($p[ 'latitude' ] < min($p1[ 'latitude' ], $p2[ 'latitude' ]) || $p[ 'latitude' ] > max($p1[ 'latitude' ], $p2[ 'latitude' ])) {//ray is outside of our interests
  1310. $p1 = $p2;
  1311. continue;//next ray left point
  1312. }
  1313. if ($p[ 'latitude' ] > min($p1[ 'latitude' ], $p2[ 'latitude' ]) && $p[ 'latitude' ] < max($p1[ 'latitude' ], $p2[ 'latitude' ])) {//ray is crossing over by the algorithm (common part of)
  1314. if ($p[ 'longitude' ] <= max($p1[ 'longitude' ], $p2[ 'longitude' ])) {//x is before of ray
  1315. if ($p1[ 'latitude' ] == $p2[ 'latitude' ] && $p[ 'longitude' ] >= min($p1[ 'longitude' ], $p2[ 'longitude' ])) {//overlies on a horizontal ray
  1316. return $boundOrVertex;
  1317. }
  1318. if ($p1[ 'longitude' ] == $p2[ 'longitude' ]) {//ray is vertical
  1319. if ($p1[ 'longitude' ] == $p[ 'longitude' ]) {//overlies on a vertical ray
  1320. return $boundOrVertex;
  1321. } else {//before ray
  1322. ++$intersectCount;
  1323. }
  1324. } else {//cross point on the left side
  1325. $xinters = ( $p[ 'latitude' ] - $p1[ 'latitude' ] ) * ( $p2[ 'longitude' ] - $p1[ 'longitude' ] ) / ( $p2[ 'latitude' ] - $p1[ 'latitude' ] ) + $p1[ 'longitude' ];//cross point of lng
  1326. if (abs($p[ 'longitude' ] - $xinters) < $precision) {//overlies on a ray
  1327. return $boundOrVertex;
  1328. }
  1329. if ($p[ 'longitude' ] < $xinters) {//before ray
  1330. ++$intersectCount;
  1331. }
  1332. }
  1333. }
  1334. } else {//special case when ray is crossing through the vertex
  1335. if ($p[ 'latitude' ] == $p2[ 'latitude' ] && $p[ 'longitude' ] <= $p2[ 'longitude' ]) {//p crossing over p2
  1336. $p3 = $pts[ ( $i + 1 ) % $N ]; //next vertex
  1337. if ($p[ 'latitude' ] >= min($p1[ 'latitude' ], $p3[ 'latitude' ]) && $p[ 'latitude' ] <= max($p1[ 'latitude' ], $p3[ 'latitude' ])) { //p.latitude lies between p1.latitude & p3.latitude
  1338. ++$intersectCount;
  1339. } else {
  1340. $intersectCount += 2;
  1341. }
  1342. }
  1343. }
  1344. $p1 = $p2;//next ray left point
  1345. }
  1346. if ($intersectCount % 2 == 0) {//偶数在多边形外
  1347. return false;
  1348. } else { //奇数在多边形内
  1349. return true;
  1350. }
  1351. }
  1352. /**
  1353. * 过滤特殊字符
  1354. * @param $strParam
  1355. * @return null|string|string[]
  1356. */
  1357. function replaceSpecialChar($strParam)
  1358. {
  1359. $regex = "/\/|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\(|\)|\_|\+|\{|\}|\:|\<|\>|\?|\[|\]|\,|\.|\/|\;|\'|\`|\-|\=|\\\|\||\s+/";
  1360. return preg_replace($regex, "", $strParam);
  1361. }
  1362. function delFile($path)
  1363. {
  1364. $res = false;
  1365. if (file_exists($path)) {
  1366. $res = unlink($path);
  1367. }
  1368. return $res;
  1369. }
  1370. /**
  1371. * base64转二进制
  1372. * @param $base64Str
  1373. * @return array|boolean
  1374. */
  1375. function base64_to_blob($base64Str)
  1376. {
  1377. if ($index = strpos($base64Str, 'base64,', 0)) {
  1378. $blobStr = substr($base64Str, $index + 7);
  1379. $typestr = substr($base64Str, 0, $index);
  1380. preg_match("/^data:(.*);$/", $typestr, $arr);
  1381. return [ 'blob' => base64_decode($blobStr), 'type' => $arr[ 1 ] ];
  1382. }
  1383. return false;
  1384. }
  1385. /**
  1386. * 获取近七日的时间
  1387. * @param $time
  1388. * @return array|boo
  1389. */
  1390. function getweeks($time = '', $format = 'Y-m-d')
  1391. {
  1392. $time = $time != '' ? $time : time();
  1393. //组合数据
  1394. $date = [];
  1395. for ($i = 1; $i <= 10; $i++) {
  1396. $date[ $i ] = date($format, strtotime('+' . ( $i - 10 ) . ' days', $time));
  1397. }
  1398. return $date;
  1399. }
  1400. /**
  1401. * 两个数字比
  1402. * @param $first | $second
  1403. * @return string
  1404. */
  1405. function diff_rate($first, $second)
  1406. {
  1407. if ($second != 0) {
  1408. $result = sprintf('%.2f', ( ( $first - $second ) / $second ) * 100) . '%';
  1409. } else if ($second == 0 & $first != 0) {
  1410. $result = '100%';
  1411. } else {
  1412. $result = '0%';
  1413. }
  1414. return $result;
  1415. }
  1416. /**
  1417. * 过滤bom
  1418. * @param $filename
  1419. */
  1420. function removeBom($contents)
  1421. {
  1422. $charset[ 1 ] = substr($contents, 0, 1);
  1423. $charset[ 2 ] = substr($contents, 1, 1);
  1424. $charset[ 3 ] = substr($contents, 2, 1);
  1425. if (ord($charset[ 1 ]) == 239 && ord($charset[ 2 ]) == 187 && ord($charset[ 3 ]) == 191) {
  1426. $rest = substr($contents, 3);
  1427. return $rest;
  1428. } else {
  1429. return $contents;
  1430. }
  1431. }
  1432. /**
  1433. * 复制拷贝
  1434. * @param string $src 原目录
  1435. * @param string $dst 复制到的目录
  1436. */
  1437. function recurseCopy($src, $dst)
  1438. {
  1439. $dir = opendir($src);
  1440. @mkdir($dst);
  1441. while (false !== ( $file = readdir($dir) )) {
  1442. if (( $file != '.' ) && ( $file != '..' )) {
  1443. if (is_dir($src . '/' . $file)) {
  1444. recurseCopy($src . '/' . $file, $dst . '/' . $file);
  1445. } else {
  1446. copy($src . '/' . $file, $dst . '/' . $file);
  1447. }
  1448. }
  1449. }
  1450. closedir($dir);
  1451. }
  1452. /**
  1453. * 获取毫秒数
  1454. * @return false|string
  1455. */
  1456. function getMillisecond()
  1457. {
  1458. list($microsecond, $time) = explode(' ', microtime());
  1459. $time = (float) sprintf('%.0f', ( floatval($microsecond) + floatval($time) ) * 1000);
  1460. return substr($time, -3);
  1461. }
  1462. /**
  1463. * #号颜色转为rgb
  1464. * @return false|string
  1465. */
  1466. function hex2rgb($color)
  1467. {
  1468. if ($color[ 0 ] == '#') {
  1469. $color = substr($color, 1);
  1470. }
  1471. if (strlen($color) == 6) {
  1472. list($r, $g, $b) = array ( $color[ 0 ] . $color[ 1 ], $color[ 2 ] . $color[ 3 ], $color[ 4 ] . $color[ 5 ] );
  1473. } elseif (strlen($color) == 3) {
  1474. list($r, $g, $b) = array ( $color[ 0 ] . $color[ 0 ], $color[ 1 ] . $color[ 1 ], $color[ 2 ] . $color[ 2 ] );
  1475. } else {
  1476. return false;
  1477. }
  1478. $r = hexdec($r);
  1479. $g = hexdec($g);
  1480. $b = hexdec($b);
  1481. return array ( $r, $g, $b );
  1482. }
  1483. /**
  1484. * 生成条形码
  1485. * @param $content
  1486. * @param string $path
  1487. * @param int $scale 条形码放大比率
  1488. * @param int $size 条形码文本大小
  1489. * @return string
  1490. */
  1491. function getBarcode($content, $path = '', $scale = 2, $size = 14)
  1492. {
  1493. $barcode = new Barcode($size, $content);
  1494. $path = $barcode->generateBarcode($path, $scale);
  1495. return $path;
  1496. }
  1497. /**
  1498. * 生成不重复的随机数
  1499. *
  1500. * @param unknown
  1501. * @return string
  1502. */
  1503. function NoRand($begin = 0, $end = 20, $limit = 5)
  1504. {
  1505. $rand_array = range($begin, $end);
  1506. shuffle($rand_array);//调用现成的数组随机排列函数
  1507. $number_arr = array_slice($rand_array, 0, $limit);//截取前$limit个
  1508. $number = '';
  1509. foreach ($number_arr as $k => $v) {
  1510. $number .= $v;
  1511. }
  1512. $number = trim($number);
  1513. return $number;
  1514. }
  1515. /**
  1516. * 获取某个日期的开始时间和结束时间
  1517. * @param string $date
  1518. * @return array
  1519. */
  1520. function getDayStartAndEndTime($date = '')
  1521. {
  1522. if (empty($date)) {
  1523. $time = time();
  1524. } else {
  1525. $time = strtotime($date);
  1526. }
  1527. //如果是第一笔订单才能累加下单会员数
  1528. $start_time = strtotime(date("Y-m-d", $time));//当日开始时间
  1529. $end_time = $start_time + 60 * 60 * 24;//当日结束时间
  1530. return [ 'start_time' => $start_time, 'end_time' => $end_time ];
  1531. }
  1532. /**
  1533. * 核验是否开启消息队列
  1534. * @param $params
  1535. * @param $fun1
  1536. * @param $fun2
  1537. * @return array
  1538. */
  1539. function checkQueue($params, $fun1, $fun2)
  1540. {
  1541. $system_config_model = new \app\model\system\SystemConfig();
  1542. $config = $system_config_model->getSystemConfig()[ 'data' ] ?? [];
  1543. $is_open_queue = $config[ 'is_open_queue' ] ?? 0;
  1544. if ($is_open_queue) {
  1545. $result = $fun1($params);
  1546. } else {
  1547. $result = $fun2($params);
  1548. }
  1549. return $result;
  1550. }
  1551. /**
  1552. * 通用处理金额的格式(主要用于业务)
  1553. * @param $money
  1554. */
  1555. function moneyFormat($money)
  1556. {
  1557. $money = round($money, 2);
  1558. return $money;
  1559. }
  1560. /**
  1561. * 长链接转短链接
  1562. * @param string $long_url
  1563. * @return string
  1564. */
  1565. function short_url(string $url) : string
  1566. {
  1567. $result = sprintf("%u", crc32($url));
  1568. $show = '';
  1569. while ($result > 0) {
  1570. $s = $result % 62;
  1571. if ($s > 35) {
  1572. $s = chr($s + 61);
  1573. } elseif ($s > 9 && $s <= 35) {
  1574. $s = chr($s + 55);
  1575. }
  1576. $show .= $s;
  1577. $result = floor($result / 62);
  1578. }
  1579. return $show;
  1580. }
  1581. function isMobile()
  1582. {
  1583. // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
  1584. if (isset($_SERVER[ 'HTTP_X_WAP_PROFILE' ])) {
  1585. return true;
  1586. }
  1587. // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
  1588. if (isset($_SERVER[ 'HTTP_VIA' ])) {
  1589. // 找不到为flase,否则为true
  1590. return stristr($_SERVER[ 'HTTP_VIA' ], "wap") ? true : false;
  1591. }
  1592. // 脑残法,判断手机发送的客户端标志,兼容性有待提高。其中'MicroMessenger'是电脑微信
  1593. if (isset($_SERVER[ 'HTTP_USER_AGENT' ])) {
  1594. $clientkeywords = array ( 'nokia', 'sony', 'ericsson', 'mot', 'samsung', 'htc', 'sgh', 'lg', 'sharp', 'sie-', 'philips', 'panasonic', 'alcatel', 'lenovo', 'iphone', 'ipod', 'blackberry', 'meizu', 'android', 'netfront', 'symbian', 'ucweb', 'windowsce', 'palm', 'operamini', 'operamobi', 'openwave', 'nexusone', 'cldc', 'midp', 'wap', 'mobile', 'MicroMessenger' );
  1595. // 从HTTP_USER_AGENT中查找手机浏览器的关键字
  1596. if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER[ 'HTTP_USER_AGENT' ]))) {
  1597. return true;
  1598. }
  1599. }
  1600. // 协议法,因为有可能不准确,放到最后判断
  1601. if (isset ($_SERVER[ 'HTTP_ACCEPT' ])) {
  1602. // 如果只支持wml并且不支持html那一定是移动设备
  1603. // 如果支持wml和html但是wml在html之前则是移动设备
  1604. if (( strpos($_SERVER[ 'HTTP_ACCEPT' ], 'vnd.wap.wml') !== false ) && ( strpos($_SERVER[ 'HTTP_ACCEPT' ], 'text/html') === false || ( strpos($_SERVER[ 'HTTP_ACCEPT' ], 'vnd.wap.wml') < strpos($_SERVER[ 'HTTP_ACCEPT' ], 'text/html') ) )) {
  1605. return true;
  1606. }
  1607. }
  1608. return false;
  1609. }
  1610. //读取csv数据, 配合生成器使用
  1611. function getCsvRow($file)
  1612. {
  1613. $handle = fopen($file, 'rb');
  1614. if ($handle === false) {
  1615. throw new \Exception();
  1616. }
  1617. while (feof($handle) === false) {
  1618. yield fgetcsv($handle);
  1619. }
  1620. fclose($handle);
  1621. }
  1622. /**
  1623. * 数组内部字段求和
  1624. * @param $arr
  1625. * @param $num1
  1626. * @param string $num2
  1627. */
  1628. function getArraySum($arr, $field1, $field2 = '')
  1629. {
  1630. $sum = 0;
  1631. foreach ($arr as $v) {
  1632. $num1 = $v[ $field1 ] ?? 0;
  1633. $num2 = $v[ $field2 ] ?? 1;
  1634. $sum += $num1 * $num2;
  1635. }
  1636. return $sum;
  1637. }
  1638. /**
  1639. * 过滤Emoji
  1640. * @param $str
  1641. * @return string|string[]|null
  1642. */
  1643. function filterEmoji($str)
  1644. {
  1645. $str = preg_replace_callback(
  1646. '/./u', function(array $match) {
  1647. return strlen($match[ 0 ]) >= 4 ? '' : $match[ 0 ];
  1648. }, $str);
  1649. return $str;
  1650. }
  1651. /**
  1652. * 数字格式化,小数点保留3位,后三位都为0时,取整数
  1653. * @param $num
  1654. * @return float
  1655. */
  1656. function numberFormat($num)
  1657. {
  1658. $num = round($num, 3);
  1659. return $num;
  1660. }