util.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. <?php
  2. namespace common\components;
  3. use Yii;
  4. use yii\helpers\Json;
  5. class util
  6. {
  7. //判断是否微信浏览器
  8. public static function isWx()
  9. {
  10. if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') == true) {
  11. return true;
  12. }
  13. return false;
  14. }
  15. //根据两点间的经纬度计算距离
  16. public static function getDistance($lat1, $lng1, $lat2, $lng2)
  17. {
  18. $earthRadius = 6367000; //approximate radius of earth in meters
  19. $lat1 = ($lat1 * pi()) / 180;
  20. $lng1 = ($lng1 * pi()) / 180;
  21. $lat2 = ($lat2 * pi()) / 180;
  22. $lng2 = ($lng2 * pi()) / 180;
  23. $calcLongitude = $lng2 - $lng1;
  24. $calcLatitude = $lat2 - $lat1;
  25. $stepOne = pow(sin($calcLatitude / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLongitude / 2), 2);
  26. $stepTwo = 2 * asin(min(1, sqrt($stepOne)));
  27. $calculatedDistance = $earthRadius * $stepTwo;
  28. return round($calculatedDistance);
  29. }
  30. /**
  31. * 生成缩略图
  32. * @param string 源图绝对完整地址{带文件名及后缀名}
  33. * @param string 目标图绝对完整地址{带文件名及后缀名}
  34. * @param int 缩略图宽{0:此时目标高度不能为0,目标宽度为源图宽*(目标高度/源图高)}
  35. * @param int 缩略图高{0:此时目标宽度不能为0,目标高度为源图高*(目标宽度/源图宽)}
  36. * @param int 是否裁切{宽,高必须非0}
  37. * @param int /float 缩放{0:不缩放, 0<this<1:缩放到相应比例(此时宽高限制和裁切均失效)}
  38. * @return boolean
  39. * @author yangzhiguo0903@163.com
  40. */
  41. public static function img2thumb($src_img, $dst_img, $width = 75, $height = 75, $cut = 0, $proportion = 0)
  42. {
  43. if (!is_file($src_img)) {
  44. return false;
  45. }
  46. $ot = pathinfo($dst_img, PATHINFO_EXTENSION);
  47. $otfunc = 'image' . ($ot == 'jpg' ? 'jpeg' : $ot);
  48. $srcinfo = getimagesize($src_img);
  49. $src_w = $srcinfo[0];
  50. $src_h = $srcinfo[1];
  51. $type = strtolower(substr(image_type_to_extension($srcinfo[2]), 1));
  52. $createfun = 'imagecreatefrom' . ($type == 'jpg' ? 'jpeg' : $type);
  53. $dst_h = $height;
  54. $dst_w = $width;
  55. $x = $y = 0;
  56. /**
  57. * 缩略图不超过源图尺寸(前提是宽或高只有一个)
  58. */
  59. if (($width > $src_w && $height > $src_h) || ($height > $src_h && $width == 0) || ($width > $src_w && $height == 0)) {
  60. $proportion = 1;
  61. }
  62. if ($width > $src_w) {
  63. $dst_w = $width = $src_w;
  64. }
  65. if ($height > $src_h) {
  66. $dst_h = $height = $src_h;
  67. }
  68. if (!$width && !$height && !$proportion) {
  69. return false;
  70. }
  71. if (!$proportion) {
  72. if ($cut == 0) {
  73. if ($dst_w && $dst_h) {
  74. if ($dst_w / $src_w > $dst_h / $src_h) {
  75. $dst_w = $src_w * ($dst_h / $src_h);
  76. $x = 0 - ($dst_w - $width) / 2;
  77. } else {
  78. $dst_h = $src_h * ($dst_w / $src_w);
  79. $y = 0 - ($dst_h - $height) / 2;
  80. }
  81. } else if ($dst_w xor $dst_h) {
  82. if ($dst_w && !$dst_h) //有宽无高
  83. {
  84. $propor = $dst_w / $src_w;
  85. $height = $dst_h = $src_h * $propor;
  86. } else if (!$dst_w && $dst_h) //有高无宽
  87. {
  88. $propor = $dst_h / $src_h;
  89. $width = $dst_w = $src_w * $propor;
  90. }
  91. }
  92. } else {
  93. if (!$dst_h) //裁剪时无高
  94. {
  95. $height = $dst_h = $dst_w;
  96. }
  97. if (!$dst_w) //裁剪时无宽
  98. {
  99. $width = $dst_w = $dst_h;
  100. }
  101. $propor = min(max($dst_w / $src_w, $dst_h / $src_h), 1);
  102. $dst_w = (int)round($src_w * $propor);
  103. $dst_h = (int)round($src_h * $propor);
  104. $x = ($width - $dst_w) / 2;
  105. $y = ($height - $dst_h) / 2;
  106. }
  107. } else {
  108. $proportion = min($proportion, 1);
  109. $height = $dst_h = $src_h * $proportion;
  110. $width = $dst_w = $src_w * $proportion;
  111. }
  112. $src = $createfun($src_img);
  113. $dst = imagecreatetruecolor($width ? $width : $dst_w, $height ? $height : $dst_h);
  114. $white = imagecolorallocate($dst, 255, 255, 255);
  115. imagefill($dst, 0, 0, $white);
  116. if (function_exists('imagecopyresampled')) {
  117. imagecopyresampled($dst, $src, $x, $y, 0, 0, $dst_w, $dst_h, $src_w, $src_h);
  118. } else {
  119. imagecopyresized($dst, $src, $x, $y, 0, 0, $dst_w, $dst_h, $src_w, $src_h);
  120. }
  121. $otfunc($dst, $dst_img);
  122. imagedestroy($dst);
  123. imagedestroy($src);
  124. //return true;
  125. return ['width' => $src_w, 'height' => $src_h];//modify sofashi
  126. }
  127. /**
  128. * 输出字符并结束运行
  129. */
  130. public static function stop($string = '')
  131. {
  132. echo $string;
  133. Yii::$app->end();
  134. }
  135. public static function end()
  136. {
  137. Yii::$app->end();
  138. }
  139. //输出json数据并结束运行
  140. public static function encode($data)
  141. {
  142. echo Json::encode($data);
  143. exit();
  144. }
  145. /**
  146. * 合并图片 ---lqh 2017-05-05
  147. * @param $background_img 背景原图
  148. * @param $inline_img 内嵌原图
  149. * @return mixed 合并图的路径名称
  150. */
  151. public static function mergeImg($background_img, $inline_img, $type = 'wx')
  152. {
  153. $app = Yii::getAlias("@app");
  154. $saveDir = $app . '/../images/qrcode/';
  155. $rand = stringUtil::buildOrderNo();
  156. $random = empty($unique) ? $rand : $unique . '_' . $rand;
  157. //背景框图
  158. $path_1 = $background_img;
  159. //二维码图片
  160. $path_2 = $inline_img;
  161. //将框和二维码图片分别取到两个画布中。 针对png格式
  162. $image_1 = imagecreatefrompng($path_1);
  163. $image_2 = imagecreatefrompng($path_2);
  164. //创建一个和框图片一样大小的真彩色画布(ps:只有这样才能保证后面copy二维码图片的时候不会失真)
  165. $image_3 = imageCreatetruecolor(imagesx($image_1), imagesy($image_1));
  166. //为真彩色画布创建白色背景,再设置为透明
  167. $color = imagecolorallocate($image_3, 255, 255, 255);
  168. imagefill($image_3, 0, 0, $color);
  169. imageColorTransparent($image_3, $color);
  170. //首先将框画布采样copy到真彩色画布中,不会失真
  171. imagecopyresampled($image_3, $image_1, 0, 0, 0, 0, imagesx($image_1), imagesy($image_1), imagesx($image_1), imagesy($image_1));
  172. //再将二维码图片copy到已经具有框图像的真彩色画布中,同样也不会失真
  173. //根据微信或则支付宝合并位置有所不同
  174. if ($type == 'wx') {
  175. imagecopymerge($image_3, $image_2, 220, 320, 0, 0, imagesx($image_2), imagesy($image_2), 100);
  176. } else {
  177. //支付宝
  178. imagecopymerge($image_3, $image_2, 450, 820, 0, 0, imagesx($image_2), imagesy($image_2), 100);
  179. }
  180. //将画布保存到指定的png文件
  181. imagepng($image_3, $saveDir . $random . '_merge.png');
  182. return '/qrcode/' . $random . '_merge.png';//组合图片
  183. }
  184. public static function mergeQrimg($backgroundImg, array $qrImg)
  185. {
  186. $app = Yii::getAlias("@app");
  187. $saveDir = $app . '/../images/qrcode/';
  188. $random = stringUtil::buildOrderNo();
  189. $dest = imagecreatefromjpeg($backgroundImg);
  190. // Get new sizes
  191. list($width, $height) = getimagesize($qrImg['wifi']);
  192. list($newwidth, $newheight) = getimagesize($qrImg['zhifubao']);
  193. $newwidth = $newwidth + 35;//下载的wifi二维码size太小,放大些
  194. $newheight = $newheight + 35;
  195. // Load
  196. $thumb = imagecreatetruecolor($newwidth, $newheight);
  197. $source = imagecreatefromjpeg($qrImg['wifi']);
  198. // Resize
  199. imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
  200. imagejpeg($thumb, $saveDir . "temp.jpeg");//Output image to file
  201. //微信(支付宝)二维码、WiFi二维码
  202. $zfbQrImg = imagecreatefrompng($qrImg['zhifubao']);
  203. $WXQrImg = imagecreatefrompng($qrImg['weixin']);
  204. $wifiQrImg = imagecreatefromjpeg($saveDir . "temp.jpeg");
  205. imagealphablending($dest, false);
  206. imagesavealpha($dest, true);
  207. imagecopymerge($dest, $zfbQrImg, 240, 538, 0, 0, imagesx($zfbQrImg), imagesy($zfbQrImg), 100);
  208. imagecopymerge($dest, $WXQrImg, 985, 538, 0, 0, imagesx($WXQrImg), imagesy($WXQrImg), 100);
  209. imagecopymerge($dest, $wifiQrImg, 1708, 520, 0, 0, imagesx($wifiQrImg), imagesy($wifiQrImg), 100);
  210. imagepng($dest, $saveDir . $random . '_fullQrImg.png');
  211. imagedestroy($dest);
  212. imagedestroy($zfbQrImg);
  213. imagedestroy($WXQrImg);
  214. imagedestroy($wifiQrImg);
  215. return '/qrcode/' . $random . '_fullQrImg.png';//组合图片
  216. }
  217. //获取服务器IP
  218. public static function serverIp()
  219. {
  220. if (isset($_SERVER)) {
  221. if ($_SERVER['SERVER_ADDR']) {
  222. $server_ip = $_SERVER['SERVER_ADDR'];
  223. } else {
  224. $server_ip = $_SERVER['LOCAL_ADDR'];
  225. }
  226. } else {
  227. $server_ip = getenv('SERVER_ADDR');
  228. }
  229. return $server_ip;
  230. }
  231. //获取根目录 ssh 2020.3.11
  232. public static function getRootDir()
  233. {
  234. $basePath = Yii::$app->basePath;
  235. if (Yii::$app->id == 'app-console') {
  236. $root = $basePath . "/../";
  237. } else {
  238. $root = $basePath . "/../../";
  239. }
  240. return $root;
  241. }
  242. //错误输出
  243. public static function fail($msg = '操作失败')
  244. {
  245. Yii::info($msg);
  246. $report = isset(Yii::$app->params['errorReport']) ? Yii::$app->params['errorReport'] : 0;
  247. if ($report == 1) {
  248. throw new \Exception($msg);
  249. }
  250. self::encode(['code' => 0, 'msg' => $msg, 'data' => []]);
  251. }
  252. public static function mistake($msg = '操作失败', $mask = false, $icon = 'none', $duration = 1500)
  253. {
  254. $report = isset(Yii::$app->params['errorReport']) ? Yii::$app->params['errorReport'] : 0;
  255. if ($report == 1) {
  256. throw new \Exception($msg);
  257. }
  258. self::encode(['code' => 0, 'msg' => $msg, 'data' => [], 'mask' => $mask, 'icon' => $icon, 'duration' => $duration]);
  259. }
  260. //错误输出,带自定义code
  261. public static function error($code, $msg)
  262. {
  263. self::encode(['code' => $code, 'msg' => $msg, 'data' => []]);
  264. }
  265. //成功输出内容
  266. public static function success($data, $msg = '操作成功')
  267. {
  268. self::encode(['code' => 1, 'msg' => $msg, 'data' => $data]);
  269. }
  270. //退出当前登陆 ssh 2020.3.8
  271. public static function logout($msg = '当前登陆信息已失效,请重新登陆')
  272. {
  273. self::encode(['code' => 2, 'msg' => $msg, 'data' => []]);
  274. }
  275. //只输出执行完成状态 ssh 2020.3.11
  276. public static function complete($msg = '')
  277. {
  278. $msg = empty($msg) ? '操作成功' : $msg;
  279. self::encode(['code' => 1, 'msg' => $msg, 'data' => []]);
  280. }
  281. public static function notLogin($msg = '您还没有登陆哦')
  282. {
  283. self::encode(['code' => -1, 'msg' => $msg, 'data' => []]);
  284. }
  285. /**
  286. * [getLock 时间锁]
  287. * @param [type] $key [string]
  288. * @param integer $expire [time]
  289. * @return [type] [bool]
  290. */
  291. public static function getLock($key, $expire = 10)
  292. {
  293. $redis = Yii::$app->redis;
  294. return $redis->setex($key, $expire, time());
  295. }
  296. /**
  297. * 检测锁是否存在
  298. * @param $key
  299. * @return bool
  300. */
  301. public static function checkLock($key)
  302. {
  303. $redis = Yii::$app->redis;
  304. if ($redis->get($key)) {
  305. return true;
  306. } else {
  307. return false;
  308. }
  309. }
  310. /**
  311. * 获取锁
  312. * @param String $key 锁标识
  313. * @param Int $expire 锁过期时间
  314. * @param Int $waitTime 等待时间(超时时间) 秒
  315. * @return Boolean
  316. */
  317. public static function lock($key, $expire = 5, $waitTime = 5)
  318. {
  319. $redis = Yii::$app->redis;
  320. $isLock = $redis->setex($key, $expire, time() + $expire);
  321. $time = microtime(true);
  322. $exitTime = $waitTime + $time;
  323. // 不能获取锁
  324. if (!$isLock) {
  325. // 判断锁是否过期 锁已过期 删除锁 重新获取 防止过期时间设置长,结束时没主动调unlock
  326. $lockTime = $redis->get($key);
  327. if ($lockTime && time() > $lockTime) {
  328. self::unlock($key);
  329. $isLock = $redis->setex($key, $expire, time() + $expire);
  330. }
  331. if (!$isLock) {
  332. while (true) {
  333. usleep(50);
  334. $isLock = $redis->setex($key, $expire, time() + $expire);
  335. if ($isLock) {
  336. break;
  337. }
  338. if (microtime(true) > $exitTime) {
  339. //超时了
  340. break;
  341. }
  342. }
  343. }
  344. }
  345. return $isLock ? true : false;
  346. }
  347. /**
  348. * 释放锁
  349. * @param String $key 锁标识
  350. * @return Boolean
  351. */
  352. public static function unlock($key)
  353. {
  354. $redis = Yii::$app->redis;
  355. return $redis->del($key);
  356. }
  357. //检查是否有重复提交 ssh 20211018
  358. public static function checkRepeatCommit($adminId, $second = 10)
  359. {
  360. $ctl = Yii::$app->controller->id;
  361. $action = Yii::$app->controller->action->id;
  362. $cacheKey = "checkRepeatCommit_" . $ctl . "_" . $action . "_" . $adminId;
  363. $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
  364. if (!empty($has)) {
  365. util::fail('请稍等几秒再提交');
  366. }
  367. Yii::$app->redis->executeCommand('SETEX', [$cacheKey, $second, 'has']);
  368. }
  369. }