


Summary of five pitfalls encountered in PHP WeChat public account development
Mar 21, 2017 pm 03:54 PMThis article mainly introduces the five pitfalls of PHP WeChat public account development in detail. It has certain reference value. Interested friends can refer to the
menu. The reply is that the XML file needs to be processed. Based on the XML file returned by WeChat, we can get the unique identifier of each WeChat user relative to the WeChat official account. The mechanism of the WeChat public platform is simply that we output a fixed-format XML file ourselves, and then the WeChat APP is responsible for parsing it, getting the information we want, and then processing the information in a unified manner.
The sixth pit, If you look at the WeChat document, then it will definitely kill you, as shown above. The ToUserName and FromUserName here must be clearly distinguished. Remember, never write them backwards. The user is A→B for WeChat, so WeChat is the other way around for the user. It seems that it should be made clear now. .
/// <summary> /// 接收微信發(fā)送的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 { //業(yè)務處理 } else { XML = ResponseMessage.ReText(WxXmlModel.FromUserName, WxXmlModel.ToUserName, "/:rose農(nóng)場大數(shù)據(jù)歡迎你!/: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);//掃描帶參數(shù)二維碼先關注后推送事件 } break; case "scan": XML = ResponseMessage.ScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//掃描帶參數(shù)二維碼已關注 直接推送事件 break; case "click"://處理單擊事件 if (WxXmlModel.EventKey == "p1") { //自己的業(yè)務邏輯 } else { //自己的業(yè)務邏輯 } break; case "unsubscribe"://取消關注 break; } break; default://默認回復 break; } Response.Write(XML);//輸出組織的XML信息 }
This is the information processing of the menu. People who don’t know the truth seem to ask what the so-called ResponseMessage means. OK, I can no longer complain about the WeChat public platform I have researched in the past three days.
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, "關鍵詞回復測試——興農(nóng)豐華:" + key); break; case "單圖文": XML = ReArticle(FromUserName, ToUserName, "測試標題", "測試詳情——興農(nóng)豐華:" + key, "http://www.xnfhtech.com/templets/boze/images/20120130083143544.gif", "http://www.xnfhtech.com/"); break; default: XML = ReText(FromUserName, ToUserName, "無對應關鍵字——興農(nóng)豐華:" + key); break; } return XML; } /// <summary> /// 未關注掃描帶參數(shù)二維碼 /// </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> /// 已關注掃描帶參數(shù)二維碼 /// </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">發(fā)送給誰(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>";//發(fā)送給誰(openid),來自誰(公眾賬號ID) XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//回復時間戳 XML += "<MsgType><![CDATA[text]]></MsgType>";//回復類型文本 XML += "<Content><![CDATA[" + Content + "]]></Content><FuncFlag>0</FuncFlag></xml>";//回復內(nèi)容 FuncFlag設置為1的時候,自動星標剛才接收到的消息,適合活動統(tǒng)計使用 return XML; } /// <summary> /// 回復單圖文 /// </summary> /// <param name="FromUserName">發(fā)送給誰(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>";//發(fā)送給誰(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">發(fā)送給誰(openid)</param> /// <param name="ToUserName">來自誰(公眾賬號ID)</param> /// <param name="ArticleCount">圖文數(shù)量</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>";//發(fā)送給誰(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, with your own logic code, is the reply perfectly implemented?
The seventh pit, I really don’t want to count anymore, are you sure this reply is okay? To be honest, I'm not sure, because after you write it, do you know where to call it? My dear, damn, it's safest to add the reply after the server verification is passed. I have no morals anymore.
What should we say next? Let’s talk about obtaining user information, because these things of ours are generally based on H5 pages. Therefore, we have to use the
thing we configured before. In fact, compared to the previous one, this one has at least a lot less pitfalls. Sincerely, baby will just temporarily Not to mention he was cheated. Let’s put some code.
//微信網(wǎng)頁授權2.0 public class Oauth2 { JavaScriptSerializer Jss = new JavaScriptSerializer(); public Oauth2() { } /// <summary> /// 對頁面是否要用授權 /// </summary> /// <param name="Appid">微信應用id</param> /// <param name="redirect_uri">回調(diào)頁面</param> /// <param name="scope">應用授權作用域snsapi_userinfo(不彈出授權頁面,直接跳轉(zhuǎn),只能獲取用戶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">回調(diào)頁面</param> /// <param name="scope">應用授權作用域snsapi_userinfo(不彈出授權頁面,直接跳轉(zhuǎn),只能獲取用戶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">回調(diào)頁面帶的code參數(shù)</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">回調(diào)頁面帶的code參數(shù)</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方法獲取信息 } }
When we need to call, we can directly use the method inside to obtain the WeChat webpage authorization. For example, we need to obtain authorization for the B view under the A controller, and obtain User-related information, then we can call it directly, such as GetCodeUrl(appid, "http://" + Url + "/A/B", "snsapi_userinfo")
Here I am still Let’s complain.
The eighth pit, WeChat menu JSON url splicing, isn’t there js verification in front, so, what the heck, just add http:/ /.
But after authorization here, because we need to use a lot of user information, this is the problem of value transfer on the H5 page. I use Session in the project and write a public method directly. If If Session has a value, it is taken directly. Regarding some of the stuff inside, I would like to explain that not all the code needs to be posted. The code here is just what I personally think needs to be posted. So there may be some methods that you can’t see. If necessary, you can leave a message on this page. Thank you.
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; }; }
Then every time I encounter a page that needs to obtain information, I usually just call this.
Basically the rest is the business logic that we have to deal with ourselves, let’s continue talking about the pitfalls.
The ninth pit, uploading pictures on WeChat, is definitely not the only one who is pitted. I really believe in this baby, whether you believe it or not. Special pictures cannot be uploaded in a for loop. Of course, this is only for Apple models, there is still no problem with Android.
I mentioned the issue of JS security verification earlier. Here we call these verifications, request some appropriate permissions, and then obtain image information and so on.
#Don’t worry, the baby is talking about the picture above, not the little brother in the picture. . . . .
Let’s continue to come back and look at the code.
Let’s first process 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權限配置的數(shù)組/四個參數(shù) /// </summary> /// <param name="Appid">應用id</param> /// <param name="Appsecret">密鑰</param> /// <returns>json格式的四個參數(shù)</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(" ", ""); } }
and then look at the specific calls.
The background code is actually very simple, just output the configuration file directly, and then directly call the front-end 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, // 圖片數(shù)量 默認9 sizeType: ['compressed'], // 可以指定是原圖還是壓縮圖,默認二者都有'original', sourceType: ['album', 'camera'], // 可以指定來源是相冊還是相機,默認二者都有 success: function (res) { var localIds = res.localIds; // 返回選定照片的本地ID列表,localId可以作為img標簽的src屬性顯示圖片 wx.uploadImage({ localId: '' + 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('src', ".." + data.result); $("#hed_pic").attr('alt', "avatarImg"); } }); } </script>
OK,后臺方法其實也很簡單,就是一個二進制文件處理,不對,簡單個蛋蛋,特么的,因為路徑的問題,坑了寶寶一個小時,特么的。還有這里建議,等微信圖片下載完成之后再給前臺加載圖片,保證每一個圖片都加載完成,保證后臺的圖片的上傳完成。
/// <summary> /// 下載多媒體文件 /// </summary> /// <param name="userName">公眾號</param> /// <param name="mediaId">媒體ID</param> /// <param name="data">返回下載是否成功</param> /// <param name="types">添加的圖片類型</param> /// <returns>返回多媒體文件數(shù)據(jù);如果下載失敗,返回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> /// 判斷目標字節(jié)數(shù)組是否位于源字節(jié)數(shù)組的開始 /// </summary> /// <param name="source">源字節(jié)數(shù)組</param> /// <param name="target">目標字節(jié)數(shù)組</param> /// <returns>返回目標字節(jié)數(shù)組是否位于源字節(jié)數(shù)組的開始</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; }
是不是以為這就算完事了,我的乖乖,頭像上傳了,微信攝像頭也特么該調(diào)用的調(diào)用了,寶寶好幸福,寶寶也是牛人一個了,記住前面的東東,寶寶還沒有說坑呢。
來重復我們的第九個坑,特么的,你JS寫個for循環(huán)要是能循環(huán)把圖片上傳到后臺,寶寶也服氣,真的,寶寶服氣。
直接說吧,最后我自己想了下,也和隊友討論了下,可能是因為微信有什么驗證,導致之后一張圖片上傳成功之后,才能進行一張,但是我們Iphone就是特么的特例,大Android沒用問題的,就是Iphone有了問題,而且問題不小,上傳四張圖片吧,老特么是最后一張,最后,找到了萬能的網(wǎng)友,感謝你,不過寶寶已經(jīng)忘記了在哪里找到的了,尷尬了。。。。。。。。。。。
<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: '' + 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('<li><p class="imgbox"><img src="/static/imghw/default1.png" data-src="/img/cechanadd.png" class="lazy" id="picture' + i + '" alt="" /></p></li>'); $("#picture" + i).attr('src', data.result); $("#picPath").append('<input value=' + data.result + ' type="hidden" id="picurl' + i + '" class="picclass" />'); i++; if (i == resurl.localIds.length - 1) { $("#picPath").append('<li><p class="imgbox"><img src="/static/imghw/default1.png" data-src="/img/cechanadd.png" class="lazy" id="picture" alt="" /></p></li>'); } up(resurl); } }); } }); } else { i = 0; } } //上傳圖片 wx.config(@Html.Raw(ViewBag.config)); wx.ready(function () { $("#picPath").click(function () { wx.chooseImage({ count: 3, // 默認9 sizeType: ['compressed'], // 可以指定是原圖還是壓縮圖,默認二者都有'original', sourceType: ['album', 'camera'], // 可以指定來源是相冊還是相機,默認二者都有 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 != '') { $("#picPath").html(""); var sear = new RegExp(','); if (sear.test(localIds)) { up(resu); } else { $("#picPath").append(' <li><p class="imgbox"><img src="/static/imghw/default1.png" data-src="/img/cechanadd.png" class="lazy" id="picture' + '@index' + '" alt="" " /></p></li>'); $("#picture" + "@index").attr('src', localIds); // 上傳照片 wx.uploadImage({ localId: '' + 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('<input value=' + data.result + ' type="hidden" id="picurl' + @index + '" class="picclass" />'); $("#picPath").append('<li><p class="imgbox"><img src="/static/imghw/default1.png" data-src="/img/cechanadd.png" class="lazy" id="picture" alt="" /></p></li>'); } }); } }); } // $("#picPath").append('<li><p class="imgbox"><img src="/static/imghw/default1.png" data-src="/img/cechanadd.png" class="lazy" id="picture" alt="" /></p></li>'); } } }); }); }); wx.error(function (res) { alert("接口驗證失敗,詳細信息:\n" + JSON.stringify(res)); }); </script>
請記住,遞歸就特么可以了。
說到這里,寶寶已經(jīng)不想多說什么了,特么的產(chǎn)品你能不能不裝逼,你特么見過那個微信能回復一個信息直接跳轉(zhuǎn)網(wǎng)頁的,你咋不去屎呢,聯(lián)想到前幾天大阿里的月餅時間,突然感覺我們程序員挺悲劇的,成功的都是特么的產(chǎn)品,然后出問題的都是我們程序員的鍋?試問一下,這個鍋真心我們程序員該背么。
算了,還是不吐槽了,已經(jīng)無力了。。。。寶寶92年降臨,現(xiàn)在確實82年的皮膚呀,唉,寶寶累了,真的。
順便給點H5頁面的建議吧。比如當點擊返回鍵的時候,我們需要刷新頁面的時候,就是所謂的判斷頁面要不要刷新,這里有很多種方法,但是微信里面寶寶還是覺得這么干靠譜。
<script type="text/javascript"> if (window.name != "hasLoad") { location.reload(); window.name = "hasLoad"; } else { window.name = ""; } </script>
還有,那個微信執(zhí)行完成之后想直接退出當前界面進入微信公眾號界面的,直接調(diào)用微信的一個內(nèi)置的方法即可。記得寫到<script></script>里面。?
WeixinJSBridge.call('closeWindow'); //這是微信關閉當前網(wǎng)頁
這么自信的以為自己搞定了所有,你跑呀,你要跑起來,嗯哼,別不服氣。?
微信公眾賬號指第十坑,我自己加的,哈哈,就是前面的JS驗證的時候,你不要頭文件,怎么搞定這些事情,哈哈。是不是寶寶贏了。Oh? perfect,I like it。
The above is the detailed content of Summary of five pitfalls encountered in PHP WeChat public account development. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)