搜尋
首頁微信小程式微信開發php微信公眾帳號開發遇到的五個坑總結

這篇文章主要為大家詳細介紹了php微信公眾帳號開發之五個坑,具有一定的參考價值,有興趣的小伙伴們可以參考一下

##菜單回覆是需要處理XML文件的,我們根據微信傳回的XML文件,可以得到每個微信用戶相對於微信公眾號的唯一識別。微信公眾平台的機制簡單的將就是我們自己輸出固定格式的xml文件,然後微信APP負責解析,得到我們想要的信息,然後對信息統一處理。 

第六坑,如果你看微信文檔,那麼,絕對坑死你,上圖。這裡的ToUserName和FromUserName一定特麼的要分清楚了,記住,千萬不要寫反了,用戶對於微信而言是A→B,那麼微信對於用戶就是反著來的,貌似現在應該說清楚了。

php微信公眾帳號開發遇到的五個坑總結


/// <summary>
 /// 接收微信发送的XML消息并且解析
 /// </summary>
 private void ReceiveXml()
 {
 try
 {
  Stream requestStream = System.Web.HttpContext.Current.Request.InputStream;
  byte[] requestByte = new byte[requestStream.Length];
  requestStream.Read(requestByte, 0, (int)requestStream.Length);
  string requestStr = Encoding.UTF8.GetString(requestByte);

  if (!string.IsNullOrEmpty(requestStr))
  { 

  //封装请求类
  XmlDocument requestDocXml = new XmlDocument();
  requestDocXml.LoadXml(requestStr);
  XmlElement rootElement = requestDocXml.DocumentElement;
  WxXmlModel WxXmlModel = new WxXmlModel();
  if (rootElement != null)
  {
   WxXmlModel.ToUserName = rootElement.SelectSingleNode("ToUserName") == null ? "" : rootElement.SelectSingleNode("ToUserName").InnerText;
   WxXmlModel.FromUserName = rootElement.SelectSingleNode("FromUserName") == null ? "" : rootElement.SelectSingleNode("FromUserName").InnerText;
   WxXmlModel.CreateTime = rootElement.SelectSingleNode("CreateTime") == null ? "" : rootElement.SelectSingleNode("CreateTime").InnerText;
   WxXmlModel.MsgType = rootElement.SelectSingleNode("MsgType") == null ? "" : rootElement.SelectSingleNode("MsgType").InnerText;
   switch (WxXmlModel.MsgType)
   {

   case "text"://文本
    WxXmlModel.Content = rootElement.SelectSingleNode("Content") == null ? "" : rootElement.SelectSingleNode("Content").InnerText;
    break;
   case "image"://图片
    WxXmlModel.PicUrl = rootElement.SelectSingleNode("PicUrl") == null ? "" : rootElement.SelectSingleNode("PicUrl").InnerText;
    break;
   case "event"://事件
    WxXmlModel.Event = rootElement.SelectSingleNode("Event") == null ? "" : rootElement.SelectSingleNode("Event").InnerText;
    if (WxXmlModel.Event != "TEMPLATESENDJOBFINISH")//关注类型
    {
    WxXmlModel.EventKey = rootElement.SelectSingleNode("EventKey") == null ? "" : rootElement.SelectSingleNode("EventKey").InnerText;
    }
    break;
   default:
    break;
   }
  }
  ResponseXML(WxXmlModel);//回复消息
  }

 

 }
 catch (Exception ee)
 {
  //记录错误日志
 }
 }

 /// <summary>
 /// 回复消息
 /// </summary>
 /// <param name="WxXmlModel"></param>
 private void ResponseXML(WxXmlModel WxXmlModel)
 {
 string XML = "";
 switch (WxXmlModel.MsgType)
 {
  case "text"://文本回复
  var info = oauth.GetUserInfo(Tools.WA_GetAccess_Token.IsExistAccess_Token(), WxXmlModel.FromUserName);
  Tools.WAEntity.OAuthUser user = Tools.JsonHelper.ParseFromJson<Tools.WAEntity.OAuthUser>(info);
  var content = WxXmlModel.Content.ToUpper();
  string NcbActUrl = ConfigurationManager.AppSettings["NcbActUrl"];
  string appid = ConfigurationManager.AppSettings["AppID"];
  if (content.Contains("T"))//接受的文字如果包含T
  {
   //业务处理
  }
  else
  {
   XML = ResponseMessage.ReText(WxXmlModel.FromUserName, WxXmlModel.ToUserName, "/:rose农场大数据欢迎你!/:rose");

  }
  break;
  case "event":
  switch (WxXmlModel.Event.ToLower())
  {
   case "subscribe":
   if (string.IsNullOrEmpty(WxXmlModel.EventKey))
   {
    XML = ResponseMessage.ReText(WxXmlModel.FromUserName, WxXmlModel.ToUserName, "关注成功!/:rose");

   }
   else
   {
    XML = ResponseMessage.SubScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//扫描带参数二维码先关注后推送事件
   }
   break;
   case "scan":
   XML = ResponseMessage.ScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//扫描带参数二维码已关注 直接推送事件
   break;
   case "click"://处理单击事件
   if (WxXmlModel.EventKey == "p1")
   {
    //自己的业务逻辑
   }
   else
   {
    //自己的业务逻辑
   }
   break;
   case "unsubscribe"://取消关注
   break;
  }
  break;
  default://默认回复
  break;
 }
 Response.Write(XML);//输出组织的XML信息

 }

這就是選單的訊息處理,不明真相的群眾貌似會問那個所謂的ResponseMessage到底有幾個意思呢, OK,我已經無力吐槽我這三天研究出來的微信公共平台的東西了。 


public class ResponseMessage

{

 #region 接收的类型
 /// <summary>
 /// 接收文本
 /// </summary>
 /// <param name="FromUserName"></param>
 /// <param name="ToUserName"></param>
 /// <param name="Content"></param>
 /// <returns></returns>
 public static string GetTextTest(string FromUserName, string ToUserName, string Content, string key)
 {
 CommonMethod.WriteTxt(Content);//接收的文本消息
 string XML = "";
 switch (Content)
 {
  case "关键字":
  XML = ReText(FromUserName, ToUserName, "关键词回复测试——兴农丰华:" + key);
  break;
  case "单图文":
  XML = ReArticle(FromUserName, ToUserName, "测试标题", "测试详情——兴农丰华:" + key, "http://www.xnfhtech.com/templets/boze/images/20120130083143544.gif", "http://www.xnfhtech.com/");
  break;
  default:
  XML = ReText(FromUserName, ToUserName, "无对应关键字——兴农丰华:" + key);
  break;
 }
 return XML;

 }

 /// <summary>
 /// 未关注扫描带参数二维码
 /// </summary>
 /// <param name="FromUserName"></param>
 /// <param name="ToUserName"></param>
 /// <param name="EventKey"></param>
 /// <returns></returns>
 public static string SubScanQrcode(string FromUserName, string ToUserName, string EventKey)
 {
 return "";
 }
 

 /// <summary>
 /// 已关注扫描带参数二维码
 /// </summary>
 /// <param name="FromUserName"></param>
 /// <param name="ToUserName"></param>
 /// <param name="EventKey"></param>
 /// <returns></returns>
 public static string ScanQrcode(string FromUserName, string ToUserName, string EventKey)
 {
 return "";
 }
 #endregion
 

 #region 回复方式
 /// <summary>
 /// 回复文本
 /// </summary>
 /// <param name="FromUserName">发送给谁(openid)</param>
 /// <param name="ToUserName">来自谁(公众账号ID)</param>
 /// <param name="Content">回复类型文本</param>
 /// <returns>拼凑的XML</returns>

 public static string ReText(string FromUserName, string ToUserName, string Content)
 {
 string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//发送给谁(openid),来自谁(公众账号ID)
 XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//回复时间戳
 XML += "<MsgType><![CDATA[text]]></MsgType>";//回复类型文本
 XML += "<Content><![CDATA[" + Content + "]]></Content><FuncFlag>0</FuncFlag></xml>";//回复内容 FuncFlag设置为1的时候,自动星标刚才接收到的消息,适合活动统计使用
 return XML;

 }
 

 /// <summary>
 /// 回复单图文
 /// </summary>
 /// <param name="FromUserName">发送给谁(openid)</param>
 /// <param name="ToUserName">来自谁(公众账号ID)</param>
 /// <param name="Title">标题</param>
 /// <param name="Description">详情</param>
 /// <param name="PicUrl">图片地址</param>
 /// <param name="Url">地址</param>
 /// <returns>拼凑的XML</returns>

 public static string ReArticle(string FromUserName, string ToUserName, string Title, string Description, string PicUrl, string Url)
 {

 string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//发送给谁(openid),来自谁(公众账号ID)
 XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//回复时间戳
 XML += "<MsgType><![CDATA[news]]></MsgType><Content><![CDATA[]]></Content><ArticleCount>1</ArticleCount><Articles>";
 XML += "<item><Title><![CDATA[" + Title + "]]></Title><Description><![CDATA[" + Description + "]]></Description><PicUrl><![CDATA[" + PicUrl + "]]></PicUrl><Url><![CDATA[" + Url + "]]></Url></item>";
 XML += "</Articles><FuncFlag>0</FuncFlag></xml>";
 return XML;

 }


 /// <summary>
 /// 多图文回复
 /// </summary>
 /// <param name="FromUserName">发送给谁(openid)</param>
 /// <param name="ToUserName">来自谁(公众账号ID)</param>
 /// <param name="ArticleCount">图文数量</param>
 /// <param name="dtArticle"></param>
 /// <returns></returns>

 public static string ReArticle(string FromUserName, string ToUserName, int ArticleCount, System.Data.DataTable dtArticle)
 {

 string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//发送给谁(openid),来自谁(公众账号ID)
 XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//回复时间戳
 XML += "<MsgType><![CDATA[news]]></MsgType><Content><![CDATA[]]></Content><ArticleCount>" + ArticleCount + "</ArticleCount><Articles>";
 foreach (System.Data.DataRow Item in dtArticle.Rows)

 {
  XML += "<item><Title><![CDATA[" + Item["Title"] + "]]></Title><Description><![CDATA[" + Item["Description"] + "]]></Description><PicUrl><![CDATA[" + Item["PicUrl"] + "]]></PicUrl><Url><![CDATA[" + Item["Url"] + "]]></Url></item>";
 }
 XML += "</Articles><FuncFlag>0</FuncFlag></xml>";
 return XML;

 }

 #endregion

 }

OK,加上自己的邏輯程式碼,是不是完美的實現了回應? 


第七坑,我真心不想數了,你確定這個回覆可以麼?說真的,寶寶不確定,因為你寫了之後知道在哪裡調用麼,我的乖乖,尼瑪,服務器驗證通過就把回復加上去是最保險的。我已經沒有節操了。

接下來我們說什麼呢,我們就說說取得使用者資訊這個東西吧,因為我們這些東西一般都是基於H5頁面的。所以,就要用到之前我們配置的


php微信公眾帳號開發遇到的五個坑總結

這個東東,其實這個相對於前面的至少坑少了很多,真心的,寶寶就暫時不說他坑了。上個代碼吧。


//微信网页授权2.0
public class Oauth2
{
 JavaScriptSerializer Jss = new JavaScriptSerializer();
 public Oauth2() { }
 

 /// <summary>
 /// 对页面是否要用授权
 /// </summary>
 /// <param name="Appid">微信应用id</param>
 /// <param name="redirect_uri">回调页面</param>
 /// <param name="scope">应用授权作用域snsapi_userinfo(不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)</param>
 /// <returns>授权地址</returns>

 public string GetCodeUrl(string Appid, string redirect_uri, string scope)
 {
 return string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope={2}&state=STATE#wechat_redirect", Appid, redirect_uri, scope);
 }

 

 /// <summary>
 /// 对页面是否要用授权
 /// </summary>
 /// <param name="Appid">微信应用id</param>
 /// <param name="redirect_uri">回调页面</param>
 /// <param name="scope">应用授权作用域snsapi_userinfo(不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)</param>
 /// <returns>授权地址</returns>
 public string GetCodeUrl(string Appid, string redirect_uri, string scope,string state)
 {
 return string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope={2}&state={3}#wechat_redirect", Appid, redirect_uri, scope, state);
 }

 

 /// <summary>
 /// 用code换取openid 此方法一般是不获取用户昵称时候使用
 /// </summary>
 /// <param name="Appid"></param>
 /// <param name="Appsecret"></param>
 /// <param name="Code">回调页面带的code参数</param>
 /// <returns>微信用户唯一标识openid</returns>
 public string CodeGetOpenid(string Appid, string Appsecret, string Code)
 {
 string url = string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", Appid, Appsecret, Code);
 string ReText = CommonMethod.WebRequestPostOrGet(url, "");//post/get方法获取信息
 Dictionary<string, object> DicText = (Dictionary<string, object>)Jss.DeserializeObject(ReText);
 if (!DicText.ContainsKey("openid"))
  return "";
 return DicText["openid"].ToString();
 }

 

 /// <summary>
 ///用code换取获取用户信息(包括非关注用户的)
 /// </summary>
 /// <param name="Appid"></param>
 /// <param name="Appsecret"></param>
 /// <param name="Code">回调页面带的code参数</param>
 /// <returns>获取用户信息(json格式)</returns>

 public string GetUserInfo(string Appid, string Appsecret, string Code)
 {

 string url = string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", Appid, Appsecret, Code);
 string ReText = CommonMethod.WebRequestPostOrGet(url, "");//post/get方法获取信息
 Dictionary<string, object> DicText = (Dictionary<string, object>)Jss.DeserializeObject(ReText);
 if (!DicText.ContainsKey("openid"))

 {

  log.Error("获取openid失败,错误码:" + DicText["errcode"].ToString());

 return "";

 }
 else

 {

  return CommonMethod.WebRequestPostOrGet("https://api.weixin.qq.com/sns/userinfo?access_token=" + DicText["access_token"] + "&openid=" + DicText["openid"] + "&lang=zh_CN", "");

 }

 }

 

 

 /// <summary>
 /// 通过openId获取用户信息
 /// </summary>
 /// <param name="accesstoken"></param>
 /// <param name="openid"></param>
 /// <returns></returns>
 public string GetUserInfo(string accesstoken, string openid)

 {
 string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN", accesstoken, openid);
 return CommonMethod.WebRequestPostOrGet(url, "");//post/get方法获取信息

 }

}

我們需要呼叫的時候直接用裡面的方法,取得微信網頁授權即可,例如對於A控制器下面的B視圖要取得授權,並且要取得使用者的相關訊息,那麼我們直接呼叫即可,如GetCodeUrl(appid, "http://" + Url + "/A/B", "snsapi_userinfo")


##在這裡我還是吐槽一下吧。


第八坑,

微信選單JSON的url拼接,裡面的前面不是加了js驗證麼,so,特麼的,還是乖乖的加上http:/ /。
不過這裡授權之後,因為使用者的許多資訊我們都要用到,這就是H5頁面傳值的問題,我在專案裡面用的是Session,直接寫一個公用方法,如果Session有值,則直接取值的。對於裡面的一些東東,我想說明一下,並不是所有的程式碼都要貼出來,我這邊的程式碼只是我個人認為需要貼出來的。所以裡面的方法可能有大家看不到的,如果需要,可以留言本寶寶,謝謝。 

public string getSession()

{

 log.Error("GetSession");
 string oauthStr = "";
 try

 {
 if (Session != null && (Session["oauthStr"] == null || string.IsNullOrEmpty(Session["oauthStr"].ToString())))
 {
  if (!string.IsNullOrEmpty(Request.QueryString["code"]))
  {
  Oauth2 oauth = new Oauth2();
  string code = Convert.ToString(Request["code"]);
  oauthStr = oauth.GetUserInfo(ConfigurationManager.AppSettings["AppID"],
   ConfigurationManager.AppSettings["AppSecret"], code);
   Session["oauthStr"] = oauthStr;
  Tools.WAEntity.OAuthUser oAuthUser = new Tools.WAEntity.OAuthUser();
  oAuthUser = Tools.JsonHelper.ParseFromJson<Tools.WAEntity.OAuthUser>(oauthStr);
  }
  return oauthStr;

 }
 else

 {

  Tools.WAEntity.OAuthUser oAuthUser = new Tools.WAEntity.OAuthUser();
  oAuthUser = Tools.JsonHelper.ParseFromJson<Tools.WAEntity.OAuthUser>(Session["oauthStr"].ToString());
  return Session["oauthStr"].ToString();

 }

 }

 catch (Exception e) { log.Error(e.ToString()); return oauthStr; };

}

然後每次遇到需要取得資訊的頁面,我通常都是呼叫這個就可以了。 


基本上剩下的都是我們自己要處理的業務邏輯了,繼續說到坑吧。 


第九坑,

微信上傳圖片,坑的絕對不只是自己。對於這個寶寶真的信了,不管你信不信。特麼的圖片不能for循環上傳。當然,這個只限蘋果機型,大Android還是沒有問題的。 前面說到了JS安全驗證的問題,這裡就是呼叫這些個驗證,請求一些應該的權限,然後取得圖片資訊等等。 

php微信公眾帳號開發遇到的五個坑總結放心好了,寶寶現在都是上圖說話,沒圖說個小弟弟呀。 。 。 。 。 


我們繼續回來看程式碼。 


先來個處理Json的


#

public class JsApi

{
 JavaScriptSerializer Jss = new JavaScriptSerializer(); 

 public JsApi() { } 
 const string URL_FORMAT_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi";

 #region 验证JsApi权限配置
 /// <summary>
 /// 获取JsApi权限配置的数组/四个参数
 /// </summary>
 /// <param name="Appid">应用id</param>
 /// <param name="Appsecret">密钥</param>
 /// <returns>json格式的四个参数</returns>
 public string GetJsApiInfo(string Appid, string Appsecret)
 {
 string jsapi_ticket = "";

 //ticket 缓存7200秒

 if (System.Web.HttpContext.Current.Session["jsapi_ticket"] == null)

 {
  string ticketurl = string.Format(URL_FORMAT_TICKET, BasicApi.GetAccessToken(Appid, Appsecret));//"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + GetAccessToken(Appid, Appsecret) + "&type=jsapi"
  jsapi_ticket = CommonMethod.WebRequestPostOrGet(ticketurl, "");//BasicApi.GetTokenSession
  System.Web.HttpContext.Current.Session["jsapi_ticket"] = jsapi_ticket;
  System.Web.HttpContext.Current.Session.Timeout = 7200;
  BasicApi.WriteTxt("jsapi_ticket1:" + jsapi_ticket);


 }
 else
 {
  jsapi_ticket = System.Web.HttpContext.Current.Session["jsapi_ticket"].ToString();
  BasicApi.WriteTxt("jsapi_ticket2:" + jsapi_ticket);
 } 

 Dictionary<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(jsapi_ticket);
 jsapi_ticket = respDic["ticket"].ToString();//获取ticket
 string timestamp = CommonMethod.ConvertDateTimeInt(DateTime.Now).ToString();//生成签名的时间戳
 string nonceStr = CommonMethod.GetRandCode(16);//生成签名的随机串
 string url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri.ToString();//当前的地址
 BasicApi.WriteTxt("url:" + url);
 string[] ArrayList = { "jsapi_ticket=" + jsapi_ticket, "timestamp=" + timestamp, "noncestr=" + nonceStr, "url=" + url };
 Array.Sort(ArrayList);
 string signature = string.Join("&", ArrayList);
 signature = FormsAuthentication.HashPasswordForStoringInConfigFile(signature, "SHA1").ToLower();
 string r = "{\"appId\":\"" + Appid + "\",\"timestamp\":" + timestamp + ",\"nonceStr\":\"" + nonceStr +
   "\",\"signature\":\"" + signature +
   "\",\"jsApiList\":[\"chooseImage\",\"previewImage\",\"uploadImage\",\"downloadImage\",\"scanQRCode\",\"onMenuShareQQ\"]}";
 BasicApi.WriteTxt("r:" + r.Replace(" ", ""));
 return r.Replace(" ", "");

 }

}

然後看具體呼叫。


後台程式碼其實很簡單的,直接輸出設定文件,然後前台js直接呼叫即可。 

#

JsApi jsApi = new JsApi();
string config = jsApi.GetJsApiInfo(appId, appSecret);
ViewBag.config = config;

前台代码,其实也不难,这个有官方的例子的。 


<script type="text/javascript">
 wx.config(@Html.Raw(ViewBag.config));//后台传递的微信配置文件
 wx.ready(function () {
 $("#avatar").click(function () {
  wx.chooseImage({
  count: 1, // 图片数量 默认9
  sizeType: [&#39;compressed&#39;], // 可以指定是原图还是压缩图,默认二者都有&#39;original&#39;,
  sourceType: [&#39;album&#39;, &#39;camera&#39;], // 可以指定来源是相册还是相机,默认二者都有
  success: function (res) {
   var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
   wx.uploadImage({
   localId: &#39;&#39; + localIds,
   isShowProgressTips: 1,
   success: function (res) {
    serverId = res.serverId;
    getWxPhoto(serverId);

   }

   });

  }

  });

 });

 });

 wx.error(function (res) {
 alert("接口验证失败,详细信息:\n" + JSON.stringify(res));
 });
 var types = 1;
 function getWxPhoto(mediaId) {
 $.ajax({
  async: false,
  type: "post",
  url: "/ActivityRegistration/DownloadWxPhoto",//自己的处理方法
  data: { mediaId: mediaId, types: types },
  success: function (data) {
  $("#imageico").val(data.result);
  $("#hed_pic").attr(&#39;src&#39;, ".." + data.result);
  $("#hed_pic").attr(&#39;alt&#39;, "avatarImg");

  }

 });

 }

</script>

OK,后台方法其实也很简单,就是一个二进制文件处理,不对,简单个蛋蛋,特么的,因为路径的问题,坑了宝宝一个小时,特么的。还有这里建议,等微信图片下载完成之后再给前台加载图片,保证每一个图片都加载完成,保证后台的图片的上传完成。 


/// <summary>
/// 下载多媒体文件
/// </summary>
/// <param name="userName">公众号</param>
/// <param name="mediaId">媒体ID</param>
/// <param name="data">返回下载是否成功</param>
/// <param name="types">添加的图片类型</param>
/// <returns>返回多媒体文件数据;如果下载失败,返回null。</returns>
public JsonResult DownloadWxPhoto(string mediaId, int types)

{

 ErrorMessage errorMessage;
 string access_token = BasicApi.GetAccessToken(ConfigurationManager.AppSettings["AppID"], ConfigurationManager.AppSettings["AppSecret"]);
 byte[] data = MediaHelper.Download(access_token, mediaId, out errorMessage);
 string files = String.Empty, fileName = String.Empty;
 files = Server.MapPath("~/Wxinphoto/");
 if (!Directory.Exists(files))
 {
 Directory.CreateDirectory(files);
 }
 fileName = files + DateTime.Now.Ticks + ".jpg";
 if (data != null)
 {
 bool flag = writeFile(data, fileName);
 if (flag)
 {
  errorMessage = new ErrorMessage(ErrorMessage.SuccessCode, "下载多媒体文件成功。");
 }
 else
 {
  errorMessage = new ErrorMessage(ErrorMessage.ExceptionCode, "从微信服务器下载多媒体文件失败。");
 }

 }
 else
 errorMessage = new ErrorMessage(ErrorMessage.ExceptionCode, "从微信服务器下载多媒体文件失败。");
 return Json(new { result = "/" + urlconvertor(fileName), errorMessage = errorMessage });

}


//读filename到byte[] 
private byte[] ReadFile(string fileName)
{
 FileStream pFileStream = null;
 byte[] pReadByte = new byte[0];
 try
 {
 pFileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
 BinaryReader r = new BinaryReader(pFileStream);
 r.BaseStream.Seek(0, SeekOrigin.Begin); //将文件指针设置到文件开
 pReadByte = r.ReadBytes((int)r.BaseStream.Length);
 return pReadByte;
 }
 catch
 {
 return pReadByte;
 }
 finally
 {
 if (pFileStream != null)
  pFileStream.Close();

 }

}

 

//写byte[]到fileName

private bool writeFile(byte[] pReadByte, string fileName)

{

 FileStream pFileStream = null;

 try

 {
 pFileStream = new FileStream(fileName, FileMode.OpenOrCreate);
 pFileStream.Write(pReadByte, 0, pReadByte.Length);
 }
 catch

 {
 return false;
 }
 finally

 {
 if (pFileStream != null)

  pFileStream.Close();

 }

 return true;

}
/// <summary>
/// 判断目标字节数组是否位于源字节数组的开始
/// </summary>
/// <param name="source">源字节数组</param>
/// <param name="target">目标字节数组</param>
/// <returns>返回目标字节数组是否位于源字节数组的开始</returns>

private bool StartsWithBytes(byte[] source, byte[] target)

{

 if (source == null && target == null)

 return true;

 if (source == null && target != null || source != null && target == null)
 return false;
 if (source.Length < target.Length)
 return false;
 bool startsWith = true;
 for (int i = 0; i < target.Length; i++)
 {
 if (source[i] != target[i])

 {
  startsWith = false;

  break;

 }

 }

 return startsWith;

}

 是不是以为这就算完事了,我的乖乖,头像上传了,微信摄像头也特么该调用的调用了,宝宝好幸福,宝宝也是牛人一个了,记住前面的东东,宝宝还没有说坑呢。
来重复我们的第九个坑,特么的,你JS写个for循环要是能循环把图片上传到后台,宝宝也服气,真的,宝宝服气。 

直接说吧,最后我自己想了下,也和队友讨论了下,可能是因为微信有什么验证,导致之后一张图片上传成功之后,才能进行一张,但是我们Iphone就是特么的特例,大Android没用问题的,就是Iphone有了问题,而且问题不小,上传四张图片吧,老特么是最后一张,最后,找到了万能的网友,感谢你,不过宝宝已经忘记了在哪里找到的了,尴尬了。。。。。。。。。。。 


<script type="text/javascript">

 var types = 2;

 var urlList="";

 var i = 0;

 function up(resurl) {

  if (i < resurl.localIds.length) {

  // 上传照片resu.localIds[i]
  wx.uploadImage({
   localId: &#39;&#39; + resurl.localIds[i],
   isShowProgressTips: 1,
   success: function (res) {
   // alert("res.serverId:" + res.serverId);
   mediaId = res.serverId;
   $.ajax({
    async: false,
    type: "post",
    url: "/ActivityRegistration/DownloadWxPhoto",
    data: { mediaId: mediaId, types: types },
    success: function (data) {
    $("#picPath").append(&#39;<li><p class="imgbox"><img src="/static/imghwm/default1.png"  data-src="/img/cechanadd.png"  class="lazy"   id="picture&#39; + i + &#39;" alt="" /></p></li>&#39;);

    $("#picture" + i).attr(&#39;src&#39;, data.result);
    $("#picPath").append(&#39;<input value=&#39; + data.result + &#39; type="hidden" id="picurl&#39; + i + &#39;" class="picclass" />&#39;);

    i++;

    if (i == resurl.localIds.length - 1) {

     $("#picPath").append(&#39;<li><p class="imgbox"><img src="/static/imghwm/default1.png"  data-src="/img/cechanadd.png"  class="lazy"   id="picture" alt="" /></p></li>&#39;);

    }

    up(resurl);
    }
   });

   }
  });
  } else {

  i = 0;
  }

 }

 

 
 //上传图片
 wx.config(@Html.Raw(ViewBag.config));
 wx.ready(function () {
  $("#picPath").click(function () {
  wx.chooseImage({
   count: 3, // 默认9
   sizeType: [&#39;compressed&#39;], // 可以指定是原图还是压缩图,默认二者都有&#39;original&#39;,
   sourceType: [&#39;album&#39;, &#39;camera&#39;], // 可以指定来源是相册还是相机,默认二者都有
   success: function (resu) {
   var localIds = resu.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
   if (localIds.indexOf("wxlocalresource") != -1) {    
   localIds = localIds.replace("wxlocalresource", "wxLocalResource");
   }
 
   @(index += 1)
   if (localIds != &#39;&#39;) {
    $("#picPath").html("");
   var sear = new RegExp(&#39;,&#39;);
    if (sear.test(localIds)) {
    up(resu);
    }

    else {
    $("#picPath").append(&#39; <li><p class="imgbox"><img src="/static/imghwm/default1.png"  data-src="/img/cechanadd.png"  class="lazy"   id="picture&#39; + &#39;@index&#39; + &#39;" alt="" " /></p></li>&#39;);
    $("#picture" + "@index").attr(&#39;src&#39;, localIds);
    // 上传照片
    wx.uploadImage({
     localId: &#39;&#39; + localIds,

    isShowProgressTips: 1,
     success: function (res) {
     mediaId = res.serverId;

     $.ajax({
      async: false,

      type: "post",
      url: "/ActivityRegistration/DownloadWxPhoto",

      data: { mediaId: mediaId, types: types },

      success: function (data) {

      $("#picPath").append(&#39;<input value=&#39; + data.result + &#39; type="hidden" id="picurl&#39; + @index + &#39;" class="picclass" />&#39;);

      $("#picPath").append(&#39;<li><p class="imgbox"><img src="/static/imghwm/default1.png"  data-src="/img/cechanadd.png"  class="lazy"   id="picture" alt="" /></p></li>&#39;);
      }
     });

    }
    });
    }
    // $("#picPath").append(&#39;<li><p class="imgbox"><img src="/static/imghwm/default1.png"  data-src="/img/cechanadd.png"  class="lazy"   id="picture" alt="" /></p></li>&#39;);

   }
   }
  });
  });
 });
 wx.error(function (res) {
  alert("接口验证失败,详细信息:\n" + JSON.stringify(res));
 });
 </script>

请记住,递归就特么可以了。

说到这里,宝宝已经不想多说什么了,特么的产品你能不能不装逼,你特么见过那个微信能回复一个信息直接跳转网页的,你咋不去屎呢,联想到前几天大阿里的月饼时间,突然感觉我们程序员挺悲剧的,成功的都是特么的产品,然后出问题的都是我们程序员的锅?试问一下,这个锅真心我们程序员该背么。 

算了,还是不吐槽了,已经无力了。。。。宝宝92年降临,现在确实82年的皮肤呀,唉,宝宝累了,真的。 

顺便给点H5页面的建议吧。比如当点击返回键的时候,我们需要刷新页面的时候,就是所谓的判断页面要不要刷新,这里有很多种方法,但是微信里面宝宝还是觉得这么干靠谱。 


<script type="text/javascript">
 if (window.name != "hasLoad") {
 location.reload();
 window.name = "hasLoad";
 } else {
 window.name = "";
 }
</script>

还有,那个微信执行完成之后想直接退出当前界面进入微信公众号界面的,直接调用微信的一个内置的方法即可。记得写到<script></script>里面。 

WeixinJSBridge.call('closeWindow'); //这是微信关闭当前网页

这么自信的以为自己搞定了所有,你跑呀,你要跑起来,嗯哼,别不服气。 

微信公众账号指第十坑,我自己加的,哈哈,就是前面的JS验证的时候,你不要头文件,怎么搞定这些事情,哈哈。是不是宝宝赢了。Oh  perfect,I like it。

以上是php微信公眾帳號開發遇到的五個坑總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),