util.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <?php
  2. namespace common\components;
  3. use Yii;
  4. use yii\helpers\Json;
  5. class util
  6. {
  7. /**
  8. * 判断是否微信浏览器
  9. * @return boolean
  10. */
  11. public static function isWeixin()
  12. {
  13. if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') == true) {
  14. return true;
  15. }
  16. Yii::info('请求头:'.$_SERVER['HTTP_USER_AGENT']);
  17. return false;
  18. }
  19. /**
  20. * @desc 根据两点间的经纬度计算距离
  21. * @param float $lat 纬度值
  22. * @param float $lng 经度值
  23. */
  24. public static function getDistance($lat1, $lng1, $lat2, $lng2)
  25. {
  26. $earthRadius = 6367000; //approximate radius of earth in meters
  27. /*
  28. Convert these degrees to radians
  29. to work with the formula
  30. */
  31. $lat1 = ($lat1 * pi()) / 180;
  32. $lng1 = ($lng1 * pi()) / 180;
  33. $lat2 = ($lat2 * pi()) / 180;
  34. $lng2 = ($lng2 * pi()) / 180;
  35. /*
  36. Using the
  37. Haversine formula
  38. http://en.wikipedia.org/wiki/Haversine_formula
  39. calculate the distance
  40. */
  41. $calcLongitude = $lng2 - $lng1;
  42. $calcLatitude = $lat2 - $lat1;
  43. $stepOne = pow(sin($calcLatitude / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLongitude / 2), 2);
  44. $stepTwo = 2 * asin(min(1, sqrt($stepOne)));
  45. $calculatedDistance = $earthRadius * $stepTwo;
  46. return round($calculatedDistance);
  47. }
  48. /**
  49. * 生成缩略图
  50. * @author yangzhiguo0903@163.com
  51. * @param string 源图绝对完整地址{带文件名及后缀名}
  52. * @param string 目标图绝对完整地址{带文件名及后缀名}
  53. * @param int 缩略图宽{0:此时目标高度不能为0,目标宽度为源图宽*(目标高度/源图高)}
  54. * @param int 缩略图高{0:此时目标宽度不能为0,目标高度为源图高*(目标宽度/源图宽)}
  55. * @param int 是否裁切{宽,高必须非0}
  56. * @param int /float 缩放{0:不缩放, 0<this<1:缩放到相应比例(此时宽高限制和裁切均失效)}
  57. * @return boolean
  58. */
  59. public static function img2thumb($src_img, $dst_img, $width = 75, $height = 75, $cut = 0, $proportion = 0)
  60. {
  61. if (!is_file($src_img)) {
  62. return false;
  63. }
  64. $ot = pathinfo($dst_img, PATHINFO_EXTENSION);
  65. $otfunc = 'image' . ($ot == 'jpg' ? 'jpeg' : $ot);
  66. $srcinfo = getimagesize($src_img);
  67. $src_w = $srcinfo[0];
  68. $src_h = $srcinfo[1];
  69. $type = strtolower(substr(image_type_to_extension($srcinfo[2]), 1));
  70. $createfun = 'imagecreatefrom' . ($type == 'jpg' ? 'jpeg' : $type);
  71. $dst_h = $height;
  72. $dst_w = $width;
  73. $x = $y = 0;
  74. /**
  75. * 缩略图不超过源图尺寸(前提是宽或高只有一个)
  76. */
  77. if (($width > $src_w && $height > $src_h) || ($height > $src_h && $width == 0) || ($width > $src_w && $height == 0)) {
  78. $proportion = 1;
  79. }
  80. if ($width > $src_w) {
  81. $dst_w = $width = $src_w;
  82. }
  83. if ($height > $src_h) {
  84. $dst_h = $height = $src_h;
  85. }
  86. if (!$width && !$height && !$proportion) {
  87. return false;
  88. }
  89. if (!$proportion) {
  90. if ($cut == 0) {
  91. if ($dst_w && $dst_h) {
  92. if ($dst_w / $src_w > $dst_h / $src_h) {
  93. $dst_w = $src_w * ($dst_h / $src_h);
  94. $x = 0 - ($dst_w - $width) / 2;
  95. } else {
  96. $dst_h = $src_h * ($dst_w / $src_w);
  97. $y = 0 - ($dst_h - $height) / 2;
  98. }
  99. } else if ($dst_w xor $dst_h) {
  100. if ($dst_w && !$dst_h) //有宽无高
  101. {
  102. $propor = $dst_w / $src_w;
  103. $height = $dst_h = $src_h * $propor;
  104. } else if (!$dst_w && $dst_h) //有高无宽
  105. {
  106. $propor = $dst_h / $src_h;
  107. $width = $dst_w = $src_w * $propor;
  108. }
  109. }
  110. } else {
  111. if (!$dst_h) //裁剪时无高
  112. {
  113. $height = $dst_h = $dst_w;
  114. }
  115. if (!$dst_w) //裁剪时无宽
  116. {
  117. $width = $dst_w = $dst_h;
  118. }
  119. $propor = min(max($dst_w / $src_w, $dst_h / $src_h), 1);
  120. $dst_w = (int)round($src_w * $propor);
  121. $dst_h = (int)round($src_h * $propor);
  122. $x = ($width - $dst_w) / 2;
  123. $y = ($height - $dst_h) / 2;
  124. }
  125. } else {
  126. $proportion = min($proportion, 1);
  127. $height = $dst_h = $src_h * $proportion;
  128. $width = $dst_w = $src_w * $proportion;
  129. }
  130. $src = $createfun($src_img);
  131. $dst = imagecreatetruecolor($width ? $width : $dst_w, $height ? $height : $dst_h);
  132. $white = imagecolorallocate($dst, 255, 255, 255);
  133. imagefill($dst, 0, 0, $white);
  134. if (function_exists('imagecopyresampled')) {
  135. imagecopyresampled($dst, $src, $x, $y, 0, 0, $dst_w, $dst_h, $src_w, $src_h);
  136. } else {
  137. imagecopyresized($dst, $src, $x, $y, 0, 0, $dst_w, $dst_h, $src_w, $src_h);
  138. }
  139. $otfunc($dst, $dst_img);
  140. imagedestroy($dst);
  141. imagedestroy($src);
  142. //return true;
  143. return ['width' => $src_w, 'height' => $src_h];//modify sofashi
  144. }
  145. /**
  146. * 输出字符并结束运行
  147. */
  148. public static function stop($string = '')
  149. {
  150. echo $string;
  151. Yii::$app->end();
  152. }
  153. public static function end()
  154. {
  155. Yii::$app->end();
  156. }
  157. /**
  158. * 输出json数据并结束运行
  159. */
  160. public static function encode($data)
  161. {
  162. echo Json::encode($data);
  163. exit();
  164. }
  165. /**
  166. * 组合需要的格式,输出json数据并结束运行
  167. * code A0001 正确 其它如:A0002表示错误
  168. */
  169. public static function failInfo($msg = '操作失败', $code = 'A0002', $data = [])
  170. {
  171. $arr = ['code' => $code, 'msg' => $msg, 'data' => $data];
  172. self::encode($arr);
  173. }
  174. public static function successInfo($msg = '操作成功', $code = 'A0001', $data = [])
  175. {
  176. $arr = ['code' => $code, 'msg' => $msg, 'data' => $data];
  177. self::encode($arr);
  178. }
  179. //操作成功,只关心数据的返回
  180. public static function sendJson($data)
  181. {
  182. $arr = ['code' => 1, 'msg' => '操作成功', 'data' => $data];
  183. self::encode($arr);
  184. }
  185. //只关心返回失败状态
  186. public static function sendFail($msg)
  187. {
  188. //要输出页面
  189. if (isset(Yii::$app->params['exportStyle']) && Yii::$app->params['exportStyle'] == 'web') {
  190. //确认平台
  191. if (Yii::$app->params['appStyle'] == 'backend') {
  192. //跳转 echo '<script> window.location.href=""; </script>';
  193. }
  194. if (Yii::$app->params['appStyle'] == 'mobile') {
  195. //跳转 echo '<script> window.location.href=""; </script>';
  196. }
  197. Yii::$app->end();
  198. }
  199. $arr = ['code' => 0, 'msg' => $msg, 'data' => []];
  200. self::encode($arr);
  201. Yii::$app->end();
  202. }
  203. //只关心返回成功状态
  204. public static function sendSuccess()
  205. {
  206. $arr = ['code' => 1, 'msg' => '操作成功', 'data' => []];
  207. self::encode($arr);
  208. }
  209. /**
  210. * 合并图片 ---lqh 2017-05-05
  211. * @param $background_img 背景原图
  212. * @param $inline_img 内嵌原图
  213. * @return mixed 合并图的路径名称
  214. */
  215. public static function mergeImg($background_img, $inline_img, $type = 'wx')
  216. {
  217. $app = Yii::getAlias("@app");
  218. $saveDir = $app . '/../images/qrcode/';
  219. $rand = stringUtil::buildOrderNo();
  220. $random = empty($unique) ? $rand : $unique . '_' . $rand;
  221. //背景框图
  222. $path_1 = $background_img;
  223. //二维码图片
  224. $path_2 = $inline_img;
  225. //将框和二维码图片分别取到两个画布中。 针对png格式
  226. $image_1 = imagecreatefrompng($path_1);
  227. $image_2 = imagecreatefrompng($path_2);
  228. //创建一个和框图片一样大小的真彩色画布(ps:只有这样才能保证后面copy二维码图片的时候不会失真)
  229. $image_3 = imageCreatetruecolor(imagesx($image_1), imagesy($image_1));
  230. //为真彩色画布创建白色背景,再设置为透明
  231. $color = imagecolorallocate($image_3, 255, 255, 255);
  232. imagefill($image_3, 0, 0, $color);
  233. imageColorTransparent($image_3, $color);
  234. //首先将框画布采样copy到真彩色画布中,不会失真
  235. imagecopyresampled($image_3, $image_1, 0, 0, 0, 0, imagesx($image_1), imagesy($image_1), imagesx($image_1), imagesy($image_1));
  236. //再将二维码图片copy到已经具有框图像的真彩色画布中,同样也不会失真
  237. //根据微信或则支付宝合并位置有所不同
  238. if ($type == 'wx') {
  239. imagecopymerge($image_3, $image_2, 220, 320, 0, 0, imagesx($image_2), imagesy($image_2), 100);
  240. } else {
  241. //支付宝
  242. imagecopymerge($image_3, $image_2, 450, 820, 0, 0, imagesx($image_2), imagesy($image_2), 100);
  243. }
  244. //将画布保存到指定的png文件
  245. imagepng($image_3, $saveDir . $random . '_merge.png');
  246. return '/qrcode/' . $random . '_merge.png';//组合图片
  247. }
  248. public static function mergeQrimg($backgroundImg, array $qrImg)
  249. {
  250. $app = Yii::getAlias("@app");
  251. $saveDir = $app . '/../images/qrcode/';
  252. $random = stringUtil::buildOrderNo();
  253. $dest = imagecreatefromjpeg($backgroundImg);
  254. // Get new sizes
  255. list($width, $height) = getimagesize($qrImg['wifi']);
  256. list($newwidth, $newheight) = getimagesize($qrImg['zhifubao']);
  257. $newwidth = $newwidth + 35;//下载的wifi二维码size太小,放大些
  258. $newheight = $newheight + 35;
  259. // Load
  260. $thumb = imagecreatetruecolor($newwidth, $newheight);
  261. $source = imagecreatefromjpeg($qrImg['wifi']);
  262. // Resize
  263. imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
  264. imagejpeg($thumb, $saveDir . "temp.jpeg");//Output image to file
  265. //微信(支付宝)二维码、WiFi二维码
  266. $zfbQrImg = imagecreatefrompng($qrImg['zhifubao']);
  267. $WXQrImg = imagecreatefrompng($qrImg['weixin']);
  268. $wifiQrImg = imagecreatefromjpeg($saveDir . "temp.jpeg");
  269. imagealphablending($dest, false);
  270. imagesavealpha($dest, true);
  271. imagecopymerge($dest, $zfbQrImg, 240, 538, 0, 0, imagesx($zfbQrImg), imagesy($zfbQrImg), 100);
  272. imagecopymerge($dest, $WXQrImg, 985, 538, 0, 0, imagesx($WXQrImg), imagesy($WXQrImg), 100);
  273. imagecopymerge($dest, $wifiQrImg, 1708, 520, 0, 0, imagesx($wifiQrImg), imagesy($wifiQrImg), 100);
  274. imagepng($dest, $saveDir . $random . '_fullQrImg.png');
  275. imagedestroy($dest);
  276. imagedestroy($zfbQrImg);
  277. imagedestroy($WXQrImg);
  278. imagedestroy($wifiQrImg);
  279. return '/qrcode/' . $random . '_fullQrImg.png';//组合图片
  280. }
  281. /*
  282. *功能:php完美实现下载远程图片保存到本地
  283. *参数:文件url,保存文件目录,保存文件名称,使用的下载方式
  284. *当保存文件名称为空时则使用远程文件原来的名称
  285. */
  286. function downLoadImage($url, $save_dir = '', $filename = '', $type = 0)
  287. {
  288. if (trim($url) == '') {
  289. return array('file_name' => '', 'save_path' => '', 'error' => 1);
  290. }
  291. if (trim($save_dir) == '') {
  292. $save_dir = './';
  293. }
  294. if (trim($filename) == '') {//保存文件名
  295. $ext = strrchr($url, '.');
  296. if ($ext != '.gif' && $ext != '.jpg') {
  297. return array('file_name' => '', 'save_path' => '', 'error' => 3);
  298. }
  299. $filename = time() . $ext;
  300. }
  301. if (0 !== strrpos($save_dir, '/')) {
  302. $save_dir .= '/';
  303. }
  304. //创建保存目录
  305. if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
  306. return array('file_name' => '', 'save_path' => '', 'error' => 5);
  307. }
  308. //获取远程文件所采用的方法
  309. if ($type) {
  310. $ch = curl_init();
  311. $timeout = 5;
  312. curl_setopt($ch, CURLOPT_URL, $url);
  313. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  314. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  315. $img = curl_exec($ch);
  316. curl_close($ch);
  317. } else {
  318. ob_start();
  319. readfile($url);
  320. $img = ob_get_contents();
  321. ob_end_clean();
  322. }
  323. //$size=strlen($img);
  324. //文件大小
  325. $fp2 = @fopen($save_dir . $filename, 'a');
  326. fwrite($fp2, $img);
  327. fclose($fp2);
  328. unset($img, $url);
  329. return array('file_name' => $filename, 'save_path' => $save_dir . $filename, 'error' => 0);
  330. }
  331. /**
  332. * 获取服务器IP
  333. * @return array|false|string
  334. */
  335. public static function serverIp()
  336. {
  337. if (isset($_SERVER)) {
  338. if ($_SERVER['SERVER_ADDR']) {
  339. $server_ip = $_SERVER['SERVER_ADDR'];
  340. } else {
  341. $server_ip = $_SERVER['LOCAL_ADDR'];
  342. }
  343. } else {
  344. $server_ip = getenv('SERVER_ADDR');
  345. }
  346. return $server_ip;
  347. }
  348. /**
  349. * 是否移动端
  350. */
  351. public static function isMobileEnd()
  352. {
  353. // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
  354. if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
  355. return true;
  356. }
  357. // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
  358. if (isset($_SERVER['HTTP_VIA'])) {
  359. // 找不到为flase,否则为true
  360. return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
  361. }
  362. // 脑残法,判断手机发送的客户端标志,兼容性有待提高。其中'MicroMessenger'是电脑微信
  363. if (isset($_SERVER['HTTP_USER_AGENT'])) {
  364. $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');
  365. // 从HTTP_USER_AGENT中查找手机浏览器的关键字
  366. if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
  367. return true;
  368. }
  369. }
  370. // 协议法,因为有可能不准确,放到最后判断
  371. if (isset ($_SERVER['HTTP_ACCEPT'])) {
  372. // 如果只支持wml并且不支持html那一定是移动设备
  373. // 如果支持wml和html但是wml在html之前则是移动设备
  374. 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')))) {
  375. return true;
  376. }
  377. }
  378. return false;
  379. }
  380. /**
  381. * 获取huahuibao根目录
  382. * @author shish <shish@zhhinc.com>
  383. * @time 2019.5.11
  384. */
  385. public static function getRootDir()
  386. {
  387. $basePath = Yii::$app->basePath;
  388. if (Yii::$app->id == 'app-console') {
  389. $root = $basePath . "/../";
  390. } else {
  391. $root = $basePath . "/../../";
  392. }
  393. return $root;
  394. }
  395. //格式化输出;用于调试时使用 shish 2019.8.20
  396. public static function print_r($data)
  397. {
  398. echo "<pre>";
  399. print_r($data);
  400. Yii::$app->end();
  401. }
  402. //错误输出
  403. public static function fail($msg='操作失败')
  404. {
  405. Yii::info($msg);
  406. self::encode(['code' => 0, 'msg' => $msg, 'data' => []]);
  407. }
  408. //成功输出内容
  409. public static function success($data, $msg = '操作成功')
  410. {
  411. self::encode(['code' => 1, 'msg' => $msg, 'data' => $data]);
  412. }
  413. //只输出成功状态
  414. public static function ok()
  415. {
  416. self::encode(['code' => 1, 'msg' => '操作成功', 'data' => []]);
  417. }
  418. public static function notLogin()
  419. {
  420. self::encode(['code' => -1, 'msg' => '没有登陆', 'data' => []]);
  421. }
  422. //shisq
  423. public static function echoStatus($num, $key, $status = 'status')
  424. {
  425. $dictionary = \common\components\configDict::$dict[$key][$status];
  426. echo $dictionary[$num];
  427. }
  428. /**
  429. * 二维数组根据字段进行排序 shisq
  430. * @params array $array 需要排序的数组
  431. * @params string $field 排序的字段
  432. * @params string $sort 排序顺序标志 SORT_DESC 降序;SORT_ASC 升序
  433. */
  434. public static function arraySequence($array, $field, $sort = 'SORT_DESC')
  435. {
  436. $arrSort = array();
  437. foreach ($array as $uniqid => $row) {
  438. foreach ($row as $key => $value) {
  439. $arrSort[$key][$uniqid] = $value;
  440. }
  441. }
  442. array_multisort($arrSort[$field], constant($sort), $array);
  443. return $array;
  444. }
  445. }