一、创建自定义菜单【测试号】
1.截图
【没有小程序,因为我没做】
1. 点击第一个一级菜单:“今日歌曲”
2. 点击第二个一级菜单:“菜单”
扫码带提示:扫描QR.jpg
扫码推事件:扫描QR.jpg
拍照或系统发图,发送位置:这两个和上的次的功能一样,给公众号发送图片和位置
赞一下
3. 点击第三个一级菜单:“关于我”
看图:为用户发送一张图片
二维码:为用户发送一张二维码图片,扫描得到
古诗文网:跳转url
往日推文:为用户发送往日的图文
2.代码实现
(1)接口函数文件:【FUN.php】
<?php
/**
* Created by PhpStorm.
* 函数文件
*/
//获取测试号的token值
function get_TOKEN(){
$appid = "测试号公众号/的Appid";
$appsecret = "测试号公众号/的AppSecret";
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appid&secret=$appsecret";
$output = https_request($url);
$result = (array)json_decode($output);
$access_token=$result['access_token'];
return $access_token;
}
//定义服务请求函数,get/post
//参考链接为:https://segmentfault.com/a/1190000006220620
//php中curl用法就是:创建curl会话 -> 配置参数 -> 执行 -> 关闭会话
function https_request($url, $data = null)
{
$curl = curl_init();//创建了一个curl会话资源,成功返回一个句柄
curl_setopt($curl, CURLOPT_URL, $url);//函数传参过来,设置URL
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);// 信任任何证书
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);// 检查证书中是否设置域名
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//设置是否将响应结果存入变量,1是存入,0是直接echo出
curl_setopt($curl, CURLOPT_TIMEOUT,60);//设置一个最长的可忍受的连接时间,秒为单位
if (!empty($data)) {
curl_setopt($curl, CURLOPT_POST, 1);//表明是POST请求
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);//设置POST的数据域
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//同上
$output = curl_exec($curl);//执行,然后将响应结果存入$output变量
curl_close($curl);//关闭curl会话资源
return $output;
}
(2)创建菜单:【Create_menu.php】
<?php
/**
* 创建自定义菜单
* https://tool.ip138.com/json/
*/
//error_reporting(0);
require "FUN.php";
$access_token = get_TOKEN();
echo "测试号access_token的值为:" . $access_token . "</br>";
//创建自定义菜单接口创建自定义菜单
$urlMenu = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=$access_token";
$MenuData = '{
"button": [
{
"type": "click",
"name": "今日歌曲",
"key": "KEY_music"
},
{
"name": "菜单",
"sub_button": [
{
"type": "scancode_waitmsg",
"name": "扫码带提示",
"key": "rselfmenu_0_0",
"sub_button": []
},
{
"type": "scancode_push",
"name": "扫码推事件",
"key": "rselfmenu_0_1",
"sub_button": []
},
{
"type": "pic_photo_or_album",
"name": "拍照或者相册发图",
"key": "rselfmenu_1_1",
"sub_button": []
},
{
"name": "发送位置",
"type": "location_select",
"key": "rselfmenu_2_0"
},
{
"type": "click",
"name": "赞一下",
"key": "KEY_good"
}
]
},
{
"name": "关于我",
"sub_button": [
{
"type": "click",
"name": "看图",
"key": "KEY_pic"
},
{
"type": "click",
"name": "二维码",
"key": "KEY_qr"
},
{
"type": "view",
"name": "古诗文网",
"url": "https://www.gushiwen.org/"
},
{
"type": "click",
"name": "往日推文",
"key": "KEY_article"
}
]
}
]
}';
$output1 = https_request($urlMenu, $MenuData);
echo $output1;
?>
(3)菜单事件实现:【Menu.php】
<?php
error_reporting(0);
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
if (!isset($_GET['echostr'])) {
$wechatObj->responseMsg();
} else {
$wechatObj->valid();
}
class wechatCallbackapiTest
{
//验证接口的函数,用于申请成为开发者时向微信发送验证信息
public function valid()
{
$echoStr = $_GET["echostr"];
if ($this->checkSignature()) {
echo $echoStr;
exit;
}
}
//校验函数,校验对接身份函数,签名验证程序
private function checkSignature()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if ($tmpStr == $signature) {
return true;
} else {
return false;
}
}
//响应消息函数
public function responseMsg()
{
//$postStr为用户在微信公众平台发的信息
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if (!empty($postStr)) {
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$RX_TYPE = trim($postObj->MsgType);//判断平台接受的消息类型
//用户发送的消息类型判断
switch ($RX_TYPE) {
case "event": //事件消息
$resultStr = $this->receiveEvent($postObj);
break;
default:
$resultStr = "unknow msg type: " . $RX_TYPE;
break;
}
echo $resultStr;
} else {
echo "???";
exit;
}
}
//7.事件处理
private function receiveEvent($object)
{
$MsgEvent = trim($object->Event);
if ($MsgEvent == 'subscribe') { //订阅事件
$keyword = $object->EventKey;
if (isset($keyword)) {
$qrscene_Str = substr(trim($keyword), 0, 7);
if ($qrscene_Str == qrscene) {
$contentStr = "欢迎关注公众号,你是来自扫描二维码关注的,你的场景值为:" . $object->EventKey . "\n";
} else {
$contentStr = "欢迎关注公众号,你不是来自扫描二维码关注的" . "\n";
}
} else {
$contentStr = "欢迎关注公众号";
}
} elseif ($MsgEvent == "SCAN") {
$keyword = $object->EventKey;
switch ($keyword) {
case "123":
// $contentStr = "你的场景值为:" . $keyword;
$contentStr = array();
$contentStr[] = array
("Title" => "推文标题",
"Description" => "公众号:介绍图文",
"PicUrl" => "图片链接",
"Url" => "推文链接");
$resultStr = $this->transmitNews($object, $contentStr);
break;
case "1234":
$contentStr = "点赞❤";
$resultStr = $this->transmitText($object, $contentStr);
default:
break;
}
return $resultStr;
} elseif ($MsgEvent == "CLICK") {//点击事件
$EventKey = $object->EventKey;
switch ($EventKey) {
case "KEY_music":
$content = array("Title" => "借一束光",
"Description" => "歌手:圈九",
"MusicUrl" => "随便一个音乐链接",
"HQMusicUrl" => "随便一个音乐链接");
$resultStr = $this->transmitMusic($object, $content);
break;
case "KEY_good":
$contentStr = "点赞❤ヾ(≧▽≦*)o";
$resultStr = $this->transmitText($object, $contentStr);
break;
case "KEY_pic":
$contentStr = array
("MediaId" => "图片的Mediaid,需要上传素材获得,代码附后,尚未研究看懂");
$resultStr = $this->transmitImage($object, $contentStr);
break;
case "KEY_article":
$contentStr = array();
$contentStr[] = array
("Title" => "推文标题",
"Description" => "单图文内容:(往日推文)",
"PicUrl" => "图片链接",
"Url" => "推文链接");
$resultStr = $this->transmitNews($object, $contentStr);
break;
case "KEY_qr":
$contentStr = array
("MediaId" => "图片的Mediaid");
$resultStr = $this->transmitImage($object, $contentStr);
break;
default:
break;
}
return $resultStr;
} elseif ($MsgEvent == "scancode_push") {
$contentStr = "扫码推事件";
} elseif ($MsgEvent == "scancode_waitmsg") {//扫码推送图文消息
// $contentStr = "为您推送公众号介绍图文";
$contentStr = "扫码带提示:类型为 " . $object->ScanCodeInfo->ScanType . " 结果为:" . $object->ScanCodeInfo->ScanResult;
}
$resultStr = $this->transmitText($object, $contentStr);
return $resultStr;
}
//1.回复文本消息
private function transmitText($object, $content)
{
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(), $content);
return $resultStr;
}
//2.回复图文消息
private function transmitNews($object, $arr_item)
{
if (!is_array($arr_item))
return;
$itemTpl = " <item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>
";
$item_str = "";
foreach ($arr_item as $item)
$item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
$newsTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<Content><![CDATA[]]></Content>
<ArticleCount>%s</ArticleCount>
<Articles>
$item_str
</Articles>
</xml>";
$resultStr = sprintf($newsTpl, $object->FromUserName, $object->ToUserName, time(), count($arr_item));
return $resultStr;
}
//3.回复音乐信息
private function transmitMusic($object, $musicArray)
{
$itemTpl = "<Music>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<MusicUrl><![CDATA[%s]]></MusicUrl>
<HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
</Music>";
$item_str = sprintf($itemTpl, $musicArray['Title'], $musicArray['Description'], $musicArray['MusicUrl'], $musicArray['HQMusicUrl']);
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[music]]></MsgType>
$item_str
</xml>";
$resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time());
return $resultStr;
}
//4.回复图片信息
private function transmitImage($object, $imageArray)
{
$itemTpl = "<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>";
$item_str = sprintf($itemTpl, $imageArray['MediaId']);
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
$item_str
</xml>";
$resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time());
return $resultStr;
}
}
?>
3.解析
菜单:
代码解析:
略,懒得写,可能过几天写。。。
注:https://tool.ip138.com/json/在线格式化json数据
学习链接:https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html
附加:上传永久素材的代码:【修改一下两处的图片名称和最开头的appid和appsercret即可】
代码摘抄于网上
<?php
$APPID = "测试号/公众号的appid";
$APPSECRET = "测试号/公众号的appsercret";
$info = json_decode(file_get_contents("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$APPID&secret=$APPSECRET"));
//获取token
$access_token = $info->access_token;
/* 使用curl函数 */
$url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=$access_token&type=image";;
$post_data = array(
'media' => '@QR.jpg',
);
$response = curl_http($url, 'POST', $post_data);
$params = array();
$params = json_decode($response, true);
if (isset($params['errcode'])) {
echo "error:" . $params['errcode'];
echo "msg :" . $params['errmsg'];
exit;
}
var_dump($params);
/**
* http请求方式: 默认GET
*/
function curl_http($url, $method = "GET", $postfields)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_URL, $url);
switch ($method) {
case "POST":
curl_setopt($ch, CURLOPT_POST, true);
if (!empty($postfields)) {
$hadFile = false;
if (is_array($postfields) && isset($postfields['media'])) {
/* 支持文件上传 */
if (class_exists('\CURLFile')) {
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
foreach ($postfields as $key => $value) {
if (isPostHasFile($value)) {
$postfields[$key] = new \CURLFile(realpath(ltrim($value, '@')));
$hadFile = true;
}
}
} elseif (defined('CURLOPT_SAFE_UPLOAD')) {
if (isPostHasFile($value)) {
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
$hadFile = true;
}
}
}
$tmpdatastr = (!$hadFile && is_array($postfields)) ? http_build_query($postfields) : $postfields;
curl_setopt($ch, CURLOPT_POSTFIELDS, $tmpdatastr);
}
break;
default:
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
break;
}
$ssl = preg_match('/^https:\/\//i', $url) ? TRUE : FALSE;
curl_setopt($ch, CURLOPT_URL, $url);
if ($ssl) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
}
$response = curl_exec($ch);
curl_close($ch);
if (empty($response)) {
exit("错误请求");
}
return $response;
}
function isPostHasFile($value)
{
if (is_string($value) && strpos($value, '@') === 0 && is_file(realpath(ltrim($value, '@')))) {
return true;
}
return false;
}
//命令不会返回错误 如果返回空 2>&1 输出报错信息 如果乱码就是用 header("content-type:text/html;charset=gbk"); curl下载地址 https://curl.haxx.se/download.html
$filepath = './QR.jpg';
/* 使用exec函数 */
$command = 'curl -F media=@' . $filepath . ' "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=' . $access_token . '&type=image"';
$retval = array();
exec($command, $retval, $status);
$params = array();
$params = json_decode($retval[0], true);
if ($status != 0) {
$params = array(
'errcode' => '-100',
'errmsg' => '公众号服务出错,请联系管理员',
);
}
return $params;
/* 使用system函数 */
$command = 'curl -F media=@' . $filepath . ' "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=' . $access_token . '&type=image" 2>&1';
$retval = 1;
$last_line = system($command, $retval);
$params = array();
$params = json_decode($last_line, true);
if ($retval != 0) {
if (isset($params['errcode'])) {
$params = array(
'errcode' => '-100',
'errmsg' => '公众号服务出错,请联系管理员',
);
}
}
return $command;
2020-06-16