一、微信开放平台注册(进行开发者资质认证)
1.1 注册开放平台账号
注册账号需要邮箱(这个邮箱贼恶心,不能是微信绑定过的,也不能是公众号平台绑定的,小程序平台绑定的也不行),然后需要提供公司主体等相关的信息
1.2 通过开发者资质认证
1.3 创建第三方平台
1.4 完善开发者信息
主要是权限集以及开发资料点击编辑进行配置
二、开发流程
步骤 说明
2.1、配置授权事件URL,用于接收component_verify_ticket 出于安全考虑,在第三方平台创建审核通过后,微信服务器 每隔 10 分钟会向第三方的消息接收地址推送一次 component_verify_ticket,用于获取第三方平台接口调用凭据。component_verify_ticket有效期为12h
// 授权事件接受地址
public function authorization(){
if (!$xml = file_get_contents('php://input')) {
error_log("\msg:无参数\n", 3, "./wxNotify.log");
}
$data = fromXml($xml);
Cache::set('component_verify_ticket',$data['Encrypt'],3600);
echo 'success';
}
2.2、获得component_verify_ticket后,按照获取第三方平台 component_access_token 接口文档,调用接口获取component_access_token component_access_token有效期2h,当遭遇异常没有及时收到component_verify_ticket时,建议以上一次可用的component_verify_ticket继续生成component_access_token。避免出现因为 component_verify_ticket 接收失败而无法更新 component_access_token 的情况。
/*接口文档 /授权相关接口 /获取令牌*/
public function get_component_access_token(){
if (Cache::has('ComponentAccessToken')) {
return Cache::get('ComponentAccessToken');
}
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_component_token';
$parmas = array();
$parmas['component_appid'] = $this->component_appid;
$parmas['component_appsecret'] = $this->component_appsecret;
$ticket = Cache::get('component_verify_ticket');
$sa = decryptMsg($ticket);
$saArr = fromXml($sa);
$ticket = $saArr['ComponentVerifyTicket'];
$parmas['component_verify_ticket'] = $ticket;
$result = curlPost($url,json_encode($parmas));
$result = json_decode( $result, true );
if (!$result) {
return false;
}
$expire = $result['expires_in'] ? intval($result['expires_in']) : 7200;
Cache::set('ComponentAccessToken', $result['component_access_token'], $expire);
return $result['component_access_token'];
}
2.3、获得component_access_token后,按照获取预授权码 pre_auth_code接口文档 ,调接口获取pre_auth_code 用于生成扫码授权二维码或者链接需要的pre_auth_code
/**
* 获取预授权码
*/
public function getPreAuthCode()
{
if (Cache::has('PreAuthCode')) {
return Cache::get('PreAuthCode');
}
$component_access_token = $this->get_component_access_token();
$app_id =$this->component_appid;
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=' . $component_access_token;
$data = [
'component_appid' => $app_id
];
$result = curlPost($url,json_encode($data));
$result = json_decode( $result, true );
if ($result) {
$expires_in = $result['expires_in'];
Cache::set('PreAuthCode', $result['pre_auth_code'], $expires_in* 0.9);
return $result['pre_auth_code'];
}
return false;
}
2.4、获得pre_auth_code后,按照授权技术流程说明文档 ,引导用户授权后获取authorization_code authorization_code有过期时间,该过期时间在授权后回调 URI进行返回;也会通过推送授权变更通知的方式将authorization_code推送给第三方平台
/****
* 授权页面
* */
public function jump(){
Cache::rm('PreAuthCode');
$a = $this->getPreAuthCode();
$url = 'https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=3&no_scan=1&component_appid='.$this->component_appid.'&pre_auth_code='.$this->getPreAuthCode().'&redirect_uri=https://assistant.txwluo.com/index.php/api/index/redirect&auth_type=3&biz_appid=xxxx#wechat_redirect';
header('location:'.$url);exit;
}
//获取授权后回调 授权token
public function redirect(){
$authorization_code = $_GET['auth_code'];
$expires_in = $_GET['expires_in'];
Cache::set('authorization_code', $authorization_code, $expires_in* 0.9);
// 根据授权码获取账号授权信息
$info = $this->authorizationInfo($authorization_code);
// 将授权信息存入数据库
echo '授权成功';
}
2.5、获得authorization_code后,按照使用授权码换取公众号或小程序的接口调用凭据和授权信息 接口文档 ,调接口获取authorizer_refresh_token 通过授权码和自己的接口调用凭据(component_access_token),换取公众号或小程序的接口调用凭据(authorizer_access_token 和用于前者快过期时用来刷新它的 authorizer_refresh_token)和授权信息(授权了哪些权限等信息)
/***
*
* 使用授权码换取公众号或小程序的接口调用凭据和授权信息
**/
public function authorizationInfo($authorization_code=''){
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token='.$this->get_component_access_token();
$parmas = array();
$parmas['component_appid'] = $this->component_appid;
$parmas['authorization_code'] = $authorization_code;
$result = curlPost($url,json_encode($parmas));
$result = json_decode( $result, true );
if (!$result) {
return false;
}
if(isset($result['errcode'])){
echo '授权失败'.$result['errmsg'];die;
}
if(isset($result['authorization_info'])){
$this->authorizerInfo($result['authorization_info']);
}
return $result;
}
/****
* 获取授权方的帐号基本信息
***/
public function authorizerInfo($account_info){
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token='.$this->get_component_access_token();
$parmas = array();
$parmas['component_appid'] = $this->component_appid;
$parmas['authorizer_appid'] = $account_info['authorizer_appid'];//从数据库读取操作的公众号的appid
// dump($parmas);
$result = curlPost($url,json_encode($parmas));
$result = json_decode( $result, true );
if (!$result) {
return false;
}
if(isset($result['authorizer_info'])){
$model = Db::name('account');
$authorizer_info = $result['authorizer_info'];
$authorization_info = $result['authorization_info'];
$insert_data['appid'] = $authorization_info['authorizer_appid'];
$insert_data['access_token'] = $account_info['authorizer_access_token'];
$insert_data['refresh_token'] = $authorization_info['authorizer_refresh_token'];
$insert_data['nick_name'] = $authorizer_info['nick_name'];
$insert_data['head_image'] = $authorizer_info['head_img'];
$insert_data['user_name'] = $authorizer_info['user_name'];
$insert_data['qrcode_image'] = $authorizer_info['qrcode_url'];
$insert_data['principal_name'] = $authorizer_info['principal_name'];
$insert_data['signature'] = $authorizer_info['signature'];
$id = $model->insertGetId($insert_data);
}
return $result;
//可以将账号基本信息存数据库
// Cache::set('api_query_auth', $result, 7200);
// dump(Cache::get('api_query_auth'));
}
2.6、获得authorizer_refresh_token后,按照获取/刷新授权公众号或小程序的接口调用凭据 接口文档 ,调接口获取authorizer_access_token 可通过 authorizer_refresh_token 获取公众号或小程序接口的调用令牌
//获取令牌tokken
public function getAuthorizerAccessToken($authorizer_appid='wx25bcc1fc10191be9'){
if (Cache::has($authorizer_appid.'authorizer_access_token')) {
//获取令牌
$access_token = Cache::get($authorizer_appid.'authorizer_access_token');
}else{
//echo 111;die;
//刷新凭证并重新存储
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token='.$this->get_component_access_token();
$parmas = array();
$parmas['component_appid'] = $this->component_appid;//微信第三方的appid
$parmas['authorizer_appid'] = $authorizer_appid;//公众号的appid
//要将authorizer_refresh_token存入数据库获取完要记得修改
$data = Db::name('account')->where(['appid'=>$authorizer_appid])->find();
// $parmas['authorizer_refresh_token'] = 'refreshtoken@@@yOEDBPV78uo8VRYSo4vqF0Zbmh8_xL_UjgGLRfgGvmE';
$parmas['authorizer_refresh_token'] = $data['refresh_token'];
// dump($parmas);
$result = curlPost($url,json_encode($parmas));
$result = json_decode( $result, true);
if (!$result) {
return false;
}
if(isset($result['authorizer_access_token'])){
$access_token = $result['authorizer_access_token'];
file_put_contents("info.txt","authorizer_refresh_token:".$result['authorizer_refresh_token'].PHP_EOL.'access_token:'.$access_token);
Cache::set($authorizer_appid.'authorizer_access_token', $result['authorizer_access_token'], 7100);
$data = Db::name('account')->where(['appid'=>$authorizer_appid])->update(['refresh_token'=>$result['authorizer_refresh_token'],'access_token'=>$access_token]);
}else{
return false;
}
//将令牌存入数据库 记得刷新
}
return $access_token;
}
2.7、按照接口文档,代替公众号或小程序调用接口 在完成授权后,第三方平台可通过公众号或小程序的接口调用凭据(authorizer_access_token)来代替它调用接口,具体请见接口文档
辅助函数
/**
* 将xml转为array
* @param $xml
* @return mixed
*/
function fromXml($xml)
{
// 禁止引用外部xml实体
libxml_disable_entity_loader(true);
return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
}
/*解密ticket*/
function decryptMsg($msg_encrypt)
{
$EncodingAESKey = 'assistanttxwluo1676542519assistanttxwluo167';
$AESKey = base64_decode($EncodingAESKey.'=');
$iv = substr($AESKey, 0, 16);
$msg_decode = base64_decode($msg_encrypt);
$msg = openssl_decrypt($msg_decode, 'AES-256-CBC', $AESKey, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$msg_len = unpack('N', substr($msg, 16, 4));
$len = $msg_len[1];
$xml = substr($msg, 20, $len);
return $xml;
}
function curlPost($url, $post_data, $timeout = 5)
{
$ch = curl_init();
if (stripos($url, 'https://') !== false) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
}
$header = empty($header) ? '' : $header;
if (is_string($post_data)) {
$strPOST = $post_data;
}
else {
$aPOST = array();
foreach ($post_data as $key => $val) {
$aPOST[] = $key . '=' . urlencode($val);
}
$strPOST = join('&', $aPOST);
}
curl_setopt($ch, CURLOPT_HTTP_VERSION, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $strPOST);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
$result = curl_exec($ch);
$aStatus = curl_getinfo($ch);
curl_close($ch);
if (intval($aStatus['http_code']) == 200) {
return $result;
}
else {
return false;
}
}
三、事件接收推送
// 授权消息与事件接收配置
public function message(){
//获取到微信推送过来post数据(xml格式)
//2.处理消息类型并设置回复类型和内容
//encodingAesKey和token均为申请三方平台是所填写的内容
$encodingAesKey = $this->encodingAesKey;
$token =$this->token;
$appId = $this->component_appid;
$timeStamp = empty ($_GET['timestamp']) ? "" : trim($_GET['timestamp']);
$nonce = empty($_GET['nonce']) ? "" : trim ($_GET['nonce']);
$msg_sign = empty($_GET ['msg_signature']) ? "" : trim($_GET['msg_signature']);
$pc = new \WXBizMsgCrypt ($token, $encodingAesKey, $appId );
//获取到微信推送过来post数据(xml格式)
$postArr=file_get_contents('php://input');
// $postArr = $GLOBALS['HTTP_RAW_POST_DATA'];
file_put_contents('message.txt',$postArr);
$msg = '';
$errCode= $pc->decryptMsg($msg_sign, $timeStamp, $nonce, $postArr,$msg);
// 解密后,当$errCode返回值为0时,代表解密成功,下一步我们就需要对消息进行解析处理:
$postObjArr =simplexml_load_string($msg,'SimpleXMLElement',LIBXML_NOCDATA);
if(strtolower($postObjArr->MsgType) =='text'){
//第三方模拟发送
if($postObjArr->Content=='TESTCOMPONENT_MSG_TYPE_TEXT'){
//回复用户消息
$content = 'TESTCOMPONENT_MSG_TYPE_TEXT_callback';
echo $this->responseText($postObjArr,$content);
}
}
if(strtolower($postObjArr->MsgType) =='event'){
//如果是扫描带有参数的二维码进入。。。。。。
if($postObjArr->Event=='SCAN' || $postObjArr->Event=='subscribe'){
//回复用户消息
$toUser=$postObjArr->FromUserName;
// $fromUser=$postObjArr['ToUserName'];
$eventKey=$postObjArr->EventKey;
$model = Db::name('user_pc');
$eventKey = ltrim($eventKey,'qrscene_');
$insert_data['user_key'] = $eventKey;
$insert_data['openid'] = $toUser;
$id = $model->insertGetId($insert_data);
echo 'success';
}
}
}
function responseText($postObj,$content){
$template ="<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$fromUser = $postObj ->ToUserName;
$toUser = $postObj -> FromUserName;
$time = time();
$msgType = 'text';
$res =sprintf($template,$toUser,$fromUser,$time,$msgType,$content);
$encodingAesKey = $this->encodingAesKey;
$token =$this->token;
$appId = $this->component_appid;
$pc = new \WXBizMsgCrypt ($token, $encodingAesKey, $appId );
$encryptMsg = '';
$errCode =$pc->encryptMsg($res,$_GET['timestamp'], $_GET['nonce'], $encryptMsg);
if ($errCode == 0) {
return $encryptMsg;
}
return $a;
}
引用文件地址:
链接: https://pan.baidu.com/s/1Ef2j8nqaBWptZq5LmeRkSg?pwd=88dq 提取码: 88dq 复制这段内容后打开百度网盘手机App,操作更方便哦