IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 微信开发者服务器接入指南 -> 正文阅读

[系统运维]微信开发者服务器接入指南

适用于小程序,小游戏。

也适用于公众号的接入,但是并没有什么卵用,因为公众号的对话服务,只能接收消息,不能向用户发消息,开通发消息功能需要微信认证,而个人公众号不支持微信认证。看看给用户发消息会返回什么:{"errcode":48001,"errmsg":"api unauthorized rid: 62922e5a-050daf94-1dcd13f6"},api?unauthorized,就是权限不足。另外,对公众号发文也没有卵用,因为无法获取群发文的列表,微信客服也许都不禁笑了,你想要文章列表做什么?看看我们的客服是怎么说的:

公众号技术运营专员-livia 公众号技术运营专员-livia 05-05
你好,你可以提供相关发表记录的页面截图,查看发布这里是否有文章。获取发布列表:只有通过草稿箱进行自由发布的内容才能获取,话题发布和视频发布的内容,以及已群发的内容无法通过此接口获取

参见:接入概述 | 微信开放文档

Step1

  1. 如果是公众号:在 设置与开发=> 基本配置;
  2. 如果是小游戏:在?开发管理=>开发设置=>消息推送。

设置 URL, Token, EncodingAESKey:

  • URL 是开发者用来接收微信消息和事件的接口URL。【就是服务器上的响应程序,例如: https://www.xxx.com/connect.php】
  • Token可由开发者可以任意填写,用作生成签名(该 Token 会和接口 URL 中包含的 Token 进行比对,从而验证安全性)。【以下用宏定义 TOKEN】
  • EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。【如果选用明文模式则用不上】

下载代码并放置在开发者服务器上。PHP示例代码下载:下载

Step2

然后在 URL?内(就是 https://www.xxx.com/connect.php 文件内)放置如下函数:

include_once "wxBizMsgCrypt.php";

define("TOKEN", "XXXXXX");  //填写自己的token

if (isset($_GET['echostr'])) {          //校验服务器地址URL
    valid();
}else{
    // 业务代码
}

function valid()
{
    $echoStr = $_GET["echostr"];
    if(checkSignature()){
        header('content-type:text');
        echo $echoStr;
        exit;
    }else{
        echo $echoStr.'+++'.TOKEN;
        exit;
    }
}

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;
    }
}

其原理是:微信服务器向 URL 发起请求,携带了 signature, timestamp, nonce, echostr?四个参数。URL 收到后,使用 TOKEN, timestamp, nonce 组合并加密得到 tmpStr,如果 tmpStr==signature,则向微信服务器返回 echostr,否则返回 failure。加密程序在示例代码 wxBizMsgCrypt.php 中,它又引用了以下文件:

include_once "sha1.php";
include_once "xmlparse.php";
include_once "pkcs7Encoder.php";
include_once "errorCode.php";

因此服务器端至少需要以上五个文件。

Step3

回到微信后台,如果是公众号:

  1. 在 设置与开发=> 公众号开发信息,设置白名单,就是开发者服务器 IP 地址;
  2. 在 设置与开发=> 基本配置,提交 Step1 填写的信息,如果通过 Step2 代码的验证,则开通成功。

如果是小游戏:

  1. 在 开发管理=>开发设置=>开发者 ID,设置白名单,就是开发者服务器 IP 地址;
  2. 在 开发管理=>开发设置=>消息推送,提交 Step1 填写的信息,如果通过 Step2 代码的验证,则开通成功。

Step4

小游戏内转到客服对话:判断条件满足后,直接调用 onContact(),就弹出对话框:「即将进入”xxx”客服会话」;

然后,用户在会话界面提交的消息,将被转发到 URL,并在 URL 中得到处理,再回复给用户。

下面才是重点:

Step 4.1

用户发来的消息,格式如下:

// 根据实测,postStr 的格式如下:
    {
        "ToUserName": "xxx",
        "FromUserName": "xxx",
        "CreateTime": ####,
        "MsgType": "text",
        "Content": "xxx",
        "MsgId": ####
    }

PHP 获取用户消息:

$postStr = file_get_contents('php://input');
//此处推荐使用file_get_contents('php://input')获取后台post过来的数据
$postArr = json_decode($postStr,true);

if(!empty($postArr['MsgType']){
    if($postArr['MsgType'] == 'text'){   //用户发送文本消息
        // TODO
    }elseif($postArr['MsgType'] == 'image'){ //用户发送图文消息
        // TODO
    }elseif($postArr['MsgType'] == 'event' && $postArr['Event']=='user_enter_tempsession'){ //用户进入客服
        // TODO
    }else{
        exit('error');
    }
}

其中,postArr['FromUserName'],就是用户的 openid。

Step 4.2

向用户发送消息:

简单地说,要发文字消息,或图片,首先把目标用户(postArr['FromUserName'], openid)、消息类型(text/image)、消息(text/image)内容打成一个 json 包,然后再调用 requestAPI 发送。图片用 media_id 表示,可以通过网页访问 URL 从服务器向微信上传图片,记录并返回 media_id。getAccessToken(APPID,SECRET) 需要 APPID 和 SECRET。

注意,access_token 是一个具有时效性的口令,每次获取前要检查是否已经有,获取了新的之后还要保存。

function sendText2User($usr,$txt){
    $data=array(
        "touser"=>$usr,
        "msgtype"=>"text",
        "text"=>array("content"=>$txt)
    );
    $json = json_encode($data,JSON_UNESCAPED_UNICODE);  //php5.4+
    requestAPI($json);
}

function sendImage2User($usr,$media_id){
    $data=array(
        "touser"=>$usr,
        "msgtype"=>"image",
        "image"=>array("media_id"=>$media_id)
    );
    $json = json_encode($data,JSON_UNESCAPED_UNICODE);  //php5.4+
    requestAPI($json);
}

function requestAPI($json){
    $access_token = get_accessToken();
    /* 
     * POST发送https请求客服接口api
     */
    if(!empty($access_token)){
        $url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$access_token;
        //以'json'格式发送post的https请求
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($json)){
            curl_setopt($curl, CURLOPT_POSTFIELDS,$json);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        //curl_setopt($curl, CURLOPT_HTTPHEADER, $headers );
        $output = curl_exec($curl);
        if (curl_errno($curl)) {
            echo 'Errno'.curl_error($curl);//捕抓异常
        }
        curl_close($curl);
        if($output == 0){
            echo 'success';
            exit;
        }
    }else{
        echo "";
        exit;
    }
    
}       
/* 调用微信api,获取access_token,有效期7200s*/
function get_accessToken(){
    $token = "";
    $tokenarr = readDataFile2Array("token.txt");
    $tokentime0 = $tokenarr[1];
    $tokentime1 = gmmktime();
    if($tokentime1-$tokentime0 < 7200  && !empty($tokenarr[0])){
        $token = $tokenarr[0];
    }else{
        $token = getAccessToken(APPID,SECRET);

        $tokentime = gmmktime();
        $tokendate = date('Y-m-d H:i:s');
        writeString2File($token."\r\n".$tokentime."\r\n".$tokendate,"token.txt");
    }

    return $token;
}


function getAccessToken($appid,$secret){
    $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}";
    $res = curl_get($url);
    $res = json_decode($res,1);
    if($res['errcode']!=0) throw new Exception($res['errmsg']);
    return $res['access_token'];
}

function curl_get($url) {
     $headers = array('User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36');
    $oCurl = curl_init();
    if(stripos($url,"https://")!==FALSE){
        curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
    }
    curl_setopt($oCurl, CURLOPT_TIMEOUT, 20);
    curl_setopt($oCurl, CURLOPT_URL, $url);
    curl_setopt($oCurl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
    $sContent = curl_exec($oCurl);
    $aStatus = curl_getinfo($oCurl);
    curl_close($oCurl);
    if(intval($aStatus["http_code"])==200){
        return $sContent;
    }else{
        return false;
    }
}

function getMediaId_image($token, $filepath){
    //$url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=".$token."&type=image";
    $url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=".$token."&type=image";
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HEADER, 0);    
    curl_setopt($ch, CURLOPT_NOBODY, 0);    //只取body头
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
     //发送 POST 请求
    curl_setopt($ch, CURLOPT_POST, true);     
    //全部数据使用HTTP协议中的 "POST" 操作来发送。 


    if (class_exists('\CURLFile')){
        curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
        $data = array('media' => new \CURLFile($filepath));//
    }else{
        curl_setopt($ch,CURLOPT_SAFE_UPLOAD,false);
        $data = array('media'=>'@'.$filepath);
    }


    //$data = array('media'=>'@'.$filepath);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    $res = curl_exec( $ch );
    curl_close( $ch );
    if($res){
            $res = json_decode($res,true);
            return $res;
    }
    else return null;
}

附1 ?用户登录

?在用户登录小程序、小游戏的时候,就已经得到了 openid,方法如下:

在前端,用户登录时,获得用户的 code,然后发送给本小程序/小游戏服务器,请求微信得到 openid。

前端代码:

function getOpenId() {
    wx.login({
      success(res) {
        //console.log('code===', res.code)
        wx.request({
          url: 'https://www.xxx.com/getOpenId.php',
          data: {
            code: res.code
          },
          success(res1) {
            userInfo["openId"] = res1.data
            //console.log('获取成功:' + userInfo["openId"] )
            getUserInfo()
          },
          fail(res2) {
            //console.log('获取失败:' + res2)
          }
        })
      }
    })
}

function getUserInfo(){
  let exportJson = {};
  let sysInfo = wx.getSystemInfoSync();
  //获取微信界面大小
  let width = sysInfo.screenWidth;
  let height = sysInfo.screenHeight;
  wx.getSetting({
    success(res) {
     //console.log(res.authSetting);
      if (res.authSetting["scope.userInfo"]) {
       //console.log("用户已授权");
        wx.getUserInfo({
          success(res) {
           //console.log(res);
            exportJson.userInfo = res.userInfo;
            //此时可进行登录操作

            userInfo["nickName"] = res.userInfo.nickName
            userInfo["avatarUrl"] = res.userInfo.avatarUrl
            userInfo["language"] = res.userInfo.language
            userInfo["gender"] = res.userInfo.gender
            userInfo["country"] = res.userInfo.country
            userInfo["province"] = res.userInfo.province

            recordLogin()
          }
        });
      } else {
       //console.log("用户未授权");
        let button = wx.createUserInfoButton({
          type: 'text',
          text: '',
          style: {
            left: 0,
            top: 0,
            width: width,
            height: height,
            backgroundColor: '#00000000',//最后两位为透明度
            color: '#ffffff',
            fontSize: 20,
            textAlign: "center",
            lineHeight: height,
          }
        });
        button.onTap((res) => {
          if (res.userInfo) {
           //console.log("用户授权:", res);
            exportJson.userInfo = res.userInfo;
            //此时可进行登录操作
            button.destroy();

            userInfo["nickName"] = res.userInfo.nickName
            userInfo["avatarUrl"] = res.userInfo.avatarUrl
            userInfo["language"] = res.userInfo.language
            userInfo["gender"] = res.userInfo.gender
            userInfo["country"] = res.userInfo.country
            userInfo["province"] = res.userInfo.province

            recordLogin()
          } else {
            //console.log("用户拒绝授权:", res);
            // TODO
          }
        });
      }
    }
  })
}

function recordLogin(){
  var curTime = new Date();
  var loginTime = util.formatTime(curTime);

  wx.request({
    url: 'https://XXX/userLogin.php', //仅为示例,并非真实的接口地址
    data: {
      openId: userInfo["openId"],
      nickName: userInfo["nickName"],
      avatarUrl: userInfo["avatarUrl"],
      language: userInfo["language"],
      gender: userInfo["gender"],
      country: userInfo["country"],
      province: userInfo["province"],
      loginTime: loginTime,
    },
    header: {
      'content-type': 'application/json' // 默认值
    },
    success(res) {
      //console.log(res.data)
      // TODO
    }
  })
}

后端代码:即前端里的?https://www.xxx.com/getOpenId.php

function getOpenid() {
    $code = $_GET['code'];//小程序传来的code值

    $appid = 'XXX';//小程序的appid
    $appSecret = 'XXX';// 小程序的$appSecret
    $wxUrl = 'https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code';
    $getUrl = sprintf($wxUrl, $appid, $appSecret, $code);//把appid,appsecret,code拼接到url里
    $result = curl_get($getUrl);//请求拼接好的url
    $wxResult = json_decode($result, true);
    if (empty($wxResult)) {
        echo '获取openid时异常,微信内部错误';
    } else {
        $loginFail = array_key_exists('errcode', $wxResult);
        if ($loginFail) {//请求失败
            var_dump($wxResult);
        } else {//请求成功
            $openid = $wxResult['openid'];
            //echo "获取openid成功成功:" . $openid;
            echo $openid;
        }
    }
}

附2 ?关于口令的使用

上述过程中使用了多种口令:

  1. 开通接口:仅需要 TOKEN;
  2. 向用户发消息,需要 access_token;
  3. 上传图片,需要?access_token;
  4. 获取 access_token,需要 APPID, APPSECRET;【注意,access_token 是一个具有时效性的口令,每次获取前要检查是否已经有,获取了新的之后还要保存。】
  5. 获取用户 openid,需要 APPID, APPSECRET。

附3 ?关于接口调试

微信提供了在线接口调试:微信公众平台接口调试工具

要点:

  1. ToUserName,就是公众号 ID;
  2. FromUserName,可以用个人的 openid;
  3. CreateTime,MsgId,都填1;
  4. 数据类型:选 json,因为 php 用的是 json 解析;
  5. 检查问题后,返回调试信息,其中的内容来自:requestAPI($json)中的 echo 'success'; ,其中的空格将自动替换为 +。其实直接 echo $output; 更有用。
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-06-04 00:07:03  更:2022-06-04 00:07:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 17:34:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码