php 留言板 留言和回复
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php 留言板 留言和回复相关的知识,希望对你有一定的参考价值。
两张表
留言表 mess
id,u_id //用户id, time, mess
回复表 reply
id,u_id,time,mess,p_id //要回复留言的id
怎样查询 才能在页面 显示所有的留言和回复
大多网友说 回复表的p_id 和留言表的id 作联接查询
但这样 如果留言表中没有 回复 就查询不到,也就无法在页面显示
该如何解决
1.先确定数据表的设计.
留言表 message
字段:
msgid
uid
content
postdate
回复表replies
repliesid
uid
msgid
content
postdate
这样的设计表,我认为是最好的。符合数据库的范式,主要是简单明了,简单就意味着性能.
2.怎么把数据库合理的提取出来,只能说是从代码上着手.
第一种最直接的方法。
$sql = "select * FROM message order postdate desc";
得到$messages留言的数组
foreach ($message as $key => $value)
$sql = "select * from replies where msgid = ".$value['msgid'];
得到留言对应的回复$replies
$message[$key]['replies'] = $replies;
最终得到数组$message;
前台显示:
foreach( $messsage as $key => $value )
echo $value[‘content']; //显示留言
foreach( $value['replies'] as $k => $val )
echo $val['content'];//显示该留言下的恢复
第二中方法,我比较喜欢,而且也一直在用
$sql = "select * FROM message order postdate desc";
得到$messages;
通过处理得到,数组$messages中的所有msgid,并存入一维数$msgids
$msgids = array();
$result = array(); //这个数组转化$messages用的.因为我们要把$messages的key值变成msgid
foreach( $message as $key => $value )
$msgids[] = $value['msgid'];
$result[$value['msgid']] = $value;
unset($messages); 这个数据就没有用了。因为已经有$result;
一次性查询出,这些留言需要的所有回复,$replies;
$sql = "select * from replies WHERE msgid in (".implode(',',$msgids).") order by postdate desc";
foreach( $replies as $key => $value )
$result[$value['msgid']]['replies'][] = $value;
前台显示:
foreach( $resultas $key => $value )
echo $value[‘content']; //显示留言
foreach( $value['replies'] as $k => $val )
echo $val['content'];//显示该留言下的恢复
追问
方法二 好像很多人用 这样 一层层 循环 是不是 效率 低啊
追答方法一是循环查询的。访问量和留言很多的,最好不要用。
方法二推荐你使用。一共2次select. 至于代码的循环,相对于数据库的操作,没有可比性,可以忽略不计。
分享微信公众号运营助手,可以在手机上回复粉丝留言
由于公司旗下有好几个微信公众号,经常来回切换登录很麻烦,粉丝留言咨询的时候常常不能及时回复,导致订单流失。于是我们团队开发了一个公众号小助手,可以把多个公众号绑定进来,只要有粉丝留言,马上管理员就收到通知了,然后还可以在手机上进行回复。
实现的功能如下:
粉丝留言自动微信通知
在微信中回复粉丝留言,文字+图片
粉丝关注自动微信通知
粉丝关注自动推送多图文消息或者历史消息
更强大的自定义菜单管理
自定义客服消息模板
支持绑定多个管理员
支持关键词自动回复
支持二次开发
虽然这个小助手很小,但是里面用到的技术我觉得还是有一定分享价值。本文就向大家分享一下这个小助手中核心的技术方案,包括:公众号绑定、粉丝信息获取、给粉丝发送消息、微信图片上传与下载、公众号自定义菜单接口、公众号临时二维码的妙用等等。
核心技术1:多个公众号的绑定
想要调用微信公众号的API,首先要通过AppId和AppSecret获取AccessToken,而AccessToken过一段时间就会过期。为了提高AccessToken的利用率并且实现自动刷新,我们专门写了一个AccessTokenContext下载 来管理多个公众号的AccessToken,这个类也是完成多个公众号绑定最重要的一步。
请看源码下载 :
1 public class AccessTokenContext 2 { 3 public static AccessTokenContext Instance { get; } 4 5 static AccessTokenContext() 6 { 7 Instance = new AccessTokenContext(); 8 } 9 10 private readonly Dictionary<Guid, AccountAccessTokenDto> _keyValues;11 12 public AccessTokenContext()13 {14 _keyValues = new Dictionary<Guid, AccountAccessTokenDto>();15 }16 17 public string GetDabenAccessToken()18 {19 return GetAccessToken(AppContext.DabenMpAccountId);20 }21 22 public string GetAccessToken(Guid accountId)23 {24 if (_keyValues.ContainsKey(accountId))25 {26 var dto = _keyValues[accountId];27 if (dto.IsExpired() == false)28 {29 return dto.AccessToken;30 }31 }32 var account = Ioc.Get<IAccountService>().Get(accountId);33 var apidto = GetByApi(account);34 _keyValues[account.Id] = apidto;35 return apidto.AccessToken;36 }37 38 public string GetAccessToken(MpAccount account)39 {40 if (_keyValues.ContainsKey(account.Id))41 {42 var dto = _keyValues[account.Id];43 if (dto.IsExpired())44 {45 dto = GetByApi(account);46 }47 return dto.AccessToken;48 }49 else50 {51 var dto = GetByApi(account);52 _keyValues[account.Id] = dto;53 return dto.AccessToken;54 }55 }56 57 private AccountAccessTokenDto GetByApi(MpAccount account)58 {59 var token = WeixinApi.GetAccessToken(account.AppId, account.AppSecret);60 if (token == null || token.IsSuccess() == false)61 {62 throw new KnownException("Mp.GetAccessToken:" + account.Name);63 }64 return new AccountAccessTokenDto(account.Id, token);65 }66 }
一旦拿到了某个公众号的AccessToken,就可以调用绝大部分接口了。
核心技术2:拉取粉丝基本信息
不同的微信公众号下面的粉丝拥有不同的OpenId,而OpenId是微信对于用于的唯一标识。
微信提供了几个事件发生的时候,程序可以获取用户的OpenId,而用OpenId就可以跟用户互动。我们仅用了2个事件获取OpenId:粉丝关注时和粉丝留言时。
下面的代码下载 展示了如何通过OpenId和AccessToken获取粉丝基本信息。
public class WeixinApi { public static UserDto GetUserInfo(string openId, string accessToken = null) { return HttpHelper.GetApiDto<UserDto>(WeixinConfigs.Urls.GetUserInfo(openId, accessToken)); } }
internal class HttpHelper { public static T GetApiDto<T>(string url) where T : ApiDtoBase { var html = DownloadString(url); try { var dto = Serializer.FromJson<T>(html); if (dto.IsSuccess() == false) { Logger.Error("GetApiDto." + typeof(T).FullName + ".NotSuccess", dto.GetFullError()); } return dto; } catch (Exception ex) { Logger.Error("GetApiDto." + typeof(T).FullName + ".Exception", ex); Logger.Error("GetApiDto." + typeof(T).FullName + ".Exception", html); } return null; } }
核心技术3:给粉丝发送消息
注意这里仅仅是发送的客服消息,也就是粉丝与公众号互动之后的48小时内可以随意给粉丝发送的消息,包括文字和图片下载 。
public class WeixinApi { public static ApiDtoBase TrySendMessage(MessageBase message, string accessToken = null) { try { return HttpHelper.PostApiDto<ApiDtoBase>(WeixinConfigs.Urls.SendMessage(message is TemplateMessageBase, accessToken), message.ToJson()); } catch (Exception ex) { Logger.Error("WeixinApi TrySendMessage", ex); } return null; } }
internal class HttpHelper { public static T PostApiDto<T>(string url, string json) where T : ApiDtoBase { string html; using (var client = new WebClient()) { var result = client.UploadData(url, "POST", Encoding.UTF8.GetBytes(json ?? string.Empty)); html = Encoding.UTF8.GetString(result); } try { var dto = Serializer.FromJson<T>(html); if (dto.IsSuccess() == false) { Logger.Error("PostApiDto." + typeof(T).FullName + ".NotSuccess", dto.GetFullError()); } return dto; } catch (Exception ex) { Logger.Error("PostApiDto." + typeof(T).FullName + ".Exception", ex); return null; } } }
如果推送的是文本消息下载 :
1 public class TextMessage : MessageBase 2 { 3 public string Text { get; set; } 4 5 public TextMessage(string openId, string text) 6 { 7 this.ToUserOpenId = openId; 8 this.Text = text; 9 }10 11 public override string ToJson()12 {13 return Serializer.ToJson(14 new15 {16 touser = this.ToUserOpenId,17 msgtype = "text",18 text = new19 {20 content = this.Text21 }22 });23 }24 }
如果推送的是图片消息,则需要先上传图片到微信服务器拿到media_Id下载 (本文后面会展示):
1 public class ImageMessage : MessageBase 2 { 3 public string MediaId { get; set; } 4 5 public ImageMessage(string openId, string mediaId) 6 { 7 this.ToUserOpenId = openId; 8 this.MediaId = mediaId; 9 }10 11 public override string ToJson()12 {13 return Serializer.ToJson(14 new15 {16 touser = this.ToUserOpenId,17 msgtype = "image",18 image = new19 {20 media_id = this.MediaId21 }22 });23 }24 }
核心技术4:微信图片上传与下载
微信图片的上传与下载都是通过media_id进行的。上传一个图片文件之后,微信服务器返回media_id;如果要下载某张图片,也需要提供media_id。
关于图片上传这块,我们封装了一个非常方便的微信图片上传控件下载 ,等以后有时间再给大家详解这个控件,绝对超cool的,现在你可以先体验下。
图片上传之前,需要先将用户上传的图片保存到服务器,然后再将服务器的图片上传到微信服务器:
public class WeixinApi { public static UploadFileDto UploadFile(string localFilePath, ResourceType type, string accessToken = null) { return HttpHelper.PostFile<UploadFileDto>(WeixinConfigs.Urls.UploadFile(type, accessToken), localFilePath); } }
1 internal class HttpHelper 2 { 3 public static T PostFile<T>(string url, string filePath) where T : ApiDtoBase 4 { 5 string html; 6 using (var client = new WebClient()) 7 { 8 var result = client.UploadFile(url, "POST", filePath); 9 html = Encoding.UTF8.GetString(result);10 }11 try12 {13 var dto = Serializer.FromJson<T>(html);14 if (dto.IsSuccess() == false)15 {16 Logger.Error("PostFile." + typeof(T).FullName + ".NotSuccess", dto.GetFullError());17 }18 return dto;19 }20 catch (Exception ex)21 {22 Logger.Error("PostFile." + typeof(T).FullName + ".Exception", ex);23 return null;24 }25 }26 }
下载 图片就非常简单了,只需要通过media_id获取下载图片的URL即可:
public static string GetMediaDownloadUrl(string mediaId, string accessToken = null) { return "http://file.api.weixin.qq.com/cgi-bin/media/get" + $"?access_token={accessToken ?? WeixinKeyManager.Instance.GetAccessToken()}&media_id={mediaId}"; }
以上是关于php 留言板 留言和回复的主要内容,如果未能解决你的问题,请参考以下文章