php微信公众账号开发之前五个坑(一)


Posted in PHP onSeptember 18, 2016

直入主题:

微信公众账号开发文档,官方版(https://mp.weixin.qq.com/wiki),相信我,我已经无力吐槽写这个文档的人了,我真心想杂碎这个键盘,但是下手之后才发现,原来键盘是我自己花钱买的。。。。尴尬了。 

废话不说,直接说怎么部署,怎么开发。 

首先,你得有一个公众平台账号,好了,开始计坑。 

第一坑,不要以为不是企业号就不能开发了,可以申请测试号的,比所谓的订阅号接口多多了。

 php微信公众账号开发之前五个坑(一)

进入后台管理之后,点击开发者工具,可以看到公众平台测试账号,直接进入即可。开始填写自己的配置。 

php微信公众账号开发之前五个坑(一)

php微信公众账号开发之前五个坑(一)

注意涂鸦部分,这部分是程序中必须要配置的东东,如果没有配置的话,这是一定不成功的。 

第二坑,当然,你这么配置也一定是不成功的,不要问我为什么。没图说个几把。。。 

php微信公众账号开发之前五个坑(一)

请不要认为企鹅帝闹着玩,这是真的,必须是80端口,其实也就发布一个域名的网站即可。因为域名的网站都是80端口出来的,继续说正题。 

企鹅帝告诉我们,要用微信账号,必须有一台服务器,然后配置我们发布的网站就行了,请注意,token是自己设定的,这个不是自动生成的,自己设定。。URL就是我们发布的网站名称 

第三坑,网站不发布,接口配置信息是永远配置不过去的,记住,是永远。 

JS接口安全域名,这个请直接参考文档(http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html)。 

JS接口安全域名的目的是为了下载图片,调用微信图片接口等等,比如当你需要调用摄像头的时候,或者说说需要上传照片的时候,这时候就需要JS安全接口了,关于具体的内容暂不做详细描述。 

在微信公众账号测试号的版本后台中,有一个体验接口权限表里面的这一项也是必须配置的。也不算是必须配置,而是这个接口可以获取到微信用户的部分信息。值得提醒的是每个公众账号对应的每个ID是唯一的,也就是说,即便网站内网不变,如果换了公众号,那么,这时候的微信公众号的数据是不能共通的,只是相对公共号唯一。 

php微信公众账号开发之前五个坑(一)

第四坑,申请微信网页授权的时候,这里的网页授权用户基本信息,这个本身没问题,但是没有提示就有问题了。 

php微信公众账号开发之前五个坑(一)

这里的网址,请注意,一定是不含www的,而且后面没有反斜杠,也就是说这里的网址的回调格式是  abc.com OK,请记住这个格式,必须这么干。好了,服务器暂且这样,暂开始用代码说话。 

首先从服务器验证说起。这个在官网是有例子的,不过是PHP的,其实说白了首先就是验证一个随机数,然后在POST的情况下,检测返回值即可。直接上代码 

public ActionResult Index()
 {
 if (Request.HttpMethod.ToLower() == "post")
 {
 if (CheckSignature())//验证服务器是否通过
 {
 GetMenuList();//加载菜单
 }
 else
 {
 Response.Write("<h1>Oh</h1><h2>我们相遇在火星吧!!!</h2>");
 Response.End();
 }
 }
 else
 {
 CheckWechat();
 }
 return View();
 }

 

 /// <summary>
 /// 返回随机数表示验证成功
 /// </summary>
 private void CheckWechat()
 {
 if (string.IsNullOrEmpty(Request.QueryString["echoStr"]))
 {
 Response.Write("消息并非来自微信");
 Response.End();
 }
 string echoStr = Request.QueryString["echoStr"];
 if (CheckSignature())
 {
 Response.Write(echoStr);
 Response.End();
 }
 }

/// <summary>
 /// 验证微信签名
 /// </summary>
 /// <returns></returns>
 /// 将token、timestamp、nonce三个参数进行字典序排序
 /// 将三个参数字符串拼接成一个字符串进行sha1加密
 /// 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。
 private bool CheckSignature()

 {
 string signature = Convert.ToString(Request["signature"]);
 string timestamp = Convert.ToString(Request["timestamp"]);
 string nonce = Convert.ToString(Request["nonce"]);
 string[] ArrTmp = { Token, timestamp, nonce };
 Array.Sort(ArrTmp); //字典排序 
 string tmpStr = string.Join("", ArrTmp);
 tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
 tmpStr = tmpStr.ToLower();
 if (tmpStr == signature)
 {
 return true;
 }
 else
 {
 return false;
 }
 }

然后,公众平台在有权限的情况下是自定义菜单的,但是一旦开始自定义菜单,原来的手动编辑的菜单是不能用的,也就是说,如果服务器验证通过,那么必须用自己的代码控制。 

我们一起来看GetMenuList()这个方法,这个其实很简单的,就是随便凭借一个JSON格式字符串。然后调用微信的接口即可。  public void GetMenuList()   

<em id="__mceDel"> { 
 string weixin1 = ""; 
 weixin1 = @" { 
 ""button"":[ 
 { 
 ""type"":""click"", 
 ""name"":""你好!"", 
 ""key"":""hello"" 
 }, 
 { 
 ""type"":""view"", 
 ""name"":""公司简介"", 
 ""url"":""http://www.xnfhtech.com"" 
 }, 
 { 
 ""name"":""产品介绍"", 
 ""sub_button"":[ 
 { 
 ""type"":""click"", 
 ""name"":""产品1"", 
 ""key"":""p1"" 
 }, 
 { 
 ""type"":""click"", 
 ""name"":""产品2"", 
 ""key"":""p2"" 

 }] 
 }] }"; 

 

 string access_token = Tools.WA_GetAccess_Token.IsExistAccess_Token(); 
 string i = this.MenuCreate(menu, access_token); 
 Response.Write(i); 
 }<br><br>
</em>
public string MenuCreate(string MenuJson, string access_token)
 {
 JavaScriptSerializer Jss = new JavaScriptSerializer();
 string setMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}";
 setMenuUrl = string.Format(setMenuUrl, access_token);//获取token、拼凑url
 string respText = WebRequestPostOrGet(setMenuUrl, MenuJson);
 Dictionary<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(respText);
 return respDic["errcode"].ToString();//返回0发布成功
 }

 

/// <summary>
 /// Post/get 提交调用抓取
 /// </summary>
 /// <param name="url">提交地址</param>
 /// <param name="param">参数</param>
 /// <returns>string</returns>
 public string WebRequestPostOrGet(string sUrl, string sParam)
 {
 byte[] bt = System.Text.Encoding.UTF8.GetBytes(sParam);
 Uri uriurl = new Uri(sUrl);
 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uriurl);//HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url + (url.IndexOf("?") > -1 ? "" : "?") + param);
 req.Method = "Post";
 req.Timeout = 120 * 1000;
 req.ContentType = "application/x-www-form-urlencoded;";
 req.ContentLength = bt.Length;

 using (Stream reqStream = req.GetRequestStream())//using 使用可以释放using段内的内存
 {
 reqStream.Write(bt, 0, bt.Length);
 reqStream.Flush();
 }
 try
 {
 using (WebResponse res = req.GetResponse())
 {
 //在这里对接收到的页面内容进行处理
 Stream resStream = res.GetResponseStream();
 StreamReader resStreamReader = new StreamReader(resStream, System.Text.Encoding.UTF8);
 string resLine;
 System.Text.StringBuilder resStringBuilder = new System.Text.StringBuilder();
 while ((resLine = resStreamReader.ReadLine()) != null)
 {
  resStringBuilder.Append(resLine + System.Environment.NewLine);
 }
 resStream.Close();
 resStreamReader.Close();
 return resStringBuilder.ToString();

 }

 }
 catch (Exception ex)
 {
 return ex.Message;//url错误时候回报错
 }

 }

好吧,我承认我是一个不明真相的吃货,怎么又多了一个access_token=IsExistAccess_Token();呢,莫着急,宝宝告诉你。

当我们阅读文档的时候,我们会发现,这里的Access_Token是每两个小时就过期的。这里的方法就是让他过期的时候自动获取。 

第五坑,这里的JSON字符串,也就是要展示的菜单,我希望大家都用小写,如果用了大写,那么,呵呵,哈哈了真心的,很操蛋的,他会告诉你没有用UTF8编码,但是你真心是编码过的,可惜还是出错,所以,还是小写吧,唉 

继续说两个小时自动获取之后,就是通过MenuCreate(调用微信菜单接口)输出即可。上代码。 

/// <summary>
/// 防止每次请求的token两个小时的变化
/// </summary>
public class WA_GetAccess_Token
{
 public WA_GetAccess_Token()
 {
 }
 public static WAEntity.Access_token GetAccess_Token()
 {
 string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ ConfigurationManager.AppSettings["AppID"] + "&secret="+ ConfigurationManager.AppSettings["AppSecret"];
 Access_token entity = new Access_token();
 try
 {
 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
 req.Method = "GET";
 using (WebResponse wr = req.GetResponse())
 {
 HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();
 StreamReader reader = new StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.UTF8);
 string content = reader.ReadToEnd();
 Access_token token = new Access_token();
 token = JsonHelper.ParseFromJson<Access_token>(content);
 entity.access_token = token.access_token;
 entity.expires_in = token.expires_in;
 }

 }

 catch{ //记录日志}
 return entity;

 }

 /// <summary> 
 /// 根据当前日期 判断Access_Token 是否超期 如果超期返回新的Access_Token 否则返回之前的Access_Token 
 /// </summary> 
 /// <param name="datetime"></param> 
 /// <returns></returns> 
 public static string IsExistAccess_Token()
 {
 try
 {
 string Token = string.Empty;
 DateTime YouXRQ;
 //读取XML文件中的数据,并显示出来
 string filepath = HttpContext.Current.Request.MapPath("~/XMLFile.xml");
 StreamReader str = new StreamReader(filepath, System.Text.Encoding.UTF8);
 XmlDocument xml = new XmlDocument();
 xml.Load(str);
 str.Close();
 str.Dispose();
 Token = xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText;
 YouXRQ = Convert.ToDateTime(xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText);
 if (DateTime.Now > YouXRQ)
 {

 DateTime _youxrq = DateTime.Now;
 WAEntity.Access_token mode = GetAccess_Token();
 xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText = mode.access_token;
 _youxrq = _youxrq.AddSeconds(Convert.ToInt32(mode.expires_in));
 xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText = _youxrq.ToString();
 xml.Save(filepath);
 Token = mode.access_token;
 }

 return Token;
 }
 catch (Exception ex)
 {
 return "";//记录日志
 }

 }

}

 

public class Access_token
{
 public Access_token()
 { }
 public string access_token { get; set; }
 public string expires_in { get; set; }

}

 

public class JsonHelper
{
 /// <summary> 
 /// 生成Json格式 
 /// </summary> 
 /// <typeparam name="T"></typeparam> 
 /// <param name="obj"></param> 
 /// <returns></returns> 
 public static string GetJson<T>(T obj)

 {
 DataContractJsonSerializer json = new DataContractJsonSerializer(obj.GetType());
 using (MemoryStream stream = new MemoryStream())
 {
 json.WriteObject(stream, obj);
 string szJson = Encoding.UTF8.GetString(stream.ToArray()); return szJson;
 }
 }
 /// <summary> 
 /// 获取Json的Model 
 /// </summary> 
 /// <typeparam name="T"></typeparam> 
 /// <param name="szJson"></param> 
 /// <returns></returns> 
 public static T ParseFromJson<T>(string szJson)
 {
 T obj = Activator.CreateInstance<T>();
 using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(szJson)))
 {
 DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
 return (T)serializer.ReadObject(ms);
 }
 }

}

原谅我又不明真相了,所谓的XMLFile.xml这又是什么鬼,好吧,我其实不想说的这么直白的,还是代码直接上比较好。

<?xml version="1.0" encoding="utf-8"?>
<xml>
 <Access_Token>获取TOKEN</Access_Token>
 <Access_YouXRQ>2015/9/12 17:56:31</Access_YouXRQ>
</xml>

我确定这个你真心不想说什么了 

好吧,默默的吃着瓜子,静静的看着你们继续,今天就先到这里,随后我们继续走起,已经五个坑了呀,宝宝心里苦呀。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php实现jQuery扩展函数
Oct 30 PHP
php addslashes和mysql_real_escape_string
Jan 24 PHP
php is_file()和is_dir()用于遍历目录时用法注意事项
Mar 02 PHP
推荐一款MAC OS X 下php集成开发环境mamp
Nov 08 PHP
PHP去掉json字符串中的反斜杠\及去掉双引号前的反斜杠
Sep 30 PHP
Zend Framework教程之Application用法实例详解
Mar 14 PHP
PHP将URL转换成短网址的算法分享
Sep 13 PHP
php Session无效分析资料整理
Nov 29 PHP
ZendFramework框架实现连接两个或多个数据库的方法
Dec 08 PHP
PHP yield关键字功能与用法分析
Jan 03 PHP
php学习笔记之字符串常见操作总结
Jul 16 PHP
PHPStorm2020.1永久激活及下载更新至2020(推荐)
Sep 25 PHP
php中实现进程锁与多进程的方法
Sep 18 #PHP
注意!PHP 7中不要做的10件事
Sep 18 #PHP
深入理解PHP类的自动载入机制
Sep 16 #PHP
PHP实现链式操作的原理详解
Sep 16 #PHP
详解PHP中websocket的使用方法
Sep 15 #PHP
PHP简单实现上一页下一页功能示例
Sep 14 #PHP
PHP自定义函数格式化json数据示例
Sep 14 #PHP
You might like
php email邮箱正则
2008/10/08 PHP
Centos6.5和Centos7 php环境搭建方法
2016/05/27 PHP
PHP数据库操作四:mongodb用法分析
2017/08/16 PHP
JS中==与===操作符的比较
2009/03/21 Javascript
jquery的attr方法禁用表单元素禁用输入内容
2014/06/23 Javascript
使用RequireJS优化JavaScript引用代码的方法
2015/07/01 Javascript
js获取鼠标位置实例详解
2015/12/09 Javascript
nodejs获取微信小程序带参数二维码实现代码
2017/04/12 NodeJs
r.js来合并压缩css文件的示例
2018/04/26 Javascript
开发一个Parcel-vue脚手架工具(详细步骤)
2018/09/22 Javascript
Nodejs核心模块之net和http的使用详解
2019/04/02 NodeJs
JS匿名函数内部this指向问题详析
2019/05/10 Javascript
微信小程序使用echarts获取数据并生成折线图
2019/10/16 Javascript
vue学习笔记之slot插槽用法实例分析
2020/02/29 Javascript
[01:01:23]完美世界DOTA2联赛PWL S2 Forest vs FTD.C 第一场 11.26
2020/11/30 DOTA
跟老齐学Python之有容乃大的list(4)
2014/09/28 Python
Python实现栈的方法
2015/05/26 Python
python实现自动登录人人网并采集信息的方法
2015/06/28 Python
Python列表list内建函数用法实例分析【insert、remove、index、pop等】
2017/07/24 Python
Python中logging实例讲解
2019/01/17 Python
PyQt5实现简易计算器
2020/05/30 Python
Python爬虫中Selenium实现文件上传
2020/12/04 Python
Sisley法国希思黎美国官方网站:享誉全球的奢华植物美容品牌
2020/06/27 全球购物
如何在发生故障的节点上重新安装 SQL Server
2013/03/14 面试题
《春笋》教学反思
2014/04/15 职场文书
工程负责人任命书
2014/06/06 职场文书
保护动物的标语
2014/06/11 职场文书
力学专业求职信
2014/07/23 职场文书
中学生关于梦想的演讲稿
2014/08/22 职场文书
幼儿园教师求职信
2015/03/20 职场文书
2015年库房工作总结
2015/04/30 职场文书
航班延误投诉信
2015/07/02 职场文书
《圆的周长》教学反思
2016/02/17 职场文书
2019奶茶店创业计划书范本!
2019/07/15 职场文书
MySQL外键约束(FOREIGN KEY)案例讲解
2021/08/23 MySQL
MySQL数据库中的锁、解锁以及删除事务
2022/05/06 MySQL