push.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. /**
  3. * 用户粉丝数:fans_count,很关键的一个参数;如果fans_count>5W时,需要使用专门服务器来处理:推送业务; and u.fans_count < 50000
  4. * 推送类型:pust_type 当会员数超过10W时,建议也要使用专门的服务器来处理:全服推送 类型的 and u.pust_type =0
  5. * @param int $min_fans 最小粉丝数
  6. * @param int $max_fans 最大粉丝数
  7. * @param array $pust_type 推送类型
  8. *
  9. *
  10. * 推送数据存储优化方案[备用]
  11. * 1、记录禁用推送功能的用户ID fanwe_user.is_remind
  12. * 2、记录不接受某个主播推送消息(主播ID,用户ID)
  13. * 3、在redis中建2张hash表【 push:ios user_id apns; push:android user_id apns】 可以在ctl=user&act=apns中更新
  14. * 4.1、全服推送时,只要取出3后,过滤1中的数据即可
  15. * 4.2、给某个主播推送时,通过$user_redis->followed_by($user_id)取出粉丝列表后,过滤1、2数量,然后分别3取并集即可
  16. *
  17. * 5、在fanwe_push_anchor表中,可以直接添加fans_count字段,插入表数据时,固化
  18. *
  19. */
  20. //服务器进程执行时间
  21. ini_set("max_execution_time", 600);//服务器会在 60 秒后强行中止正在执行的程序
  22. function push_notice($min_fans = 0,$max_fans = 0,$pust_type = array(0,1)){
  23. $sql = "select pa.id, pa.pust_type, pa.user_id, pa.nick_name, pa.city,pa.room_id, v.room_type from ".DB_PREFIX."push_anchor as pa
  24. left join ".DB_PREFIX."video as v on v.id = pa.room_id
  25. left join ".DB_PREFIX."user as u on u.id = pa.user_id
  26. where v.room_type = 3 and v.live_in= 1 and pa.status = 0 and u.mobile != '13888888888' and u.mobile != '13999999999' ";// pa.pust_type = 0 and u.fans_count < 50000
  27. if ($min_fans > 0) $sql .= ' and u.fans_count>='.$min_fans;
  28. if ($max_fans > 0) $sql .= ' and u.fans_count<='.$max_fans;
  29. if (is_array($pust_type) && count($pust_type) > 0) $sql .= ' and pa.pust_type in('.implode(',',$pust_type).")";
  30. $list = $GLOBALS['db']->getAll($sql,true,true);
  31. if (count($list)> 0){
  32. fanwe_require(APP_ROOT_PATH.'system/schedule/android_list_schedule.php');
  33. fanwe_require(APP_ROOT_PATH.'system/schedule/ios_list_schedule.php');
  34. fanwe_require(APP_ROOT_PATH.'system/schedule/android_file_schedule.php');
  35. fanwe_require(APP_ROOT_PATH.'system/schedule/ios_file_schedule.php');
  36. fanwe_require(APP_ROOT_PATH.'mapi/lib/redis/BaseRedisService.php');
  37. fanwe_require(APP_ROOT_PATH.'mapi/lib/redis/UserFollwRedisService.php');
  38. }
  39. foreach ($list as $k => $v )
  40. {
  41. //查询主播设备号
  42. $apns_code_sql = "select u.apns_code from ".DB_PREFIX."user as u where u.id =".$v['user_id'];
  43. $my_apns_code = $GLOBALS['db']->getOne($apns_code_sql,true,true);
  44. $sql = "update ".DB_PREFIX."push_anchor set status = 1 where status = 0 and id = ".$v['id'];
  45. $status = $GLOBALS['db']->query($sql);
  46. if($GLOBALS['db']->affected_rows()==1)
  47. {
  48. //$code_sql = "select u.apns_code,u.device_type from ".DB_PREFIX."video_private as vp left join ".DB_PREFIX."user as u on u.id = vp.user_id where u.is_effect =1 and u.device_type <> '' and vp.video_id =".$v['room_id'];
  49. //$code_list = $GLOBALS['db']->getAll($code_sql);
  50. //判断推送类型
  51. if($v['pust_type'] == 1){
  52. //查找全服推送【如果会员数大多如上百万时,建议使用独立的服务器来专门做推送,并做好缓存,直接分IOS,安卓缓存成友盟需要的文件格式】
  53. $code_sql = "select u.apns_code,u.device_type from ".DB_PREFIX."user as u where u.id not in(".$v['user_id'].") and u.device_type in (1,2) and u.is_effect =1 and u.is_remind=1";
  54. $code_list = $GLOBALS['db']->getAll($code_sql,true,true);
  55. }else{
  56. //查找粉丝推送
  57. $user_id = $v['user_id'];
  58. $code_list = array();
  59. $user_redis = new UserFollwRedisService($user_id);
  60. $list = $user_redis->followed_by($user_id);//获得粉丝列表,可能很大,如有上百W的粉丝,做推送时,需要独立的服务器来处理
  61. do{
  62. $keys = array_splice($list,0,4000);//一次读取4000条数据
  63. if (count($keys)>0){
  64. $user_list = implode(',',$keys);
  65. $code_sql = "select u.apns_code,u.device_type from ".DB_PREFIX."user as u where u.is_effect =1 and u.device_type in (1,2) and u.id in (".$user_list.") and u.is_remind=1";
  66. $apns_list = $GLOBALS['db']->getAll($code_sql,true,true);
  67. $code_list = array_merge($code_list,$apns_list);
  68. }
  69. }while (count($keys)>0);
  70. //$code_list = array_unique($code_list);//加上array_unique,合并时可以过滤重复的?
  71. /*
  72. $page =1;
  73. $page_size =1000;
  74. $code_list = array();
  75. do{
  76. //$list = $user_redis->get_follonging_by_user($user_id,$page,$page_size);
  77. $list = $user_redis->followed_by($user_id);
  78. $start = ($page-1)*$page_size;
  79. $keys = array_slice($list,$start,$page_size);
  80. //file_put_contents(APP_ROOT_PATH_PUSH."/public/push.txt", print_r($list,1),FILE_APPEND);
  81. $user_list = implode(',',$keys);
  82. $code_sql = "select u.apns_code,u.device_type from ".DB_PREFIX."user as u where u.is_effect =1 and u.device_type in (1,2) and u.id in (".$user_list.") and u.is_remind=1";
  83. //file_put_contents(APP_ROOT_PATH_PUSH."/public/push.txt", print_r($code_sql,1),FILE_APPEND);
  84. $apns_list = $GLOBALS['db']->getAll($code_sql,true,true);
  85. foreach($apns_list as $kk =>$vv){
  86. $code_list[] = $vv;
  87. }
  88. //$code_list = array_merge($code_list,$apns_list);
  89. $page = $page + 1;
  90. }while (count($keys) == $page_size);
  91. */
  92. }
  93. //推送消息文本
  94. $content =emoji_decode($v['nick_name'])."正在".$v['city']."直播,邀请你一起";
  95. $room_id = $v['room_id'];
  96. //过滤重复的推送数据数据
  97. $array = array_map('json_encode', $code_list);
  98. $array = array_unique($array);
  99. $code_list = array_map('json_decode', $array);
  100. $num =count($code_list);
  101. //大于10000条的推送,使用文件方式,小于1000条直接推送
  102. if(intval($num)>10000){
  103. $code_arr =array();
  104. $code_android_arr =array();
  105. $code_ios_arr =array();
  106. foreach($code_list as $ck =>$cv){
  107. $apns_code = $cv->apns_code;
  108. $device_type = $cv->device_type;
  109. //排除主播设备号
  110. if($my_apns_code==$apns_code||in_array($apns_code,$code_android_arr)||in_array($apns_code,$code_ios_arr)){
  111. continue;
  112. }
  113. if($device_type==1){
  114. $code_android_arr[] = $apns_code;
  115. }
  116. if($device_type==2){
  117. $code_ios_arr[] = $apns_code;
  118. }
  119. }
  120. if($code_android_arr){
  121. $code_android_file = implode("\n",$code_android_arr);
  122. }
  123. if($code_ios_arr){
  124. $code_ios_file = implode("\n",$code_ios_arr);
  125. }
  126. //device_type 1:安卓机型。2:ios
  127. //安卓推送信息
  128. if($code_android_arr){
  129. $AndroidFile = new android_file_schedule();
  130. $data = array(
  131. 'file_code' =>$code_android_file,
  132. 'content' =>$content,
  133. 'room_id'=>$room_id,
  134. 'type'=>0,
  135. );
  136. $return = $AndroidFile->exec($data);
  137. $sql = "update ".DB_PREFIX."push_anchor set ret_android_status = '".$return['res']['ret']."', ret_android_data = '".serialize($return['res']['data'])."', android_file_id = '".$return['file_id']."' where id = ".$v['id'];
  138. $GLOBALS['db']->query($sql);
  139. }
  140. //ios 推送信息
  141. if($code_ios_arr){
  142. $IosFile = new ios_file_schedule();
  143. $Ios_data = array(
  144. 'file_code' =>$code_ios_file,
  145. 'content' =>$content,
  146. 'room_id'=>$room_id,
  147. 'type'=>0,
  148. );
  149. $return = $IosFile->exec($Ios_data);
  150. $sql = "update ".DB_PREFIX."push_anchor set ret_ios_status = '".$return['res']['ret']."', ret_ios_data = '".serialize($return['res']['data'])."', ios_file_id = '".$return['file_id']."' where id = ".$v['id'];
  151. $GLOBALS['db']->query($sql);
  152. }
  153. }else{
  154. //得到机器码列表
  155. $apns_app_code_list = array();
  156. $apns_ios_code_list = array();
  157. $j=$i=0;
  158. foreach($code_list as $kk=>$vv){
  159. $apns_code = $vv->apns_code;
  160. $device_type = $vv->device_type;
  161. //排除主播设备号
  162. if($my_apns_code==$apns_code||in_array($apns_code,$apns_app_code_list)){
  163. continue;
  164. }
  165. //获取android机器码
  166. if($device_type==1){
  167. $apns_app_code_list[$i] = $apns_code;
  168. $i++;
  169. }
  170. //获取IOS机器码
  171. if($device_type==2){
  172. $apns_ios_code_list[$j] = $apns_code;
  173. $j++;
  174. }
  175. //安卓推送信息
  176. if($i%500==0&&$i!=0){
  177. $AndroidList = new android_list_schedule();
  178. $android_dest = implode(",",$apns_app_code_list);
  179. $data = array(
  180. 'dest' =>$android_dest,
  181. 'content' =>$content,
  182. 'room_id'=>$room_id,
  183. 'type'=>0,
  184. );
  185. $return = $AndroidList->exec($data);
  186. $sql = "update ".DB_PREFIX."push_anchor set ret_android_status = '".$return['res']['ret']."', ret_android_data = '".serialize($return['res']['data'])."' where id = ".$v['id'];
  187. $GLOBALS['db']->query($sql);
  188. //重置机器列表
  189. $i=0;
  190. unset($apns_app_code_list);
  191. }
  192. //ios 推送信息
  193. if($j%500==0&&$j!=0){
  194. $IosList = new ios_list_schedule();
  195. $ios_dest = implode(",",$apns_ios_code_list);
  196. $ios_data1 = array(
  197. 'dest' =>$ios_dest,
  198. 'content' =>$content,
  199. 'room_id'=>$room_id,
  200. 'type'=>0,
  201. );
  202. $return = $IosList->exec($ios_data1);
  203. // ios_dest = '".$ios_dest."',
  204. $sql = "update ".DB_PREFIX."push_anchor set ret_ios_status = '".$return['res']['ret']."', ret_ios_data = '".serialize($return['res']['data'])."' where id = ".$v['id'];
  205. $GLOBALS['db']->query($sql);
  206. //重置机器列表
  207. $j=0;
  208. unset($apns_ios_code_list);
  209. }
  210. }
  211. //安卓推送信息
  212. if(count($apns_app_code_list)>0){
  213. $AndroidList = new android_list_schedule();
  214. $android_dest = implode(",",$apns_app_code_list);
  215. $data = array(
  216. 'dest' =>$android_dest,
  217. 'content' =>$content,
  218. 'room_id'=>$room_id,
  219. 'type'=>0,
  220. );
  221. $return = $AndroidList->exec($data);
  222. $sql = "update ".DB_PREFIX."push_anchor set ret_android_status = '".$return['res']['ret']."', ret_android_data = '".serialize($return['res']['data'])."' where id = ".$v['id'];
  223. $GLOBALS['db']->query($sql);
  224. //打印推送列表
  225. //$this->chack_push_notice($android_dest);
  226. //$this->chack_push_notice($return);
  227. }
  228. //ios 推送信息
  229. if(count($apns_ios_code_list)>0){
  230. $IosList = new ios_list_schedule();
  231. $ios_dest = implode(",",$apns_ios_code_list);
  232. $ios_data = array(
  233. 'dest' =>$ios_dest,
  234. 'content' =>$content,
  235. 'room_id'=>$room_id,
  236. 'type'=>0,
  237. );
  238. $return = $IosList->exec($ios_data);
  239. $sql = "update ".DB_PREFIX."push_anchor set ret_ios_status = '".$return['res']['ret']."', ret_ios_data = '".serialize($return['res']['data'])."' where id = ".$v['id'];
  240. $GLOBALS['db']->query($sql);
  241. }
  242. //打印推送列表
  243. //$this->chack_push_notice($android_dest);
  244. //$this->chack_push_notice($return);
  245. }
  246. //推送结束
  247. $sql = "update ".DB_PREFIX."push_anchor set status = 2 where status = 1 and id = ".$v['id'];
  248. $GLOBALS['db']->query($sql);
  249. }
  250. }
  251. return true;
  252. }
  253. // @param array or string $dates
  254. function chack_push_notice($dates){
  255. if(IS_DEBUG){
  256. $api_log = array();
  257. if(is_array($dates)){
  258. $parma= implode('',$dates);
  259. }else{
  260. $parma = $dates;
  261. }
  262. $api_log['parma'] = $parma;
  263. $GLOBALS['db']->autoExecute(DB_PREFIX."api_log", $api_log,'INSERT');
  264. }
  265. }
  266. ?>