Wang Chen пре 4 година
родитељ
комит
12975a0cb4
52 измењених фајлова са 6334 додато и 0 уклоњено
  1. 329 0
      app/Libs/Push/HuaWei/Admin/Application.php
  2. 103 0
      app/Libs/Push/HuaWei/Admin/Constants.php
  3. 141 0
      app/Libs/Push/HuaWei/Admin/Msg/Android/AndroidConfig.php
  4. 393 0
      app/Libs/Push/HuaWei/Admin/Msg/Android/AndroidNotification.php
  5. 79 0
      app/Libs/Push/HuaWei/Admin/Msg/Android/Badge.php
  6. 125 0
      app/Libs/Push/HuaWei/Admin/Msg/Android/ClickAction.php
  7. 85 0
      app/Libs/Push/HuaWei/Admin/Msg/Android/LightSetting.php
  8. 97 0
      app/Libs/Push/HuaWei/Admin/Msg/Android/LightSettingColor.php
  9. 92 0
      app/Libs/Push/HuaWei/Admin/Msg/Apns/Alert.php
  10. 60 0
      app/Libs/Push/HuaWei/Admin/Msg/Apns/ApnsConfig.php
  11. 116 0
      app/Libs/Push/HuaWei/Admin/Msg/Apns/ApnsHeaders.php
  12. 47 0
      app/Libs/Push/HuaWei/Admin/Msg/Apns/ApnsHmsOptions.php
  13. 78 0
      app/Libs/Push/HuaWei/Admin/Msg/Apns/Aps.php
  14. 60 0
      app/Libs/Push/HuaWei/Admin/Msg/InstanceApp/InstanceAppConfig.php
  15. 98 0
      app/Libs/Push/HuaWei/Admin/Msg/InstanceApp/InstanceAppPushBody.php
  16. 60 0
      app/Libs/Push/HuaWei/Admin/Msg/InstanceApp/InstanceAppRingTone.php
  17. 84 0
      app/Libs/Push/HuaWei/Admin/Msg/Notification/Notification.php
  18. 104 0
      app/Libs/Push/HuaWei/Admin/Msg/PushMessage.php
  19. 18 0
      app/Libs/Push/HuaWei/Admin/Msg/ValidatorUtil.php
  20. 66 0
      app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushConfig.php
  21. 55 0
      app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushHeaders.php
  22. 40 0
      app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushHmsOptions.php
  23. 158 0
      app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushNotification.php
  24. 55 0
      app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushNotificationAction.php
  25. 173 0
      app/Libs/Push/HuaWei/Admin/PushConfig.php
  26. 107 0
      app/Libs/Push/HuaWei/Admin/PushLogConfig.php
  27. 225 0
      app/Libs/Push/HuaWei/HwPushCommon.php
  28. 846 0
      app/Libs/Push/HuaWei/PushMsgCommon.php
  29. 56 0
      app/Libs/Push/HuaWei/config.ini
  30. 73 0
      app/Libs/Push/OPPOPush/Constants.php
  31. 308 0
      app/Libs/Push/OPPOPush/OPPOPushCommon.php
  32. 213 0
      app/Libs/Push/OPPOPush/PushMessage.php
  33. 113 0
      app/Libs/Push/XMPush/Builder.php
  34. 148 0
      app/Libs/Push/XMPush/Constants.php
  35. 30 0
      app/Libs/Push/XMPush/DevTools.php
  36. 16 0
      app/Libs/Push/XMPush/ErrorCode.php
  37. 24 0
      app/Libs/Push/XMPush/Feedback.php
  38. 167 0
      app/Libs/Push/XMPush/HttpBase.php
  39. 104 0
      app/Libs/Push/XMPush/IOSBuilder.php
  40. 55 0
      app/Libs/Push/XMPush/Message.php
  41. 78 0
      app/Libs/Push/XMPush/MiPushCommon.php
  42. 222 0
      app/Libs/Push/XMPush/PushRequestPath.php
  43. 15 0
      app/Libs/Push/XMPush/PushRequestType.php
  44. 29 0
      app/Libs/Push/XMPush/Region.php
  45. 30 0
      app/Libs/Push/XMPush/Result.php
  46. 210 0
      app/Libs/Push/XMPush/Sender.php
  47. 98 0
      app/Libs/Push/XMPush/Server.php
  48. 199 0
      app/Libs/Push/XMPush/ServerSwitch.php
  49. 41 0
      app/Libs/Push/XMPush/Stats.php
  50. 125 0
      app/Libs/Push/XMPush/Subscription.php
  51. 43 0
      app/Libs/Push/XMPush/TargetedMessage.php
  52. 43 0
      app/Libs/Push/XMPush/Tracer.php

+ 329 - 0
app/Libs/Push/HuaWei/Admin/Application.php

@@ -0,0 +1,329 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin;
+
+
+class Application
+{
+    private $appid;
+
+    private $appsecret;
+
+    private $token_expiredtime;
+
+    private $access_token;
+
+    private $validate_only;
+
+    private $token_url;
+
+    private $send_url;
+
+    private $token_query_url;
+
+    private $topic_sub_url;
+
+    private $topic_unsub_url;
+
+    private $topic_list_url;
+
+    private $fields;
+
+
+    public function __construct($appid, $appsecret)
+    {
+        $this->appid             = $appid;
+        $this->appsecret         = $appsecret;
+        $this->token_url         = config('push.server.huawei.authToken');
+        $this->send_url          = config('push.server.huawei.messageSend');
+        $this->token_query_url   = config('push.server.huawei.tokenQuery');
+        $this->topic_sub_url     = config('push.server.huawei.topicSub');
+        $this->topic_unsub_url   = config('push.server.huawei.topicUnSub');
+        $this->topic_list_url    = config('push.server.huawei.topicList');
+        $this->token_expiredtime = null;
+        $this->accesstoken       = null;
+        $this->validate_only     = false;
+    }
+
+    public function appid($value)
+    {
+        $this->appid = $value;
+    }
+
+    public function appsecret($value)
+    {
+        $this->appsecret = $value;
+    }
+
+    public function validate_only($value)
+    {
+        $this->validate_only = $value;
+    }
+
+    public function getApplicationFields()
+    {
+        $keys = [
+            'appid',
+            'appsecret',
+            'token_url',
+            'send_url',
+            'token_query_url',
+            'topic_sub_url',
+            'topic_unsub_url',
+            'topic_list_url',
+            'validate_only',
+            'accesstoken',
+            'token_expiredtime'
+        ];
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+
+        return $this->fields;
+    }
+
+    private function logPush($className, $message, $data = [])
+    {
+        var_dump('[' . $className . '] ' . $message, $data);
+        myLog('push')->info('[' . $className . '] ' . $message, $data);
+    }
+
+    private function is_token_expired()
+    {
+        if (empty($this->accesstoken)) {
+            return true;
+        }
+        if (time() > $this->token_expiredtime) {
+            return true;
+        }
+        return false;
+    }
+
+    private function refresh_token()
+    {
+        // 请求地址
+        $result = $this->curl_https_post($this->token_url, http_build_query([
+            'grant_type'    => 'client_credentials',
+            'client_secret' => $this->appsecret,
+            'client_id'     => $this->appid
+        ]), ['Content-Type: application/x-www-form-urlencoded;charset=utf-8']);
+        $result = json_decode($result, true);
+
+        // 判断
+        if ($result === null || !array_key_exists('access_token', $result)) {
+            $this->logPush(__FUNCTION__, 'refresh_token result error!');
+            return null;
+        }
+
+        $this->logPush(__FUNCTION__, 'refresh_token result:', $result);
+        $this->accesstoken       = getProp($result, 'access_token');
+        $this->token_expiredtime = time() + getProp($result, 'expires_in');
+        return $this->access_token;
+    }
+
+    /**
+     * push_send_msg for push msg
+     */
+    public function push_send_msg($msg)
+    {
+        $body = [
+            'validate_only' => $this->validate_only,
+            'message'       => $msg
+        ];
+        $this->logPush(__FUNCTION__, 'push_send_msg body:', $body);
+
+        if ($this->is_token_expired()) {
+            $this->refresh_token();
+        }
+
+        if (empty($this->accesstoken)) {
+            $this->logPush(__FUNCTION__, 'accesstoken is empty!');
+            return null;
+        }
+
+        $url    = str_replace('{appid}', $this->appid, $this->send_url);
+        $header = ['Content-Type: application/json', "Authorization: Bearer {$this->accesstoken}"];
+        $result = $this->curl_https_post($url, json_encode($body), $header);
+        $result = json_decode($result, true);
+
+        $this->logPush(__FUNCTION__, 'push_send_msg result:', $result);
+
+        return $result;
+    }
+
+    /**
+     * common_send_msg for topic msg/other
+     */
+    public function common_send_msg($msg)
+    {
+        $this->logPush(__FUNCTION__, 'common_send_msg msg:', compact('msg'));
+        if ($this->is_token_expired()) {
+            $this->refresh_token();
+        }
+
+        if (empty($this->accesstoken)) {
+            $this->logPush(__FUNCTION__, 'accesstoken is empty!');
+            return null;
+        }
+
+        $url    = str_replace('{appid}', $this->appid, $this->send_url);
+        $header = ['Content-Type: application/json', "Authorization: Bearer {$this->accesstoken}"];
+        $result = $this->curl_https_post($url, json_encode($msg), $header);
+        $result = json_decode($result, true);
+
+        $this->logPush(__FUNCTION__, 'common_send_msg result:', $result);
+
+        return $result;
+    }
+
+    /**
+     * 数据控制者数据查询
+     * @param $pushToken
+     * @return mixed|null
+     */
+    public function query_push_token($pushToken)
+    {
+        $body = ['token' => $pushToken];
+        $this->logPush(__FUNCTION__, 'query_push_token body:', $body);
+
+        if ($this->is_token_expired()) {
+            $this->refresh_token();
+        }
+
+        if (empty($this->accesstoken)) {
+            $this->logPush(__FUNCTION__, 'accesstoken is empty!');
+            return null;
+        }
+
+        $url    = str_replace('{appid}', $this->appid, $this->token_query_url);
+        $header = ['Content-Type: application/json', "Authorization: Bearer {$this->accesstoken}"];
+        $result = $this->curl_https_post($url, json_encode($body), $header);
+        $result = json_decode($result, true);
+
+        $this->logPush(__FUNCTION__, 'common_send_msg result:', $result);
+
+        return $result;
+    }
+
+    /**
+     * 主题订阅
+     * @param       $topic
+     * @param array $tokenArray
+     * @return bool|mixed|string|null
+     */
+    public function subscribe_topic($topic, array $tokenArray)
+    {
+        $body = ['topic' => $topic, 'tokenArray' => $tokenArray];
+        $this->logPush(__FUNCTION__, 'subscribe_topic body:', $body);
+
+        if ($this->is_token_expired()) {
+            $this->refresh_token();
+        }
+
+        if (empty($this->accesstoken)) {
+            $this->logPush(__FUNCTION__, 'accesstoken is empty!');
+            return null;
+        }
+
+        $url    = str_replace('{appid}', $this->appid, $this->topic_sub_url);
+        $header = ['Content-Type: application/json', "Authorization: Bearer {$this->accesstoken}"];
+        $result = $this->curl_https_post($url, json_encode($body), $header);
+        $result = json_decode($result, true);
+
+        $this->logPush(__FUNCTION__, 'subscribe_topic result:', $result);
+
+        return $result;
+    }
+
+    /**
+     * 主题退订
+     * @param       $topic
+     * @param array $tokenArray
+     * @return bool|mixed|string|null
+     */
+    public function unsubscribe_topic($topic, array $tokenArray)
+    {
+        $body = ['topic' => $topic, 'tokenArray' => $tokenArray];
+        $this->logPush(__FUNCTION__, 'unsubscribe_topic body:', $body);
+
+        if ($this->is_token_expired()) {
+            $this->refresh_token();
+        }
+
+        if (empty($this->accesstoken)) {
+            $this->logPush(__FUNCTION__, 'accesstoken is empty!');
+            return null;
+        }
+
+        $url    = str_replace('{appid}', $this->appid, $this->topic_unsub_url);
+        $header = ['Content-Type: application/json', "Authorization: Bearer {$this->accesstoken}"];
+        $result = $this->curl_https_post($url, json_encode($body), $header);
+        $result = json_decode($result, true);
+
+        $this->logPush(__FUNCTION__, 'unsubscribe_topic result:', $result);
+
+        return $result;
+    }
+
+    /**
+     * 主题列表
+     * @param $token
+     * @return bool|mixed|string|null
+     */
+    public function topic_list($token)
+    {
+        $body = ['token' => $token];
+        $this->logPush(__FUNCTION__, 'topic_list body:', $body);
+
+        if ($this->is_token_expired()) {
+            $this->refresh_token();
+        }
+
+        if (empty($this->accesstoken)) {
+            $this->logPush(__FUNCTION__, 'accesstoken is empty!');
+            return null;
+        }
+
+        $url    = str_replace('{appid}', $this->appid, $this->topic_list_url);
+        $header = ['Content-Type: application/json', "Authorization: Bearer {$this->accesstoken}"];
+        $result = $this->curl_https_post($url, json_encode($body), $header);
+        $result = json_decode($result, true);
+
+        $this->logPush(__FUNCTION__, 'topic_list result:', $result);
+
+        return $result;
+    }
+    
+    private function curl_https_post($url, $data = [], $header = [])
+    {
+        $this->logPush(__FUNCTION__, 'curl_https_post:', compact('url', 'data'));
+        $ch = curl_init($url);
+
+        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
+
+        // resolve SSL: no alternative certificate subject name matches target host name
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // check verify
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
+        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+        curl_setopt($ch, CURLOPT_POST, 1); // regular post request
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // Post submit data
+
+        $ret = @curl_exec($ch);
+        if ($ret === false) {
+            return null;
+        }
+
+        $info = curl_getinfo($ch);
+
+        curl_close($ch);
+
+        return $ret;
+    }
+
+}

+ 103 - 0
app/Libs/Push/HuaWei/Admin/Constants.php

@@ -0,0 +1,103 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin;
+
+
+class Constants
+{
+
+    /**
+     * push_msg
+     */
+
+    const WEBPUSH_URGENCY_VERY_LOW = "very-low";
+
+    const WEBPUSH_URGENCY_LOW = "low";
+
+    const WEBPUSH_URGENCY_NORMAL = "normal";
+
+    const WEBPUSH_URGENCY_HIGH = "high";
+
+    /*
+     * Notification Type
+     */
+    const PUSHMSG_NOTIFICATION_MSG_TYPE = 1;
+
+    const PUSHMSG_PASS_THROUGHT_MSG_TYPE = 2;
+
+    const PUSHMSG_TOPIC_MSG_TYPE = 3;
+
+    const PUSHMSG_CONDITION_MSG_TYPE = 4;
+
+    const PUSHMSG_FASTAPP_MSG_TYPE = 5;
+
+    const APN_MSG_TYPE = 6;
+
+    const WEB_PUSH_MSG_TYPE = 7;
+
+    const TOPIC_SUBSCRIBE_MSG_TYPE = 8;
+    const TOPIC_UNSUBSCRIBE_MSG_TYPE = 9;
+    const TOPIC_SUBSCRIBE_QUERY_MSG_TYPE = 10;
+
+    /**
+     * log
+     */
+    const HW_PUSH_LOG_PUSH_MSG_MODULE = "PushMsg";
+
+    const HW_PUSH_LOG_TOPIC_SUBSCRIBE_MODULE = "TopicSubsScribe";
+
+    const HW_PUSH_LOG_TOPIC_UNSUBSCRIBE_MODULE = "TopicUnSubsScribe";
+
+    const HW_PUSH_LOG_DEBUG_LEVEL = 4;
+
+    const HW_PUSH_LOG_INFO_LEVEL = 3;
+
+    const HW_PUSH_LOG_WARN_LEVEL = 2;
+
+    const HW_PUSH_LOG_ERROR_LEVEL = 1;
+
+    const HW_PUSH_LOG_FILE_NAME = 'push.log';
+
+    const URL_PATTERN = "/^https.*/";
+    const VIBRATE_PATTERN = "/[0-9]+|[0-9]+[sS]|[0-9]+[.][0-9]{1,9}|[0-9]+[.][0-9]{1,9}[sS]/";
+    const COLOR_PATTERN = "/^#[0-9a-fA-F]{6}$/";
+    const TTL_PATTERN = "/\\d+|\\d+[sS]|\\d+.\\d{1,9}|\\d+.\\d{1,9}[sS]/";
+
+    const APN_AUTHORIZATION_PATTERN = "/^bearer*/";
+    const APN_ID_PATTERN = "/[0-9a-z]{8}(-[0-9a-z]{4}){3}-[0-9a-z]{12}/";
+}
+
+class Visibility {
+    const VISIBILITY_UNSPECIFIED= "VISIBILITY_UNSPECIFIED";
+    const PRIVATE_STR="PRIVATE";
+    const PUBLIC_STR="PUBLIC";
+    const SECRET_STR="SECRET";
+}
+
+class NotificationPriority {
+    const NOTIFICATION_PRIORITY_LOW = 'LOW';
+
+    const NOTIFICATION_PRIORITY_NORMAL = 'NORMAL';
+
+    const NOTIFICATION_PRIORITY_HIGH = 'HIGH';
+}
+
+class AndroidConfigDeliveryPriority{
+    const PRIORITY_HIGH = 'HIGH';
+
+    const PRIORITY_NORMAL = 'NORMAL';
+}
+
+class ApnConstant{
+
+    //APN PRIORITY
+    const ANP_PRIORITY_SEND_IMMEDIATELY = "10";
+    const ANP_PRIORITY_SEND_BY_GROUP = "5";
+
+    //APN TARGET USER
+    const APN_TARGET_USER_TEST_USER = 1;
+    const APN_TARGET_USER_FORMAL_USER = 2;
+    const APN_TARGET_USER_VOIP_USER = 3;
+
+}

+ 141 - 0
app/Libs/Push/HuaWei/Admin/Msg/Android/AndroidConfig.php

@@ -0,0 +1,141 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Android;
+
+
+use App\Libs\Push\HuaWei\Admin\AndroidConfigDeliveryPriority;
+use App\Libs\Push\HuaWei\Admin\Msg\ValidatorUtil;
+use Exception;
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+
+class AndroidConfig
+{
+    private $collapse_key;
+
+    private $category;
+
+    private $urgency;
+
+    private $ttl;
+
+    private $bi_tag;
+
+    private $fast_app_target;
+
+    private $notification;
+
+    private $fields;
+
+    private $data;
+
+    public function __construct()
+    {
+        $this->urgency      = null;
+        $this->notification = null;
+        $this->fields       = array();
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function collapse_key($value)
+    {
+        $this->collapse_key = $value;
+    }
+
+    public function category($value)
+    {
+        $this->category = $value;
+    }
+
+    public function urgency($value)
+    {
+        $this->urgency = $value;
+    }
+
+    public function ttl($value)
+    {
+        $this->ttl = $value;
+    }
+
+    public function bi_tag($value)
+    {
+        $this->bi_tag = $value;
+    }
+
+    public function fast_app_target($value)
+    {
+        $this->fast_app_target = $value;
+    }
+
+    public function notification($value)
+    {
+        $this->notification = $value;
+    }
+
+    public function data($value)
+    {
+        $this->data = $value;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+//             echo $e;
+            PushLogConfig::getSingleInstance()->LogMessage($e, Constants::HW_PUSH_LOG_ERROR_LEVEL);
+            return;
+        }
+        $keys = array(
+            'collapse_key',
+            'category',
+            'urgency',
+            'ttl',
+            'bi_tag',
+            'fast_app_target',
+            'notification',
+            'data'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (!empty($this->collapse_key) && ($this->collapse_key < -1 || $this->collapse_key > 100)) {
+            throw new Exception("Collapse Key should be [-1, 100]");
+        }
+        if (!empty($this->fast_app_target) && !in_array($this->fast_app_target, array(
+                1,
+                2
+            ))) {
+            throw new Exception("Invalid fast app target type[one of 1 or 2]");
+        }
+
+        if (!empty($this->urgency) && !in_array($this->urgency, array(
+                AndroidConfigDeliveryPriority::PRIORITY_HIGH,
+                AndroidConfigDeliveryPriority::PRIORITY_NORMAL
+            ))) {
+            throw new Exception("delivery priority shouid be [HIGH, NOMAL]");
+        }
+
+        if (!empty($this->ttl)) {
+            if (FALSE == ValidatorUtil::validatePattern(Constants::TTL_PATTERN, $this->ttl)) {
+                throw new Exception("The TTL's format is wrong");
+            }
+        }
+    }
+
+    public function get_all_vars()
+    {
+        var_dump(get_object_vars($this));
+    }
+}

+ 393 - 0
app/Libs/Push/HuaWei/Admin/Msg/Android/AndroidNotification.php

@@ -0,0 +1,393 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Android;
+
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\Msg\ValidatorUtil;
+use App\Libs\Push\HuaWei\Admin\NotificationPriority;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+use App\Libs\Push\HuaWei\Admin\Visibility;
+use Exception;
+
+class AndroidNotification
+{
+    private $title;
+
+    private $body;
+
+    private $icon;
+
+    private $color;
+
+    private $sound;
+
+    private $tag;
+
+    private $click_action;
+
+    private $body_loc_key;
+
+    private $body_loc_args;
+
+    private $title_loc_key;
+
+    private $title_loc_args;
+
+    private $channel_id;
+
+    private $notify_summary;
+
+    private $image;
+
+    private $notify_icon;
+
+    /**
+     * notification style:
+     * 0:default
+     * 1:big text
+     * 2:big photo
+     */
+    private $style;
+
+    private $big_title;
+
+    private $big_body;
+
+    private $auto_clear;
+
+    private $notify_id;
+
+    private $group;
+
+    private $badge;
+
+    private $ticker;
+
+    private $auto_cancel;
+
+    private $when;
+
+    private $importance;
+
+    private $use_default_vibrate;
+
+    private $use_default_light;
+
+    private $vibrate_config;
+
+    private $visibility;
+
+    private $light_settings;
+
+    private $foreground_show;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->click_action    = array();
+        $this->body_loc_args   = array();
+        $this->title_loc_args  = array();
+        $this->badge           = array();
+        $this->light_settings  = array();
+        $this->foreground_show = true;
+        $this->fields          = array();
+    }
+
+    public function title($value)
+    {
+        $this->title = $value;
+    }
+
+    public function body($value)
+    {
+        $this->body = $value;
+    }
+
+    public function icon($value)
+    {
+        $this->icon = $value;
+    }
+
+    public function color($value)
+    {
+        $this->color = $value;
+    }
+
+    public function sound($value)
+    {
+        $this->sound = $value;
+    }
+
+    public function tag($value)
+    {
+        $this->tag = $value;
+    }
+
+    public function click_action($value)
+    {
+        $this->click_action = $value;
+    }
+
+    public function body_loc_key($value)
+    {
+        $this->body_loc_key = $value;
+    }
+
+    public function body_loc_args($value)
+    {
+        $this->body_loc_args = $value;
+    }
+
+    public function title_loc_key($value)
+    {
+        $this->title_loc_key = $value;
+    }
+
+    public function title_loc_args($value)
+    {
+        $this->title_loc_args = $value;
+    }
+
+    public function channel_id($value)
+    {
+        $this->channel_id = $value;
+    }
+
+    public function notify_summary($value)
+    {
+        $this->notify_summary = $value;
+    }
+
+    // added
+    public function image($value)
+    {
+        $this->image = $value;
+    }
+
+    public function notify_icon($value)
+    {
+        $this->notify_icon = $value;
+    }
+
+    public function style($value)
+    {
+        $this->style = $value;
+    }
+
+    public function big_title($value)
+    {
+        $this->big_title = $value;
+    }
+
+    public function big_body($value)
+    {
+        $this->big_body = $value;
+    }
+
+    public function auto_clear($value)
+    {
+        $this->auto_clear = $value;
+    }
+
+    public function notify_id($value)
+    {
+        $this->notify_id = $value;
+    }
+
+    public function group($value)
+    {
+        $this->group = $value;
+    }
+
+    public function badge($value)
+    {
+        $this->badge = $value;
+    }
+
+    public function ticker($value)
+    {
+        $this->ticker = $value;
+    }
+
+    public function auto_cancel($value)
+    {
+        $this->auto_cancel = $value;
+    }
+
+    public function when($value)
+    {
+        $this->when = $value;
+    }
+
+    public function importance($value)
+    {
+        $this->importance = $value;
+    }
+
+    public function use_default_vibrate($value)
+    {
+        $this->use_default_vibrate = $value;
+    }
+
+    public function use_default_light($value)
+    {
+        $this->use_default_light = $value;
+    }
+
+    public function vibrate_config($value)
+    {
+        $this->vibrate_config = $value;
+    }
+
+    public function visibility($value)
+    {
+        $this->visibility = $value;
+    }
+
+    public function light_settings($value)
+    {
+        $this->light_settings = $value;
+    }
+
+    public function foreground_show($value)
+    {
+        $this->foreground_show = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            PushLogConfig::getSingleInstance()->LogMessage($e, Constants::HW_PUSH_LOG_ERROR_LEVEL);
+            return;
+        }
+
+        $keys = array(
+            'title',
+            'body',
+            'image',
+            'icon',
+            'color',
+            'sound',
+            'tag',
+            'click_action',
+            'body_loc_key',
+            'body_loc_args',
+            'title_loc_key',
+            'title_loc_args',
+            'channel_id',
+            'notify_summary',
+            'notify_icon',
+            'style',
+            'big_title',
+            'big_body',
+            'auto_clear',
+            'notify_id',
+            'group',
+            'badge',
+            'ticker',
+            'auto_cancel',
+            'when',
+            'importance',
+            'use_default_vibrate',
+            'use_default_light',
+            'vibrate_config',
+            'visibility',
+            'light_settings',
+            'foreground_show'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (empty($this->title)) {
+            throw new Exception("title should be set");
+        }
+        if (empty($this->body)) {
+            throw new Exception("body should be set");
+        }
+
+        if (!empty($this->color)) {
+            if (FALSE == ValidatorUtil::validatePattern(Constants::COLOR_PATTERN, $this->color)) {
+                throw new Exception("Wrong color format, color must be in the form #RRGGBB");
+            }
+        }
+
+        if (!empty($this->body_loc_args) && empty($this->body_loc_key)) {
+            throw new Exception("bodyLocKey is required when specifying bodyLocArgs");
+        }
+
+        if (!empty($this->title_loc_args) && empty($this->title_loc_key)) {
+            throw new Exception("titleLocKey is required when specifying titleLocArgs");
+        }
+
+        if (!empty($this->image)) {
+            if (FALSE == ValidatorUtil::validatePattern(Constants::URL_PATTERN, $this->image)) {
+                throw new Exception("notifyIcon must start with https");
+            }
+        }
+
+        if (($this->style) && (gettype($this->style) != "integer")) {
+            throw new Exception("type of style is wrong.");
+        }
+
+        if (!in_array($this->style, array(
+            0,
+            1
+        ))) {
+            throw new Exception("style should be one of 0:default, 1: big text");
+        }
+
+        // importance
+        if (!empty($this->importance) && !in_array($this->importance, array(
+                NotificationPriority::NOTIFICATION_PRIORITY_LOW,
+                NotificationPriority::NOTIFICATION_PRIORITY_NORMAL,
+                NotificationPriority::NOTIFICATION_PRIORITY_HIGH,
+            ))) {
+            throw new Exception("notification priority shouid be [LOW,NORMAL,HIGH]");
+        }
+
+        // vibrate_config
+        if (!empty($this->vibrate_config)) {
+            foreach ($this->vibrate_config as $key) {
+                if (FALSE == ValidatorUtil::validatePattern(Constants::VIBRATE_PATTERN, $key)) {
+                    throw new Exception("Wrong vibrate timing format");
+                }
+            }
+        }
+
+        // visibility
+        if (!empty($this->visibility) && !in_array($this->visibility, array(
+                Visibility::VISIBILITY_UNSPECIFIED,
+                Visibility::PRIVATE_STR,
+                Visibility::PUBLIC_STR,
+                Visibility::SECRET_STR
+            ))) {
+            throw new Exception("visibility shouid be [VISIBILITY_UNSPECIFIED, PRIVATE, PUBLIC, SECRET]");
+        }
+
+        // auto_clear
+        if (($this->auto_clear) && (gettype($this->auto_clear) != "integer")) {
+            throw new Exception("type of auto_clear is wrong.");
+        }
+        // notify_id
+        if (($this->notify_id) && (gettype($this->notify_id) != "integer")) {
+            throw new Exception("type of notify_id is wrong.");
+        }
+
+
+    }
+}

+ 79 - 0
app/Libs/Push/HuaWei/Admin/Msg/Android/Badge.php

@@ -0,0 +1,79 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Android;
+
+
+use Exception;
+
+class Badge
+{
+    private $add_num;
+
+    private $class;
+
+    private $set_num;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->fields = array();
+    }
+
+    public function add_num($value)
+    {
+        $this->add_num = $value;
+    }
+
+    public function setclass($value)
+    {
+        $this->class = $value;
+    }
+
+    public function set_num($value)
+    {
+        $this->set_num = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            echo $e;
+        }
+        $keys = array(
+            'add_num',
+            'class',
+            'set_num'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (($this->add_num) && (gettype($this->add_num) != "integer")) {
+            throw new Exception("type of add_num is wrong.");
+        }
+        if (is_int($this->add_num) && ($this->add_num < 1 || $this->add_num > 100)) {
+            throw new Exception("add_num should locate between 0 and 100");
+        }
+        if (($this->set_num) && (gettype($this->set_num) != "integer")) {
+            throw new Exception("type of set_num is wrong.");
+        }
+        if (is_int($this->set_num) && ($this->set_num < 1 || $this->set_num > 100)) {
+            throw new Exception("set_num should locate between 0 and 100");
+        }
+
+    }
+}

+ 125 - 0
app/Libs/Push/HuaWei/Admin/Msg/Android/ClickAction.php

@@ -0,0 +1,125 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Android;
+
+use App\Libs\Push\HuaWei\Admin\Msg\ValidatorUtil;
+use Exception;
+
+class ClickAction
+{
+    private $type;
+
+    private $intent;
+
+    private $url;
+
+    private $rich_resource;
+
+    // added
+    private $action;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->rich_resource = null;
+        $this->url           = null;
+    }
+
+    public function type($value)
+    {
+        $this->type = $value;
+    }
+
+    public function intent($value)
+    {
+        $this->intent = $value;
+    }
+
+    public function url($value)
+    {
+        $this->url = $value;
+    }
+
+    public function rich_resource($value)
+    {
+        $this->rich_resource = $value;
+    }
+
+    // added
+    public function action($value)
+    {
+        $this->action = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            echo $e;
+        }
+        $keys = array(
+            'type',
+            'intent',
+            'url',
+            'rich_resource',
+            // add
+            'action'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (($this->type) && (gettype($this->type) != "integer")) {
+            throw new Exception("type of type is wrong.");
+        }
+        if (!in_array($this->type, array(1, 2, 3, 4))) {
+            throw new Exception("click type should be one of 1: customize action, 2: open url, 3: open app, 4: open rich media");
+        }
+        $PATTERN = "/^https.*/";
+        switch ($this->type) {
+            case 1:
+                {
+                    if (is_null($this->intent) && is_null($this->action)) {
+                        throw new Exception("when type=1,intent/action at least one is valid");
+                    }
+                }
+                break;
+            case 2:
+                {
+                    if (is_null($this->url)) {
+                        throw new Exception("url is required when click type=2");
+                    }
+                    if (FALSE == ValidatorUtil::validatePattern($PATTERN, $this->url)) {
+                        throw new Exception("url must start with https");
+                    }
+                }
+                break;
+            case 4:
+                {
+                    if (is_null($this->richResource)) {
+                        throw new Exception("richResource is required when click type=4");
+                    }
+
+                    if (FALSE == ValidatorUtil::validatePattern($PATTERN, $this->richResource)) {
+                        throw new Exception("richResource must start with https");
+                    }
+                }
+                break;
+        }
+
+
+    }
+}

+ 85 - 0
app/Libs/Push/HuaWei/Admin/Msg/Android/LightSetting.php

@@ -0,0 +1,85 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Android;
+
+use App\Libs\Push\HuaWei\Admin\Msg\ValidatorUtil;
+use Exception;
+
+class LightSetting
+{
+    private $color;
+
+    private $light_on_duration;
+
+    private $light_off_duration;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->color  = array();
+        $this->fields = array();
+    }
+
+    public function color($value)
+    {
+        $this->color = $value;
+    }
+
+    public function light_on_duration($value)
+    {
+        $this->light_on_duration = $value;
+    }
+
+    public function light_off_duration($value)
+    {
+        $this->light_off_duration = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            echo $e;
+        }
+        $keys = array(
+            'color',
+            'light_on_duration',
+            'light_off_duration'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (empty($this->color)) {
+            throw new Exception("color must be selected when light_settings is set");
+        }
+        if (empty($this->light_on_duration)) {
+            throw new Exception("light_on_duration must be selected when light_settings is set");
+        }
+        if (empty($this->light_off_duration)) {
+            throw new Exception("light_off_duration must be selected when light_settings is set");
+        }
+        $LIGTH_DURATION_PATTERN = "/\\d+|\\d+[sS]|\\d+.\\d{1,9}|\\d+.\\d{1,9}[sS]/";
+        if (FALSE == ValidatorUtil::validatePattern($LIGTH_DURATION_PATTERN, $this->light_on_duration)) {
+            throw new Exception("light_on_duration format is wrong");
+        }
+        if (FALSE == ValidatorUtil::validatePattern($LIGTH_DURATION_PATTERN, $this->light_off_duration)) {
+            throw new Exception("light_off_duration format is wrong");
+        }
+
+
+    }
+}

+ 97 - 0
app/Libs/Push/HuaWei/Admin/Msg/Android/LightSettingColor.php

@@ -0,0 +1,97 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Android;
+
+use Exception;
+
+class LightSettingColor
+{
+    private $alpha;
+
+    private $red;
+
+    private $green;
+
+    private $blue;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->alpha  = 1;
+        $this->red    = 0;
+        $this->green  = 0;
+        $this->blue   = 0;
+        $this->fields = array();
+    }
+
+    public function setgenFullcolor($alpha, $red, $green, $blue)
+    {
+        $this->alpha = $alpha;
+        $this->red   = $red;
+        $this->green = $green;
+        $this->blue  = $blue;
+    }
+
+    public function alpha($value)
+    {
+        $this->alpha = $value;
+    }
+
+    public function red($value)
+    {
+        $this->red = $value;
+    }
+
+    public function green($value)
+    {
+        $this->green = $value;
+    }
+
+    public function blue($value)
+    {
+        $this->blue = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            echo $e;
+        }
+        $keys = array(
+            'alpha',
+            'red',
+            'green',
+            'blue'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (empty($this->alpha) && (gettype($this->alpha) != "integer")) {
+            throw new Exception("type of alpha is wrong.");
+        }
+        if (empty($this->red) && (gettype($this->red) != "integer")) {
+            throw new Exception("type of red is wrong.");
+        }
+        if (empty($this->green) && (gettype($this->green) != "integer")) {
+            throw new Exception("type of green is wrong.");
+        }
+        if (empty($this->blue) && (gettype($this->blue) != "integer")) {
+            throw new Exception("type of blue is wrong.");
+        }
+    }
+}

+ 92 - 0
app/Libs/Push/HuaWei/Admin/Msg/Apns/Alert.php

@@ -0,0 +1,92 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Apns;
+
+
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+
+class Alert
+{
+    private $title;
+    private $body;
+    private $title_loc_key;
+    private $title_loc_args;
+    private $action_loc_key;
+    private $loc_key;
+    private $loc_args;
+    private $launch_image;
+
+    private $fields;
+
+    public function title($value)
+    {
+        $this->title = $value;
+    }
+
+    public function body($value)
+    {
+        $this->body = $value;
+    }
+
+    public function title_loc_key($value)
+    {
+        $this->title_loc_key = $value;
+    }
+
+    public function title_loc_args($value)
+    {
+        $this->title_loc_args = $value;
+    }
+
+    public function action_loc_key($value)
+    {
+        $this->action_loc_key = $value;
+    }
+
+    public function loc_key($value)
+    {
+        $this->loc_key = $value;
+    }
+
+    public function loc_args($value)
+    {
+        $this->loc_args = $value;
+    }
+
+    public function launch_image($value)
+    {
+        $this->launch_image = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        $keys = array(
+            'title',
+            'body',
+            'title-loc-key',
+            'title-loc-args',
+            'action-loc-key',
+            'loc-key',
+            'loc-args',
+            'launch-image'
+        );
+        foreach ($keys as $key) {
+
+            $value = str_replace('-', '_', $key);
+
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][before key:' . $key . '][after key:' . $value . ']', Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+            if (isset($this->$value)) {
+                $this->fields[$key] = $this->$value;
+            }
+        }
+        PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][buildFields result:' . json_encode($this->fields), Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+    }
+}

+ 60 - 0
app/Libs/Push/HuaWei/Admin/Msg/Apns/ApnsConfig.php

@@ -0,0 +1,60 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Apns;
+
+
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+
+class ApnsConfig
+{
+    private $payload;
+    private $headers;
+    private $hms_options;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->fields = array();
+    }
+
+    public function payload($value)
+    {
+        $this->payload = $value;
+    }
+
+    public function headers($value)
+    {
+        $this->headers = $value;
+    }
+
+    public function hms_options($value)
+    {
+        $this->hms_options = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+
+        $keys = array(
+            'headers',
+            'hms_options',
+            'payload'
+        );
+        foreach ($keys as $key) {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][key:' . $key . '][value:' . json_encode($this->$key) . ']', Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+        PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][buildFields result:' . json_encode($this->fields), Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+    }
+}

+ 116 - 0
app/Libs/Push/HuaWei/Admin/Msg/Apns/ApnsHeaders.php

@@ -0,0 +1,116 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Apns;
+
+use App\Libs\Push\HuaWei\Admin\ApnConstant;
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\Msg\ValidatorUtil;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+use Exception;
+
+class ApnsHeaders
+{
+    private $authorization;
+
+    private $apns_id;
+
+    private $apns_expiration;
+
+    private $apns_priority;
+
+    private $apns_topic;
+
+    private $apns_collapse_id;
+
+    private $fields;
+
+    public function authorization($value)
+    {
+        $this->authorization = $value;
+    }
+
+    public function apns_id($value)
+    {
+        $this->apns_id = $value;
+    }
+
+    public function apns_expiration($value)
+    {
+        $this->apns_expiration = $value;
+    }
+
+    public function apns_priority($value)
+    {
+        $this->apns_priority = $value;
+    }
+
+    public function apns_topic($value)
+    {
+        $this->apns_topic = $value;
+    }
+
+    public function apns_collapse_id($value)
+    {
+        $this->apns_collapse_id = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            echo $e;
+        }
+        $keys = array(
+            'authorization',
+            'apns-id',
+            'apns-expiration',
+            'apns-priority',
+            'apns-topic',
+            'apns-collapse-id'
+        );
+        foreach ($keys as $key) {
+
+            $value = str_replace('-', '_', $key);
+
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][before key:' . $key . '][after key:' . $value . ']', Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+            if (isset($this->$value)) {
+                $this->fields[$key] = $this->$value;
+            }
+        }
+        PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][buildFields result:' . json_encode($this->fields), Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+    }
+
+    private function check_parameter()
+    {
+        if (!empty($this->authorization)) {
+            if (FALSE == ValidatorUtil::validatePattern(Constants::APN_AUTHORIZATION_PATTERN, $this->authorization)) {
+                throw new Exception("authorization must start with bearer");
+            }
+        }
+        if (!empty($this->apns_id)) {
+            if (FALSE == ValidatorUtil::validatePattern(Constants::APN_ID_PATTERN, $this->apns_id)) {
+                throw new Exception("apns-id format error");
+            }
+        }
+        if (!empty($this->apns_priority)) {
+            if (!in_array($this->apns_priority, array(
+                ApnConstant::ANP_PRIORITY_SEND_BY_GROUP,
+                ApnConstant::ANP_PRIORITY_SEND_IMMEDIATELY
+            ))) {
+                throw new Exception("apns-priority should be SEND_BY_GROUP:5  or SEND_IMMEDIATELY:10");
+            }
+        }
+        if (!empty($this->apns_collapse_id)) {
+            if (strlen($this->apns_priority) >= 64) {
+                throw new Exception("Number of apnsCollapseId bytes should be less than 64");
+            }
+        }
+    }
+}

+ 47 - 0
app/Libs/Push/HuaWei/Admin/Msg/Apns/ApnsHmsOptions.php

@@ -0,0 +1,47 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Apns;
+
+
+use Exception;
+
+class ApnsHmsOptions
+{
+    private $target_user_type;
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function target_user_type($value)
+    {
+        $this->target_user_type = $value;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            echo $e;
+        }
+        $keys = array(
+            'target_user_type'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (!empty($this->target_user_type)
+            && !in_array($this->target_user_type, array(1, 2, 3))) {
+            throw new Exception("target_user_type range TEST_USER:1,FORMAL_USER:2,VOIP_USER:3");
+        }
+    }
+}

+ 78 - 0
app/Libs/Push/HuaWei/Admin/Msg/Apns/Aps.php

@@ -0,0 +1,78 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Apns;
+
+
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+
+class Aps
+{
+    private $alert;
+    private $badge;
+    private $sound;
+    private $content_available;
+    private $category;
+    private $thread_id;
+
+    private $fields;
+
+    public function alert($value)
+    {
+        $this->alert = $value;
+    }
+
+    public function badge($value)
+    {
+        $this->badge = $value;
+    }
+
+    public function sound($value)
+    {
+        $this->sound = $value;
+    }
+
+    public function content_available($value)
+    {
+        $this->content_available = $value;
+    }
+
+    public function category($value)
+    {
+        $this->category = $value;
+    }
+
+    public function thread_id($value)
+    {
+        $this->thread_id = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        $keys = array(
+            'alert',
+            'badge',
+            'sound',
+            'content-available',
+            'category',
+            'thread-id'
+        );
+        foreach ($keys as $key) {
+
+            $value = str_replace('-', '_', $key);
+
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][before key:' . $key . '][after key:' . $value . ']', Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+            if (isset($this->$value)) {
+                $this->fields[$key] = $this->$value;
+            }
+        }
+        PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][buildFields result:' . json_encode($this->fields), Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+    }
+}

+ 60 - 0
app/Libs/Push/HuaWei/Admin/Msg/InstanceApp/InstanceAppConfig.php

@@ -0,0 +1,60 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\InstanceApp;
+
+
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+
+class InstanceAppConfig
+{
+//push_type 0:notification;1,pass-through
+    private $pushtype;
+    private $pushbody;
+    private $fields;
+
+    public function __construct()
+    {
+    }
+
+    public function pushtype($value)
+    {
+        $this->pushtype = $value;
+    }
+    public function pushbody($value)
+    {
+        $this->pushbody = $value;
+    }
+
+    public function getFields()
+    {
+        $result = "{";
+        foreach ($this->fields as $key=>$value) {
+            $result = $result .$key.":".json_encode($value).",";
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][result:' .$result, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        }
+        if (strlen($result) > 1){
+            $result = rtrim($result, ",");
+        }
+        $result = $result."}";
+        return $result;
+    }
+
+    public function buildFields()
+    {
+
+        $keys = array(
+            'pushtype',
+            'pushbody'
+        );
+        foreach ($keys as $key) {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][key:' . $key . '][value:' . json_encode($this->$key) . ']', Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+        PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][buildFields result:' . json_encode($this->fields), Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+    }
+}

+ 98 - 0
app/Libs/Push/HuaWei/Admin/Msg/InstanceApp/InstanceAppPushBody.php

@@ -0,0 +1,98 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\InstanceApp;
+
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+
+class InstanceAppPushBody
+{
+// for pass-through
+    private $messageId;
+    private $data;
+
+    // for notification
+    private $title;
+    private $description;
+    private $page;
+    private $params;
+    private $ringtone;
+
+    private $fields;
+
+    public function __construct()
+    {
+    }
+
+    public function messageId($value)
+    {
+        $this->messageId = $value;
+    }
+
+    public function data($value)
+    {
+        $this->data = $value;
+    }
+
+    public function title($value)
+    {
+        $this->title = $value;
+    }
+
+    public function description($value)
+    {
+        $this->description = $value;
+    }
+
+    public function page($value)
+    {
+        $this->page = $value;
+    }
+
+    public function params($value)
+    {
+        $this->params = $value;
+    }
+
+    public function ringtone($value)
+    {
+        $this->ringtone = $value;
+    }
+
+    public function getFields()
+    {
+        $result = "{";
+        foreach ($this->fields as $key => $value) {
+            $result = $result . $key . ":" . json_encode($value) . ",";
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][result:' . $result, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        }
+        if (strlen($result) > 1) {
+            $result = rtrim($result, ",");
+        }
+        $result = $result . "}";
+        return $result;
+    }
+
+    public function buildFields()
+    {
+
+        $keys = array(
+            'messageId',
+            'data',
+            'title',
+            'description',
+            'page',
+            'params',
+            'ringtone'
+        );
+        foreach ($keys as $key) {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][key:' . $key . '][value:' . json_encode($this->$key) . ']', Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+        PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][buildFields result:' . json_encode($this->fields), Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+    }
+}

+ 60 - 0
app/Libs/Push/HuaWei/Admin/Msg/InstanceApp/InstanceAppRingTone.php

@@ -0,0 +1,60 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\InstanceApp;
+
+
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+
+class InstanceAppRingTone
+{
+    private $vibration;
+    private $breathLight;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->fields = array();
+    }
+
+    public function vibration($value)
+    {
+        $this->vibration = $value;
+    }
+
+    public function breathLight($value)
+    {
+        $this->breathLight = $value;
+    }
+
+    public function getFields()
+    {
+        $result = "{";
+        foreach ($this->fields as $key => $value) {
+            $result = $result . $key . ":" . json_encode($value) . ",";
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][result:' . $result, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        }
+        if (strlen($result) > 1) {
+            $result = rtrim($result, ",");
+        }
+        $result = $result . "}";
+        return $result;
+    }
+
+    public function buildFields()
+    {
+        $keys = array(
+            'vibration',
+            'breathLight'
+        );
+        foreach ($keys as $key) {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][key:' . $key . '][value:' . json_encode($this->$key) . ']', Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+        PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . '][buildFields result:' . json_encode($this->fields), Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+    }
+}

+ 84 - 0
app/Libs/Push/HuaWei/Admin/Msg/Notification/Notification.php

@@ -0,0 +1,84 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\Notification;
+
+
+use Exception;
+
+class Notification
+{
+    /**
+     * optional
+     */
+    private $title;
+
+    /**
+     * optional
+     */
+    private $body;
+
+    /**
+     * optional
+     */
+    private $image;
+
+    private $fields;
+
+    public function __construct($title, $body, $image)
+    {
+        $this->title  = $title;
+        $this->body   = $body;
+        $this->image  = $image;
+        $this->fields = array();
+    }
+
+    public function title($value)
+    {
+        $this->title = $value;
+    }
+
+    public function body($value)
+    {
+        $this->body = $value;
+    }
+
+    public function image($value)
+    {
+        $this->image = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            echo $e;
+        }
+        $keys = array(
+            'title',
+            'body',
+            'image'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (empty($this->title)) {
+            throw new Exception("title should be set");
+        }
+        if (empty($this->body)) {
+            throw new Exception("body should be set");
+        }
+    }
+}

+ 104 - 0
app/Libs/Push/HuaWei/Admin/Msg/PushMessage.php

@@ -0,0 +1,104 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg;
+
+
+class PushMessage
+{
+    private $data;
+
+    private $notification;
+
+    private $android;
+
+    private $apns;
+
+    private $webpush;
+
+    private $token;
+
+    private $topic;
+
+    private $condition;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->fields       = array();
+        $this->token        = null;
+        $this->condition    = null;
+        $this->topic        = null;
+        $this->notification = null;
+    }
+
+    public function data($value)
+    {
+        $this->data = $value;
+    }
+
+    public function notification($value)
+    {
+        $this->notification = $value;
+    }
+
+    public function android($value)
+    {
+        $this->android = $value;
+    }
+
+    public function token($value)
+    {
+        $this->token = $value;
+    }
+
+    public function get_token()
+    {
+        return $this->token;
+    }
+
+    public function topic($value)
+    {
+        $this->topic = $value;
+    }
+
+    public function condition($value)
+    {
+        $this->condition = $value;
+    }
+
+    public function apns($value)
+    {
+        $this->apns = $value;
+    }
+
+    public function webpush($value)
+    {
+        $this->webpush = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        $keys = array(
+            'data',
+            'notification',
+            'android',
+            'token',
+            'topic',
+            'condition',
+            'apns',
+            'webpush'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+}

+ 18 - 0
app/Libs/Push/HuaWei/Admin/Msg/ValidatorUtil.php

@@ -0,0 +1,18 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg;
+
+
+class ValidatorUtil
+{
+    public static function validatePattern($pattern, $value)
+    {
+        $result = preg_match($pattern, $value);
+
+        if (1 == $result) {
+            return TRUE;
+        }
+        return FALSE;
+    }
+}

+ 66 - 0
app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushConfig.php

@@ -0,0 +1,66 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\WebPush;
+
+
+class WebPushConfig
+{
+    private $headers;
+
+    private $data;
+
+    private $notification;
+
+    private $hms_options;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->headers      = array();
+        $this->notification = array();
+        $this->hmsOptions   = array();
+        $this->fields       = array();
+    }
+
+    public function headers($value)
+    {
+        $this->headers = $value;
+    }
+
+    public function data($value)
+    {
+        $this->data = $value;
+    }
+
+    public function notification($value)
+    {
+        $this->notification = $value;
+    }
+
+    public function hmsOptions($value)
+    {
+        $this->hms_options = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        $keys = array(
+            'headers',
+            'data',
+            'notification',
+            'hms_options'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+}

+ 55 - 0
app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushHeaders.php

@@ -0,0 +1,55 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\WebPush;
+
+
+class WebPushHeaders
+{
+    private $ttl;
+
+    private $topic;
+
+    private $urgency;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->fields = array();
+    }
+
+    public function ttl($value)
+    {
+        $this->ttl = $value;
+    }
+
+    public function topic($value)
+    {
+        $this->topic = $value;
+    }
+
+    public function urgency($value)
+    {
+        $this->urgency = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        $keys = array(
+            'ttl',
+            'topic',
+            'urgency'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+}

+ 40 - 0
app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushHmsOptions.php

@@ -0,0 +1,40 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\WebPush;
+
+
+class WebPushHmsOptions
+{
+    private $link;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->fields = array();
+    }
+
+    public function link($value) {
+        $this->link = $value;
+    }
+
+
+
+    public function getFields() {
+        return $this->fields;
+    }
+
+    public function buildFields() {
+
+
+        $keys = array(
+            'link'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+}

+ 158 - 0
app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushNotification.php

@@ -0,0 +1,158 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\WebPush;
+
+
+use Exception;
+
+class WebPushNotification
+{
+    private $title;
+    private $body;
+    private $icon;
+    private $image;
+    private $lang;
+    private $tag;
+    private $badge;
+    private $dir;
+    private $vibrate;
+    private $renotify;
+
+    private $require_interaction;
+    private $silent;
+    private $timestamp;
+
+    private $actions;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->actions = array();
+        $this->fields  = array();
+    }
+
+    public function title($value)
+    {
+        $this->title = $value;
+    }
+
+    public function body($value)
+    {
+        $this->body = $value;
+    }
+
+    public function icon($value)
+    {
+        $this->icon = $value;
+    }
+
+    public function image($value)
+    {
+        $this->image = $value;
+    }
+
+    public function lang($value)
+    {
+        $this->lang = $value;
+    }
+
+    public function tag($value)
+    {
+        $this->tag = $value;
+    }
+
+    public function badge($value)
+    {
+        $this->badge = $value;
+    }
+
+    public function dir($value)
+    {
+        $this->dir = $value;
+    }
+
+    public function vibrate($value)
+    {
+        $this->vibrate = $value;
+    }
+
+    public function renotify($value)
+    {
+        $this->renotify = $value;
+    }
+
+    public function require_interaction($value)
+    {
+        $this->require_interaction = $value;
+    }
+
+
+    public function silent($value)
+    {
+        $this->silent = $value;
+    }
+
+    public function timestamp($value)
+    {
+        $this->timestamp = $value;
+    }
+
+    public function actions($value)
+    {
+        $this->actions = $value;
+    }
+
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        try {
+            $this->check_parameter();
+        } catch (Exception $e) {
+            echo $e;
+        }
+
+        $keys = array(
+            'title',
+            'body',
+            'icon',
+            'image',
+            'lang',
+            'tag',
+            'badge',
+            'dir',
+            'vibrate',
+            'renotify',
+            'require_interaction',
+            'silent',
+            'timestamp',
+            'actions'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+
+    private function check_parameter()
+    {
+        if (($this->renotify) && (gettype($this->renotify) != "boolean")) {
+            throw new Exception("type of renotify is wrong.");
+        }
+        if (($this->require_interaction) && (gettype($this->require_interaction) != "boolean")) {
+            throw new Exception("type of requireInteraction is wrong.");
+        }
+        if (($this->silent) && (gettype($this->silent) != "boolean")) {
+            throw new Exception("type of silent is wrong.");
+        }
+
+
+    }
+}

+ 55 - 0
app/Libs/Push/HuaWei/Admin/Msg/WebPush/WebPushNotificationAction.php

@@ -0,0 +1,55 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin\Msg\WebPush;
+
+
+class WebPushNotificationAction
+{
+    private $title;
+
+    private $icon;
+
+    private $action;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->fields = array();
+    }
+
+    public function title($value)
+    {
+        $this->title = $value;
+    }
+
+    public function action($value)
+    {
+        $this->action = $value;
+    }
+
+    public function icon($value)
+    {
+        $this->icon = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        $keys = array(
+            'title',
+            'icon',
+            'action'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+}

+ 173 - 0
app/Libs/Push/HuaWei/Admin/PushConfig.php

@@ -0,0 +1,173 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin;
+
+
+class PushConfig
+{
+// ORDINAL APP
+    public $HW_APPID;
+    public $HW_APPSECRET;
+    public $HW_PUSH_TOKEN_ARR;
+    public $APN_PUSH_TOKEN_ARR;
+    public $WEBPUSH_PUSH_TOKEN_ARR;
+
+    // FAST APP
+    public $HW_FAST_APPID;
+    public $HW_FAST_APPSECRET;
+    public $HW_FAST_PUSH_TOKEN;
+
+    public $HW_TOKEN_SERVER;
+    public $HW_PUSH_SERVER;
+    public $HW_PUSH_TOKEN_QUERY_SERVER;
+    public $HW_TOPIC_SUBSCRIBE_SERVER;
+    public $HW_TOPIC_UNSUBSCRIBE_SERVER;
+    public $HW_TOPIC_QUERY_SUBSCRIBER_SERVER;
+
+    public $HW_DEFAULT_LOG_LEVEL = 3;
+
+
+    private $log_read_flag = false;
+
+    private function __construct()
+    {
+        if ($this->log_read_flag == false) {
+            $file_path = app_path('/Libs/Push/HuaWei/config.ini');
+            if (file_exists($file_path)) {
+                $file_contents = file($file_path);
+                // read line
+                for ($i = 0; $i < count($file_contents); $i++) {
+                    $this->processConfigData($file_contents[$i]);
+                }
+                $this->log_read_flag = true;
+            } else {
+                echo $file_path . " not exist,please config first!!!<br>";
+            }
+        }
+    }
+
+    public static function getSingleInstance()
+    {
+        static $obj;
+        if (!isset($obj)) {
+            $obj = new PushConfig();
+        }
+        return $obj;
+    }
+
+    private function processConfigData($lineData)
+    {
+        if (empty($lineData)) {
+            return;
+        }
+        if (strncmp($lineData, "#", 1) == 0) {
+            return;
+        }
+        $lineData  = str_replace("\"", "", $lineData);
+        $lineData  = str_replace("\'", "", $lineData);
+        $lineData  = str_replace(" ", "", $lineData);
+        $lineData  = str_replace(";", "", $lineData);
+        $lineData  = str_replace(PHP_EOL, '', $lineData);
+        $resultPos = stripos($lineData, "=");
+        if (FALSE == $resultPos) {
+            return;
+        }
+        $key = substr($lineData, 0, $resultPos);
+
+        if (FALSE == $key) {
+            return;
+        }
+
+        $value = $this->processConfigValueData(substr($lineData, $resultPos + 1));
+        switch ($key) {
+            case "HW_APPID":
+                {
+                    $this->HW_APPID = $value;
+                }
+                break;
+            case "HW_APPSECRET":
+                {
+                    $this->HW_APPSECRET = $value;
+                }
+                break;
+            case "HW_TOKEN_SERVER":
+                {
+                    $this->HW_TOKEN_SERVER = $value;
+                }
+                break;
+            case "HW_PUSH_SERVER":
+                {
+                    $this->HW_PUSH_SERVER = $value;
+                }
+                break;
+            case "HW_TOPIC_SUBSCRIBE_SERVER":
+                {
+                    $this->HW_TOPIC_SUBSCRIBE_SERVER = $value;
+                }
+                break;
+            case "HW_TOPIC_UNSUBSCRIBE_SERVER":
+                {
+                    $this->HW_TOPIC_UNSUBSCRIBE_SERVER = $value;
+                }
+                break;
+            case "HW_TOPIC_QUERY_SUBSCRIBER_SERVER":
+                {
+                    $this->HW_TOPIC_QUERY_SUBSCRIBER_SERVER = $value;
+                }
+                break;
+
+            case "HW_PUSH_TOKEN_ARR":
+                {
+                    $this->HW_PUSH_TOKEN_ARR = $value;
+                }
+                break;
+
+            case "APN_PUSH_TOKEN_ARR":
+                {
+                    $this->APN_PUSH_TOKEN_ARR = $value;
+                }
+                break;
+
+            case "WEBPUSH_PUSH_TOKEN_ARR":
+                {
+                    $this->WEBPUSH_PUSH_TOKEN_ARR = $value;
+                }
+                break;
+            case "HW_DEFAULT_LOG_LEVEL":
+                {
+                    $this->HW_DEFAULT_LOG_LEVEL = $value;
+                }
+                break;
+
+            case "HW_FAST_APPID":
+                {
+                    $this->HW_FAST_APPID = $value;
+                }
+                break;
+            case "HW_FAST_APPSECRET":
+                {
+                    $this->HW_FAST_APPSECRET = $value;
+                }
+                break;
+            case "HW_FAST_PUSH_TOKEN":
+                {
+                    $this->HW_FAST_PUSH_TOKEN = $value;
+                }
+                break;
+
+        }
+    }
+
+    private function processConfigValueData($lineDataMapValue)
+    {
+        $key = stripos($lineDataMapValue, "\"");
+        if (FALSE == $key) {
+            return trim($lineDataMapValue);
+        }
+        if ($key > 0) {
+            return str_replace("\"", "", substr($lineDataMapValue, $key));
+        }
+        return trim($lineDataMapValue);
+    }
+}

+ 107 - 0
app/Libs/Push/HuaWei/Admin/PushLogConfig.php

@@ -0,0 +1,107 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei\Admin;
+
+use Exception;
+
+class PushLogConfig
+{
+    private $LogFile;
+
+    private $logBanner = "
+    ___ ___  __      __  __________ ____ ___  _________ ___ ___   __________  ___ _____________
+    /   |   \/  \    /  \ \______   \    |   \/   _____//   |   \  \______   \/   |   \______   \
+    /    ~    \   \/\/   /  |     ___/    |   /\_____  \/    ~    \  |     ___/    ~    \     ___/
+    \    Y    /\        /   |    |   |    |  / /        \    Y    /  |    |   \    Y    /    |
+    \___|_  /  \__/\  /    |____|   |______/ /_______  /\___|_  /   |____|    \___|_  /|____|
+    \/        \/                               \/       \/                    \/          
+";
+
+    private $LOG_MODULE_FIXED_LEN = 20;
+
+    private $default_log_level = Constants::HW_PUSH_LOG_INFO_LEVEL;
+
+    private function __construct()
+    {
+        $this->LogFile = @fopen(Constants::HW_PUSH_LOG_FILE_NAME, 'a+');
+        if (! is_resource($this->LogFile)) {
+            throw new Exception(Constants::HW_PUSH_LOG_FILE_NAME . 'invalid file Stream');
+        }
+
+        fwrite($this->LogFile, $this->logBanner);
+
+        $pushConfig = PushConfig::getSingleInstance();
+
+        $this->default_log_level = $pushConfig->HW_DEFAULT_LOG_LEVEL;
+        if (empty($this->default_log_level)){
+            $this->default_log_level = Constants::HW_PUSH_LOG_INFO_LEVEL;
+        }
+    }
+
+    /**
+     * single instance
+     */
+    public static function getSingleInstance()
+    {
+        static $obj;
+        if (! isset($obj)) {
+            $obj = new PushLogConfig();
+        }
+        return $obj;
+    }
+
+    /**
+     * core log process
+     */
+    public function LogMessage($msg, $logLevel = Constants::HW_PUSH_LOG_INFO_LEVEL, $module = null, $timeZone = 'Asia/shanghai', $timeFormat = "%Y-%m-%d %H:%M:%S")
+    {
+        if (empty($logLevel)) {
+            $logLevel = Constants::HW_PUSH_LOG_INFO_LEVEL;
+        }
+
+        if ($logLevel > $this->default_log_level) {
+            return;
+        }
+        date_default_timezone_set($timeZone);
+        $time = strftime($timeFormat, time());
+        $msg = str_replace("\t", '', $msg);
+        $msg = str_replace("\n", '', $msg);
+        $strLogLevel = $this->levelToString($logLevel);
+        if (isset($module)) {
+            $module = '[' . str_pad(str_replace(array(
+                    "\n",
+                    "\t"
+                ), array(
+                    "",
+                    ""
+                ), $module), $this->LOG_MODULE_FIXED_LEN) . ']';
+            $logLine = "$time\t$strLogLevel\t$module\t$msg\r\n";
+        } else {
+            $logLine = "$time\t$strLogLevel\t$msg\r\n";
+        }
+
+        print_r($logLine . '<br>');
+        fwrite($this->LogFile, $logLine);
+    }
+
+    private function levelToString($logLevel)
+    {
+        $ret = 'LOG::UNKNOWN';
+        switch ($logLevel) {
+            case Constants::HW_PUSH_LOG_DEBUG_LEVEL:
+                $ret = 'LOG::DEBUG';
+                break;
+            case Constants::HW_PUSH_LOG_INFO_LEVEL:
+                $ret = 'LOG::INFO';
+                break;
+            case Constants::HW_PUSH_LOG_WARN_LEVEL:
+                $ret = 'LOG::WARNING';
+                break;
+            case Constants::HW_PUSH_LOG_ERROR_LEVEL:
+                $ret = 'LOG::ERROR';
+                break;
+        }
+        return $ret;
+    }
+}

+ 225 - 0
app/Libs/Push/HuaWei/HwPushCommon.php

@@ -0,0 +1,225 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei;
+
+
+use App\Libs\Push\HuaWei\Admin\AndroidConfigDeliveryPriority;
+use App\Libs\Push\HuaWei\Admin\Application;
+use App\Libs\Push\HuaWei\Admin\Msg\Android\AndroidConfig;
+use App\Libs\Push\HuaWei\Admin\Msg\InstanceApp\InstanceAppConfig;
+use App\Libs\Push\HuaWei\Admin\Msg\InstanceApp\InstanceAppPushBody;
+use App\Libs\Push\HuaWei\Admin\Msg\InstanceApp\InstanceAppRingTone;
+use App\Libs\Push\HuaWei\Admin\Msg\PushMessage;
+
+/**
+ * 快应用
+ * Class FastAppPushCommon
+ * @package App\Libs\Push\HuaWei
+ */
+class HwPushCommon
+{
+    private $_app_id;
+    private $_app_secret;
+    private $_token = [];
+    private $_topic = '';
+    private $_fast_app_target = 2;
+    private $_big_tag = 'app';
+
+    public function __construct($appId, $appSecret)
+    {
+        $this->_app_id     = $appId;
+        $this->_app_secret = $appSecret;
+
+    }
+
+    /**
+     * 设置token
+     * @param $tokenArr
+     */
+    public function setToken($tokenArr)
+    {
+        $this->_token = $tokenArr;
+    }
+
+    /**
+     * 设置topic
+     * @param $topic
+     */
+    public function setTopic($topic)
+    {
+        $this->_topic = $topic;
+    }
+
+    /**
+     * 设置开发态和生产态,1:开发态, 2:生产态
+     * @param $target
+     */
+    public function setFastAppTarget($target)
+    {
+        $this->_fast_app_target = $target;
+    }
+
+    /**
+     * 设置bigTag
+     * @param $bigTag
+     */
+    public function setBigTag($bigTag)
+    {
+        $this->_big_tag = $bigTag;
+    }
+
+    /**
+     * 发送通知消息
+     * @param $title
+     * @param $desc
+     * @param $pageUrl
+     * @return mixed|null
+     */
+    public function sendPushMessage($title, $desc, $pageUrl)
+    {
+        // 组装发送数据
+        $data    = $this->createFastAppConfigNotificationData($title, $desc, $pageUrl);
+        $message = $this->createFastAppMsg($data->getFields());
+
+        # 创建app
+        $application = $this->createApplication();
+
+        # 发送消息
+        return $application->push_send_msg($message->getFields());
+    }
+
+    /**
+     * 查询push_token信息
+     * @param $pushToken
+     * @return mixed|null
+     */
+    public function queryPushToken($pushToken)
+    {
+        # 创建app
+        $application = $this->createApplication();
+
+        return $application->query_push_token($pushToken);
+    }
+
+    /**
+     * 主题订阅
+     * @param $topic
+     * @param $tokenArr
+     * @return bool|mixed|string|null
+     */
+    public function subscribeTopic($topic, $tokenArr)
+    {
+        # 创建app
+        $application = $this->createApplication();
+
+        return $application->subscribe_topic($topic, $tokenArr);
+    }
+
+    /**
+     * 主题退订
+     * @param $topic
+     * @param $tokenArr
+     * @return bool|mixed|string|null
+     */
+    public function unSubscribeTopic($topic, $tokenArr)
+    {
+        # 创建app
+        $application = $this->createApplication();
+
+        return $application->unsubscribe_topic($topic, $tokenArr);
+    }
+
+    /**
+     * 主题退订
+     * @param $token
+     * @return bool|mixed|string|null
+     */
+    public function subscribeList($token)
+    {
+        # 创建app
+        $application = $this->createApplication();
+
+        return $application->topic_list($token);
+    }
+
+    /**
+     * @param        $data
+     * @param array  $tokenArr
+     * @param string $topic
+     * @return PushMessage
+     */
+    private function createFastAppMsg($data): PushMessage
+    {
+        $message = new PushMessage();
+        $message->data($data);
+        $message->android($this->createAndroidConfig()->getFields());
+        if ($this->_topic) {
+            // 按照Topic向订阅了本topic的用户推消息
+            $message->topic($this->_topic);
+        } else {
+            // 按照Token向目标用户推消息
+            $message->token($this->_token);
+        }
+        $message->buildFields();
+        return $message;
+    }
+
+    /**
+     * @param        $title
+     * @param        $desc
+     * @param string $pageUrl
+     * @param int    $pushType
+     * @param array  $params
+     * @return InstanceAppConfig
+     */
+    private function createFastAppConfigNotificationData($title, $desc, $pageUrl = '/', $pushType = 0, $params = []): InstanceAppConfig
+    {
+        // 设置推送类型,0为通知栏消息
+        $instanceAppConfig = new InstanceAppConfig();
+        $instanceAppConfig->pushtype($pushType);
+
+        //快应用推送消息体
+        $instanceAppPushBody = new InstanceAppPushBody();
+        $instanceAppPushBody->title($title);
+        $instanceAppPushBody->description($desc);
+        $instanceAppPushBody->page($pageUrl);
+        $instanceAppPushBody->params($params);
+
+        // 设置是否震动和显示呼吸灯
+        $instanceAppRingTone = new InstanceAppRingTone();
+        $instanceAppRingTone->breathLight(true);
+        $instanceAppRingTone->vibration(true);
+        $instanceAppRingTone->buildFields();
+
+        $instanceAppPushBody->ringtone($instanceAppRingTone->getFields());
+        $instanceAppPushBody->buildFields();
+
+        $instanceAppConfig->pushbody($instanceAppPushBody->getFields());
+        $instanceAppConfig->buildFields();
+
+        return $instanceAppConfig;
+    }
+
+    /**
+     * @return AndroidConfig
+     */
+    private function createAndroidConfig(): AndroidConfig
+    {
+        $android_config = new AndroidConfig();
+        $android_config->collapse_key(-1);
+        $android_config->urgency(AndroidConfigDeliveryPriority::PRIORITY_HIGH);
+        $android_config->bi_tag('app');
+        $android_config->fast_app_target($this->_fast_app_target);
+        $android_config->buildFields();
+        return $android_config;
+    }
+
+    /**
+     * @return Application
+     */
+    private function createApplication(): Application
+    {
+        return new Application($this->_app_id, $this->_app_secret);
+    }
+}

+ 846 - 0
app/Libs/Push/HuaWei/PushMsgCommon.php

@@ -0,0 +1,846 @@
+<?php
+
+
+namespace App\Libs\Push\HuaWei;
+
+
+use App\Libs\Push\HuaWei\Admin\AndroidConfigDeliveryPriority;
+use App\Libs\Push\HuaWei\Admin\ApnConstant;
+use App\Libs\Push\HuaWei\Admin\Application;
+use App\Libs\Push\HuaWei\Admin\Constants;
+use App\Libs\Push\HuaWei\Admin\Msg\Android\AndroidConfig;
+use App\Libs\Push\HuaWei\Admin\Msg\Android\AndroidNotification;
+use App\Libs\Push\HuaWei\Admin\Msg\Android\Badge;
+use App\Libs\Push\HuaWei\Admin\Msg\Android\ClickAction;
+use App\Libs\Push\HuaWei\Admin\Msg\Android\LightSetting;
+use App\Libs\Push\HuaWei\Admin\Msg\Android\LightSettingColor;
+use App\Libs\Push\HuaWei\Admin\Msg\Apns\Alert;
+use App\Libs\Push\HuaWei\Admin\Msg\Apns\ApnsConfig;
+use App\Libs\Push\HuaWei\Admin\Msg\Apns\ApnsHeaders;
+use App\Libs\Push\HuaWei\Admin\Msg\Apns\ApnsHmsOptions;
+use App\Libs\Push\HuaWei\Admin\Msg\Apns\Aps;
+use App\Libs\Push\HuaWei\Admin\Msg\InstanceApp\InstanceAppConfig;
+use App\Libs\Push\HuaWei\Admin\Msg\InstanceApp\InstanceAppPushBody;
+use App\Libs\Push\HuaWei\Admin\Msg\InstanceApp\InstanceAppRingTone;
+use App\Libs\Push\HuaWei\Admin\Msg\Notification\Notification;
+use App\Libs\Push\HuaWei\Admin\Msg\PushMessage;
+use App\Libs\Push\HuaWei\Admin\Msg\WebPush\WebPushConfig;
+use App\Libs\Push\HuaWei\Admin\Msg\WebPush\WebPushHeaders;
+use App\Libs\Push\HuaWei\Admin\Msg\WebPush\WebPushHmsOptions;
+use App\Libs\Push\HuaWei\Admin\Msg\WebPush\WebPushNotification;
+use App\Libs\Push\HuaWei\Admin\Msg\WebPush\WebPushNotificationAction;
+use App\Libs\Push\HuaWei\Admin\NotificationPriority;
+use App\Libs\Push\HuaWei\Admin\PushConfig;
+use App\Libs\Push\HuaWei\Admin\PushLogConfig;
+
+class PushMsgCommon
+{
+    // ordinal app
+    private $appid;
+    private $appsecret;
+    // FOR PUSH MSG NOTIFICATION,PASSTHROUGH TOPIC/TOKEN/CONDITION
+    public $hw_push_token_key;
+    // FOR APN
+    public $apn_push_token_key;
+    // FOR WEBPUSH
+    public $webpush_push_token_key;
+
+    // fast app
+    private $fast_appid;
+    private $fast_appsecret;
+    // fast app token
+    public $fast_push_token;
+
+
+    private $hw_token_server;
+    private $hw_push_server;
+    private $hw_push_token_query_server;
+    private $log_suffix_show_start = ".............................";
+    private $log_suffix_show_end = "-----------------------------";
+    private $push_msg_type;
+    private $default_topic = 'defaultTopic';
+
+    private $str_len = 35;
+
+    public function __construct()
+    {
+        $pushConfig = PushConfig::getSingleInstance();
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_APPID", $this->str_len, '=') . ">" . $pushConfig->HW_APPID);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_APPSECRET", $this->str_len, '=') . ">" . $pushConfig->HW_APPSECRET);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_TOKEN_SERVER", $this->str_len, '=') . ">" . $pushConfig->HW_TOKEN_SERVER);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_PUSH_TOKEN_ARR", $this->str_len, '=') . ">" . $pushConfig->HW_PUSH_TOKEN_ARR);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("WEBPUSH_PUSH_TOKEN_ARR", $this->str_len, '=') . ">" . $pushConfig->WEBPUSH_PUSH_TOKEN_ARR);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("APN_PUSH_TOKEN_ARR", $this->str_len, '=') . ">" . $pushConfig->APN_PUSH_TOKEN_ARR);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_TOPIC_SUBSCRIBE_SERVER", $this->str_len, '=') . ">" . $pushConfig->HW_TOPIC_SUBSCRIBE_SERVER);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_TOPIC_UNSUBSCRIBE_SERVER", $this->str_len, '=') . ">" . $pushConfig->HW_TOPIC_UNSUBSCRIBE_SERVER);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_TOPIC_QUERY_SUBSCRIBER_SERVER", $this->str_len, '=') . ">" . $pushConfig->HW_TOPIC_QUERY_SUBSCRIBER_SERVER);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_FAST_APPID", $this->str_len, '=') . ">" . $pushConfig->HW_FAST_APPID);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_FAST_APPSECRET", $this->str_len, '=') . ">" . $pushConfig->HW_FAST_APPSECRET);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_FAST_PUSH_TOKEN", $this->str_len, '=') . ">" . $pushConfig->HW_FAST_PUSH_TOKEN);
+        PushLogConfig::getSingleInstance()->LogMessage(str_pad("HW_PUSH_TOKEN_QUERY_SERVER", $this->str_len, '=') . ">" . $pushConfig->HW_PUSH_TOKEN_QUERY_SERVER);
+
+        $this->appsecret              = $pushConfig->HW_APPSECRET;
+        $this->appid                  = $pushConfig->HW_APPID;
+        $this->hw_token_server        = $pushConfig->HW_TOKEN_SERVER;
+        $this->hw_push_server         = $pushConfig->HW_PUSH_SERVER;
+        $this->hw_push_token_key      = $pushConfig->HW_PUSH_TOKEN_ARR;
+        $this->apn_push_token_key     = $pushConfig->APN_PUSH_TOKEN_ARR;
+        $this->webpush_push_token_key = $pushConfig->WEBPUSH_PUSH_TOKEN_ARR;
+
+        $this->fast_appsecret  = $pushConfig->HW_FAST_APPSECRET;
+        $this->fast_appid      = $pushConfig->HW_FAST_APPID;
+        $this->fast_push_token = $pushConfig->HW_FAST_PUSH_TOKEN;
+
+    }
+
+    function sendPushMsgMessageByMsgType($msg_type, $topic = "")
+    {
+        $application_server = $this->hw_push_server;
+        $this->printLogMethodOperate("push msg start" . $this->log_suffix_show_start, __FUNCTION__ . ':' . __LINE__);
+
+        $this->push_msg_type = $msg_type;
+        $message             = $this->getMessageByMsgType($msg_type);
+
+        $this->printLogMethodOperate("msg body:" . json_encode($message->getFields()), __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+        $application = $this->createApplication($application_server);
+        $this->printLogMethodOperate("application server:" . json_encode($application->getApplicationFields()), __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+        $application->push_send_msg($message->getFields());
+        $this->printLogMethodOperate("push msg end" . $this->log_suffix_show_end, __FUNCTION__ . ':' . __LINE__);
+    }
+
+    function sendPushMsgRealMessage($message, $push_msg_type = "")
+    {
+        $this->printLogMethodOperate("sendPushMsgRealMessage start push_msg_type:" . $push_msg_type, __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        if (!empty($push_msg_type)) {
+            $this->push_msg_type = $push_msg_type;
+        }
+        $this->printLogMethodOperate("sendPushMsgRealMessage start push_msg_type:" . $this->push_msg_type, __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        $application_server = $this->hw_push_server;
+        $application        = $this->createApplication($application_server);
+        $this->printLogMethodOperate("application server:" . json_encode($application->getApplicationFields()), __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+        $application->push_send_msg($message);
+        $this->printLogMethodOperate("push msg end" . $this->log_suffix_show_end, __FUNCTION__ . ':' . __LINE__);
+    }
+
+    function sendPushTopicMsgMessage($topic = "")
+    {
+        if (empty($topic)) {
+            $topic = $this->default_topic;
+        }
+        $testTopicCommonSample = new TestTopicCommonSample($topic);
+
+        $this->printLogMethodOperate("start subscribe topic:" . $topic, __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_INFO_LEVEL);
+        // subscribe msg
+        $testTopicCommonSample->sendTopicMessage(Constants::TOPIC_SUBSCRIBE_MSG_TYPE);
+        // query subscribe msg
+        $testTopicCommonSample->sendTopicMessage(Constants::TOPIC_SUBSCRIBE_QUERY_MSG_TYPE);
+    }
+
+    /**
+     * $result==>{"msg":"success","code":"80000000","requestId":"157561883923402813000201",
+     * "topics":[{"name":"defaultTopic","addDate":"2019-12-06"},
+     * {"name":"push-test","addDate":"2019-12-06"},
+     * {"name":"targetTopic","addDate":"2019-12-06"},
+     * {"name":"weather","addDate":"2019-12-06"}]}
+     */
+    private function isTopicInTopicList($result, $topic)
+    {
+        $this->printLogMethodOperate("isTopicInTopicList topic[" . $topic . "],result:" . json_encode($result) . "", __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_INFO_LEVEL);
+        if (empty($result)) {
+            return FALSE;
+        }
+
+        $arrResult = json_decode(json_encode($result), true);
+        $this->printLogMethodOperate("isTopicInTopicList arrResult:" . json_encode($arrResult) . "][code:" . $arrResult["code"], __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+        if (empty($arrResult["code"])) {
+            return FALSE;
+        }
+        $this->printLogMethodOperate("isTopicInTopicList code:" . $arrResult["code"], __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+        if (!in_array($arrResult["code"], array(
+            "80000000",
+            80000000
+        ))) {
+            return FALSE;
+        }
+        if (empty($arrResult["topics"])) {
+            return FALSE;
+        }
+
+        $topicArr = $arrResult["topics"];
+        $this->printLogMethodOperate("isTopicInTopicList topicArr:" . json_encode($topicArr), __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        if (empty($topicArr)) {
+            return FALSE;
+        }
+
+        foreach ($topicArr as $topicObject) {
+            if ($topicObject["name"] == $topic) {
+                return TRUE;
+            }
+        }
+        $this->printLogMethodOperate("isTopicInTopicList False,topic is not subscribe", __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        return FALSE;
+    }
+
+    private function getDefaultAndroidNotificationContent($titel)
+    {
+        $prefixTitleData = '';
+        switch ($this->push_msg_type) {
+            case Constants::PUSHMSG_NOTIFICATION_MSG_TYPE:
+                {
+                    $prefixTitleData = ' notification ';
+                    break;
+                }
+            case Constants::PUSHMSG_PASS_THROUGHT_MSG_TYPE:
+                {
+                    $prefixTitleData = ' passthrough ';
+                    break;
+                }
+
+            case Constants::PUSHMSG_FASTAPP_MSG_TYPE:
+                {
+                    $prefixTitleData = ' fastapp ';
+                    break;
+                }
+            case Constants::PUSHMSG_TOPIC_MSG_TYPE:
+                {
+                    $prefixTitleData = ' topic ';
+                    break;
+                }
+            case Constants::PUSHMSG_CONDITION_MSG_TYPE:
+                {
+                    $prefixTitleData = ' condition ';
+                    break;
+                }
+
+            case Constants::APN_MSG_TYPE:
+                {
+                    $prefixTitleData = ' apn ';
+                    break;
+                }
+            case Constants::WEB_PUSH_MSG_TYPE:
+                {
+                    $prefixTitleData = ' webpush ';
+                    break;
+                }
+        }
+
+        return $prefixTitleData . $titel . $prefixTitleData;
+    }
+
+    private function createAndroidNotification()
+    {
+        // generate click_action msg body for android notification-3-click_action
+        $click_action = new ClickAction();
+        $click_action->type(2);
+        $click_action->type(1);
+
+        $click_action->intent("#Intent;compo=com.rvr/.Activity;S.W=U;end");
+        $click_action->action("test add");
+        $click_action->url("https://www.baidu.com");
+        $click_action->rich_resource("test rich resource");
+        $click_action->buildFields();
+
+        // generate Badge for android notification-3-badge
+        $badge = new Badge();
+        $badge->add_num(99);
+        $badge->setclass("Classic");
+        $badge->set_num(99);
+        $badge->buildFields();
+
+        // generate Light Settings for android notification-3-badge
+        $lightSetting = new LightSetting();
+        $lightSetting->light_on_duration("3.5");
+        $lightSetting->light_off_duration("5S");
+        // set light setting color
+        $LightSettingColor = new LightSettingColor();
+        $LightSettingColor->setgenFullcolor(0, 0, 1, 1);
+        $LightSettingColor->buildFields();
+        $lightSetting->color($LightSettingColor->getFields());
+        $lightSetting->buildFields();
+
+        // 构建android notification消息体-2 for android config
+        $android_notification = new AndroidNotification();
+        $android_notification->title($this->getDefaultAndroidNotificationContent("default hw title "));
+        $android_notification->body($this->getDefaultAndroidNotificationContent("default hw body"));
+        $android_notification->icon("https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png");
+        $android_notification->color("#AACCDD");
+        $android_notification->sound("https://att.chinauui.com/day_120606/20120606_7fcf2235b44f1eab0b4dadtAkAGMTBHK.mp3");
+        $android_notification->tag("tagBoom");
+        $android_notification->body_loc_key("M.String.body");
+        $android_notification->body_loc_args(array(
+            "Boy",
+            "Dog"
+        ));
+        $android_notification->title_loc_key("M.String.title");
+        $android_notification->title_loc_args(array(
+            "Girl",
+            "Cat"
+        ));
+        $android_notification->channel_id("RingRing");
+        $android_notification->notify_summary("Some Summary");
+        $android_notification->image("https://developer-portalres-drcn.dbankcdn.com/system/modules/org.opencms.portal.template.core/resources/images/icon_Promotion.png");
+        $android_notification->style(1);
+        $android_notification->big_title("Big Boom Title");
+        $android_notification->big_body("Big Boom Body");
+        $android_notification->auto_clear(86400000);
+        $android_notification->notify_id(486);
+        $android_notification->group("Espace");
+        $android_notification->importance(NotificationPriority::NOTIFICATION_PRIORITY_NORMAL);
+        $android_notification->ticker("i am a ticker");
+        $android_notification->auto_cancel(false);
+        $android_notification->when("2019-11-05");
+        $android_notification->use_default_vibrate(true);
+        $android_notification->use_default_light(false);
+        $android_notification->visibility("PUBLIC");
+        $android_notification->foreground_show(true);
+        $android_notification->vibrate_config(array(
+            "1.5",
+            "2.000000001",
+            "3"
+        ));
+        $android_notification->click_action($click_action->getFields());
+        $android_notification->badge($badge->getFields());
+        $android_notification->light_settings($lightSetting->getFields());
+        $android_notification->buildFields();
+
+        return $android_notification;
+    }
+
+    private function createAndroidConfig()
+    {
+        $android_notification = $this->createAndroidNotification();
+
+        $android_config = new AndroidConfig();
+        $android_config->collapse_key(-1);
+        $android_config->urgency(AndroidConfigDeliveryPriority::PRIORITY_HIGH);
+        $android_config->ttl("1448s");
+        $android_config->bi_tag("Trump");
+        if ($this->push_msg_type == Constants::PUSHMSG_FASTAPP_MSG_TYPE) {
+            $android_config->fast_app_target(1);
+        } else {
+            $android_config->notification($android_notification->getFields());
+        }
+        $android_config->buildFields();
+        return $android_config;
+    }
+
+    private function createNotification()
+    {
+        $notification = new Notification("Big News", "This is a Big News!", "https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2_0.png");
+        $notification->buildFields();
+        return $notification;
+    }
+
+    private function createApnsConfig()
+    {
+        // ApnsHeaders
+        $apnsHeaders = new ApnsHeaders();
+        $apnsHeaders->apns_topic("hmspush");
+        $apnsHeaders->apns_priority(ApnConstant::ANP_PRIORITY_SEND_IMMEDIATELY);
+        $apnsHeaders->buildFields();
+
+        // ApnHmsOptions
+        $apnsHmsOptions = new ApnsHmsOptions();
+        $apnsHmsOptions->target_user_type(ApnConstant::APN_TARGET_USER_TEST_USER);
+        $apnsHmsOptions->buildFields();
+
+        // Aps
+        // Alert
+        $alert = new Alert();
+        $alert->title("hw default ios message title");
+        $alert->body("hw default ios message body");
+        $alert->action_loc_key("PLAY");
+        $alert->buildFields();
+
+        $aps = new Aps();
+        $aps->alert($alert->getFields());
+        $aps->badge(5);
+        $aps->buildFields();
+
+        $apnsConfig = new ApnsConfig();
+        $apnsConfig->headers($apnsHeaders->getFields());
+        $apnsConfig->hms_options($apnsHmsOptions->getFields());
+
+        $apn_payload["aps"]   = $aps->getFields();
+        $apn_payload["acme1"] = "bar";
+        $apn_payload["acme2"] = array(
+            "bang",
+            "whiz"
+        );
+        $apnsConfig->payload($apn_payload);
+
+        $apnsConfig->buildFields();
+
+        return $apnsConfig;
+    }
+
+    private function createWebPush()
+    {
+        $webPushConfig = new WebPushConfig();
+        $webPushConfig->data("test webpush data");
+
+        $webPushHeaders = new WebPushHeaders();
+        $webPushHeaders->topic("12313ceshi");
+        $webPushHeaders->ttl("990");
+        $webPushHeaders->urgency(Constants::WEBPUSH_URGENCY_VERY_LOW);
+        $webPushHeaders->buildFields();
+        $webPushConfig->headers($webPushHeaders->getFields());
+
+        $webPushHmsOptions = new WebPushHmsOptions();
+        $webPushHmsOptions->link("https://www.huawei.com/");
+        $webPushHmsOptions->buildFields();
+        $webPushConfig->hmsOptions($webPushHmsOptions->getFields());
+
+        $webPUshNotionfication = new WebPushNotification();
+        $webPUshNotionfication->title("notication string");
+        $webPUshNotionfication->body("web push body");
+        $webPUshNotionfication->icon("https://developer-portalres-drcn.dbankcdn.com/system/modules/org.opencms.portal.template.core/resources/images/icon_Promotion.png");
+        $webPUshNotionfication->image("https://developer-portalres-drcn.dbankcdn.com/system/modules/org.opencms.portal.template.core/resources/images/icon_Promotion.png");
+        $webPUshNotionfication->lang("string");
+        $webPUshNotionfication->tag("string");
+        $webPUshNotionfication->badge("string");
+        $webPUshNotionfication->dir("auto");
+        $webPUshNotionfication->vibrate(array(
+            1,
+            2,
+            3
+        ));
+        $webPUshNotionfication->renotify(false);
+        $webPUshNotionfication->require_interaction(false);
+        $webPUshNotionfication->silent(false);
+        $webPUshNotionfication->timestamp(1545201266);
+        $webPushNotificationAction = new WebPushNotificationAction();
+        $webPushNotificationAction->title("string");
+        $webPushNotificationAction->action("123");
+        $webPushNotificationAction->icon("https://developer-portalres-drcn.dbankcdn.com/system/modules/org.opencms.portal.template.core/resources/images/icon_Promotion.png");
+        $webPushNotificationAction->buildFields();
+        $webPUshNotionfication->actions(array(
+            $webPushNotificationAction->getFields()
+        ));
+        $webPUshNotionfication->buildFields();
+        $webPushConfig->notification($webPUshNotionfication->getFields());
+        $webPushConfig->buildFields();
+
+        return $webPushConfig;
+    }
+
+    private function printLogMethodOperate($dataFlow, $functionName = "", $logLevel = "")
+    {
+        $logModule = Constants::HW_PUSH_LOG_PUSH_MSG_MODULE;
+
+        if (empty($logLevel)) {
+            $logLevel = Constants::HW_PUSH_LOG_INFO_LEVEL;
+        }
+
+        if (empty($functionName)) {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . ']' . $dataFlow, $logLevel, $logModule);
+        } else {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . ']' . '[' . $functionName . ']' . $dataFlow, $logLevel, $logModule);
+        }
+    }
+
+    private function createApplication($application_server)
+    {
+        $this->printLogMethodOperate("createApplication push_msg_type:" . $this->push_msg_type, __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        if ($this->push_msg_type == Constants::PUSHMSG_FASTAPP_MSG_TYPE) {
+            $this->printLogMethodOperate("createApplication PUSHMSG_FASTAPP_MSG_TYPE", __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+            $application = new Application($this->fast_appid, $this->fast_appsecret, $this->hw_token_server, $application_server, $this->hw_push_token_query_server);
+            return $application;
+        }
+        $application = new Application($this->appid, $this->appsecret, $this->hw_token_server, $application_server, $this->hw_push_token_query_server);
+        return $application;
+    }
+
+    private function getMessageByMsgType($msg_type)
+    {
+        switch ($msg_type) {
+            case Constants::PUSHMSG_NOTIFICATION_MSG_TYPE:
+                {
+                    return $this->createNotificationMsg();
+                }
+            case Constants::PUSHMSG_PASS_THROUGHT_MSG_TYPE:
+                {
+                    return $this->createPassThroughMsg();
+                }
+
+            case Constants::PUSHMSG_FASTAPP_MSG_TYPE:
+                {
+                    return $this->createFastAppMsg();
+                }
+            case Constants::PUSHMSG_TOPIC_MSG_TYPE:
+                {
+                    return $this->createTopicMsg();
+                }
+            case Constants::PUSHMSG_CONDITION_MSG_TYPE:
+                {
+                    return $this->createConditionMsg();
+                }
+
+            case Constants::APN_MSG_TYPE:
+                {
+                    return $this->createApnsMsg();
+                }
+            case Constants::WEB_PUSH_MSG_TYPE:
+                {
+                    return $this->createWebPushMsg();
+                }
+        }
+    }
+
+    private function createFastAppConfigNotificationData()
+    {
+        $instanceAppConfig = new InstanceAppConfig();
+        $instanceAppConfig->pushtype(0);
+
+        $instanceAppPushbody = new InstanceAppPushBody();
+        $instanceAppPushbody->title("test fast app");
+        $instanceAppPushbody->description("test fast app description");
+        $instanceAppPushbody->page("/");
+        $instanceAppPushbody->params(array(
+            "key1" => "test1",
+            "key2" => "test2"
+        ));
+
+        $instanceAppRingtone = new InstanceAppRingTone();
+        $instanceAppRingtone->breathLight(true);
+        $instanceAppRingtone->vibration(true);
+        $instanceAppRingtone->buildFields();
+
+        $instanceAppPushbody->ringtone($instanceAppRingtone->getFields());
+        $instanceAppPushbody->buildFields();
+
+        $instanceAppConfig->pushbody($instanceAppPushbody->getFields());
+        $instanceAppConfig->buildFields();
+
+        return $instanceAppConfig;
+
+    }
+
+    private function createFastAppConfigPassThroughData()
+    {
+        $instanceAppConfig = new InstanceAppConfig();
+        $instanceAppConfig->pushtype(1);
+
+        $instanceAppPushbody = new InstanceAppPushbody();
+        $instanceAppPushbody->messageId("111110001");
+        $instanceAppPushbody->data("hw default passthroug test");
+        $instanceAppPushbody->buildFields();
+
+        $instanceAppConfig->pushbody($instanceAppPushbody->getFields());
+        $instanceAppConfig->buildFields();
+
+        return $instanceAppConfig;
+
+    }
+
+    private function createFastAppMsg()
+    {
+        $this->printLogMethodOperate("push msg notification start", __FUNCTION__ . ':' . __LINE__);
+        $message = new PushMessage();
+
+        $message->data($this->createFastAppConfigNotificationData()->getFields());
+
+        $message->android($this->createAndroidConfig()
+            ->getFields());
+
+        $message->token(array(
+            $this->fast_push_token
+        ));
+
+        $message->buildFields();
+        $this->printLogMethodOperate("push msg notification end", __FUNCTION__ . ':' . __LINE__);
+        return $message;
+    }
+
+    private function createNotificationMsg()
+    {
+        $this->printLogMethodOperate("push msg notification start", __FUNCTION__ . ':' . __LINE__);
+        $message = new PushMessage();
+
+        $message->android($this->createAndroidConfig()
+            ->getFields());
+        $message->notification($this->createNotification()
+            ->getFields());
+
+        $message->token(array(
+            $this->hw_push_token_key
+        ));
+
+        $message->buildFields();
+        $this->printLogMethodOperate("push msg notification end", __FUNCTION__ . ':' . __LINE__);
+        return $message;
+    }
+
+    private function createTopicMsg()
+    {
+        $this->printLogMethodOperate("push msg createTopicMsg start", __FUNCTION__ . ':' . __LINE__);
+        $message = new PushMessage();
+
+        $message->android($this->createAndroidConfig()
+            ->getFields());
+        // $message->notification($this->createNotification()->buildFields());
+
+        $message->topic($this->default_topic);
+
+        $message->buildFields();
+        $this->printLogMethodOperate("push msg createTopicMsg end", __FUNCTION__ . ':' . __LINE__);
+        return $message;
+    }
+
+    private function createConditionMsg()
+    {
+        $this->printLogMethodOperate("push msg createTopicMsg start", __FUNCTION__ . ':' . __LINE__);
+        $message = new PushMessage();
+
+        $message->android($this->createAndroidConfig()
+            ->getFields());
+        // $message->notification($this->createNotification()->buildFields());
+        $message->condition("'defaultTopic' in topics");
+        // $message->condition("'weather' in topics || ('TopicB' in topics && 'TopicC' in topics)");
+
+        $message->buildFields();
+        $this->printLogMethodOperate("push msg createTopicMsg end", __FUNCTION__ . ':' . __LINE__);
+        return $message;
+    }
+
+    private function createPassThroughMsg()
+    {
+        $this->printLogMethodOperate("push msg passthrough start", __FUNCTION__ . ':' . __LINE__);
+        $message = new PushMessage();
+
+        $message->data("1111");
+        $message->token(array(
+            $this->hw_push_token_key
+        ));
+
+        $message->buildFields();
+        $this->printLogMethodOperate("push msg passthrough end", __FUNCTION__ . ':' . __LINE__);
+        return $message;
+    }
+
+    private function createApnsMsg()
+    {
+        $this->printLogMethodOperate("push msg apns start", __FUNCTION__ . ':' . __LINE__);
+        $message    = new PushMessage();
+        $apnsConfig = $this->createApnsConfig();
+        $message->apns($apnsConfig->getFields());
+
+        $message->token(array(
+            $this->apn_push_token_key
+        ));
+        $message->buildFields();
+
+        $this->printLogMethodOperate("push msg apns end", __FUNCTION__ . ':' . __LINE__);
+        return $message;
+    }
+
+    private function createWebPushMsg()
+    {
+        $this->printLogMethodOperate("push msg webpush start", __FUNCTION__ . ':' . __LINE__);
+        $message = new PushMessage();
+
+        $message->webpush($this->createWebPush()
+            ->getFields());
+        $message->token(array(
+            $this->webpush_push_token_key
+        ));
+
+        PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . ']' . '[web-token:' . json_encode($message->get_token()) . ']', Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+        $message->buildFields();
+
+        $this->printLogMethodOperate("push msg webpush end", __FUNCTION__ . ':' . __LINE__);
+        return $message;
+    }
+}
+
+class TestTopicCommonSample
+{
+
+    private $topic = "defaultTopic";
+
+    private $topic_msg_create_type = 1;
+
+    private $appsecret;
+
+    private $appid;
+
+    private $hw_token_server;
+
+    private $hw_topic_subscriber_server;
+
+    private $hw_topic_unsubscriber_server;
+
+    private $hw_topic_query_subscriber_server;
+
+    private $tokenServerKey;
+
+    private $log_suffix_show = ".............................";
+
+    public function __construct($topic_value = "", $default_msg_create_type = "")
+    {
+        if (!empty($topic_value)) {
+            $this->topic = $topic_value;
+        }
+        if (!empty($default_msg_create_type)) {
+            $this->topic_msg_create_type = $default_msg_create_type;
+        }
+
+        $pushConfig = PushConfig::getSingleInstance();
+
+        $this->appsecret       = $pushConfig->HW_APPSECRET;
+        $this->appid           = $pushConfig->HW_APPID;
+        $this->hw_token_server = $pushConfig->HW_TOKEN_SERVER;
+        $this->tokenServerKey  = $pushConfig->HW_PUSH_TOKEN_ARR;
+
+        $this->hw_topic_subscriber_server       = $pushConfig->HW_TOPIC_SUBSCRIBE_SERVER;
+        $this->hw_topic_unsubscriber_server     = $pushConfig->HW_TOPIC_UNSUBSCRIBE_SERVER;
+        $this->hw_topic_query_subscriber_server = $pushConfig->HW_TOPIC_QUERY_SUBSCRIBER_SERVER;
+    }
+
+    private function createTopicData()
+    {
+        $topicMsg = new TopicMsg();
+        $topicMsg->topic($this->topic);
+        $topicMsg->tokenArray(array(
+            $this->tokenServerKey
+        ));
+        $topicMsg->buildFields();
+
+        return $topicMsg;
+    }
+
+    private function createApplication($application_server)
+    {
+        $application = new Application($this->appid, $this->appsecret, $this->hw_token_server, $application_server);
+        return $application;
+    }
+
+    private function printLogMethodOperate($msg_type, $dataFlow, $functionName = "", $logLevel = "")
+    {
+        $dataFlow  = 'subscribe topic ' . $dataFlow;
+        $logModule = Constants::HW_PUSH_LOG_TOPIC_SUBSCRIBE_MODULE;
+        switch ($msg_type) {
+            case Constants::TOPIC_UNSUBSCRIBE_MSG_TYPE:
+                {
+                    $dataFlow  = 'unsubscribe topic' . $dataFlow;
+                    $logModule = Constants::HW_PUSH_LOG_TOPIC_UNSUBSCRIBE_MODULE;
+                }
+                break;
+        }
+        if (empty($logLevel)) {
+            $logLevel = Constants::HW_PUSH_LOG_INFO_LEVEL;
+        }
+
+        if (empty($functionName)) {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . ']' . $dataFlow . $this->log_suffix_show, $logLevel, $logModule);
+        } else {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . ']' . '[' . $functionName . ']' . $dataFlow . $this->log_suffix_show, $logLevel, $logModule);
+        }
+    }
+
+    private function printLogMsgOperate($msg_type, $dataFlow, $functionName = "", $logLevel = "")
+    {
+        $logModule = Constants::HW_PUSH_LOG_TOPIC_SUBSCRIBE_MODULE;
+        switch ($msg_type) {
+            case Constants::TOPIC_UNSUBSCRIBE_MSG_TYPE:
+                {
+                    $logModule = Constants::HW_PUSH_LOG_TOPIC_UNSUBSCRIBE_MODULE;
+                }
+                break;
+        }
+        if (empty($logLevel)) {
+            $logLevel = Constants::HW_PUSH_LOG_INFO_LEVEL;
+        }
+
+        if (empty($functionName)) {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . ']' . $dataFlow . $this->log_suffix_show, $logLevel, $logModule);
+        } else {
+            PushLogConfig::getSingleInstance()->LogMessage('[' . __CLASS__ . ']' . '[' . $functionName . ']' . $dataFlow . $this->log_suffix_show, $logLevel, $logModule);
+        }
+    }
+
+    /**
+     * topic subscribe/unsubscribe
+     */
+    function sendTopicMessage($msg_type)
+    {
+        $this->printLogMethodOperate($msg_type, "start", __FUNCTION__ . ':' . __LINE__);
+        $topicMsg = $this->createTopicData();
+        if ($this->topic_msg_create_type == 1) {
+            $this->printLogMsgOperate($msg_type, "topicMsg:" . json_encode($topicMsg->getFields()), __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+        }
+
+        $application_server = $this->hw_topic_subscriber_server;
+        if ($msg_type == Constants::TOPIC_UNSUBSCRIBE_MSG_TYPE) {
+            $application_server = $this->hw_topic_unsubscriber_server;
+        } else if ($msg_type == Constants::TOPIC_SUBSCRIBE_QUERY_MSG_TYPE) {
+            $application_server = $this->hw_topic_query_subscriber_server;
+            $topicMsg           = array(
+                'token' => $this->tokenServerKey
+            );
+        }
+        $application = $this->createApplication($application_server);
+        $this->printLogMsgOperate($msg_type, "application server:" . json_encode($application->getApplicationFields()), __FUNCTION__ . ':' . __LINE__, Constants::HW_PUSH_LOG_DEBUG_LEVEL);
+
+        $topicResult = "";
+        if ($msg_type == Constants::TOPIC_SUBSCRIBE_QUERY_MSG_TYPE) {
+            $topicResult = $application->common_send_msg($topicMsg);
+        } else {
+            $topicResult = $application->common_send_msg($topicMsg->getFields());
+        }
+
+        $this->printLogMethodOperate($msg_type, "end", __FUNCTION__ . ':' . __LINE__);
+        return $topicResult;
+    }
+}
+
+class TopicMsg
+{
+
+    // madatory
+    private $topic;
+
+    // madatory
+    private $tokenArray;
+
+    private $fields;
+
+    public function __construct()
+    {
+        $this->fields = array();
+    }
+
+    public function topic($value)
+    {
+        $this->topic = $value;
+    }
+
+    public function tokenArray($value)
+    {
+        $this->tokenArray = $value;
+    }
+
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    public function buildFields()
+    {
+        $keys = array(
+            'topic',
+            'tokenArray'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+            }
+        }
+    }
+}

+ 56 - 0
app/Libs/Push/HuaWei/config.ini

@@ -0,0 +1,56 @@
+  ___ ___  __      __  __________ ____ ___  _________ ___ ___   __________  ___ _____________ 
+ /   |   \/  \    /  \ \______   \    |   \/   _____//   |   \  \______   \/   |   \______   \
+/    ~    \   \/\/   /  |     ___/    |   /\_____  \/    ~    \  |     ___/    ~    \     ___/
+\    Y    /\        /   |    |   |    |  / /        \    Y    /  |    |   \    Y    /    |    
+ \___|_  /  \__/\  /    |____|   |______/ /_______  /\___|_  /   |____|    \___|_  /|____|    
+       \/        \/                               \/       \/                    \/          
+
+********************************************************************************************
+**********      instruction: 1)two part:private personal data and public url      **********
+**********                   2)don't change split character such as =/"           **********
+**********                   3)don't new line for  HW_PUSH_TOKEN_ARR              **********
+**********                   4)Space will be removed, cannot be a variable        **********
+********************************************************************************************
+
+********************************************************************************************
+**********      here is private variable personal data,you must change it!        **********
+********************************************************************************************
+HW_APPID="xxxxx"
+HW_APPSECRET="xxxxx"
+
+### Business Push Token,For common push msg ####
+HW_PUSH_TOKEN_ARR="xxxxx"
+
+### Business Push Token,For IOS apn ####
+APN_PUSH_TOKEN_ARR="xxxxx"
+
+### Business Push Token,For webpush ####
+WEBPUSH_PUSH_TOKEN_ARR="xxxxx"
+
+### FAST APP INFO : different from ordinal app####
+HW_FAST_APPID="102612543"
+HW_FAST_APPSECRET="07c896089f432163421923bdcab83a8da9d386274be43e61d510c27f56c23269"
+HW_FAST_PUSH_TOKEN="AFeXAq0cGG3n-b8Oiksz-g7UGPn2ojinG_Fq-PQJ8tpDf4hQhbOuwQeEOO5sDdfrvxZntrET5kqsu5_SJz_Ai53qtVRZ1-38HkZGPU3d-of_HKU-8g5DnqpNJ-44WV-mpw"
+
+
+********************************************************************************************
+**********      below is public url entry,please don't modify if not necessary    **********
+********************************************************************************************
+### Token Server for push msg and top subscribe/unsubscribe ####
+HW_TOKEN_SERVER="https://oauth-login.cloud.huawei.com/oauth2/v2/token"
+
+
+### Push Server address ####
+HW_PUSH_SERVER="https://push-api.cloud.huawei.com/v1/{appid}/messages:send"
+
+### Push Server address ####
+HW_PUSH_TOKEN_QUERY_SERVER="https://push-api.cloud.huawei.com/v1/{appid}/token:query"
+
+
+### Topic Server address ####
+HW_TOPIC_SUBSCRIBE_SERVER="https://push-api.cloud.huawei.com/v1/{appid}/topic:subscribe"
+HW_TOPIC_UNSUBSCRIBE_SERVER="https://push-api.cloud.huawei.com/v1/{appid}/topic:unsubscribe"
+HW_TOPIC_QUERY_SUBSCRIBER_SERVER="https://push-api.cloud.huawei.com/v1/{appid}/topic:list"
+
+### LogLevel:ERROR(1),WARN(2),INFO(3),DEBUG(4) ####
+HW_DEFAULT_LOG_LEVEL=3

+ 73 - 0
app/Libs/Push/OPPOPush/Constants.php

@@ -0,0 +1,73 @@
+<?php
+
+
+namespace App\Libs\Push\OPPOPush;
+
+
+class Constants
+{
+    // =================== 推送管理 ==================
+
+    // 国内生产环境
+    const PUSH_SERVER = 'https://api.push.oppomobile.com';
+
+    // 开发者身份鉴权
+    const AUTH_URL = '/server/v1/auth';
+
+    // 保存通知栏消息内容体
+    const SAVE_MESSAGE_CONTENT_URL = '/server/v1/message/notification/save_message_content';
+
+    // 广播推送-通知栏消息
+    const BROADCAST = '/server/v1/message/notification/broadcast';
+
+    // 单推-通知栏消息推送
+    const NOTIFICATION_UNICAST_URL = '/server/v1/message/notification/unicast';
+
+    // 批量单推-通知栏消息推送
+    const NOTIFICATION_UNICAST_BATCH_URL = '/server/v1/message/notification/unicast_batch';
+
+    // =================== 别名管理 ==================
+
+    // 国内生产环境
+    const ALIAS_SERVER = 'https://api-device.push.heytapmobi.com';
+
+    // 建立registration_id与alias的映射关系
+    const SET_ALIAS_URL = '/server/v1/device/set_alias';
+
+    // 删除别名
+    const DELETE_ALIAS_URL = '/server/v1/device/delete_alias';
+
+    // 查询别名
+    const GET_ALIAS_URL = '/server/v1/device/get_alias';
+
+    // =================== 标签管理 ==================
+
+    // 国内生产环境
+    const TAG_SERVER = 'https://api-device.push.heytapmobi.com';
+
+    // 添加标签
+    const ADD_TAG_URL = '/server/v1/device/add_tags';
+
+    // 添加标签组
+    const ADD_TAG_GROUP_URL = '/server/v1/device/add_tag_group';
+
+    // 标签订阅接口
+    const SUBSCRIBE_TAGS_URL = '/server/v1/device/subscribe_tags';
+
+    // 取消标签订阅接口
+    const UNSUBSCRIBE_TAGS_URL = '/server/v1/device/unsubscribe_tags';
+
+    // 查询所有标签
+    const GET_ALL_TAGS_URL = '/server/v1/device/get_all_tags';
+
+    // =================== FeedBack管理 ==================
+
+    // 国内生产环境
+    const FEEDBACK_SERVER = 'https://feedback.push.oppomobile.com';
+
+    // 获取失效的registration_id列表
+    const FETCH_INVALID_REGIDLIST_URL = '/server/v1/feedback/fetch_invalid_regidList';
+
+    // 查询APP当天发送量的状态
+    const FETCG_PUSH_PERMIT = '/server/v1/feedback/fetch_push_permit';
+}

+ 308 - 0
app/Libs/Push/OPPOPush/OPPOPushCommon.php

@@ -0,0 +1,308 @@
+<?php
+
+
+namespace App\Libs\Push\OPPOPush;
+
+use Exception;
+use GuzzleHttp\Client;
+use GuzzleHttp\Exception\GuzzleException;
+
+class OPPOPushCommon
+{
+    // app key
+    private $_appKey;
+
+    // master secret
+    private $_masterSecret;
+
+    // token
+    private $_authToken;
+
+    private $_reg_arr;
+
+    /**
+     * OPPOPushCommon constructor.
+     * @param $appKey
+     * @param $masterSecret
+     * @throws GuzzleException
+     */
+    public function __construct($appKey, $masterSecret)
+    {
+        $this->_appKey       = $appKey;
+        $this->_masterSecret = $masterSecret;
+        $this->_authToken    = $this->getAuthToken();
+    }
+
+    public function setRegArr($regArr)
+    {
+        $this->_reg_arr = $regArr;
+    }
+
+    /**
+     * 全部推送
+     * @param $messageId
+     * @return mixed
+     * @throws GuzzleException
+     */
+    public function broadCastAll($messageId)
+    {
+        return $this->broadCast('all', $messageId);
+    }
+
+    /**
+     * 批量推送
+     * @param $messageId
+     * @return mixed
+     * @throws GuzzleException
+     */
+    public function broadCastRegIds($messageId)
+    {
+        return $this->broadCast(2, $messageId);
+    }
+
+    /**
+     * 保存通知栏消息内容体
+     * @param $title
+     * @param $content
+     * @param $url
+     * @return mixed|string
+     * @throws GuzzleException
+     */
+    public function getMessageId($title, $content, $url)
+    {
+        // 组装数据
+        $pushMessage = new PushMessage();
+        $pushMessage->style(1);
+        $pushMessage->title($title);
+        $pushMessage->content($content);
+        $pushMessage->click_action_type(1);
+        $pushMessage->click_action_activity($url);
+        $pushMessage->channel_id('OPPO PUSH');
+        $pushMessage->auth_token($this->_authToken);
+        $fields = $pushMessage->getData();
+
+        // 请求数据
+        $data = [
+            'form_params' => $fields
+        ];
+
+        // 请求
+        $client    = new Client(['base_uri' => config('push.server.oppo.saveMessage'), 'timeout' => 10.0,]);
+        $response  = $client->request('POST', '', $data);
+        $body      = $response->getBody();
+        $result    = json_decode($body, true);
+        $messageId = getProp($result['data'], 'message_id');
+        if (!$messageId) {
+            throw new Exception('保存通知栏消息内容体失败');
+        }
+
+        myLog('push')->info(__FUNCTION__, compact('data', 'messageId'));
+        return $messageId;
+    }
+
+    /**
+     * 添加标签
+     * @param $name
+     * @param $desc
+     * @return mixed
+     * @throws GuzzleException
+     */
+    public function addTags($name, $desc)
+    {
+        $data = [
+            'headers' => [
+                'auth_token' => $this->_authToken
+            ],
+            'json'    => [
+                'name' => $name,
+                'desc' => $desc,
+            ]
+        ];
+
+        // 请求
+        $client   = new Client(['base_uri' => config('push.server.oppo.addTags'), 'timeout' => 10.0,]);
+        $response = $client->request('POST', '', $data);
+        $body     = $response->getBody();
+        $result   = json_decode($body, true);
+
+        myLog('push')->info(__FUNCTION__, compact('data', 'result'));
+        return $result;
+    }
+
+    /**
+     * 标签订阅接口
+     * @param $regId
+     * @param $tags
+     * @return mixed
+     * @throws GuzzleException
+     */
+    public function subscribeTags($regId, $tags)
+    {
+        $data = [
+            'headers' => [
+                'auth_token' => $this->_authToken
+            ],
+            'json'    => [
+                'registration_id' => $regId,
+                'tags'            => $tags,
+            ]
+        ];
+
+        // 请求
+        $client   = new Client(['base_uri' => config('push.server.oppo.subTags'), 'timeout' => 10.0,]);
+        $response = $client->request('POST', '', $data);
+        $body     = $response->getBody();
+        $result   = json_decode($body, true);
+
+        myLog('push')->info(__FUNCTION__, compact('data', 'result'));
+        return $result;
+    }
+
+    /**
+     * 取消标签订阅接口
+     * @param $regId
+     * @param $tags
+     * @return mixed
+     * @throws GuzzleException
+     */
+    public function unSubscribeTags($regId, $tags)
+    {
+        $data = [
+            'headers' => [
+                'auth_token' => $this->_authToken
+            ],
+            'json'    => [
+                'registration_id' => $regId,
+                'tags'            => $tags,
+            ]
+        ];
+
+        // 请求
+        $client   = new Client(['base_uri' => config('push.server.oppo.unSubTags'), 'timeout' => 10.0,]);
+        $response = $client->request('POST', '', $data);
+        $body     = $response->getBody();
+        $result   = json_decode($body, true);
+
+        myLog('push')->info(__FUNCTION__, compact('data', 'result'));
+        return $result;
+    }
+
+    /**
+     * 取消标签订阅接口
+     * @param $regId
+     * @return mixed
+     * @throws GuzzleException
+     */
+    public function getAllTags($regId)
+    {
+        $data = [
+            'headers' => [
+                'auth_token' => $this->_authToken
+            ],
+            'json'    => [
+                'registration_id' => $regId,
+            ]
+        ];
+
+        // 请求
+        $client   = new Client(['base_uri' => config('push.server.oppo.getAllTags'), 'timeout' => 10.0,]);
+        $response = $client->request('POST', '', $data);
+        $body     = $response->getBody();
+        $result   = json_decode($body, true);
+
+        myLog('push')->info(__FUNCTION__, compact('data', 'result'));
+        return $result;
+    }
+
+    /**
+     * 查询APP当天发送量的状态
+     * @return mixed
+     * @throws GuzzleException
+     */
+    public function fetchPushPermit()
+    {
+        $data = [
+            'headers' => [
+                'auth_token' => $this->_authToken
+            ]
+        ];
+
+        // 请求
+        $client   = new Client(['base_uri' => config('push.server.oppo.fetchPushPermit'), 'timeout' => 10.0,]);
+        $response = $client->request('GET', '', $data);
+        $body     = $response->getBody();
+        $result   = json_decode($body, true);
+
+        myLog('push')->info(__FUNCTION__, compact('data', 'result'));
+        return $result;
+    }
+
+    /**
+     * 获得auth_token权限令牌
+     * @return mixed|string
+     * @throws GuzzleException
+     */
+    private function getAuthToken()
+    {
+        // 生成sign
+        $timestamp = getMillisecond();
+        $sign      = hash('sha256', $this->_appKey . $timestamp . $this->_masterSecret);
+
+        // 数据组装
+        $data = [
+            'form_params' => [
+                'app_key'   => $this->_appKey,
+                'sign'      => $sign,
+                'timestamp' => $timestamp
+            ]
+        ];
+
+        $client    = new Client(['base_uri' => config('push.server.oppo.auth'), 'timeout' => 10.0,]);
+        $response  = $client->request('POST', '', $data);
+        $body      = $response->getBody();
+        $result    = json_decode($body, true);
+        $authToken = getProp($result['data'], 'auth_token');
+        if (!$authToken) {
+            throw new Exception('获取auth token失败');
+        }
+
+        myLog('push')->info(__FUNCTION__, compact('authToken'));
+        return $authToken;
+    }
+
+    /**
+     * 广播推送-通知栏消息
+     * @param       $targetType
+     * @param       $messageId
+     * @return mixed
+     * @throws GuzzleException
+     */
+    private function broadCast($targetType, $messageId)
+    {
+        $param = [
+            'auth_token'  => $this->_authToken,
+            'message_id'  => $messageId,
+            'target_type' => $targetType,
+        ];
+
+        // reg_id 批量
+        if ((int)$targetType === 2 && $this->_reg_arr) {
+            $param['target_value'] = implode(',', $this->_reg_arr);
+        }
+
+        // 请求数据
+        $data = [
+            'form_params' => $param
+        ];
+
+        // 请求
+        $client   = new Client(['base_uri' => config('push.server.oppo.broadcast'), 'timeout' => 10.0,]);
+        $response = $client->request('POST', '', $data);
+        $body     = $response->getBody();
+        $result   = json_decode($body, true);
+
+        myLog('push')->info(__FUNCTION__, compact('targetType', 'messageId', 'result'));
+        return $result;
+    }
+
+}

+ 213 - 0
app/Libs/Push/OPPOPush/PushMessage.php

@@ -0,0 +1,213 @@
+<?php
+
+
+namespace App\Libs\Push\OPPOPush;
+
+
+class PushMessage
+{
+    private $app_message_id;
+
+    private $style;
+
+    private $big_picture_id;
+
+    private $small_picture_id;
+
+    private $title;
+
+    private $sub_title;
+
+    private $content;
+
+    private $click_action_type;
+
+    private $click_action_activity;
+
+    private $click_action_url;
+
+    private $action_parameters;
+
+    private $show_time_type;
+
+    private $show_start_time;
+
+    private $show_end_time;
+
+    private $off_line;
+
+    private $off_line_ttl;
+
+    private $push_time_type;
+
+    private $push_start_time;
+
+    private $time_zone;
+
+    private $fix_speed;
+
+    private $fix_speed_rate;
+
+    private $network_type;
+
+    private $call_back_url;
+
+    private $call_back_parameter;
+
+    private $channel_id;
+
+    private $auth_token;
+
+    public function app_message_id($value)
+    {
+        return $this->app_message_id = $value;
+    }
+
+    public function style($value)
+    {
+        return $this->style = $value;
+    }
+
+    public function big_picture_id($value)
+    {
+        return $this->big_picture_id = $value;
+    }
+
+    public function small_picture_id($value)
+    {
+        return $this->small_picture_id = $value;
+    }
+
+    public function title($value)
+    {
+        return $this->title = $value;
+    }
+
+    public function sub_title($value)
+    {
+        return $this->sub_title = $value;
+    }
+
+    public function content($value)
+    {
+        return $this->content = $value;
+    }
+
+    public function click_action_type($value)
+    {
+        return $this->click_action_type = $value;
+    }
+
+    public function click_action_activity($value)
+    {
+        return $this->click_action_activity = $value;
+    }
+
+    public function click_action_url($value)
+    {
+        return $this->click_action_url = $value;
+    }
+
+    public function action_parameters($value)
+    {
+        return $this->action_parameters = $value;
+    }
+
+    public function show_time_type($value)
+    {
+        return $this->show_time_type = $value;
+    }
+
+    public function show_start_time($value)
+    {
+        return $this->show_start_time = $value;
+    }
+
+    public function show_end_time($value)
+    {
+        return $this->show_end_time = $value;
+    }
+
+    public function off_line($value)
+    {
+        return $this->off_line = $value;
+    }
+
+    public function off_line_ttl($value)
+    {
+        return $this->off_line_ttl = $value;
+    }
+
+    public function push_time_type($value)
+    {
+        return $this->push_time_type = $value;
+    }
+
+    public function push_start_time($value)
+    {
+        return $this->push_start_time = $value;
+    }
+
+    public function time_zone($value)
+    {
+        return $this->time_zone = $value;
+    }
+
+    public function fix_speed($value)
+    {
+        return $this->fix_speed = $value;
+    }
+
+    public function fix_speed_rate($value)
+    {
+        return $this->fix_speed_rate = $value;
+    }
+
+    public function network_type($value)
+    {
+        return $this->network_type = $value;
+    }
+
+    public function call_back_url($value)
+    {
+        return $this->call_back_url = $value;
+    }
+
+    public function call_back_parameter($value)
+    {
+        return $this->call_back_parameter;
+    }
+
+    public function channel_id($value)
+    {
+        return $this->channel_id = $value;
+    }
+
+    public function auth_token($value)
+    {
+        return $this->auth_token = $value;
+    }
+
+    public function getData()
+    {
+        $keys = [
+            'style',
+            'type',
+            'title',
+            'content',
+            'click_action_type',
+            'click_action_activity',
+            'channel_id',
+            'auth_token'
+        ];
+
+        $result = [];
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $result[$key] = $this->$key;
+            }
+        }
+
+        return $result;
+    }
+}

+ 113 - 0
app/Libs/Push/XMPush/Builder.php

@@ -0,0 +1,113 @@
+<?php
+/**
+ * (android)消息体.
+ * @author wangkuiwei
+ * @name Builder
+ * @desc 构建发送给Android设备的Message对象。
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class Builder extends Message {
+    const soundUri = 'sound_uri';
+    const notifyForeground = 'notify_foreground';
+    const notifyEffect = 'notify_effect';
+    const intentUri = 'intent_uri';
+    const webUri = 'web_uri';
+    const flowControl = 'flow_control';
+    const callback = 'callback';
+    const instantNotify = 'instant_notify';
+
+    public function __construct() {
+        $this->notify_id = 0;
+        $this->notify_type = -1;
+        $this->payload = '';
+        $this->restricted_package_name = Constants::$packageName;
+        parent::__construct();
+    }
+
+    public function payload($payload) {
+        $this->payload = $payload;
+    }
+
+    public function title($title) {
+        $this->title = $title;
+    }
+
+    public function description($description) {
+        $this->description = $description;
+    }
+
+    public function passThrough($passThrough) {
+        $this->pass_through = $passThrough;
+    }
+
+    public function notifyType($type) {
+        $this->notify_type = $type;
+    }
+
+    public function restrictedPackageNames($packageNameList) {
+        $jointPackageNames = '';
+        foreach ($packageNameList as $packageName) {
+            if (isset($packageName)) {
+                $jointPackageNames .= $packageName . Constants::$comma;
+            }
+        }
+        $this->restricted_package_name = $jointPackageNames;
+    }
+
+    public function timeToLive($ttl) {
+        $this->time_to_live = $ttl;
+    }
+
+    public function timeToSend($timeToSend) {
+        $this->time_to_send = $timeToSend;
+    }
+
+    public function instantNotify($isInstantNotify) {
+        if ($isInstantNotify) {
+            $this->extra(self::instantNotify, "1");
+        } else {
+            unset($this->extra[self::instantNotify]);
+        }
+    }
+
+    public function notifyId($notifyId) {
+        $this->notify_id = $notifyId;
+    }
+
+    public function hybridPath($value) {
+        $this->extra[self::HYBRID_PATH] = $value;
+    }
+
+    public function extra($key, $value) {
+        $this->extra[$key] = $value;
+    }
+
+    public function build() {
+        $keys = array(
+            'payload', 'title', 'description', 'pass_through', 'notify_type',
+            'restricted_package_name', 'time_to_live', 'time_to_send', 'notify_id'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+                $this->json_infos[$key] = $this->$key;
+            }
+        }
+
+        //单独处理extra
+        $JsonExtra = array();
+        if (count($this->extra) > 0) {
+            foreach ($this->extra as $extraKey => $extraValue) {
+                $this->fields[Message::EXTRA_PREFIX . $extraKey] = $extraValue;
+                $JsonExtra[$extraKey] = $extraValue;
+            }
+        }
+        $this->json_infos['extra'] = $JsonExtra;
+
+    }
+}
+
+
+?>

+ 148 - 0
app/Libs/Push/XMPush/Constants.php

@@ -0,0 +1,148 @@
+<?php
+/**
+ * 常量定义.
+ * @author wangkuiwei
+ * @name Constants
+ * @desc 常量定义
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+
+class Constants
+{
+    public static $comma = ',';
+    public static $multi_topic_split = ';$;';
+    public static $packageName = '';
+    public static $bundle_id = '';
+    public static $secret = '';
+
+    /**
+     * 是否在网络访问问题时,自动切换访问的域名
+     */
+    public static $autoSwitchHost = true;
+
+    /**
+     * 网络访问的超时时间,当超过该时间时,则认为可用性较低,会优先选择其他域名
+     */
+    public static $accessTimeOut = 5000;
+
+    public static $HTTP_PROTOCOL = "https";
+
+    public static $USE_HTTPS = true;
+    /**
+     * 是否测试环境
+     */
+    public static $sandbox = false;
+    /**
+     * 如果设置了IP、域名,则使用手动设置的值,只用于内部测试,不对外开放
+     */
+    /**
+     * @return string
+     */
+    public static $host = null;
+
+    const reg_url = '/v3/message/regid';
+    const alias_url = '/v3/message/alias';
+    const user_account_url = '/v2/message/user_account';
+    const topic_url = '/v3/message/topic';
+    const multi_topic_url = '/v3/message/multi_topic';
+    const all_url = '/v3/message/all';
+    const multi_messages_regids_url = '/v2/multi_messages/regids';
+    const multi_messages_aliases_url = '/v2/multi_messages/aliases';
+    const multi_messages_user_accounts_url = '/v2/multi_messages/user_accounts';
+    const stats_url = '/v1/stats/message/counters';
+    const message_trace_url = '/v1/trace/message/status';
+    const messages_trace_url = '/v1/trace/messages/status';
+    const validation_regids_url = '/v1/validation/regids';
+    const subscribe_url = '/v2/topic/subscribe';
+    const unsubscribe_url = '/v2/topic/unsubscribe';
+    const subscribe_alias_url = '/v2/topic/subscribe/alias';
+    const unsubscribe_alias_url = '/v2/topic/unsubscribe/alias';
+    const fetch_invalid_regids_url = 'https://feedback.xmpush.xiaomi.com/v1/feedback/fetch_invalid_regids';
+    const delete_schedule_job = '/v2/schedule_job/delete';
+    const check_schedule_job_exist = '/v2/schedule_job/exist';
+    const get_all_aliases = '/v1/alias/all';
+    const get_all_topics = '/v1/topic/all';
+
+    const UNION = 'UNION';
+    const INTERSECTION = 'INTERSECTION';
+    const EXCEPT = 'EXCEPT';
+
+    /**
+     * 相关域名定义
+     */
+    const HOST_EMQ = "emq.xmpush.xiaomi.com";
+    const HOST_SANDBOX = "sandbox.xmpush.xiaomi.com";
+
+    /**
+     * 国内机房相关域名
+     */
+    const HOST_PRODUCTION = "api.xmpush.xiaomi.com";
+    const HOST_PRODUCTION_FEEDBACK = "feedback.xmpush.xiaomi.com";
+
+    /**
+     * 海外机房相关域名
+     */
+    const HOST_GLOBAL_PRODUCTION = "api.xmpush.global.xiaomi.com";
+    const HOST_GLOBAL_PRODUCTION_FEEDBACK = "feedback.xmpush.global.xiaomi.com";
+
+    /**
+     *  VIP域名
+     */
+    const HOST_VIP = "vip.api.xmpush.xiaomi.com";
+
+    const X_PUSH_HOST_LIST = "X-PUSH-HOST-LIST";
+    const HOST_RESPONSE_EXPECT_TIME = 5; // 响应时间低于这个值,host降权
+    const X_PUSH_SDK_VERSION = "X-PUSH-SDK-VERSION";
+    const SDK_VERSION = "PHP_SDK_V2.2.21";
+
+    const EXTRA_PARAM_NOTIFY_EFFECT = "notify_effect";
+    const NOTIFY_LAUNCHER_ACTIVITY = "1";
+    const NOTIFY_ACTIVITY = "2";
+    const NOTIFY_WEB = "3";
+    const EXTRA_PARAM_INTENT_URI = "intent_uri";
+    const EXTRA_PARAM_WEB_URI = "web_uri";
+
+    public static function setPackage($package)
+    {
+        self::$packageName = $package;
+    }
+
+    public static function setSecret($secret)
+    {
+        self::$secret = $secret;
+    }
+
+    public static function setBundleId($bundleId)
+    {
+        self::$bundle_id = $bundleId;
+    }
+
+    public static function useOfficial()
+    {
+        self::$sandbox = false;
+        self::$host    = null;
+    }
+
+    public static function useSandbox()
+    {
+        self::$sandbox = true;
+        self::$host    = null;
+    }
+
+    /**
+     * 仅限内部使用,用户测试专门的IP
+     */
+    public static function useInternalHost($hostOrIP)
+    {
+        self::$host = $hostOrIP;
+    }
+
+    public static function useHttp()
+    {
+        self::$HTTP_PROTOCOL = "http";
+    }
+}
+
+?>

+ 30 - 0
app/Libs/Push/XMPush/DevTools.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * 设备查询工具集.
+ * @author wangkuiwei
+ * @name DevTools
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class DevTools extends HttpBase {
+
+    public function __construct() {
+        parent::__construct();
+    }
+
+    public function getAliasesOf($packageName, $regId, $retries = 1) {
+        $fields = array('registration_id' => $regId, 'restricted_package_name' => $packageName);
+        $result = $this->getResult(PushRequestPath::V1_GET_ALL_ALIAS(), $fields, $retries);
+        return $result;
+    }
+
+    public function getTopicsOf($packageName, $regId, $retries = 1) {
+        $fields = array('registration_id' => $regId, 'restricted_package_name' => $packageName);
+        $result = $this->getResult(PushRequestPath::V1_GET_ALL_TOPIC(), $fields, $retries);
+        return $result;
+    }
+
+}
+
+?>

+ 16 - 0
app/Libs/Push/XMPush/ErrorCode.php

@@ -0,0 +1,16 @@
+<?php
+/**
+ * 错误码定义.
+ * @author wangkuiwei
+ * @name ErrorCode
+ * @desc 错误码
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class ErrorCode {
+    const Success = 0;
+    const NETWORK_ERROR_TIMEOUT = -1;
+}
+
+?>

+ 24 - 0
app/Libs/Push/XMPush/Feedback.php

@@ -0,0 +1,24 @@
+<?php
+/**
+ * 获取失效的regId列表.
+ * @author wangkuiwei
+ * @name Feedback
+ * @desc 获取失效的regId列表。
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class Feedback extends HttpBase {
+
+    public function __construct() {
+        parent::__construct();
+    }
+
+    public function getInvalidRegIds($retries = 1) {
+        $result = $this->getResult(PushRequestPath::V1_FEEDBACK_INVALID_REGID(), array(), $retries);
+        return $result;
+    }
+
+}
+
+?>

+ 167 - 0
app/Libs/Push/XMPush/HttpBase.php

@@ -0,0 +1,167 @@
+<?php
+/**
+ * @author wangkuiwei
+ * @name HttpBase
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class HttpBase {
+    private $appSecret;
+    private $region;
+    private $isVip;
+
+    /**
+     * @param string $appSecret
+     */
+    public function setAppSecret($appSecret) {
+        $this->appSecret = $appSecret;
+    }
+
+    /**
+     * @param int $region
+     */
+    public function setRegion($region) {
+        $this->region = $region;
+    }
+
+    /**
+     * @param bool $isVip
+     */
+    public function setIsVip($isVip) {
+        $this->isVip = $isVip;
+    }
+
+
+    public function __construct() {
+        $this->appSecret = Constants::$secret;
+        $this->region = Region::China;
+        $this->isVip = false;
+    }
+
+    //发送请求,获取result,带重试
+    public function getResult($requestPath, $fields, $retries) {
+        $result = new Result($this->getReq($requestPath, $fields));
+        if ($result->getErrorCode() == ErrorCode::Success) {
+            return $result;
+        }
+        //重试
+        for ($i = 0; $i < $retries; $i++) {
+            $result = new Result($this->getReq($requestPath, $fields));
+            if ($result->getErrorCode() == ErrorCode::Success) {
+                break;
+            }
+        }
+        return $result;
+    }
+
+    //get方式发送请求
+    public function getReq($requestPath, $fields, $timeout = 3) {
+        return $this->httpRequest($requestPath, $fields, "Get", $timeout);
+    }
+
+    //发送请求,获取result,带重试
+    public function postResult($requestPath, $fields, $retries) {
+        $result = new Result($this->postReq($requestPath, $fields));
+        if ($result->getErrorCode() == ErrorCode::Success) {
+            return $result;
+        }
+        //重试
+        for ($i = 0; $i < $retries; $i++) {
+            $result = new Result($this->postReq($requestPath, $fields));
+            if ($result->getErrorCode() == ErrorCode::Success) {
+                break;
+            }
+        }
+        return $result;
+    }
+
+    //post方式发送请求
+    public function postReq($requestPath, $fields, $timeout = 10) {
+        return $this->httpRequest($requestPath, $fields, "Post", $timeout);
+    }
+
+    private function buildFullRequestURL(Server $server, PushRequestPath $requestPath) {
+        return Constants::$HTTP_PROTOCOL . "://" . $server->getHost() . $requestPath->getPath();
+    }
+
+    private function httpRequest($requestPath, $fields, $method, $timeout = 10) {
+        $server = ServerSwitch::getInstance()->selectServer($requestPath, $this->region, $this->isVip);
+        $url = $this->buildFullRequestURL($server, $requestPath);
+
+        $headers = array('Authorization: key=' . $this->appSecret,
+            'Content-Type: application/x-www-form-urlencoded;charset=UTF-8',
+            Constants::X_PUSH_SDK_VERSION . ': ' . Constants::SDK_VERSION);
+        if (Constants::$autoSwitchHost && ServerSwitch::getInstance()->needRefreshHostList()) {
+            array_push($headers, Constants::X_PUSH_HOST_LIST . ': true');
+        }
+        array_push($headers, "Expect:");
+
+        // Open connection
+        $ch = curl_init();
+
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($ch, CURLOPT_HEADER, true);
+        if ($method == "Post") {
+            curl_setopt($ch, CURLOPT_URL, $url);
+            curl_setopt($ch, CURLOPT_POST, true);
+            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
+        } else {
+            curl_setopt($ch, CURLOPT_URL, $url . '?' . http_build_query($fields));
+            curl_setopt($ch, CURLOPT_POST, false);
+        }
+        $content = curl_exec($ch);
+        $result = "";
+        if ($content !== false) {
+            $info = curl_getinfo($ch);
+            $total_time = $info['total_time'];
+            if ($total_time > Constants::HOST_RESPONSE_EXPECT_TIME) {
+                $server->decrPriority();
+            } else {
+                $server->incrPriority();
+            }
+            list($responseHeaderStr, $result) = explode("\r\n\r\n", $content, 2);
+            $responseHeaders = $this->convertHeaders($responseHeaderStr);
+            if (array_key_exists(Constants::X_PUSH_HOST_LIST, $responseHeaders)) {
+                $serverListStr = $responseHeaders[Constants::X_PUSH_HOST_LIST];
+                ServerSwitch::getInstance()->initialize($serverListStr);
+            }
+        } else {
+            $server->decrPriority();
+            $result = json_encode(array(
+                "code" => ErrorCode::NETWORK_ERROR_TIMEOUT,
+                "reason" => "network error or timeout"
+            ));
+        }
+
+        // Close connection
+        curl_close($ch);
+
+        return $result;
+    }
+
+    /**
+     * @param $responseHeaderStr
+     * @return array
+     */
+    private function convertHeaders($responseHeaderStr) {
+        $responseHeaderArr = explode("\r\n", $responseHeaderStr);
+        $responseHeaders = array();
+        foreach ($responseHeaderArr as $responseHeader) {
+            $items = explode(":", $responseHeader, 2);
+            if ($items !== false) {
+                if (count($items) == 2) {
+                    $responseHeaders[trim($items[0])] = trim($items[1]);
+                } else {
+                    $responseHeaders["Header_" . count($responseHeaders)] = trim($responseHeader);
+                }
+            }
+        }
+        return $responseHeaders;
+    }
+}
+
+?>

+ 104 - 0
app/Libs/Push/XMPush/IOSBuilder.php

@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * IOS设备的消息体.
+ * @author wangkuiwei
+ * @name IOSBuilder
+ * @desc 构建发送给IOS设备的Message对象。
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class IOSBuilder extends Message {
+    const soundUrl = 'sound_url';
+    const badge = 'badge';
+    protected $apsProperFields; // 用于存储aps的属性,为的是支持新的扩展属性
+
+    public function __construct() {
+        parent::__construct();
+        $this->apsProperFields = array();
+    }
+
+    public function description($description) {
+        $this->description = $description;
+    }
+
+    public function timeToLive($ttl) {
+        $this->time_to_live = $ttl;
+    }
+
+    public function timeToSend($timeToSend) {
+        $this->time_to_send = $timeToSend;
+    }
+
+    public function soundUrl($url) {
+        $this->extra(IOSBuilder::soundUrl, $url);
+    }
+
+    public function badge($badge) {
+        $this->extra(IOSBuilder::badge, $badge);
+    }
+
+    public function contentAvailable($value) {
+        $this->extra("content-available", $value);
+    }
+
+    public function showContent() {
+        $this->extra("show-content", "1");
+    }
+
+    public function extra($key, $value) {
+        $this->extra[$key] = $value;
+    }
+
+    public function title($title) {
+        $this->apsProperFields["title"] = $title;
+    }
+
+    public function subtitle($subtitle) {
+        $this->apsProperFields["subtitle"] = $subtitle;
+    }
+
+    public function body($body) {
+        $this->apsProperFields["body"] = $body;
+    }
+
+    public function mutableContent($mutableContent) {
+        $this->apsProperFields["mutable-content"] = $mutableContent;
+    }
+
+    public function apsProperFields($key, $value) {
+        $this->apsProperFields[$key] = $value;
+    }
+
+    public function build() {
+        $keys = array(
+            'description', 'time_to_live', 'time_to_send'
+        );
+        foreach ($keys as $key) {
+            if (isset($this->$key)) {
+                $this->fields[$key] = $this->$key;
+                $this->json_infos[$key] = $this->$key;
+            }
+        }
+
+        //单独处理extra
+        $JsonExtra = array();
+        if (count($this->extra) > 0) {
+            foreach ($this->extra as $extraKey => $extraValue) {
+                $this->fields[Message::EXTRA_PREFIX . $extraKey] = $extraValue;
+                $JsonExtra[$extraKey] = $extraValue;
+            }
+        }
+        $this->json_infos['extra'] = $JsonExtra;
+
+        // 单独处理apsProperFields
+        if (count($this->apsProperFields) > 0) {
+            foreach ($this->apsProperFields as $key => $value) {
+                $this->fields[Message::APS_PROPER_FIELDS_PREFIX . $key] = $value;
+            }
+        }
+    }
+}
+
+?>

+ 55 - 0
app/Libs/Push/XMPush/Message.php

@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * 消息体.
+ * @author wangkuiwei
+ * @name Message
+ * @desc 构建要发送的消息内容。
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class Message {
+    const EXTRA_PREFIX = 'extra.';
+    const APS_PROPER_FIELDS_PREFIX = 'aps_proper_fields.';
+
+    const HYBRID_PUSH_ACTION = "push_server_action";
+    const HYBRID_ACTION_MESSAGE = "hybrid_message";
+    const HYBRID_DEBUG = "hybrid_debug";
+    const HYBRID_PATH = "hybrid_pn";
+
+    protected $payload;                //消息内容
+    protected $restricted_package_name;            //支持多包名
+    protected $pass_through;            //是否透传给app(1 透传 0 通知栏信息)
+    protected $notify_type;                //通知类型 可组合 (-1 Default_all,1 Default_sound,2 Default_vibrate(震动),4 Default_lights)
+    protected $notify_id;                //0-4同一个notifyId在通知栏只会保留一条
+    protected $extra;                    //可选项,额外定义一些key value(字符不能超过1024,key不能超过10个)
+    protected $description;                //在通知栏的描述,长度小于128
+    protected $title;                    //在通知栏的标题,长度小于16
+    protected $time_to_live;            //可选项,当用户离线是,消息保留时间,默认两周,单位ms
+    protected $time_to_send;            //可选项,定时发送消息,用自1970年1月1日以来00:00:00.0 UTC时间表示(以毫秒为单位的时间)。
+
+    protected $fields;                //含有本条消息所有属性的数组
+    protected $json_infos;
+
+    /* IOS 使用 */
+    protected $sound_url;            //可选,消息铃声
+    protected $badge;                //可选,自定义通知数字角标
+
+
+    public function __construct() {
+        $this->extra = array();
+        $this->fields = array();
+    }
+
+    public function getFields() {
+        return $this->fields;
+    }
+
+    public function getJSONInfos() {
+        return $this->json_infos;
+    }
+
+}
+
+?>

+ 78 - 0
app/Libs/Push/XMPush/MiPushCommon.php

@@ -0,0 +1,78 @@
+<?php
+
+
+namespace App\Libs\Push\XMPush;
+
+
+class MiPushCommon
+{
+    private $_reg_arr = [];
+
+    /**
+     * XMPushCommon constructor.
+     * @param $package
+     * @param $appSecret
+     */
+    public function __construct($package, $appSecret)
+    {
+        // 常量设置必须在new Sender()方法之前调用
+        Constants::setPackage($package);
+        Constants::setSecret($appSecret);
+    }
+
+    public function setRegArr($regArr)
+    {
+        $this->_reg_arr = $regArr;
+    }
+
+    /**
+     * 发送消息
+     * @param $title
+     * @param $desc
+     * @param $url
+     * @return mixed
+     */
+    public function sendMessage($title, $desc, $url)
+    {
+        $sender  = new Sender();
+        $message = $this->buildMessage($title, $desc, $url);
+        return $sender->sendToIds($message, $this->_reg_arr)->getRaw();
+    }
+
+    /**
+     * 向所有设备发送消息
+     * @param $title
+     * @param $desc
+     * @param $url
+     * @return mixed
+     */
+    public function sendMessageToAll($title, $desc, $url)
+    {
+        $sender  = new Sender();
+        $message = $this->buildMessage($title, $desc, $url);
+        return $sender->broadcastAll($message)->getRaw();
+    }
+
+    /**
+     * @param        $title
+     * @param        $desc
+     * @param        $url
+     * @param int    $pusType
+     * @param string $payload
+     * @return Builder
+     */
+    private function buildMessage($title, $desc, $url, $pusType = 0, $payload = '')
+    {
+        $message = new Builder();
+        $message->title($title);  // 通知栏的title
+        $message->description($desc); // 通知栏的descption
+        $message->passThrough($pusType);  // 这是一条通知栏消息,如果需要透传,把这个参数设置成1,同时去掉title和descption两个参数
+        $message->payload($payload); // 携带的数据,点击后将会通过客户端的receiver中的onReceiveMessage方法传入。
+        $message->extra(Builder::intentUri, $url); // 此处设置预定义点击行为,1为打开app
+        $message->extra(Builder::notifyEffect, 2); // 此处设置预定义点击行为,1为打开app 2通知栏点击后打开app的任一Activity
+        $message->extra(Builder::notifyForeground, 1); // 应用在前台是否展示通知,如果不希望应用在前台时候弹出通知,则设置这个参数为0
+        $message->notifyId(2); // 通知类型。最多支持0-4 5个取值范围,同样的类型的通知会互相覆盖,不同类型可以在通知栏并存
+        $message->build();
+        return $message;
+    }
+}

+ 222 - 0
app/Libs/Push/XMPush/PushRequestPath.php

@@ -0,0 +1,222 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: zhangdali
+ * Date: 2016/12/7
+ * Time: 下午6:30
+ */
+
+namespace App\Libs\Push\XMPush;
+
+class PushRequestPath {
+    // regid message
+    static function V2_SEND() {
+        return new static("/v2/send", PushRequestType::MESSAGE);
+    }
+
+    static function V2_REGID_MESSAGE() {
+        return new static("/v2/message/regid", PushRequestType::MESSAGE);
+    }
+
+    static function V3_REGID_MESSAGE() {
+        return new static("/v3/message/regid", PushRequestType::MESSAGE);
+    }
+
+    // subscribe topic
+    static function V2_SUBSCRIBE_TOPIC() {
+        return new static("/v2/topic/subscribe", PushRequestType::MESSAGE);
+    }
+
+    static function V2_UNSUBSCRIBE_TOPIC() {
+        return new static("/v2/topic/unsubscribe", PushRequestType::MESSAGE);
+    }
+
+    static function V2_SUBSCRIBE_TOPIC_BY_ALIAS() {
+        return new static("/v2/topic/subscribe/alias", PushRequestType::MESSAGE);
+    }
+
+    static function V2_UNSUBSCRIBE_TOPIC_BY_ALIAS() {
+        return new static("/v2/topic/unsubscribe/alias", PushRequestType::MESSAGE);
+    }
+
+    // alias message
+    static function V2_ALIAS_MESSAGE() {
+        return new static("/v2/message/alias", PushRequestType::MESSAGE);
+    }
+
+    static function V3_ALIAS_MESSAGE() {
+        return new static("/v3/message/alias", PushRequestType::MESSAGE);
+    }
+
+    // broadcast message
+    static function V2_BROADCAST_TO_ALL() {
+        return new static("/v2/message/all", PushRequestType::MESSAGE);
+    }
+
+    static function V3_BROADCAST_TO_ALL() {
+        return new static("/v3/message/all", PushRequestType::MESSAGE);
+    }
+
+    static function V2_BROADCAST() {
+        return new static("/v2/message/topic", PushRequestType::MESSAGE);
+    }
+
+    static function V3_BROADCAST() {
+        return new static("/v3/message/topic", PushRequestType::MESSAGE);
+    }
+
+    static function V2_MULTI_TOPIC_BROADCAST() {
+        return new static("/v2/message/multi_topic", PushRequestType::MESSAGE);
+    }
+
+    static function V3_MILTI_TOPIC_BROADCAST() {
+        return new static("/v3/message/multi_topic", PushRequestType::MESSAGE);
+    }
+
+    static function V2_DELETE_BROADCAST_MESSAGE() {
+        return new static("/v2/message/delete", PushRequestType::MESSAGE);
+    }
+
+    // user account message
+    static function V2_USER_ACCOUNT_MESSAGE() {
+        return new static("/v2/message/user_account", PushRequestType::MESSAGE);
+    }
+
+    // miid message
+    static function V2_MIID_MESSAGE() {
+        return new static("/v2/message/miid", PushRequestType::MESSAGE);
+    }
+
+    // multi message
+    static function V2_SEND_MULTI_MESSAGE_WITH_REGID() {
+        return new self("/v2/multi_messages/regids", PushRequestType::MESSAGE);
+    }
+
+    static function V2_SEND_MULTI_MESSAGE_WITH_ALIAS() {
+        return new self("/v2/multi_messages/aliases", PushRequestType::MESSAGE);
+    }
+
+    static function V2_SEND_MULTI_MESSAGE_WITH_ACCOUNT() {
+        return new self("/v2/multi_messages/user_accounts", PushRequestType::MESSAGE);
+    }
+
+    // validate
+    static function V1_VALIDATE_REGID() {
+        return new static("/v1/validation/regids", PushRequestType::MESSAGE);
+    }
+
+    static function V1_GET_ALL_ACCOUNT() {
+        return new static("/v1/account/all", PushRequestType::MESSAGE);
+    }
+
+    static function V1_GET_ALL_TOPIC() {
+        return new static("/v1/topic/all", PushRequestType::MESSAGE);
+    }
+
+    static function V1_GET_ALL_ALIAS() {
+        return new static("/v1/alias/all", PushRequestType::MESSAGE);
+    }
+
+    static function V1_GET_ALL_MIID() {
+        return new static("/v1/miid/all", PushRequestType::MESSAGE);
+    }
+
+    // trace
+    static function V1_MESSAGES_STATUS() {
+        return new static("/v1/trace/messages/status", PushRequestType::MESSAGE);
+    }
+
+    static function V1_MESSAGE_STATUS() {
+        return new static("/v1/trace/message/status", PushRequestType::MESSAGE);
+    }
+
+    static function V1_GET_MESSAGE_COUNTERS() {
+        return new static("/v1/stats/message/counters", PushRequestType::MESSAGE);
+    }
+
+    // presence
+    static function V1_REGID_PRESENCE() {
+        return new static("/v1/regid/presence", PushRequestType::MESSAGE);
+    }
+
+    static function V2_REGID_PRESENCE() {
+        return new static("/v1/regid/presence", PushRequestType::MESSAGE);
+    }
+
+    // schedule job
+    static function V2_DELETE_SCHEDULE_JOB() {
+        return new static("/v2/schedule_job/delete", PushRequestType::MESSAGE);
+    }
+
+    static function V3_DELETE_SCHEDULE_JOB() {
+        return new static("/v3/schedule_job/delete", PushRequestType::MESSAGE);
+    }
+
+    static function V2_CHECK_SCHEDULE_JOB_EXIST() {
+        return new static("/v2/schedule_job/exist", PushRequestType::MESSAGE);
+    }
+
+    static function V2_QUERY_SCHEDULE_JOB() {
+        return new static("/v2/schedule_job/query", PushRequestType::MESSAGE);
+    }
+
+    // feedback
+    static function V1_FEEDBACK_INVALID_ALIAS() {
+        return new static("/v1/feedback/fetch_invalid_aliases", PushRequestType::FEEDBACK);
+    }
+
+    static function V1_FEEDBACK_INVALID_REGID() {
+        return new static("/v1/feedback/fetch_invalid_regids", PushRequestType::FEEDBACK);
+    }
+
+    static function V1_FEEDBACK_INVALID_MIID() {
+        return new static("/v1/feedback/fetch_invalid_miid", PushRequestType::FEEDBACK);
+    }
+
+    // emq job
+    static function V1_EMQ_ACK_INFO() {
+        return new static("/msg/ack/info", PushRequestType::EMQ);
+    }
+
+    static function V1_EMQ_CLICK_INFO() {
+        return new static("/msg/click/info", PushRequestType::EMQ);
+    }
+
+    static function V1_EMQ_INVALID_REGID() {
+        return new static("/app/invalid/regid", PushRequestType::EMQ);
+    }
+
+    /**
+     * PushRequestPath constructor.
+     * @param string $path
+     * @param int $requestType
+     */
+    public function __construct($path, $requestType) {
+        $this->path = $path;
+        $this->requestType = $requestType;
+    }
+
+    /**
+     * @return int
+     */
+    public function getRequestType() {
+        return $this->requestType;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPath() {
+        return $this->path;
+    }
+
+
+    /**
+     * @var string
+     */
+    private $path;
+    /**
+     * @var int
+     */
+    private $requestType;
+}

+ 15 - 0
app/Libs/Push/XMPush/PushRequestType.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: zhangdali
+ * Date: 2016/12/13
+ * Time: 下午5:26
+ */
+
+namespace App\Libs\Push\XMPush;
+
+class PushRequestType {
+    const MESSAGE = 0;
+    const FEEDBACK = 1;
+    const EMQ = 2;
+}

+ 29 - 0
app/Libs/Push/XMPush/Region.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: zhangdali
+ * Date: 2018/3/12
+ * Time: 下午5:44
+ */
+
+namespace App\Libs\Push\XMPush;
+
+
+class Region {
+    const China = 0;          // 国内
+    const Other = 1;          // 国外其他地方,比如新加坡
+
+    public static function getFeedbackHostList() {
+        return array(
+            Region::China => Constants::HOST_PRODUCTION_FEEDBACK,
+            Region::Other => Constants::HOST_GLOBAL_PRODUCTION_FEEDBACK
+        );
+    }
+
+    public static function getApiHostList() {
+        return array(
+            Region::China => Constants::HOST_PRODUCTION,
+            Region::Other => Constants::HOST_GLOBAL_PRODUCTION
+        );
+    }
+}

+ 30 - 0
app/Libs/Push/XMPush/Result.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * 服务器返回的结果.
+ * @author wangkuiwei
+ * @name Result
+ * @desc Sender发送消息后,服务器返回的结果。
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class Result {
+    private $errorCode;
+    private $raw;
+
+    public function __construct($jsonStr) {
+        $data = json_decode($jsonStr, true);
+        $this->raw = $data;
+        $this->errorCode = $data['code'];
+    }
+
+    public function getErrorCode() {
+        return $this->errorCode;
+    }
+
+    public function getRaw() {
+        return $this->raw;
+    }
+}
+
+?>

+ 210 - 0
app/Libs/Push/XMPush/Sender.php

@@ -0,0 +1,210 @@
+<?php
+/**
+ * MiPush消息发送类.
+ * @author wangkuiwei
+ * @name Sender
+ * @desc MiPush消息发送
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class Sender extends HttpBase
+{
+
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    //指定regId单发消息
+    public function send(Message $message, $regId, $retries = 1)
+    {
+        $fields                    = $message->getFields();
+        $fields['registration_id'] = $regId;
+        return $this->postResult(PushRequestPath::V2_REGID_MESSAGE(), $fields, $retries);
+    }
+
+    //指定regId列表群发
+    public function sendToIds(Message $message, $regIdList, $retries = 1)
+    {
+        $fields                    = $message->getFields();
+        $jointRegIds               = implode(',', $regIdList);
+        $fields['registration_id'] = $jointRegIds;
+        return $this->postResult(PushRequestPath::V2_REGID_MESSAGE(), $fields, $retries);
+    }
+
+    //多条发送
+    public function multiSend($targetMessages, $type, $retries = 1)
+    {
+        $requestPath = $this->multiSendRequestPath($type);
+        $data        = array();
+        foreach ($targetMessages as $targetMsg) {
+            array_push($data, $targetMsg->getFields());
+        }
+        $fields = array('messages' => json_encode($data));
+        return $this->postResult($requestPath, $fields, $retries);
+    }
+
+    //多条发送
+    public function multiSendAtTime($targetMessages, $type, $timeToSend, $retries = 1)
+    {
+        $requestPath = $this->multiSendRequestPath($type);
+        $data        = array();
+        foreach ($targetMessages as $targetMsg) {
+            array_push($data, $targetMsg->getFields());
+        }
+        $fields = array('messages' => json_encode($data), 'time_to_send' => $timeToSend);
+        return $this->postResult($requestPath, $fields, $retries);
+    }
+
+    //指定别名单发
+    public function sendToAlias(Message $message, $alias, $retries = 1)
+    {
+        $fields          = $message->getFields();
+        $fields['alias'] = $alias;
+        return $this->postResult(PushRequestPath::V3_ALIAS_MESSAGE(), $fields, $retries);
+    }
+
+    //指定别名列表群发
+    public function sendToAliases(Message $message, $aliasList, $retries = 1)
+    {
+        $fields       = $message->getFields();
+        $jointAliases = '';
+        foreach ($aliasList as $alias) {
+            if (strlen($jointAliases) > 0) {
+                $jointAliases = $jointAliases . Constants::$comma;
+            }
+            $jointAliases = $jointAliases . $alias;
+        }
+        $fields['alias'] = $jointAliases;
+        return $this->postResult(PushRequestPath::V3_ALIAS_MESSAGE(), $fields, $retries);
+    }
+
+    //指定userAccount群发
+    public function sendToUserAccount(Message $message, $userAccount, $retries = 1)
+    {
+        $fields                 = $message->getFields();
+        $fields['user_account'] = $userAccount;
+        return $this->postResult(PushRequestPath::V2_USER_ACCOUNT_MESSAGE(), $fields, $retries);
+    }
+
+    //指定userAccount列表群发
+    public function sendToUserAccounts(Message $message, $userAccountList, $retries = 1)
+    {
+        $fields            = $message->getFields();
+        $jointUserAccounts = '';
+        foreach ($userAccountList as $userAccount) {
+            if (strlen($jointUserAccounts) > 0) {
+                $jointUserAccounts = $jointUserAccounts . Constants::$comma;
+            }
+            $jointUserAccounts = $jointUserAccounts . $userAccount;
+        }
+        $fields['user_account'] = $jointUserAccounts;
+        return $this->postResult(PushRequestPath::V2_USER_ACCOUNT_MESSAGE(), $fields, $retries);
+    }
+
+    //指定topic群发
+    public function broadcast(Message $message, $topic, $retries = 1)
+    {
+        $fields          = $message->getFields();
+        $fields['topic'] = $topic;
+        return $this->postResult(PushRequestPath::V2_BROADCAST(), $fields, $retries);
+    }
+
+    //向所有设备发送消息
+    public function broadcastAll(Message $message, $retries = 1)
+    {
+        $fields = $message->getFields();
+        return $this->postResult(PushRequestPath::V2_BROADCAST_TO_ALL(), $fields, $retries);
+    }
+
+    //广播消息,多个topic,支持topic间的交集、并集或差集
+    public function multiTopicBroadcast(Message $message, $topicList, $topicOp, $retries = 1)
+    {
+        if (count($topicList) === 1) {
+            return $this->broadcast($message, $topicList[0], $retries);
+        }
+        $fields      = $message->getFields();
+        $jointTopics = '';
+        foreach ($topicList as $topic) {
+            if (strlen($jointTopics) > 0) {
+                $jointTopics = $jointTopics . Constants::$multi_topic_split;
+            }
+            $jointTopics = $jointTopics . $topic;
+        }
+        $fields['topics']   = $jointTopics;
+        $fields['topic_op'] = $topicOp;
+        return $this->postResult(PushRequestPath::V2_MULTI_TOPIC_BROADCAST(), $fields, $retries);
+    }
+
+    // 检测定时任务是否存在
+    public function checkScheduleJobExist($msgId, $retries = 1)
+    {
+        $fields = array('job_id' => $msgId);
+        return $this->postResult(PushRequestPath::V2_CHECK_SCHEDULE_JOB_EXIST(), $fields, $retries);
+    }
+
+    // 删除定时任务
+    public function deleteScheduleJob($msgId, $retries = 1)
+    {
+        $fields = array('job_id' => $msgId);
+        return $this->postResult(PushRequestPath::V2_DELETE_SCHEDULE_JOB(), $fields, $retries);
+    }
+
+
+    // Hybrid
+    public function sendHybridMessageByRegId(Message $message, $regIdList, $isDebug = false, $retries = 1)
+    {
+        $fields = $message->getFields();
+        $this->hybridHandle($isDebug, $fields);
+        $jointRegIds = '';
+        foreach ($regIdList as $regId) {
+            if (isset($regId)) {
+                $jointRegIds .= $regId . Constants::$comma;
+            }
+        }
+        $fields['registration_id'] = $jointRegIds;
+        return $this->postResult(PushRequestPath::V2_REGID_MESSAGE(), $fields, $retries);
+    }
+
+    public function broadcastHybridAll(Message $message, $isDebug = false, $retries = 1)
+    {
+        $fields = $message->getFields();
+        $this->hybridHandle($isDebug, $fields);
+        return $this->postResult(PushRequestPath::V2_BROADCAST_TO_ALL(), $fields, $retries);
+    }
+
+    /**
+     * @param $type
+     * @return PushRequestPath
+     */
+    private function multiSendRequestPath($type)
+    {
+        if ($type == TargetedMessage::TARGET_TYPE_ALIAS) {
+            $requestPath = PushRequestPath::V2_SEND_MULTI_MESSAGE_WITH_ALIAS();
+            return $requestPath;
+        } else if ($type == TargetedMessage::TARGET_TYPE_USER_ACCOUNT) {
+            $requestPath = PushRequestPath::V2_SEND_MULTI_MESSAGE_WITH_ACCOUNT();
+            return $requestPath;
+        } else {
+            $requestPath = PushRequestPath::V2_SEND_MULTI_MESSAGE_WITH_REGID();
+            return $requestPath;
+        }
+    }
+
+    /**
+     * @param $isDebug
+     * @param $fields
+     * @return mixed
+     */
+    private function hybridHandle($isDebug, &$fields)
+    {
+        $fields[Message::EXTRA_PREFIX . Message::HYBRID_PUSH_ACTION] = Message::HYBRID_ACTION_MESSAGE;
+        if ($isDebug) {
+            $fields[Message::EXTRA_PREFIX . Message::HYBRID_DEBUG] = "1";
+        }
+        return $fields;
+    }
+}
+
+?>

+ 98 - 0
app/Libs/Push/XMPush/Server.php

@@ -0,0 +1,98 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: zhangdali
+ * Date: 2016/12/5
+ * Time: 下午4:36
+ */
+
+namespace App\Libs\Push\XMPush;
+
+
+class Server {
+
+    /**
+     * @var string
+     */
+    private $host;
+    /**
+     * @var int
+     */
+    private $priority;
+    private $minPriority;
+    private $maxPriority;
+    private $decrStep;
+    private $incrStep;
+
+    /**
+     * Server constructor.
+     * @param string $host
+     * @param int $minPriority
+     * @param int $maxPriority
+     * @param int $decrStep
+     * @param int $incrStep
+     */
+    public function __construct($host, $minPriority, $maxPriority, $decrStep, $incrStep) {
+        $this->host = $host;
+        $this->priority = $maxPriority;
+        $this->minPriority = $minPriority;
+        $this->maxPriority = $maxPriority;
+        $this->decrStep = $decrStep;
+        $this->incrStep = $incrStep;
+    }
+
+    function __destruct() {
+    }
+
+
+    /**
+     * @return string
+     */
+    public function getHost() {
+        return $this->host;
+    }
+
+    /**
+     * @param $host
+     */
+    public function setHost($host) {
+        $this->host = $host;
+    }
+
+    /**
+     * @return int
+     */
+    public function getPriority() {
+        return $this->priority;
+    }
+
+    /**
+     * @param int $priority
+     */
+    public function setPriority($priority) {
+        $this->priority = $priority;
+    }
+
+    public function incrPriority() {
+        $this->changePriority(true, $this->incrStep);
+    }
+
+    public function decrPriority() {
+        $this->changePriority(false, $this->incrStep);
+    }
+
+    /**
+     * @param bool $incr
+     * @param int $step
+     */
+    private function changePriority($incr, $step) {
+        $newPriority = $incr ? $this->priority + $step : $this->priority - $step;
+        if ($newPriority < $this->minPriority) {
+            $newPriority = $this->minPriority;
+        }
+        if ($newPriority > $this->maxPriority) {
+            $newPriority = $this->maxPriority;
+        }
+        $this->priority = $newPriority;
+    }
+}

+ 199 - 0
app/Libs/Push/XMPush/ServerSwitch.php

@@ -0,0 +1,199 @@
+<?php
+/**
+ * 用于多个域名之间的切换逻辑
+ * Created by PhpStorm.
+ * User: zhangdali
+ * Date: 2016/12/5
+ * Time: 下午4:29
+ */
+
+namespace App\Libs\Push\XMPush;
+
+
+class ServerSwitch {
+    /**
+     * 存储message的server
+     * @var array Server
+     */
+    private $servers;
+    private $apiRegionList;
+    private $feedbackRegionList;
+    private $sandbox;
+    private $specified;
+    private $emq;
+    private $messageVip;
+    private $defaultServer;
+    private $inited = false;
+    private $lastRefreshTime;
+    static $REFRESH_SERVER_HOST_INTERVAL = 300000; // 5 * 60 * 1000
+
+
+    /**
+     * @var ServerSwitch reference to singleton instance
+     */
+    private static $instance;
+
+    /**
+     * 通过延迟加载(用到时才加载)获取实例
+     *
+     * @return self
+     */
+    public static function getInstance() {
+        if (!isset(self::$instance)) {
+            $class = __CLASS__;
+            self::$instance = new $class;
+        }
+
+        return self::$instance;
+    }
+
+    /**
+     * 是否需要刷新host列表
+     * @return bool
+     */
+    public function needRefreshHostList() {
+        return !$this->inited ||
+            $this->currentTimeMillis() - $this->lastRefreshTime >= self::$REFRESH_SERVER_HOST_INTERVAL;
+    }
+
+    /**
+     * @param String $serverListStr : host:min:max:step,host:min:max:step,...
+     */
+    public function initialize($serverListStr) {
+        if (!$this->needRefreshHostList()) {
+            return;
+        }
+        $serverStrArr = explode(',', $serverListStr);
+        $servers = array();
+        $i = 0;
+        foreach ($serverStrArr as $serverStr) {
+            $sp = explode(":", $serverStr);
+            if (count($sp) < 5) {
+                $servers[$i] = $this->defaultServer;
+                continue;
+            }
+            $servers[$i] = new Server($sp[0], intval($sp[1]), intval($sp[2]), intval($sp[3]), intval($sp[4]));
+            if (!empty($this->servers)) {
+                foreach ($this->servers as $server) {
+                    if (strcmp($server->getHost(), $servers[$i]->getHost())) {
+                        $servers[$i]->setPriority($server->getPriority());
+                    }
+                }
+            }
+            $i++;
+        }
+        $this->inited = true;
+        $this->lastRefreshTime = $this->currentTimeMillis();
+        $this->servers = $servers;
+    }
+
+    /**
+     * @param PushRequestPath $requestPath
+     */
+    /**
+     * @param PushRequestPath $requestPath
+     * @return Server
+     */
+    public function &selectServer($requestPath, $region, $isVip) {
+        if (isset(Constants::$host)) {
+            $this->specified->setHost(Constants::$host);
+            return $this->specified;
+        }
+        if (Constants::$sandbox) {
+            return $this->sandbox;
+        }
+        switch ($requestPath->getRequestType()) {
+            case PushRequestType::FEEDBACK:
+                switch ($region) {
+                    case Region::Other:
+                        return $this->feedbackRegionList[$region];
+                    default:
+                        return $this->feedbackRegionList[Region::China];
+
+                }
+            case PushRequestType::EMQ:
+                return $this->emq;
+            default:
+                switch ($region) {
+                    case Region::Other:
+                        return $this->apiRegionList[$region];
+                    default:
+                        if ($isVip) {
+                            return $this->messageVip;
+                        }
+                        return $this->selectMsgServer();
+                }
+        }
+
+    }
+
+    /**
+     * @return mixed|Server
+     */
+    private function &selectMsgServer() {
+        if (!Constants::$autoSwitchHost || !$this->inited) {
+            return $this->defaultServer;
+        }
+        $allPriority = 0;
+        $priorities = array();
+        foreach ($this->servers as $server) {
+            $priorities[] = $server->getPriority();
+            $allPriority += $server->getPriority();
+        }
+        $randomPoint = mt_rand(0, $allPriority);
+        $sum = 0;
+        for ($i = 0; $i < count($priorities); $i++) {
+            $sum += $priorities[$i];
+            if ($randomPoint <= $sum) {
+                return $this->servers[$i];
+            }
+        }
+        return $this->defaultServer;
+    }
+
+    /**
+     * 构造函数私有,不允许在外部实例化
+     */
+    private function __construct() {
+        $this->sandbox = new Server(Constants::HOST_SANDBOX, 100, 100, 0, 0);
+        $this->specified = new Server(Constants::$host, 100, 100, 0, 0);
+        $this->emq = new Server(Constants::HOST_EMQ, 100, 100, 0, 0);
+        $this->defaultServer = new Server(Constants::HOST_PRODUCTION, 1, 90, 10, 5);
+        $this->lastRefreshTime = $this->currentTimeMillis();
+        $hostList = Region::getFeedbackHostList();
+        $this->feedbackRegionList = array();
+        foreach ($hostList as $region => $host) {
+            $this->feedbackRegionList[$region] = new Server($host, 100, 100, 0, 0);
+        }
+        $hostList = Region::getApiHostList();
+        $this->apiRegionList = array();
+        foreach ($hostList as $region => $host) {
+            $this->apiRegionList[$region] = new Server($host, 100, 100, 0, 0);
+        }
+        $this->messageVip = new Server(Constants::HOST_VIP, 100, 100, 0, 0);
+    }
+
+    /**
+     * 防止对象实例被克隆
+     *
+     * @return void
+     */
+    private function __clone() {
+    }
+
+    /**
+     * 防止被反序列化
+     *
+     * @return void
+     */
+    private function __wakeup() {
+    }
+
+    /**
+     * 获取当前时间(毫秒)
+     * @return int
+     */
+    private function currentTimeMillis() {
+        return ceil(microtime(true) * 1000);
+    }
+}

+ 41 - 0
app/Libs/Push/XMPush/Stats.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * 获取发送的消息统计数据.
+ * @author wangkuiwei
+ * @name Stats
+ * @desc 获取发送的消息统计数据。
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class Stats extends HttpBase {
+    private $package;   //android用
+    private $bundle;    //ios用
+
+    public function __construct() {
+        parent::__construct();
+        $this->package = Constants::$packageName;
+        $this->bundle = Constants::$bundle_id;
+    }
+
+    public function getStats($startDate, $endDate, $type = 'android', $retries = 1) {
+        if ($type == 'ios') {
+            $fields = array(
+                'start_date' => $startDate,
+                'end_date' => $endDate,
+                'restricted_package_name' => $this->bundle
+            );
+        } else {
+            $fields = array(
+                'start_date' => $startDate,
+                'end_date' => $endDate,
+                'restricted_package_name' => $this->package
+            );
+        }
+        $result = $this->getResult(PushRequestPath::V1_GET_MESSAGE_COUNTERS(), $fields, $retries);
+        return $result;
+    }
+
+}
+
+?>

+ 125 - 0
app/Libs/Push/XMPush/Subscription.php

@@ -0,0 +1,125 @@
+<?php
+/**
+ * 订阅/取消订阅标签.
+ * @author wangkuiwei
+ * @name Subscription
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class Subscription extends HttpBase {
+
+    public function __construct() {
+        parent::__construct();
+    }
+
+    public function subscribe($regId, $topic, $retries = 1) {
+        $fields = array('registration_id' => $regId, 'topic' => $topic);
+        return $this->postResult(PushRequestPath::V2_SUBSCRIBE_TOPIC(), $fields, $retries);
+    }
+
+    public function subscribeForRegids($regIdList, $topic, $retries = 1) {
+        $jointRegIds = '';
+        foreach ($regIdList as $regId) {
+            if (isset($regId)) {
+                $jointRegIds .= $regId . Constants::$comma;
+            }
+        }
+        $fields = array('registration_id' => $jointRegIds, 'topic' => $topic);
+        return $this->postResult(PushRequestPath::V2_SUBSCRIBE_TOPIC(), $fields, $retries);
+    }
+
+    public function unsubscribe($regId, $topic, $retries = 1) {
+        $fields = array('registration_id' => $regId, 'topic' => $topic);
+        return $this->postResult(PushRequestPath::V2_UNSUBSCRIBE_TOPIC(), $fields, $retries);
+    }
+
+    public function unsubscribeForRegids($regIdList, $topic, $retries = 1) {
+        $jointRegIds = '';
+        foreach ($regIdList as $regId) {
+            if (isset($regId)) {
+                $jointRegIds .= $regId . Constants::$comma;
+            }
+        }
+        $fields = array('registration_id' => $jointRegIds, 'topic' => $topic);
+        return $this->postResult(PushRequestPath::V2_UNSUBSCRIBE_TOPIC(), $fields, $retries);
+    }
+
+    public function subscribeTopicByAlias($aliasList, $topic, $retries = 1) {
+        $jointAliases = '';
+        foreach ($aliasList as $alias) {
+            if (isset($alias)) {
+                $jointAliases .= $alias . Constants::$comma;
+            }
+        }
+        $fields = array('aliases' => $jointAliases, 'topic' => $topic);
+        return $this->postResult(PushRequestPath::V2_SUBSCRIBE_TOPIC_BY_ALIAS(), $fields, $retries);
+    }
+
+    public function unsubscribeTopicByAlias($aliasList, $topic, $retries = 1) {
+        $jointAliases = '';
+        foreach ($aliasList as $alias) {
+            if (isset($alias)) {
+                $jointAliases .= $alias . Constants::$comma;
+            }
+        }
+        $fields = array('aliases' => $jointAliases, 'topic' => $topic);
+        return $this->postResult(PushRequestPath::V2_UNSUBSCRIBE_TOPIC_BY_ALIAS(), $fields, $retries);
+    }
+
+    public function subscribeByPackageName($regId, $topic, $packageName, $retries = 1) {
+        $fields = array('registration_id' => $regId, 'topic' => $topic, 'restricted_package_name' => $packageName);
+        return $this->postResult(PushRequestPath::V2_SUBSCRIBE_TOPIC(), $fields, $retries);
+    }
+
+    public function subscribeForRegidsByPackageName($regIdList, $topic, $packageName, $retries = 1) {
+        $jointRegIds = '';
+        foreach ($regIdList as $regId) {
+            if (isset($regId)) {
+                $jointRegIds .= $regId . Constants::$comma;
+            }
+        }
+        $fields = array('registration_id' => $jointRegIds, 'topic' => $topic, 'restricted_package_name' => $packageName);
+        return $this->postResult(PushRequestPath::V2_SUBSCRIBE_TOPIC(), $fields, $retries);
+    }
+
+    public function unsubscribeByPackageName($regId, $topic, $packageName, $retries = 1) {
+        $fields = array('registration_id' => $regId, 'topic' => $topic, 'restricted_package_name' => $packageName);
+        return $this->postResult(PushRequestPath::V2_UNSUBSCRIBE_TOPIC(), $fields, $retries);
+    }
+
+    public function unsubscribeForRegidsByPackageName($regIdList, $topic, $packageName, $retries = 1) {
+        $jointRegIds = '';
+        foreach ($regIdList as $regId) {
+            if (isset($regId)) {
+                $jointRegIds .= $regId . Constants::$comma;
+            }
+        }
+        $fields = array('registration_id' => $jointRegIds, 'topic' => $topic, 'restricted_package_name' => $packageName);
+        return $this->postResult(PushRequestPath::V2_UNSUBSCRIBE_TOPIC(), $fields, $retries);
+    }
+
+    public function subscribeTopicByPackageNameAlias($aliasList, $topic, $packageName, $retries = 1) {
+        $jointAliases = '';
+        foreach ($aliasList as $alias) {
+            if (isset($alias)) {
+                $jointAliases .= $alias . Constants::$comma;
+            }
+        }
+        $fields = array('aliases' => $jointAliases, 'topic' => $topic, 'restricted_package_name' => $packageName);
+        return $this->postResult(PushRequestPath::V2_SUBSCRIBE_TOPIC_BY_ALIAS(), $fields, $retries);
+    }
+
+    public function unsubscribeTopicByPackageNameAlias($aliasList, $topic, $packageName, $retries = 1) {
+        $jointAliases = '';
+        foreach ($aliasList as $alias) {
+            if (isset($alias)) {
+                $jointAliases .= $alias . Constants::$comma;
+            }
+        }
+        $fields = array('aliases' => $jointAliases, 'topic' => $topic, 'restricted_package_name' => $packageName);
+        return $this->postResult(PushRequestPath::V2_UNSUBSCRIBE_TOPIC_BY_ALIAS(), $fields, $retries);
+    }
+}
+
+?>

+ 43 - 0
app/Libs/Push/XMPush/TargetedMessage.php

@@ -0,0 +1,43 @@
+<?php
+/**
+ * 要发送的消息内容和消息的发送目标.
+ * @author wangkuiwei
+ * @name TargetedMessage
+ * @desc 构建要发送的消息内容和消息的发送目标。
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class TargetedMessage {
+    const TARGET_TYPE_REGID = 1;
+    const TARGET_TYPE_ALIAS = 2;
+    const TARGET_TYPE_USER_ACCOUNT = 3;
+    private $targetType;
+    private $target;
+    /**
+     * @var Message
+     */
+    private $message;
+
+    public function __construct() {
+
+    }
+
+    public function setTarget($target, $targetType) {
+        $this->targetType = $targetType;
+        $this->target = $target;
+    }
+
+    public function setMessage(Message $message) {
+        $this->message = $message;
+    }
+
+    public function getFields() {
+        return array(
+            'target' => $this->target,
+            'message' => $this->message->getJSONInfos()
+        );
+    }
+}
+
+?>

+ 43 - 0
app/Libs/Push/XMPush/Tracer.php

@@ -0,0 +1,43 @@
+<?php
+/**
+ * 消息状态追踪API.
+ * @author wangkuiwei
+ * @name Tracer
+ * @desc 消息状态追踪API。
+ *
+ */
+namespace App\Libs\Push\XMPush;
+
+class Tracer extends HttpBase {
+
+    public function __construct() {
+        parent::__construct();
+    }
+
+    public function getMessageStatusById($msgId, $retries = 1) {
+        $fields = array(
+            'msg_id' => $msgId
+        );
+        $result = $this->getResult(PushRequestPath::V1_MESSAGE_STATUS(), $fields, $retries);
+        return $result;
+    }
+
+    public function getMessageStatusByJobKey($jobKey, $retries = 1) {
+        $fields = array(
+            'job_key' => $jobKey
+        );
+        $result = $this->getResult(PushRequestPath::V1_MESSAGE_STATUS(), $fields, $retries);
+        return $result;
+    }
+
+    public function getMessagesStatusByTimeArea($beginTime, $endTime, $retries = 1) {
+        $fields = array(
+            'begin_time' => $beginTime,
+            'end_time' => $endTime
+        );
+        $result = $this->getResult(PushRequestPath::V1_MESSAGES_STATUS(), $fields, $retries);
+        return $result;
+    }
+}
+
+?>