php微信公众号开发
一、Introduction
微信公众号是一个平台。目前,提供了4类帐号,订阅号、服务号、小程序、企业微信。具体区别在官网有说明。
二、使用接口测试号开发
1. 申请接口测试号
平台提供了接口测试号。到公众平台开发者文档,可以申请测试号开发。申请后提供appID和appsecret等,以供开发使用。
2. access_token
access_token是公众号的全局唯一接口调用凭证,调用接口时都需使用access_token,以提高安全性。access_token的请求方式,通过客户端,或通过企业服务器。获取方式三种,
第一种,通过浏览器访问url,https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
第二种,通过微信平台获取,在开发者文档获取access_token,点击使用网页调试工具调试该接口;
第三种,编写php程序来获取,使用cURL函数库,client url library。使用curl,先在php.ini开启curl的扩展。
<?php
/**
* 使用curl函数
*/
function_request($curl, $https=true, $method='get', $data=null)
{
//初始化
$ch = curl_init();
//设置url
curl_setopt($ch, CURLOPT_URL, $curl);
//设置不需要头信息
curl_setopt($ch, CURLOPT_HEADER,false);
//至获取页面内容,但不输出
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
if($https)
{
//设置不做服务器认证
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false);
//不做客户端认证
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST, false);
}
if($method == 'post')
{
//设置请求方式为post
curl_setopt($ch,CURLOPT_POST, true);
//设置请求数据
curl_setopt($ch,CURLOPT_POSTFIELDS, $data);
}
//执行并接收输出
$str = curl_exec($ch);
//释放资源
curl_close($ch);
return $str;
}
echo _request("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx49119aeb8923abfd&secret=96e13016d1cb24026545e5ed7c133fac");
/**
* 获取access_token
*/
function_getAccesstoken()
{
$file = './accessToken.txt';
//判断文件是否存在
if(file_exists($file))
{
$content =file_get_contents($file);
//json解码文件的内容
$content =json_decode($content);
//判断是否过期
if(time() - filemtime($file)< $content->expires_in)
{
return$content->access_token;
}
}
$content =_request("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx49119aeb8923abfd&secret=96e13016d1cb24026545e5ed7c133fac");
file_put_contents($file, $content);
$content = json_decode($content);
return $content->access_token;
}
echo_getAccesstoken();
3. 使用php封装一个获取access_token的工具类
<?php
/**
* 定义微信工具类
*/
class WeChat
{
//appid
private $_appid;
//appsecret
private $_appsecret;
//token
private $_token;
/**********************************************************/
/**
* 构造函数
*/
public function __construct($appid,$appsecret, $token)
{
$this->_appid = $appid;
$this->_appsecret =$appsecret;
$this->_token = $token;
}
/**
* 使用curl函数抓取url内容
*/
private function _request($curl,$https=true, $method='get', $data=null)
{
//初始化
$ch = curl_init();
//设置url
curl_setopt($ch, CURLOPT_URL,$curl);
//设置不需要头信息
curl_setopt($ch,CURLOPT_HEADER, false);
//至获取页面内容,但不输出
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
if($https)
{
//设置不做服务器认证
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false);
//不做客户端认证
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST, false);
}
if($method == 'post')
{
//设置请求方式为post
curl_setopt($ch,CURLOPT_POST, true);
//设置请求数据
curl_setopt($ch,CURLOPT_POSTFIELDS, $data);
}
//执行并接收输出
$str = curl_exec($ch);
//释放资源
curl_close($ch);
return $str;
}
/**
* 获取access_token
*/
private function _getAccesstoken()
{
$file = './accessToken.txt';
//判断文件是否存在
if(file_exists($file))
{
$content =file_get_contents($file);
//json解码文件的内容
$content =json_decode($content);
//判断是否过期
if(time() -filemtime($file) < $content->expires_in)
{
return $content->access_token;
}
}
$content =_request("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->_appid."&secret=".$this->_appsecret);
file_put_contents($file,$content);
$content = json_decode($content);
return$content->access_token;
}
}
4. 生成带参数的二维码
QR Code,Quick Response Code。用于用户渠道推广分析和用户帐号绑定等场景。分为临时二维码和永久二维码。获取的步骤,创建二维码ticket,凭借ticket到指定url获取二维码。
获取ticket
在工具类中添加获取ticket的方法
/**
* 获取ticket
* expires_seconds,int,二维码的有效期,单位s;
* type,str,二维码的类型,永久或临时;
* scene,int,使用二维码场景编号;
*/
public function_getTicket($expires_seconds = 604800, $type = "temp", $scene = 1)
{
if($type == "temp")
{
$data ='{"expire_seconds": '.$expires_seconds.', "action_name":"QR_STR_SCENE", "action_info": {"scene":{"scene_str": "'.$scene.'"}}}';
return$this->_request("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$this->_getAccesstoken(),true, "post", $data);
}
else
{
$data ='{"action_name": "QR_LIMIT_STR_SCENE","action_info": {"scene": {"scene_str":"'.$scene.'"}}}';
return$this->_request("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$this->_getAccesstoken(),true, "post", $data);
}
}
通过ticket获取二维码
在类中添加获取二维码的方法
/**
* 获取二维码的方法
*/
public function_getQRCode($expires_seconds = '604800', $type = 'temp', $scene = 1)
{
$content =$this->_getTicket($expires_seconds, $type, $scene);
$content =json_decode($content);
$ticket =$content->ticket;
$image =$this->_request("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".urlencode($ticket));
$file ="./".date("Y-m-d").'_'.$type.$scene.".jpg";
file_put_contents($file,$image);
return $image;
}
测试获取二维码的方法
<?php
define("APPID","wx49119aeb8923abfd");
define("APPSECRET","96e13016d1cb24026545e5ed7c133fac");
define("TOKEN","");
require'./Wechat.class.php';
header('Content-type:image/jpg');
$wechat = newWeChat(APPID, APPSECRET, TOKEN);
// echo $wechat->_getTicket($expires_seconds= 604800, $type = "yongjiu", $scene = 2);
echo$wechat->_getQRCode(604800, 'temp', 5);
5. 接口配置
接入校验,就是微信服务器地址是否正确。在接收消息时,要验证消息真实性。
平台官网提供了验证的样本代码,可以修改token为自己需要的。
<?php
/**
* wechat php test
* update time: 20141008
*/
//define your token
define("TOKEN","testwechat");//可以修改TOKEN
$wechatObj = newwechatCallbackapiTest();
$data = array();
$data[] =$_SERVER['REMOTE_ADDR'];
$data[] =$_SERVER['QUERY_STRING'];
$file ='./server.log';
//输出服务端信息,用于检测状态,如果无法写入文件,请修改父目录权限
file_put_contents($file,$data);
$wechatObj->valid();
classwechatCallbackapiTest
{
public function valid()
{
$echoStr = $_GET["echostr"];
//valid signature , option
if($this->checkSignature()){
echo$echoStr;
exit;
}
}
public function responseMsg()
{
//get post data, May be dueto the different environments
$postStr =$GLOBALS["HTTP_RAW_POST_DATA"];
//extractpost data
if (!empty($postStr)){
$postObj= simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername =$postObj->FromUserName;
$toUsername =$postObj->ToUserName;
$keyword =trim($postObj->Content);
$time = time();
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
if(!empty($keyword ))
{
$msgType= "text";
$contentStr = "Welcome to wechat world!";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername,$time, $msgType, $contentStr);
echo $resultStr;
}else{
echo "Input something...";
}
}else {
echo"";
exit;
}
}
private function checkSignature()
{
$signature =$_GET["signature"];
$timestamp =$_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token,$timestamp, $nonce);
sort($tmpArr, SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}
?>
如果token能对的上,就配置成功。一次成功后,后续微信平台就知道了这个接口的使用者。除非更改了url或者token,可以再次验证。
为了便于通过类来管理,可以将样本提供的方法,复制到wechat的工具类中。那么,index.php不需要写这个类了。
然后在index.php中
<?php
define("APPID","wx49119aeb8923abfd");
define("APPSECRET","96e13016d1cb24026545e5ed7c133fac");
define("TOKEN","testwechat");
require("./WeChat.class.php");
//header('Content-type:image/jpg');
$wechat = newWeChat(APPID, APPSECRET, TOKEN);
// echo$wechat->_getTicket($expires_seconds = 604800, $type = "yongjiu",$scene = 2);
// echo$wechat->_getQRCode(604800, 'temp', 5);
$wechat->valid();
6. 接收普通消息
普通消息分为文本消息、图片消息、语音消息、视频消息、地理位置消息、链接信息等。也是使用平台提供的模版,就是上述验证的第二个方法responseMsg()
<?php
define("APPID","wx49119aeb8923abfd");
define("APPSECRET","96e13016d1cb24026545e5ed7c133fac");
define("TOKEN","testwechat");
require("./WeChat.class.php");
// header('Content-type:image/jpg');
$wechat = newWeChat(APPID, APPSECRET, TOKEN);
// echo$wechat->_getTicket($expires_seconds = 604800, $type = "yongjiu",$scene = 2);
// echo$wechat->_getQRCode(604800, 'temp', 5);
//$wechat->valid();//一次验证,可以延续使用,无需多次验证,除非验证url和token有更改
$wechat->responseMsg();
这样客户端向在公众号发送内容后,就会得到回复
在responseMsg()方法中,$contentStr = "Welcome to wechat world!";
可以对客户发送的内容进行判断,回复不同的内容。
平台提供了回复不同的内容的xml的格式,可以直接使用。
MsgType属性是关于回复的内容的类型的。根据回复的类型进行不同的处理。
在wechat工具类中
/**
* 回复客户端信息的方法
*/
public function responseMsg()
{
//get post data, May be dueto the different environments
$postStr =$GLOBALS["HTTP_RAW_POST_DATA"];
//extractpost data
if (!empty($postStr)){
$postObj= simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$file= './post.log';
file_put_contents($file,'['.date('Y-m-d H:i:s').']content:'.$postObj->MsgType.PHP_EOL, FILE_APPEND);
switch ($postObj->MsgType) {
//文本类型
case'text':
$this->_doText($postObj);
break;
//图片
case'image':
$this->_doImage($postObj);
break;
//语音
case 'voice':
$this->_doVoice($postObj);
break;
//视频
case 'video':
$this->_doVideo($postObj);
break;
//定位信息
case 'location':
$this->_doLocation($postObj);
break;
//小视频
case 'shortvideo':
$this->_doShortVideo($postObj);
break;
//链接信息
case 'link':
$this->_doLink($postObj);
break;
default:exit;
}
}else {
echo"";
exit;
}
}
/**
* 处理文本内容的回复
*/
private function _doText($postObj)
{
$fromUsername =$postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
if(!empty( $keyword ))
{
$contentStr= "Welcome to wessssssssssssschat world!";
if($keyword=="看看")
{
$contentStr= "没sssss有";
}
if($keyword== "走了")
{
$contentStr= "有ssss了";
}
$msgType= "text";
$resultStr= sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo$resultStr;
}
exit;
}
/**
* 处理图片内容的回复
*/
private function _doImage($postObj)
{
$file = './post.log';
$fromUsername= $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
//使用被动回复消息的模版
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$contentStr = '您发送的图片在-->'.$postObj->PicUrl.'<--';
$msgType= "text";
$str = sprintf($textTpl,$fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $str;
file_put_contents($file,'['.date('Y-m-d H:i:s').']content:'.$str.PHP_EOL, FILE_APPEND);
exit;
}
7. 接收事件推送
事件推送的类型有关注/取消事件,扫描带参数二维码,上报地理位置,自定义菜单,点击菜单,点击菜单取消消息,点击菜单跳转链接等。
在回复方法中添加处理event类型的分支
switch($postObj->MsgType) {
//事件类型
case 'event':
$this->_doEvent($postObj);
break;
……
}
/**
* 处理事件类型
*/
private function _doEvent($postObj)
{
switch($postObj->Event)
{
//订阅
case 'subscribe':
$this->_doSubscribe($postObj);
break;
//取关
case 'unsubscribe':
$this->_doUnsubscribe($postObj);
break;
default:;
}
}
/**
* 处理订阅事件
*/
private function _doSubscribe($postObj)
{
$fromUsername =$postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
//使用被动回复消息的模版
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$contentStr = '欢迎订阅php1';
$msgType= "text";
$str = sprintf($textTpl,$fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $str;
exit;
}
/**
* 处理取关事件
*/
private function _doUnsubscribe($postObj)
{
exit;
}
8. 自定义菜单
为了丰富用户的操作,可以添加菜单,自定义操作。
1) 创建菜单
使用微信平台的测试工具,可以直接创建菜单。
打开网页测试工具。选择接口类型为自定义菜单,接口列表为menu/create,body可以复制提供的样板,根据实际做修改:
{
"button": [
{
"type":"click",
"name": "今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"name": "菜单",
"sub_button": [
{
"type":"view",
"name": "搜索",
"url":"http://www.soso.com/"
},
{
"type":"click",
"name": "赞一下我们",
"key":"V1001_GOOD"
}
]
}
]
}
检查问题就可以创建菜单,取关后重新关注,可以查看效果。
也可通过接口添加菜单
/**
* 创建菜单的方法
*/
public function _createMenu($menu)
{
$url="https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$this->_getAccesstoken();
$result= $this->_request($url, true, 'post', $menu);
$result= json_decode($result);
if($result->errcode== 0)
{
$info= '菜单创建成功';
}
else
{
$info= '服务器异常,请联系管理员';
}
return$info;
}
调用创建菜单的方法
<?php
define("APPID","wx49119aeb8923abfd");
define("APPSECRET","96e13016d1cb24026545e5ed7c133fac");
define("TOKEN","testwechat");
require("./WeChat.class.php");
//header('Content-type:image/jpg');
header('content-type:text/html;charset=utf-8');
$wechat = newWeChat(APPID, APPSECRET, TOKEN);
$menu = '{
"button": [
{
"type":"click",
"name": "今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"name": "游戏",
"sub_button": [
{
"type":"view",
"name": "吃货大作战",
"url":"http://my.59600.com/pc/webgame/?id=9696003&name=%E5%90%83%E8%B4%A7%E5%A4%A7%E4%BD%9C%E6%88%98"
},
{
"type":"click",
"name": "赞一下我们",
"key":"V1001_GOOD"
}
]
}
]
}';
echo$wechat->_createMenu($menu);
2) 删除菜单
可以在这个页面,接口列表,选择为menu/delete,检查问题就可以删除菜单。
也可以使用平台提供删除菜单的接口
/**
* 删除菜单的方法
*/
public function _deleteMenu()
{
$url= "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=".$this->_getAccesstoken();
$result= $this->_request($url);
$result= json_decode($result);
if($result->errcode== 0)
{
$info= '菜单删除成功';
}
else
{
$info= '服务器异常,请联系管理员';
}
$file= "./deletemenu.txt";
file_put_contents($file, '['.date('Y-m-dH:i:s').']content:'.$info.PHP_EOL, FILE_APPEND);
return$info;
}
3) 查询菜单
使用自定义菜单内的查询接口。返回的是json形式的字符串。
/**
* 查询菜单的方法
*/
public function _queryMenu()
{
$url="https://api.weixin.qq.com/cgi-bin/menu/get?access_token=".$this->_getAccesstoken();
$menu= $this->_request($url);
$file= "./menu.txt";
file_put_contents($file, '['.date('Y-m-dH:i:s').']content:'.$menu.PHP_EOL, FILE_APPEND);
return$menu;
}
4) 发送图文信息(被动)
当用户点击了某个菜单选项后,可以被动向用户发送图文信息。当用户点击了菜单后,会触发自定义菜单事件,平台会把点击事件推送给开发者,注意的是,点击菜单弹出子菜单,不会产生上报。推送的xml数据包中含有参数Event和EventKey,即创建按钮时设置的按钮的type和key。点击的哪个按钮,就推送这个按钮的type和key,然后被动发送图文信息等。
在处理事件的方法中添加处理点击事件的分支。
//鼠标点击事件
case 'CLICK':
$this->_doClick($postObj);
break;
创建点击的方法
/**
* 处理点击事件
*/
private function _doClick($postObj)
{
$eventKey =$postObj->EventKey;
if($eventKey == 'news')
{
$fromUsername =$postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
//使用被动回复消息的模版
$textTpl ="<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<ArticleCount>%s</ArticleCount>
<Articles>
%s
</Articles>
</xml>";
$itemTpl ="<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>";
$items = array(
array(
'title'=>'阿森纳叛温格',
'desc'=>'提起阿德巴约,阿森纳评温格虚伪,阿森纳无情。还表示自己最喜欢的教练是穆里尼奥,他永远爱穆帅。',
'picurl'=>'http://n.sinaimg.cn/sports/transform/w650h364/20180119/G4LB-fyqtwzu6103615.jpg',
'url'=>'http://sports.sina.com.cn/g/pl/2018-01-19/doc-ifyquptv7864181.shtml?cre=tianyi&mod=pcspth&loc=9&r=25&doct=0&rfunc=6&tj=none&tr=1',
),
array(
'title'=>'桑切斯去曼德的',
'desc'=>'桑切斯加盟曼联的转会已经进入倒计时,阿森纳主帅温格也亲自承认:“桑切斯的交易很可能会发生。料地投奔昔日恩师、现任曼城主帅瓜迪奥拉。对此,《太阳报》首席评论员尼尔',
'picurl'=>'http://n.sinaimg.cn/sports/transform/w650h457/20180119/Ofj1-fyqtwzu6235171.jpg',
'url'=>'http://sports.sina.com.cn/g/pl/2018-01-19/doc-ifyqtwzu6240517.shtml?cre=tianyi&mod=pcspth&loc=5&r=0&doct=0&rfunc=6&tj=none&tr=1',
),
);
foreach ($items as$k => $v)
{
$itemContent.= sprintf($itemTpl, $v['title'], $v['desc'], $v['picurl'], $v['url']);
}
$msgType ="news";
$str =sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, count($items),$itemContent);
echo $str;
exit;
}
}
9. 定位信息的处理
在接收普通消息中,有地理位置消息。这个消息中有发送点的经纬度信息。在处理类型中添加处理地理位置的分支。并创建对应的方法。
/**
* 处理地理位置
*/
private function _doLocation($postObj)
{
$file = './post.log';
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
//使用被动回复消息的模版
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$contentStr = '您所在的地理位置为:N '.$postObj->Location_X.',E '.$postObj->Location_Y;
$msgType= "text";
$str = sprintf($textTpl,$fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $str;
file_put_contents($file,'['.date('Y-m-d H:i:s').']content:'.$str.PHP_EOL, FILE_APPEND);
exit;
}
10. 模版优化
由于程序中经常使用到模版,可以将模版提取为属性。
//模版
private $tpl = array(
//文本模版
'text' => '<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>',
//被动回复消息的模版
'retext' => '<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>',
);
然后,在程序中使用到模版的地方改为使用属性。
$str = sprintf($this->tpl['retext'],$fromUsername, $toUsername, $time, $contentStr);
11. 获取用户列表
平台提供了接口获取用户列表。这个接口得到的是用户的openid,结合获取用户基本信息的接口,可以获取到用户的基本信息。
在微信工具类中创建_getUserlist()
/**
* 获取用户openid
*/
public function _getUserOpenid()
{
$url ="https://api.weixin.qq.com/cgi-bin/user/get?access_token=".$this->_getAccesstoken();
$content =$this->_request($url);
$file ="./userlist.txt";
file_put_contents($file,'['.date('Y-m-d H:i:s').']content:'.$content.PHP_EOL, FILE_APPEND);
$content =json_decode($content);
$users =$content->data->openid;
return $users;
}
/**
* 获取用户列表
*/
public function _getUserlist()
{
//获取所有用户的openid
$users =$this->_getUserOpenid();
$jsonUsers = array();
foreach ($users as $k =>$v)
{
$jsonUsers['user_list'][$k]['openid']= $v;
$jsonUsers['user_list'][$k]['lang']= "zh_CN";
}
$jsonUsers =json_encode($jsonUsers);
$url ='https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token='.$this->_getAccesstoken();
$userInfolist =$this->_request($url, true, 'post', $jsonUsers);
$userInfolist =json_decode($userInfolist)->user_info_list;
//var_dump($userInfolist);die;
//拼写html代码将用户信息以表格输出
$html = "<tableborder='1' cellspacing='0'>";
$html.="<tr><td>openid</td><td>昵称</td><td>性别</td><td>国家</td><td>订阅否</td><td>订阅时间</td></tr>";
foreach ($userInfolist as $k=> $v)
{
$html .="<tr>";
$html .='<td>'.$v->openid.'</td>';
$html .='<td>'.$v->nickname.'</td>';
if($v->sex == 1)
{
$html .='<td>男</td>';
}
else
{
$html .='<td>女</td>';
}
$html .='<td>'.$v->country.'</td>';
if($v->subscribe== 1)
{
$html .='<td>是</td>';
}
else
{
$html .='<td>否</td>';
}
$html .='<td>'.date('Y-m-d H:i:s', $v->subscribe_time).'</td>';
$html .="</tr>";
}
$html.="</table>";
return $html;
}
创建调用获取列表的php脚本
<?php
define("APPID","wx49119aeb8923abfd");
define("APPSECRET","96e13016d1cb24026545e5ed7c133fac");
define("TOKEN","testwechat");
require("./WeChat.class.php");
//header('Content-type:image/jpg');
header('content-type:text/html;charset=utf-8');
$wechat = newWeChat(APPID, APPSECRET, TOKEN);
echo$wechat->_getUserlist();
12. 群发文本信息到用户
使用群发文本信息的接口。
注意对发送的文本内容先urlencode,后urldecode,以防止内容被unicode编码化。
/**
* 群发信息
*/
public function _sendAll($content)
{
//获取所有用户的openid
$users =$this->_getUserOpenid();
//根据平台提供的模版制作post数据
/*
{
"touser":[
"OPENID1",
"OPENID2"
],
"msgtype": "text",
"text": { "content":"hello from boxer."}
}
*/
$data = array();
foreach ($users as $k =>$v)
{
$data['touser'][] =$v;
}
$data['msgtype'] = 'text';
$data['text']['content'] =urlencode($content);//对文本内容进行urlencode,以防止被解析为unicode
$data = urldecode(json_encode($data));//在对urlencode的内容进行urldecode,返回原来的编码格式
$url ='https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token='.$this->_getAccesstoken();
$result =$this->_request($url, true, 'post', $data);
$result =json_decode($result);
if($result->errcode == 0)
{
echo '发送成功';
}
else
{
echo '系统异常,请联系管理员';
}
exit;
}
编写群发消息的php脚本
<?php
define("APPID","wx49119aeb8923abfd");
define("APPSECRET","96e13016d1cb24026545e5ed7c133fac");
define("TOKEN","testwechat");
require("./WeChat.class.php");
//header('Content-type:image/jpg');
header('content-type:text/html;charset=utf-8');
$wechat = newWeChat(APPID, APPSECRET, TOKEN);
$content = '可以';
$wechat->_sendAll($content);
13. 添加素材
可以新增临时或永久多媒体素材。新增素材存放在平台上,在调用时速度更快。
在微信工具类中创建_addMedia()方法
/**
* 添加素材
*/
public function _addMedia($type, $file)
{
$curl ="https://api.weixin.qq.com/cgi-bin/media/upload?access_token=".$this->_getAccesstoken()."&type=".$type;
$data['type'] = $type;
$data['media'] = '@'.$file;
$result = $this->_request($curl,true, 'post', $data);
echo $result;
}
编写脚本调用这个方法
<?php
define("APPID","wx49119aeb8923abfd");
define("APPSECRET","96e13016d1cb24026545e5ed7c133fac");
define("TOKEN","testwechat");
require("./WeChat.class.php");
// header('Content-type:image/jpg');
header('content-type:text/html;charset=utf-8');
$wechat = newWeChat(APPID, APPSECRET, TOKEN);
$type = 'image';
$file = './php1.jpg';
$wechat->_addMedia($type,$file);
14. 搜索音乐的功能
使用音乐搜索引擎实现搜索音乐,听歌的功能。
当用户输入歌曲歌名@歌手名,后得到音乐消息。
在doText()方法中,添加关键字开头二字为歌曲的分支结构
if(mb_substr($keyword, 0,2, 'utf-8') == '歌曲')
{
$this->_sendMusic($postObj);
exit;
}
创建处理音乐消息的方法
/**
* 搜索歌曲的方法
*/
private function _sendMusic($postObj)
{
$content =$postObj->Content;
$content =mb_substr($content, 2,strlen($content)-2, 'utf-8');
$arr = explode('@',$content);
$singer = '';
$song = '';
if(isset($arr[1]))
{
$singer = $arr[1];
$song = $arr[0];
$curl ='http://www.xiami.com/search?key='.$arr[0].'+'.$arr[1];
}
else
{
$song = $arr[0];
$curl ='http://www.xiami.com/search?key='.$arr[0];
}
$response =$this->_request($curl, false);
$file =('./searchMusic.txt');
$response =mb_strstr($response, '</thead>', false, 'utf-8');
$response = mb_strstr($response,'</tbody>', true, 'utf-8');
$response = strstr($response,'http');
$response = strstr($response,'"', true);
$response =$this->_request($response, false);
$response = strstr($response,'<a onclick="play');
$response = strstr($response,"'");
$response = strstr($response,",", true);
$response = substr($response,1, strlen($response)-2);
file_put_contents($file,$response);
$fromUsername =$postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$time = time();
$title= $song.'>>>'.$singer;
$desc= '欢迎收听'.$song.'&&&';
$musicUrl= 'http://www.xiami.com/play?ids=/song/playlist/id/'.$response;
$thumbMediaId= 'AoR3l2l-cNv6_fsns4SnKev1_riF8yvpTP3TJ7y9SLdl6ug9BlZXV9te_Pgcu_pT';
$resultStr= sprintf($this->tpl['music'], $fromUsername, $toUsername, $time, $title,$desc, $musicUrl, '', $thumbMediaId);
echo$resultStr;
exit;