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 作联接查询
但这样 如果留言表中没有 回复 就查询不到,也就无法在页面显示
该如何解决

看了你的问题.和数据库的2个表设计.
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. 至于代码的循环,相对于数据库的操作,没有可比性,可以忽略不计。

参考技术A 我感觉有时候也完全可以把留言与回复放在一个表中,我不知你这个实现的具体功能所以不好说行不行,不过,楼上的两种方法是一般做法可以效仿,只是web服务器与sql服务器交互太过频繁可能会降低整个网站的响应能力,当你对关系数据库比较了解后,可以去找更优化的方法,如。引入存储程序等,哈哈。。。 参考技术B v

分享微信公众号运营助手,可以在手机上回复粉丝留言

由于公司旗下有好几个微信公众号,经常来回切换登录很麻烦,粉丝留言咨询的时候常常不能及时回复,导致订单流失。于是我们团队开发了一个公众号小助手,可以把多个公众号绑定进来,只要有粉丝留言,马上管理员就收到通知了,然后还可以在手机上进行回复。

 

实现的功能如下:

  1. 粉丝留言自动微信通知

  2. 在微信中回复粉丝留言,文字+图片

  3. 粉丝关注自动微信通知

  4. 粉丝关注自动推送多图文消息或者历史消息

  5. 更强大的自定义菜单管理

  6. 自定义客服消息模板

  7. 支持绑定多个管理员

  8. 支持关键词自动回复

  9. 支持二次开发

 

虽然这个小助手很小,但是里面用到的技术我觉得还是有一定分享价值。本文就向大家分享一下这个小助手中核心的技术方案,包括:公众号绑定、粉丝信息获取、给粉丝发送消息、微信图片上传与下载、公众号自定义菜单接口、公众号临时二维码的妙用等等。

 

核心技术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 留言板 留言和回复的主要内容,如果未能解决你的问题,请参考以下文章

求一步一步教PHP留言板制作方法

假日留言回复时,将使用标题中的哪个电子邮件地址?

开源 免费 java CMS - FreeCMS1.8 留言管理

微信公众平台开发之留言板

微信公众平台开发之留言板

开源 java CMS - FreeCMS2.3 留言管理