util.php 15 KB

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