WeChatAdService.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <?php
  2. namespace app\main\service;
  3. use app\common\library\Redis;
  4. use app\common\library\WeChatObject;
  5. use EasyWeChat\Factory;
  6. use GuzzleHttp\Client as Http;
  7. use GuzzleHttp\Exception\GuzzleException;
  8. use Symfony\Component\Cache\Simple\RedisCache;
  9. use think\Config;
  10. use think\Exception;
  11. use think\Log;
  12. class WeChatAdService extends BaseService {
  13. private $bashUrl = 'https://api.weixin.qq.com/marketing/';
  14. const ACTION_TYPE_COMPLETE_ORDER = 'COMPLETE_ORDER'; //下单
  15. const ACTION_TYPE_REGISTER = 'REGISTER'; //关注即注册
  16. public $error_msg = '';
  17. /**
  18. * @var WeChatAdService
  19. */
  20. protected static $self = NULL;
  21. /**
  22. * @return WeChatAdService
  23. */
  24. public static function instance()
  25. {
  26. if (self::$self == NULL) {
  27. self::$self = new self();
  28. }
  29. return self::$self;
  30. }
  31. /**
  32. * 上传微信数据源
  33. * @param $admin_id
  34. * @param $params ['url', 'open_id', 'money', 'product_name', 'product_id', 'action_type']
  35. * @return bool
  36. */
  37. //public function SendWxAdSource($admin_id,$url,$open_id, $money, $product_name = '', $action_type = 'COMPLETE_ORDER'){
  38. public function SendWxAdSource($admin_id, $params){
  39. if($adminConfig = model('AdminConfig')->getAdminInfoAll($admin_id)){
  40. $wx_ad_state = intval($adminConfig['wx_ad_state'] ?? 0);
  41. $wx_ad_source_id = $adminConfig['wx_ad_source_id'] ?? '';
  42. //微信AD数据源开启时&数据源ID存在时,上传数据
  43. if($wx_ad_state && $wx_ad_source_id){
  44. $weChatConfig = Config::get('wechat');
  45. $weChatConfig['http']['base_uri'] = 'https://api.weixin.qq.com/';
  46. $weChatConfig['app_id'] = $adminConfig['platform_appid'];
  47. $weChatConfig['secret'] = $adminConfig['platform_secret'];
  48. $weChatConfig['token'] = $adminConfig['platform_token'];
  49. $weChatConfig['aes_key'] = $adminConfig['platform_aes_key'];
  50. $openPlatform = Factory::openPlatform($weChatConfig);
  51. $openPlatform['cache'] = new RedisCache(Redis::instanceCache());
  52. $officialAccount = $openPlatform->officialAccount($adminConfig['appid'], $adminConfig['refresh_token']);
  53. $access_token = current($officialAccount->access_token->getToken());
  54. $source_params = [
  55. 'admin_id' => $adminConfig['admin_id'],
  56. 'access_token' => $access_token,
  57. 'wx_ad_source_id' => $wx_ad_source_id,
  58. 'url' => $params['url'],
  59. 'app_id' => $adminConfig['appid'],
  60. 'open_id' => $params['open_id'],
  61. 'money' => $params['money'],
  62. 'product_name' => $params['product_name'],
  63. 'product_id' => $params['product_id'],
  64. 'action_type' => $params['action_type'],
  65. ];
  66. return $this->sendAdSource($source_params);
  67. }
  68. }
  69. return false;
  70. }
  71. /**
  72. * 渠道创建微信AD数据源ID
  73. * @param $admin_id
  74. * @return bool|string
  75. */
  76. public function createChannelWxAdSourceId($admin_id){
  77. if($adminConfig = model('AdminConfig')->getAdminInfoAll($admin_id)){
  78. $wx_ad_state = intval($adminConfig['wx_ad_state'] ?? 0);
  79. $wx_ad_source_id = $adminConfig['wx_ad_source_id'] ?? '';
  80. if( $wx_ad_state && empty($wx_ad_source_id) ){
  81. $weChatConfig = Config::get('wechat');
  82. $weChatConfig['http']['base_uri'] = 'https://api.weixin.qq.com/';
  83. $weChatConfig['app_id'] = $adminConfig['platform_appid'];
  84. $weChatConfig['secret'] = $adminConfig['platform_secret'];
  85. $weChatConfig['token'] = $adminConfig['platform_token'];
  86. $weChatConfig['aes_key'] = $adminConfig['platform_aes_key'];
  87. $openPlatform = Factory::openPlatform($weChatConfig);
  88. $openPlatform['cache'] = new RedisCache(Redis::instanceCache());
  89. $officialAccount = $openPlatform->officialAccount($adminConfig['appid'], $adminConfig['refresh_token']);
  90. $access_token = current($officialAccount->access_token->getToken());
  91. if($wx_ad_source_id = $this->createAdSourceId($adminConfig['admin_id'],$access_token, $adminConfig['appid'],'CPS下单','CPS下单')){
  92. $update = model('AdminConfig')->where('admin_id',$adminConfig['admin_id'])->update(['wx_ad_source_id'=>$wx_ad_source_id]);
  93. if($update === false){
  94. $this->error_msg = 'Write Db Fail';
  95. Log::notice("WeChatAd: AdminId:{$adminConfig['admin_id']} AdSourceId:{$wx_ad_source_id} WriteWeChatAdSourceId To Mysql Fail");
  96. return false;
  97. }
  98. model('AdminConfig')->delAdminInfoAllCache($adminConfig['admin_id']);
  99. return $wx_ad_source_id;
  100. }
  101. }
  102. }
  103. return false;
  104. }
  105. /**
  106. * 查看数据源报表
  107. * @param $admin_id
  108. * @param $access_token
  109. * @param $source_id
  110. * @param $start_time
  111. * @param $end_time
  112. * @return mixed|\Psr\Http\Message\ResponseInterface|null
  113. */
  114. private function searchAdSource($admin_id,$access_token,$source_id,$start_time,$end_time){
  115. try{
  116. $httpConfig = [
  117. 'base_uri' => $this->bashUrl,
  118. 'connect_timeout' => 10,
  119. 'timeout' => 30,
  120. 'http_errors' => true, //抛出异常 true是 false否
  121. 'verify' => false, //不验证ssl证书
  122. ];
  123. $proxy = OpenPlatformService::instance()->getProxyconfigByChannel($admin_id);
  124. if ($proxy) {
  125. $httpConfig = array_merge($httpConfig, ['proxy' => $proxy]);
  126. }
  127. $client = new Http($httpConfig);
  128. $data = ['start_date' => $start_time, 'end_date' => $end_time];
  129. $result = $client->get("user_action_set_reports/get?version=v1.0&access_token=$access_token&user_action_set_id=$source_id&time_granularity=HOURLY&aggregation=RESERVATION&date_range=".urlencode(json_encode($data)));
  130. if($result = json_decode($result->getBody(),true)){
  131. return $result;
  132. }
  133. }catch (\Exception $e){
  134. $this->error_msg = $e->getMessage();
  135. Log::error("WeChatAd: AdminId:{$admin_id} CreateAdSourceId Fail,Error:".$e->getMessage());
  136. return null;
  137. }
  138. return null;
  139. }
  140. /**
  141. * 上传微信AD数据源信息
  142. * @param $params ['admin_id' ,'access_token' , 'wx_ad_source_id' ,'url' ,'app_id' ,'open_id' ,'money' ,'product_name' ,'product_id' ,'action_type' ]
  143. * @return bool
  144. */
  145. //private function sendAdSource($admin_id,$access_token,$wx_source_id,$url,$app_id,$open_id, $money, $product_name = '', $action_type)
  146. private function sendAdSource($params)
  147. {
  148. try{
  149. $httpConfig = [
  150. 'base_uri' => $this->bashUrl,
  151. 'connect_timeout' => 10,
  152. 'timeout' => 30,
  153. 'http_errors' => true, //抛出异常 true是 false否
  154. 'verify' => false, //不验证ssl证书
  155. ];
  156. $proxy = OpenPlatformService::instance()->getProxyconfigByChannel($params['admin_id']);
  157. if ($proxy) {
  158. $httpConfig = array_merge($httpConfig, ['proxy' => $proxy]);
  159. }
  160. $client = new Http($httpConfig);
  161. $data['actions'][0] = [
  162. 'user_action_set_id' => $params['wx_ad_source_id'],
  163. 'action_type' => $params['action_type'],
  164. 'action_time' => time(),
  165. 'url' => $params['url'],
  166. 'user_id' => [
  167. 'wechat_app_id' => $params['app_id'],
  168. 'wechat_openid' => $params['open_id'],
  169. ],
  170. 'action_param' => [
  171. "product_name" => $params['product_name'],
  172. "product_id" => $params['product_id'],
  173. "value" => intval($params['money'] * 100),
  174. "source" => "Biz",
  175. "wechat_app_id" => $params['app_id'],
  176. 'claim_type' => 0
  177. ]
  178. ];
  179. $result = $client->request('POST',
  180. "user_actions/add?version=v1.0&access_token=".$params['access_token'],
  181. [
  182. 'headers' => [
  183. 'Content-Type' => 'application/json',
  184. 'charset' => 'utf-8'
  185. ],
  186. 'body' => json_encode($data)
  187. ]
  188. );
  189. Log::info("WeChatMpApiHeader:".json_encode($result->getHeaders()));
  190. if($result = json_decode($result->getBody(),true)){
  191. if(intval($result['errcode'])){
  192. $this->error_msg = $result['errmsg'];
  193. Log::notice("WeChatAd: AdminId:{$params['admin_id']} SendWeChatSource Fail Data:".json_encode($data)." Error:".$result['errmsg']);
  194. return false;
  195. }else{
  196. Log::info("WeChatAd: AdminId:{$params['admin_id']} SendWeChatSource Success Data:".json_encode($data));
  197. return true;
  198. }
  199. }
  200. }catch (\Exception $e){
  201. $this->error_msg = $e->getMessage();
  202. Log::error("WeChatAd: AdminId:{$params['admin_id']} source_id:{$params['wx_ad_source_id']} SendWeChatSource Fail,Error:".$e->getMessage());
  203. return false;
  204. }
  205. return false;
  206. }
  207. /**
  208. * 创建微信AD数据源
  209. * @param $admin_id
  210. * @param $accessToken
  211. * @param $name
  212. * @param $des
  213. * @param string $type
  214. * @return bool
  215. */
  216. private function createAdSourceId($admin_id,$accessToken,$app_id,$name,$des,$type = 'WECHAT', $platform_id=null){
  217. try{
  218. //判断是否已经获取
  219. $key = 'ASAD:'.$app_id;
  220. if (($id = Redis::instance()->get($key)) !== false) {
  221. return $id;
  222. }
  223. $httpConfig = [
  224. 'base_uri' => $this->bashUrl,
  225. 'connect_timeout' => 10,
  226. 'timeout' => 30,
  227. 'http_errors' => true, //抛出异常 true是 false否
  228. 'verify' => false, //不验证ssl证书
  229. ];
  230. if (!is_null($platform_id)) {
  231. $proxy = OpenPlatformService::instance()->getProxyconfigById($platform_id);
  232. if ($proxy) {
  233. $httpConfig = array_merge($httpConfig, ['proxy' => $proxy]);
  234. }
  235. } else {
  236. $proxy = OpenPlatformService::instance()->getProxyconfigByChannel($admin_id);
  237. if ($proxy) {
  238. $httpConfig = array_merge($httpConfig, ['proxy' => $proxy]);
  239. }
  240. }
  241. $client = new Http($httpConfig);
  242. $data = ['type' => $type, 'name' => $name, 'description' => $des,'wechat_app_id'=>$app_id];
  243. $result = $client->request('POST',
  244. "user_action_sets/add?version=v1.0&access_token=$accessToken",
  245. [
  246. 'headers' => [
  247. 'Content-Type' => 'application/json',
  248. 'charset' => 'utf-8'
  249. ],
  250. 'body' => json_encode($data)
  251. ]
  252. );
  253. if($result = json_decode($result->getBody(),true)){
  254. if(intval($result['errcode'])){
  255. //失败
  256. if(intval($result['errcode']) == 900351000){
  257. //已存在时,截取ID,并返回成功
  258. $errMsg = explode(':',$result['errmsg']);
  259. $wx_ad_source_id = intval(end($errMsg)) ?? false;
  260. Log::info("WeChatAd: AdminId:{$admin_id} CreateAdSourceId Exists source_id:{$wx_ad_source_id} Data:".json_encode($result));
  261. return $wx_ad_source_id;
  262. }else{
  263. //失败时处理
  264. $this->error_msg = $result['errmsg'];
  265. Log::notice("WeChatAd: AdminId:{$admin_id} CreateAdSourceId Fail,Error:".$result['errmsg']);
  266. return false;
  267. }
  268. }else{
  269. //成功
  270. Log::info("WeChatAd: AdminId:{$admin_id} CreateAdSourceId Success Data:".json_encode($result));
  271. return $result['data']['user_action_set_id'] ?? false;
  272. }
  273. }
  274. }catch (\Exception $e){
  275. $this->error_msg = $e->getMessage();
  276. Log::error("WeChatAd: AdminId:{$admin_id} CreateAdSourceId Fail,Error:".$e->getMessage());
  277. return false;
  278. }
  279. }
  280. /**
  281. * 指定平台 执行微信的 AD
  282. * @param $app_id
  283. * @param $platform_id
  284. */
  285. public function createWxAdSourceId($app_id, $platform_id, $refresh_token)
  286. {
  287. $access_token = current((new WeChatObject(null))->getOfficialAccountByPlatform($platform_id, $app_id, $refresh_token)->access_token->getRefreshedToken());
  288. if(
  289. $wx_ad_source_id = $this->createAdSourceId(null,$access_token, $app_id,'CPS下单','CPS下单', 'WECHAT', $platform_id)
  290. ){
  291. return $wx_ad_source_id;
  292. } else {
  293. Log::notice("AbWeChatAd: appid:{$app_id} CreateAdSourceId Fail,Error:");
  294. }
  295. return false;
  296. }
  297. /**
  298. * 调用接口
  299. * @param $httpConfig
  300. * @param $access_token
  301. * @param $data
  302. * @return bool
  303. */
  304. public function send($httpConfig,$access_token, $data, $api_url = 'user_actions/add')
  305. {
  306. try{
  307. $httpConfig['base_uri'] = $this->bashUrl;
  308. $client = new Http($httpConfig);
  309. $result = $client->request('POST',
  310. $api_url. "?version=v1.0&access_token=$access_token",
  311. [
  312. 'headers' => [
  313. 'Content-Type' => 'application/json',
  314. 'charset' => 'utf-8'
  315. ],
  316. 'body' => json_encode($data)
  317. ]
  318. );
  319. if($result = json_decode($result->getBody(),true)){
  320. if(intval($result['errcode'])){
  321. $this->error_msg = $result['errmsg'];
  322. Log::error("AbWeChatAd: SendWeChatSource Fail Data:".json_encode($data)." Error:".$result['errmsg']);
  323. return false;
  324. }else{
  325. Log::info("AbWeChatAd: SendWeChatSource Success Data:".json_encode($data));
  326. return true;
  327. }
  328. }
  329. }catch (\Exception $e){
  330. $this->error_msg = $e->getMessage();
  331. Log::error("AbWeChatAd: SendWeChatSource Fail,Error:".$e->getMessage());
  332. return false;
  333. }
  334. return false;
  335. }
  336. }