讀古今文學網 > 微信公眾平台開發:從零基礎到ThinkPHP5高性能框架實踐 > 6.6.2 同步所有用戶信息 >

6.6.2 同步所有用戶信息

很多時候,公眾號需要將微信用戶的信息導出到自己的服務器上。其實現流程如下。

首先設計一個表,用於存儲用戶的基本信息。創建表的SQL語句如下。


CREATE TABLE IF NOT EXISTS 'tp_user' (
    'id' bigint(9) NOT NULL AUTO_INCREMENT COMMENT '序號',
    'openid' varchar(30) NOT NULL COMMENT '微信id',
    'nickname' varchar(20) NOT NULL COMMENT '暱稱',
    'sex' varchar(4) NOT NULL COMMENT '性別',
    'country' varchar(10) NOT NULL COMMENT '國家',
    'province' varchar(16) NOT NULL COMMENT '省份',
    'city' varchar(16) NOT NULL COMMENT '城市',
    'headimgurl' varchar(200) NOT NULL COMMENT '頭像',
    'subscribe' varchar(15) NOT NULL COMMENT '關注時間',
    PRIMARY KEY ('id'),
    UNIQUE KEY 'openid' ('openid')
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
  

在微信類文件中,定義獲取用戶列表及獲取用戶基本信息的接口。


 1 class class_weixin
 2 {
 3     var $appid = APPID;
 4     var $appsecret = APPSECRET;
 5 
 6     // 構造函數,獲取Access Token
 7     public function __construct($appid = NULL, $appsecret = NULL)
 8     {
 9         if($appid && $appsecret){
10             $this->appid = $appid;
11             $this->appsecret = $appsecret;
12         }
13         // 緩存形式
14         if (isset($_SERVER['HTTP_APPNAME'])){                // SAE環境,需要開通memcache
15             $mem = memcache_init();
16         }else {                                                // 本地環境,須安裝memcache
17             $mem = new Memcache;
18             $mem->connect('localhost', 11211) or die ("Could not connect");
19         }
20         $this->access_token = $mem->get($this->appid);
21         if (!isset($this->access_token) || empty($this->access_token)){
22             $url = "https:// api.weixin.qq.com/cgi-bin/token?grant_type=client_creden
               tial&appid=".$this->appid."&secret=".$this->appsecret;
23             $res = $this->http_request($url);
24             $result = json_decode($res, true);
25             $this->access_token = $result["access_token"];
26             $mem->set($this->appid, $this->access_token, 0, 3600);
27         }
28     }
29 
30     // 獲取用戶列表
31     public function get_user_list($next_openid = NULL)
32     {
33         $url = "https:// api.weixin.qq.com/cgi-bin/user/get?access_token=".$this->
       access_token."&next_openid=".$next_openid;
34         $res = $this->http_request($url);
35         $list = json_decode($res, true);
36         if ($list["count"] == 10000){
37             $new = $this->get_user_list($next_openid = $list["next_openid"]);
38             $list["data"]["openid"] = array_merge_recursive($list["data"]["open
               id"], $new["data"]["openid"]); // 合併OpenID列表
39         }
40         return $list;
41     }
42 
43     // 獲取用戶基本信息
44     public function get_user_info($openid)
45     {
46         $url = "https:// api.weixin.qq.com/cgi-bin/user/info?access_token=".$this->
           access_token."&openid=".$openid."&lang=zh_CN";
47         $res = $this->http_request($url);
48         return json_decode($res, true);
49     }
50 
51     // HTTP請求(支持HTTP/HTTPS,支持GET/POST)
52     protected function http_request($url, $data = null)
53     {
54         $curl = curl_init();
55         curl_setopt($curl, CURLOPT_URL, $url);
56         curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
57         curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
58         if (!empty($data)){
59             curl_setopt($curl, CURLOPT_POST, 1);
60             curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
61         }
62         curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
63         $output = curl_exec($curl);
64         curl_close($curl);
65         return $output;
66     }
67 }
  

在獲取用戶列表的實現過程中,使用了遞歸函數。首先獲取10000名用戶的列表(第33~35行),如果發現本次統計的OpenID數為10000(第36行),一般意味著還有沒有拉取到的用戶,這時就將本次取得的netx_openid作為遞歸中的起始OpenID(第37行)。當取到新的用戶OpenID列表時,將新的OpenID列表合併到上次取得的OpenID列表中(第38行)。

數據庫類文件的實現如下。


 1 class class_mysql
 2 {
 3     function __construct(){
 4         $host = MYSQLHOST;
 5         $port = MYSQLPORT;
 6         $user = MYSQLUSER;
 7         $pwd =  MYSQLPASSWORD;
 8         $dbname = MYSQLDATABASE;
 9         $link = @mysql_connect("{$host}:{$port}", $user, $pwd, true);
10         mysql_query("SET NAMES 'UTF8'");
11         mysql_select_db($dbname, $link);
12     }
13 
14     // 執行SQL
15     function query($sql)
16     {
17         if (!($query = mysql_query($sql))){
18             return $query;
19         }
20         return $query;
21     }
22     
23     // 返回數組
24     function query_array($sql){
25         $result = mysql_query($sql);
26         if(!$result)return false;
27         $arr = array();
28         while ($row = mysql_fetch_array($result)) {
29             $arr[] = $row;
30         }
31         return $arr;
32     }
33 }
 

上述代碼解讀如下。

第3~12行:類的構造函數,主要功能是連接數據庫,設置字符集,選擇要連接的數據庫。

第15~21行:執行原生的SQL語句。

第24~32行:執行SQL語句,並將結果以數組的形式返回。

上述準備工作做好之後,就開始獲取用戶列表,並將每個用戶的OpenID存到數據庫中,代碼如下。


 1 require_once('weixin.class.php');
 2 $weixin = new class_weixin();
 3 
 4 require_once('mysql.class.php');
 5 $db = new class_mysql();
 6 
 7 // 拉取用戶列表
 8 $userlist = $weixin->get_user_list();
 9 for($i = 0; $i < count($userlist["data"]["openid"]); $i++)
10 {
11     $openid = $userlist["data"]["openid"][$i];
12     $mysql_state = "INSERT INTO 'tp_user' ('id', 'openid') VALUES (NULL, '".$open
       id."');";
13     $result = $db->query($mysql_state);
14 }
  

更新用戶信息的代碼如下。


 1 <?php
 2 header("Content-type: text/html; charset=utf-8");
 3 
 4 require_once('weixin.class.php');
 5 $weixin = new class_weixin();
 6 
 7 require_once('mysql.class.php');
 8 $db = new class_mysql();
 9 
10 $mysql_state = "SELECT * FROM 'tp_user' WHERE 'subscribe' = '' LIMIT 0, 1";
11 $result = $db->query_array($mysql_state);
12 
13 $sexes = array("", "男", "女");
14 if (count($result) > 0){
15     $openid = $result[0]["openid"];
16     var_dump($openid);
17     $info = $weixin->get_user_info($openid);
18     var_dump($info);
19     $mysql_state2 = "UPDATE 'tp_user' SET 
20         'sex' = '".$sexes[$info['sex']]."', 
21         'country' = '".$info['country']."', 
22         'province' = '".$info['province']."', 
23         'city' = '".$info['city']."', 
24         'headimgurl' = '".$info['headimgurl']."',
25         'subscribe' = '".$info['subscribe_time']."'
26         WHERE 'openid' = '".$openid."';";
27     $result = $db->query($mysql_state2);
28     $mysql_state3 = "UPDATE 'tp_user' SET 'nickname' = '".$info['nickname']."' 
       WHERE 'openid' = '".$openid."';";
29     $result = $db->query($mysql_state3);
30     echo "<script language=JavaScript> location.replace(location.href);</script>";
31 }else{
32     echo "over";
33 }
  

上述代碼解讀如下。

第2行:設置編碼為UTF-8,以便顯示內容的頁面不會亂碼。

第4~8行:包含數據庫類文件及微信類文件。

第10~11行:檢索一個沒有更新用戶信息的記錄,這裡以subscribe字段為空作為檢測條件。

第13~30行:如果記錄存在,則讀取這個記錄的OpenID,並查詢該用戶的基本信息,然後將除了暱稱之外的所有信息寫入數據庫,之後再將暱稱更新到數據庫。完成之後,使用JavaScript將該頁面刷新進行下一個用戶記錄的更新。

第31~33行:如果沒有要更新的用戶記錄,則返回一個提示。

用戶同步到服務器後的記錄如圖6-2所示。

圖6-2 同步到服務器的用戶信息列表