|
@@ -0,0 +1,330 @@
|
|
|
+<?php
|
|
|
+/**
|
|
|
+ * Created by PhpStorm.
|
|
|
+ * User: wangchen
|
|
|
+ * Date: 2019-05-07
|
|
|
+ * Time: 15:22
|
|
|
+ */
|
|
|
+
|
|
|
+namespace App\Libs;
|
|
|
+
|
|
|
+
|
|
|
+use App\Cache\CacheKeys;
|
|
|
+use Hashids;
|
|
|
+use App\Exceptions\ApiException;
|
|
|
+use PhpAmqpLib\Connection\AMQPStreamConnection;
|
|
|
+use PhpAmqpLib\Message\AMQPMessage;
|
|
|
+
|
|
|
+class Utils
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 异常报错
|
|
|
+ * @param $errorData
|
|
|
+ * @throws ApiException
|
|
|
+ */
|
|
|
+ public static function throwError($errorData)
|
|
|
+ {
|
|
|
+ // 分解错误码、错误信息
|
|
|
+ $arr = explode(':', (string)$errorData);
|
|
|
+ $code = (int)$arr[0];
|
|
|
+ $msg = (string)$arr[1];
|
|
|
+
|
|
|
+ throw new ApiException($code, $msg);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解码加密id
|
|
|
+ * @param $idStr
|
|
|
+ * @return int
|
|
|
+ */
|
|
|
+ public static function getDecodeId($idStr)
|
|
|
+ {
|
|
|
+ if (!is_numeric($idStr)) {
|
|
|
+ $idArr = Hashids::decode($idStr);
|
|
|
+ $id = isset($idArr[0]) ? (int)$idArr[0] : 0;
|
|
|
+ } else {
|
|
|
+ $id = $idStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ return $id;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加密id
|
|
|
+ * @param $id
|
|
|
+ * @return mixed
|
|
|
+ */
|
|
|
+ public static function getEncodeId($id)
|
|
|
+ {
|
|
|
+ return Hashids::encode($id);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取redis的key
|
|
|
+ * @param $keyStr // 例如:wap.rank_page
|
|
|
+ * @param array $args // 例如:[10, 2000]
|
|
|
+ *
|
|
|
+ * Utils::getCacheKey('wap.rank_page', [10, 2000])
|
|
|
+ * Utils::getCacheKey('promotion.setStatus')
|
|
|
+ * Utils::getCacheKey('promotion.infos', [2])
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public static function getCacheKey($keyStr, $args = [])
|
|
|
+ {
|
|
|
+ $stdStr = array_get(CacheKeys::$all, $keyStr, '');
|
|
|
+ if ($args) {
|
|
|
+ $stdStr = sprintf($stdStr, ...$args);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $stdStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 展示友好数字
|
|
|
+ * @param $num
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public static function showNiceNumber($num)
|
|
|
+ {
|
|
|
+ if ($num >= 10000) {
|
|
|
+ $num = sprintf('%.1f', round($num / 10000 * 100) / 100) . '万';
|
|
|
+ } elseif ($num >= 1000) {
|
|
|
+ $num = sprintf('%.1f', round($num / 1000 * 100) / 100) . '千';
|
|
|
+ }
|
|
|
+ return $num;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据日期获得这周的周一
|
|
|
+ * @param $date
|
|
|
+ * @param int $d
|
|
|
+ * @param string $format
|
|
|
+ * @return false|string
|
|
|
+ */
|
|
|
+ public static function firstOfWeek($date, $d = 0, $format = 'Ymd')
|
|
|
+ {
|
|
|
+ $now = strtotime($date) - $d * 86400; //当时的时间戳
|
|
|
+ $number = date("w", $now); //当时是周几
|
|
|
+ $number = $number == 0 ? 7 : $number; //如遇周末,将0换成7
|
|
|
+ $diff_day = $number - 1; //求到周一差几天
|
|
|
+ return date($format, $now - ($diff_day * 60 * 60 * 24));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 老原创的签名
|
|
|
+ * @param $time
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public static function getOldYcSign($time): string
|
|
|
+ {
|
|
|
+ $privateKey = env('EXTERNAL_PRIVATE_KEY');
|
|
|
+ return md5(md5($time . $privateKey) . $privateKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param array $data
|
|
|
+ * @param array $colHeaders
|
|
|
+ * @param bool $asString
|
|
|
+ * @return bool|string
|
|
|
+ */
|
|
|
+ public static function toCSV(array $data, array $colHeaders = array(), $asString = false)
|
|
|
+ {
|
|
|
+ $stream = $asString ? fopen('php://temp/maxmemory', 'wb+') : fopen('php://output', 'wb');
|
|
|
+
|
|
|
+ if (!empty($colHeaders)) {
|
|
|
+ fputcsv($stream, $colHeaders);
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($data as $record) {
|
|
|
+ fputcsv($stream, $record);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($asString) {
|
|
|
+ rewind($stream);
|
|
|
+ $returnVal = stream_get_contents($stream);
|
|
|
+ fclose($stream);
|
|
|
+ return $returnVal;
|
|
|
+ }
|
|
|
+
|
|
|
+ fclose($stream);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设备信息
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public static function getDeviceType(): string
|
|
|
+ {
|
|
|
+ //全部变成小写字母
|
|
|
+ $agent = strtolower(getProp($_SERVER, 'HTTP_USER_AGENT'));
|
|
|
+ $type = 'other';
|
|
|
+ //分别进行判断
|
|
|
+ if (strpos($agent, 'iphone') || strpos($agent, 'ipad')) {
|
|
|
+ $type = 'ios';
|
|
|
+ }
|
|
|
+
|
|
|
+ if (strpos($agent, 'android')) {
|
|
|
+ $type = 'android';
|
|
|
+ }
|
|
|
+ return $type;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否在微信内打卡
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function isOpenedInWechat(): bool
|
|
|
+ {
|
|
|
+ //全部变成小写字母
|
|
|
+ $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
|
|
|
+
|
|
|
+ //判断
|
|
|
+ if (strpos($agent, 'micromessenger')) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装meta数据
|
|
|
+ * @param $page
|
|
|
+ * @param $total
|
|
|
+ * @param int $pageSize
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public static function buildMeta($page, $total, $pageSize = 15): array
|
|
|
+ {
|
|
|
+ $lastPage = (int)ceil($total / $pageSize);
|
|
|
+ return [
|
|
|
+ 'current_page' => (int)$page,
|
|
|
+ 'next_page' => ++$page,
|
|
|
+ 'last_page' => $lastPage ?? 1,
|
|
|
+ 'per_page' => (int)$pageSize,
|
|
|
+ 'total' => (int)$total,
|
|
|
+ 'next_page_url' => '',
|
|
|
+ 'prev_page_url' => ''
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 随机书币
|
|
|
+ * @param $coin
|
|
|
+ * @param $num
|
|
|
+ * @return array|bool
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ public static function getRandomCoin($coin, $num)
|
|
|
+ {
|
|
|
+ $result = [];
|
|
|
+ if ($coin < $num || $coin < 1 || $num < 1) {
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算平均值
|
|
|
+ $rem = $coin % $num;
|
|
|
+ $mean = ($coin - $rem) / $num;
|
|
|
+
|
|
|
+ // 水平分割
|
|
|
+ for ($i = 0; $i < $num; $i++) {
|
|
|
+ $result[$i] = $mean;
|
|
|
+ }
|
|
|
+ // 水平分割后将取模多余部分分配给第一个红包
|
|
|
+ $result[0] += $rem;
|
|
|
+
|
|
|
+ // 随机分配金额
|
|
|
+ for ($i = 0; $i < $num; $i++) {
|
|
|
+ $r1 = random_int(0, $num - 1);
|
|
|
+ $r2 = random_int(0, $num - 1);
|
|
|
+ $per = random_int(1, 99) / 100;
|
|
|
+
|
|
|
+ // 随机金额
|
|
|
+ $mon = $result[$r1] - floor($result[$r1] * $per);
|
|
|
+ if ($result[$r1] - $mon > 0) {
|
|
|
+ // 减去随机金额
|
|
|
+ $result[$r1] -= $mon;
|
|
|
+ // 添加随机金额
|
|
|
+ $result[$r2] += $mon;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将数据推送到rabbitMq
|
|
|
+ * 参考:https://www.vckai.com/xiao-xi-dui-lie-rabbitmq-san-phpde-shi-yong-shi-li
|
|
|
+ * @param $messageBody
|
|
|
+ * @param string $queue
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function pushDataToAppSyncMq($messageBody, $queue = 'ycsd_sync'): bool
|
|
|
+ {
|
|
|
+ $exchange = $queue; // 交换器
|
|
|
+ $routing_key = $queue;
|
|
|
+
|
|
|
+ try {
|
|
|
+ $host = env('RABBITMQ_HOST');
|
|
|
+ $port = env('RABBITMQ_PORT');
|
|
|
+ $user = env('RABBITMQ_LOGIN');
|
|
|
+ $passwd = env('RABBITMQ_PASSWORD');
|
|
|
+ $vhost = env('RABBITMQ_VHOST');
|
|
|
+ $connection = new AMQPStreamConnection($host, $port, $user, $passwd, $vhost);
|
|
|
+
|
|
|
+ // 创建通道
|
|
|
+ $channel = $connection->channel();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建队列(Queue)
|
|
|
+ * name: hello // 队列名称
|
|
|
+ * passive: false // 如果用户仅仅想查询某一个队列是否已存在,如果不存在,不想建立该队列,仍然可以调用queue.declare,
|
|
|
+ * 只不过需要将参数passive设为true,传给queue.declare,如果该队列已存在,则会返回true;
|
|
|
+ * 如果不存在,则会返回Error,但是不会创建新的队列。
|
|
|
+ * durable: true // 是不持久化, true ,表示持久化,会存盘,服务器重启仍然存在,false,非持久化
|
|
|
+ * exclusive: false // 是否排他,指定该选项为true则队列只对当前连接有效,连接断开后自动删除
|
|
|
+ * auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
|
|
|
+ */
|
|
|
+ $channel->queue_declare($queue, true, false, false, false);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建交换机(Exchange)
|
|
|
+ * name: vckai_exchange// 交换机名称
|
|
|
+ * type: direct // 交换机类型,分别为direct/fanout/topic,参考另外文章的Exchange Type说明。
|
|
|
+ * passive: false // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
|
|
|
+ * durable: false // 是否持久化,设置false是存放到内存中的,RabbitMQ重启后会丢失
|
|
|
+ * auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
|
|
|
+ */
|
|
|
+ // $channel->exchange_declare('', 'direct', true, false, false);
|
|
|
+
|
|
|
+ // 绑定消息交换机和队列
|
|
|
+ // $channel->queue_bind($queue, $exchange);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建AMQP消息类型
|
|
|
+ * delivery_mode 消息是否持久化
|
|
|
+ * AMQPMessage::DELIVERY_MODE_NON_PERSISTENT 不持久化
|
|
|
+ * AMQPMessage::DELIVERY_MODE_PERSISTENT 持久化
|
|
|
+ */
|
|
|
+ $msg = new AMQPMessage($messageBody, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_NON_PERSISTENT]);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送消息
|
|
|
+ * msg: $msg // AMQP消息内容
|
|
|
+ * exchange: vckai_exchange // 交换机名称
|
|
|
+ * queue: hello // 队列名称
|
|
|
+ */
|
|
|
+ $channel->basic_publish($msg, '', $routing_key);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 关闭链接
|
|
|
+ */
|
|
|
+ $channel->close();
|
|
|
+ $connection->close();
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ sendNotice('RabbitMq 连接失败 ' . $e->getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|