Utils.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: wangchen
  5. * Date: 2019-05-07
  6. * Time: 15:22
  7. */
  8. namespace App\Libs;
  9. use App\Cache\CacheKeys;
  10. use Hashids;
  11. use App\Exceptions\ApiException;
  12. use PhpAmqpLib\Connection\AMQPStreamConnection;
  13. use PhpAmqpLib\Message\AMQPMessage;
  14. class Utils
  15. {
  16. /**
  17. * 异常报错
  18. * @param $errorData
  19. * @throws ApiException
  20. */
  21. public static function throwError($errorData)
  22. {
  23. // 分解错误码、错误信息
  24. $arr = explode(':', (string)$errorData);
  25. $code = (int)$arr[0];
  26. $msg = (string)$arr[1];
  27. throw new ApiException($code, $msg);
  28. }
  29. /**
  30. * 解码加密id
  31. * @param $idStr
  32. * @return int
  33. */
  34. public static function getDecodeId($idStr)
  35. {
  36. if (!is_numeric($idStr)) {
  37. $idArr = Hashids::decode($idStr);
  38. $id = isset($idArr[0]) ? (int)$idArr[0] : 0;
  39. } else {
  40. $id = $idStr;
  41. }
  42. return $id;
  43. }
  44. /**
  45. * 加密id
  46. * @param $id
  47. * @return mixed
  48. */
  49. public static function getEncodeId($id)
  50. {
  51. return Hashids::encode($id);
  52. }
  53. /**
  54. * 获取redis的key
  55. * @param $keyStr // 例如:wap.rank_page
  56. * @param array $args // 例如:[10, 2000]
  57. *
  58. * Utils::getCacheKey('wap.rank_page', [10, 2000])
  59. * Utils::getCacheKey('promotion.setStatus')
  60. * Utils::getCacheKey('promotion.infos', [2])
  61. *
  62. * @return string
  63. */
  64. public static function getCacheKey($keyStr, $args = [])
  65. {
  66. $stdStr = array_get(CacheKeys::$all, $keyStr, '');
  67. if ($args) {
  68. $stdStr = sprintf($stdStr, ...$args);
  69. }
  70. return $stdStr;
  71. }
  72. /**
  73. * 展示友好数字
  74. * @param $num
  75. * @return string
  76. */
  77. public static function showNiceNumber($num)
  78. {
  79. if ($num >= 10000) {
  80. $num = sprintf('%.1f', round($num / 10000 * 100) / 100) . '万';
  81. } elseif ($num >= 1000) {
  82. $num = sprintf('%.1f', round($num / 1000 * 100) / 100) . '千';
  83. }
  84. return $num;
  85. }
  86. /**
  87. * 根据日期获得这周的周一
  88. * @param $date
  89. * @param int $d
  90. * @param string $format
  91. * @return false|string
  92. */
  93. public static function firstOfWeek($date, $d = 0, $format = 'Ymd')
  94. {
  95. $now = strtotime($date) - $d * 86400; //当时的时间戳
  96. $number = date("w", $now); //当时是周几
  97. $number = $number == 0 ? 7 : $number; //如遇周末,将0换成7
  98. $diff_day = $number - 1; //求到周一差几天
  99. return date($format, $now - ($diff_day * 60 * 60 * 24));
  100. }
  101. /**
  102. * 老原创的签名
  103. * @param $time
  104. * @return string
  105. */
  106. public static function getOldYcSign($time): string
  107. {
  108. $privateKey = env('EXTERNAL_PRIVATE_KEY');
  109. return md5(md5($time . $privateKey) . $privateKey);
  110. }
  111. /**
  112. * @param array $data
  113. * @param array $colHeaders
  114. * @param bool $asString
  115. * @return bool|string
  116. */
  117. public static function toCSV(array $data, array $colHeaders = array(), $asString = false)
  118. {
  119. $stream = $asString ? fopen('php://temp/maxmemory', 'wb+') : fopen('php://output', 'wb');
  120. if (!empty($colHeaders)) {
  121. fputcsv($stream, $colHeaders);
  122. }
  123. foreach ($data as $record) {
  124. fputcsv($stream, $record);
  125. }
  126. if ($asString) {
  127. rewind($stream);
  128. $returnVal = stream_get_contents($stream);
  129. fclose($stream);
  130. return $returnVal;
  131. }
  132. fclose($stream);
  133. return true;
  134. }
  135. /**
  136. * 设备信息
  137. * @return string
  138. */
  139. public static function getDeviceType(): string
  140. {
  141. //全部变成小写字母
  142. $agent = strtolower(getProp($_SERVER, 'HTTP_USER_AGENT'));
  143. $type = 'other';
  144. //分别进行判断
  145. if (strpos($agent, 'iphone') || strpos($agent, 'ipad')) {
  146. $type = 'ios';
  147. }
  148. if (strpos($agent, 'android')) {
  149. $type = 'android';
  150. }
  151. return $type;
  152. }
  153. /**
  154. * 是否在微信内打卡
  155. * @return bool
  156. */
  157. public static function isOpenedInWechat(): bool
  158. {
  159. //全部变成小写字母
  160. $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
  161. //判断
  162. if (strpos($agent, 'micromessenger')) {
  163. return true;
  164. }
  165. return false;
  166. }
  167. /**
  168. * 组装meta数据
  169. * @param $page
  170. * @param $total
  171. * @param int $pageSize
  172. * @return array
  173. */
  174. public static function buildMeta($page, $total, $pageSize = 15): array
  175. {
  176. $lastPage = (int)ceil($total / $pageSize);
  177. return [
  178. 'current_page' => (int)$page,
  179. 'next_page' => ++$page,
  180. 'last_page' => $lastPage ?? 1,
  181. 'per_page' => (int)$pageSize,
  182. 'total' => (int)$total,
  183. 'next_page_url' => '',
  184. 'prev_page_url' => ''
  185. ];
  186. }
  187. /**
  188. * 随机书币
  189. * @param $coin
  190. * @param $num
  191. * @return array|bool
  192. * @throws \Exception
  193. */
  194. public static function getRandomCoin($coin, $num)
  195. {
  196. $result = [];
  197. if ($coin < $num || $coin < 1 || $num < 1) {
  198. return $result;
  199. }
  200. // 计算平均值
  201. $rem = $coin % $num;
  202. $mean = ($coin - $rem) / $num;
  203. // 水平分割
  204. for ($i = 0; $i < $num; $i++) {
  205. $result[$i] = $mean;
  206. }
  207. // 水平分割后将取模多余部分分配给第一个红包
  208. $result[0] += $rem;
  209. // 随机分配金额
  210. for ($i = 0; $i < $num; $i++) {
  211. $r1 = random_int(0, $num - 1);
  212. $r2 = random_int(0, $num - 1);
  213. $per = random_int(1, 99) / 100;
  214. // 随机金额
  215. $mon = $result[$r1] - floor($result[$r1] * $per);
  216. if ($result[$r1] - $mon > 0) {
  217. // 减去随机金额
  218. $result[$r1] -= $mon;
  219. // 添加随机金额
  220. $result[$r2] += $mon;
  221. }
  222. }
  223. return $result;
  224. }
  225. /**
  226. * 将数据推送到rabbitMq
  227. * 参考:https://www.vckai.com/xiao-xi-dui-lie-rabbitmq-san-phpde-shi-yong-shi-li
  228. * @param $messageBody
  229. * @param string $queue
  230. * @return bool
  231. */
  232. public static function pushDataToAppSyncMq($messageBody, $queue = 'ycsd_sync'): bool
  233. {
  234. $exchange = $queue; // 交换器
  235. $routing_key = $queue;
  236. try {
  237. $host = env('RABBITMQ_HOST');
  238. $port = env('RABBITMQ_PORT');
  239. $user = env('RABBITMQ_LOGIN');
  240. $passwd = env('RABBITMQ_PASSWORD');
  241. $vhost = env('RABBITMQ_VHOST');
  242. $connection = new AMQPStreamConnection($host, $port, $user, $passwd, $vhost);
  243. // 创建通道
  244. $channel = $connection->channel();
  245. /**
  246. * 创建队列(Queue)
  247. * name: hello // 队列名称
  248. * passive: false // 如果用户仅仅想查询某一个队列是否已存在,如果不存在,不想建立该队列,仍然可以调用queue.declare,
  249. * 只不过需要将参数passive设为true,传给queue.declare,如果该队列已存在,则会返回true;
  250. * 如果不存在,则会返回Error,但是不会创建新的队列。
  251. * durable: true // 是不持久化, true ,表示持久化,会存盘,服务器重启仍然存在,false,非持久化
  252. * exclusive: false // 是否排他,指定该选项为true则队列只对当前连接有效,连接断开后自动删除
  253. * auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
  254. */
  255. $channel->queue_declare($queue, true, false, false, false);
  256. /**
  257. * 创建交换机(Exchange)
  258. * name: vckai_exchange// 交换机名称
  259. * type: direct // 交换机类型,分别为direct/fanout/topic,参考另外文章的Exchange Type说明。
  260. * passive: false // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
  261. * durable: false // 是否持久化,设置false是存放到内存中的,RabbitMQ重启后会丢失
  262. * auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
  263. */
  264. // $channel->exchange_declare('', 'direct', true, false, false);
  265. // 绑定消息交换机和队列
  266. // $channel->queue_bind($queue, $exchange);
  267. /**
  268. * 创建AMQP消息类型
  269. * delivery_mode 消息是否持久化
  270. * AMQPMessage::DELIVERY_MODE_NON_PERSISTENT 不持久化
  271. * AMQPMessage::DELIVERY_MODE_PERSISTENT 持久化
  272. */
  273. $msg = new AMQPMessage($messageBody, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_NON_PERSISTENT]);
  274. /**
  275. * 发送消息
  276. * msg: $msg // AMQP消息内容
  277. * exchange: vckai_exchange // 交换机名称
  278. * queue: hello // 队列名称
  279. */
  280. $channel->basic_publish($msg, '', $routing_key);
  281. /**
  282. * 关闭链接
  283. */
  284. $channel->close();
  285. $connection->close();
  286. } catch (\Exception $e) {
  287. sendNotice('RabbitMq 连接失败 ' . $e->getMessage());
  288. }
  289. return true;
  290. }
  291. }