前言:
最近需要做个用户上传图片,服务端校验图片问题的需求。需要使用小程序消息推送,异步接受腾讯的图片验证回调。实在太多坑了。
相信10分钟看完本文的朋友,可以非常顺利避坑。
前期准备:
首先需要一个消息推送帮助类wechat.class.php,在这里下载:https://github.com/dodgepudding/wechat-php-sdk
小程序管理界面配置接口
测试代码编写:
写一个接收代码php,放在上面URL(服务器地址)对应的服务器上。
php define('IN_MOD', TRUE); header("Content-Type: text/html;charset=utf-8"); date_default_timezone_set('PRC');//其中PRC为“中华人民共和国 include_once('wechat.class.php'); $options = array( 'token'=>'填写界面配置的 Token(令牌)', 'encodingaeskey'=>'填写界面配置的 EncodingAESKey(消息加密密钥)', 'appid'=>'填写小程序的appid', 'appsecret'=>'填写小程序的appsecret', ); $weObj = new Wechat($options); $weObj->valid(); return true; ?>
红色部分是需要替换成自己小程序实际配置。
注意把当前文件和wechat.class.php文件放在统一个目录下,可以被URL服务器地址访问。
测试消息推送——巨坑提醒!
打开微信的客服小程序:
注意小程序左上角,有个叫“客服在线”,设置为客服离线!
这是个超级巨坑,如果设置了客服在线,会发现非常多的消息,接口都收不到,只能收到event类型的推送。这里小编被坑了12个小时,无意中才发现。所以要用接口,就必须设置离线。
消息推送——消息转发给客服
由于我们设置了离线,但是对于无法处理的消息,还是要给人工处理,所以代码需要修改:
php define('IN_MOD', TRUE); header("Content-Type: text/html;charset=utf-8"); date_default_timezone_set('PRC');//其中PRC为“中华人民共和国 include_once('wechat.class.php'); $options = array( 'token'=>'填写界面配置的 Token(令牌)', 'encodingaeskey'=>'填写界面配置的 EncodingAESKey(消息加密密钥)', 'appid'=>'填写小程序的appid', 'appsecret'=>'填写小程序的appsecret', ); $weObj = new Wechat($options); $weObj->valid(); // RECRIECT TO SERVICE $msg = array( 'ToUserName'=>$weObj->getRev()->getRevFrom(), 'FromUserName'=>$weObj->getRev()->getRevTo(), 'CreateTime'=>$weObj->getRev()->getRevCtime(), 'MsgType'=>'transfer_customer_service', ); $weObj->transfer_customer_service()->reply(); return true; ?>
增加一段代码,让无法处理的消息,转发给客服小程序。这样即使离线也可以收到推送。
消息推送——回复消息给用户 巨坑2!
这里又出现第二个巨坑,就是不能直接return结构体回复给顾客,必须调用服务端接口。代码如下:
php define('IN_MOD', TRUE); header("Content-Type: text/html;charset=utf-8"); date_default_timezone_set('PRC');//其中PRC为“中华人民共和国 include_once('wechat.class.php'); $options = array( 'token'=>'填写界面配置的 Token(令牌)', 'encodingaeskey'=>'填写界面配置的 EncodingAESKey(消息加密密钥)', 'appid'=>'填写小程序的appid', 'appsecret'=>'填写小程序的appsecret', ); $weObj = new Wechat($options); $weObj->valid(); // REPLY TO CUSTOMER if ($weObj->getRev()->getRevType() == 'text' && $weObj->getRev()->getRevContent()."" == "TEST") { $url='https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='.$weObj->checkAuth(); $msg = array( 'touser' => $weObj->getRev()->getRevFrom(), 'msgtype' => 'text', 'text' => array( 'content' => 'HELLOWORLD!' ) ); $msg = json_encode($msg); $ret = $weObj->http_post($url, $msg); return 'success'; } // RECRIECT TO SERVICE $msg = array( 'ToUserName'=>$weObj->getRev()->getRevFrom(), 'FromUserName'=>$weObj->getRev()->getRevTo(), 'CreateTime'=>$weObj->getRev()->getRevCtime(), 'MsgType'=>'transfer_customer_service', ); $weObj->transfer_customer_service()->reply(); return true; ?>
如果收到的用户消息,并且内容是TEST的时候,返回HELLOWORLD,效果如下:
图片校验是否违法请求1——巨坑3!
相关文档在这里:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/sec-check/security.mediaCheckAsync.html
首先使用java构造个http请求,推送给微信:
String mediaurl = "http://www.pixysoft.cn/images/pages/moc/dab7b3_81493ed8bd1e4d53bc3a9ce761734675~mv2.png"; String url = "https://api.weixin.qq.com/wxa/media_check_async?access_token=ACCESS_TOKEN"; JsonObject params = new JsonObject(); params.addProperty("version", 2); params.addProperty("openid", "o6qII0dUQxFt3Dvs1m6sXv5vZydQ"); params.addProperty("scene", 1); params.addProperty("media_url", mediaurl); params.addProperty("media_type", 2); CloseableHttpClient httpClient = HttpClientBuilder.create().build(); HttpPost httpPost = new HttpPost(url.replace("ACCESS_TOKEN", WxssJSSDKCache.getAccessToken())); httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json"); String body = JsonUtils.toJson(params).toString(); StringEntity entity = new StringEntity(body, "utf-8"); entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); httpPost.setEntity(entity); org.apache.http.HttpResponse response1; response1 = httpClient.execute(httpPost); InputStream inputStream = response1.getEntity().getContent(); ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buffer = new byte[8192]; int bytesRead = 0; while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) { out.write(buffer, 0, bytesRead); } out.flush(); out.close(); System.out.println(new String(out.toByteArray()));
- 首先要求这个openid的用户在2小时内登录过小程序。
- 其次通过接口获取access_token,这个步骤咱们就省略了,可以看这里:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
- 最后,注意请求体必须声明"UTF-8"。我看到很多朋友调用敏感字检查的时候,都没有正确返回屏蔽信息,就是因为没有使用utf-8!
调用成功,会返回:
{"errcode":0,"errmsg":"ok","trace_id":"62219863-342b4e47-6dedd2b5"}
图片校验是否违法请求2——异步回调
修改服务端的php代码,新增一个事件监听:
php define('IN_MOD', TRUE); header("Content-Type: text/html;charset=utf-8"); date_default_timezone_set('PRC');//其中PRC为“中华人民共和国 include_once('wechat.class.php'); $options = array( 'token'=>'填写界面配置的 Token(令牌)', 'encodingaeskey'=>'填写界面配置的 EncodingAESKey(消息加密密钥)', 'appid'=>'填写小程序的appid', 'appsecret'=>'填写小程序的appsecret', ); $weObj = new Wechat($options); $weObj->valid(); // EVENT HANDLE if ($weObj->getRev()->getRevType() == 'event') { $event = $weObj->getRev()->getRevEvent(); $event = $event['event']; if ($event == 'wxa_media_check') { $url = 'https://www.pixysoft.cn:8443/sso/wxss/callback/wxa_media_check'; $t = time(); $sign = 'wxa_media_check'.$t.$options['appsecret']; $sign = md5($sign); $postdata = array( 'req' => json_encode($weObj->getRevData()), 't' => $t, 'sign' => $sign, ); return $weObj->http_post($url, $postdata); } } // REPLY TO CUSTOMER if ($weObj->getRev()->getRevType() == 'text' && $weObj->getRev()->getRevContent()."" == "TEST") { $url='https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='.$weObj->checkAuth(); $msg = array( 'touser' => $weObj->getRev()->getRevFrom(), 'msgtype' => 'text', 'text' => array( 'content' => 'HELLOWORLD!' ) ); $msg = json_encode($msg); $ret = $weObj->http_post($url, $msg); return 'success'; } // RECRIECT TO SERVICE $msg = array( 'ToUserName'=>$weObj->getRev()->getRevFrom(), 'FromUserName'=>$weObj->getRev()->getRevTo(), 'CreateTime'=>$weObj->getRev()->getRevCtime(), 'MsgType'=>'transfer_customer_service', ); $weObj->transfer_customer_service()->reply(); return true; ?>
判断回调数据是否event,类型是否wxa_media_check,如果是,则表示图片检测结果出来了, 我就把结果打个包,发给服务端程序进一步处理。得到的返回数据是:
格式化一下:
{ "ToUserName": "gh_f8935bc8ccb8", "FromUserName": "o6qII0bS2NFHsMtZ7XGGPC6JapuA", "CreateTime": "1646368869", "MsgType": "event", "Event": "wxa_media_check", "appid": "wx207f784d4c617ec9", "trace_id": "62219863-342b4e47-6dedd2b5", "version": "2", "detail": { "strategy": "content_model", "errcode": "0", "suggest": "pass", "label": "100", "prob": "90" }, "errcode": "0", "errmsg": "ok", "result": { "suggest": "pass", "label": "100" } }
到了这里,整个图片检测逻辑就完成了。今天的入门包括了客服接口配置、接口php逻辑编写、图片检测回调。
文所有代码在这里可以下载:
链接: https://pan.baidu.com/s/1pkFfEgFHoHOG0tFiS-P1RA
提取码: ab9u
也欢迎大家关注咱们公众号:辰同学技术 微信公众号,同样会分享各种技术10分钟从入门到吐槽: