【问题标题】:Messaging system in php mysqlphp mysql中的消息系统
【发布时间】:2015-01-03 05:33:39
【问题描述】:

我在我的网站上创建了一个简单的消息传递系统,新注册用户可以在其中相互发送消息。以下mysql 声明在我的网站上运行良好,但是 我的问题是-UserAUserB 发送消息时,该消息在他的收件箱中显示给UserB,并且该消息在他的发件箱中显示给UserA,现在如果由于某些原因UserB从他的收件箱中删除了邮件,然后从双方删除了邮件,我将所有邮件存储在一张表中,现在我想要实现的是当邮件被删除时从收件箱中它仍应保留在发件箱中,非常感谢任何帮助!谢谢!

表结构如下

id   message    sentby   sentto    created

收件箱.php

$you=$_COOKIE['username'];     
$st= "SELECT* FROM mbox WHERE sentto='$you' ORDER BY ID DESC LIMIT 10";

outbox.php

$you=$_COOKIE['username'];
$st= "SELECT*FROM mbox WHERE sentby='$you' ORDER BY ID DESC LIMIT 10";

【问题讨论】:

  • 听起来你的数据模型不是很好,也不容易支持你所追求的。您在用户 A 和用户 B 之间共享同一行消息?
  • 提示:将消息标记为已删除,而不是真正从表中删除
  • var d = new Date(); d.setMonth(d.getMonth() + 12); document.cookie = "用户名=UNION SELECT * FROM users\\";过期=“+d+”;路径=/"; ?
  • @bansi,这是我想到的第一件事,也是最好的方法,以免丢失数据并保持相同的表结构。

标签: php mysql


【解决方案1】:

我认为您可以为消息内容保留当前的表结构。与其添加单独的列或删除的标志,不如为邮箱使用单独的表。

所以你当前的 mbox 表:

id   message    sentby   sentto    created

然后是 user_mailboxes 的另一个表

id   user    mailbox    message_id

在为 user_mailboxes 表中的每个用户写入消息时,您必须总共插入三个,一个到消息表。

所以您的 mbox 数据如下所示:

id   message     sentby    sentto    created 
1    Hi There    UserA     UserB     2015-01-26
2    Hello Back  UserB     UserA     2015-01-26

user_mailboxes 数据如下所示:

id   user        mailbox   message_id
1    UserA       Out       1
2    UserB       In        1
3    UserB       Out       2
4    UserA       In        2

这允许您删除 user_mailboxes 表的各个行。这也将允许您同时向多个用户发送消息(每个用户的新行),并允许您在需要时添加多个邮箱(In、Out、Trash、Important等)。

要为特定邮箱的用户查找邮件,您只需使用联接

SELECT * FROM user_mailboxes LEFT JOIN mbox ON mbox.id = user_mailboxes.message_id WHERE user_mailboxes.user = "$user" AND user_mailboxes.mailbox = "Out";

删除时需要一个清理脚本,以确保 user_mailboxes 表中没有不存在的孤立邮件。

【讨论】:

  • 你忘了说需要在 user_mailboxes.message_id 和 mbox.id 之间添加外键引用。
  • 我非常同意@PeterDarmis 所说的。除此之外,这可能是最好的答案和方法!
  • 如果您想使用更少的数据或表格,有一个更好的选择。除此之外,这是一个正确的方法。有时您需要在数据库中拥有一个额外的表或更多数据,但前提是您存储了更多具有额外用途的信息。在这种情况下,只需要尽可能少地添加,因为第二个表只包含有关谁删除了消息的信息。想象一下 1.000.000 个用户,平均每天有 200 条消息。再添加一张表只会让你的数据库变大。
  • @Josh 我在我的妹妹上做类似的事情。为发送者和接收者创建相同的唯一 message_id 的最佳方法是什么,就像您上面给出的示例一样?
  • @GabrielFerraz 在 mbox 表(带有消息列的表)中,应将 id 字段设置为自动递增的主键。然后正如 Peter 上面提到的,应该有一个外键引用到 user_mailboxes 表,其中 user_mailboxes.message_id = mbox.id。在 mbox 中创建消息后,您可以获取新插入的消息的 id 并将其存储在 user_mailboxes message_id 列中。
【解决方案2】:

只需做一件事,在现有表中添加两个新字段

  1. is_sender_deleted
  2. is_receiver_deleted

如果有人将其从发件箱中删除,则将 is_sender_deleted 值设为 1。因此,当您在发件箱中显示数据时,您只需列出所有 is_sender_deleted 字段值为 0 的记录。

同样的情况,如果有人从收件箱中删除它,然后将 is_receiver_deleted 值设为 1。因此,当在收件箱中显示数据时,您只需列出所有 is_receiver_deleted 值为 0 的记录。

希望这个解决方案能帮到你。

【讨论】:

    【解决方案3】:

    我也解决了这个任务。我认为一张桌子在这种情况下没有用。所以,我建议使用 2 个表:

    CREATE TABLE `message` (
      `id`       int(11) NOT NULL AUTO_INCREMENT,
      `subject`  varchar(255) NOT NULL,
      `body`     text NOT NULL,
      `date`     datetime NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    CREATE TABLE `message_user` (
      `id`           int(11) NOT NULL AUTO_INCREMENT,
      `message_id`   int(11) NOT NULL,
      `user_id`      int(11) NOT NULL,
      `interlocutor` int(11) DEFAULT NULL,
      `folder`       enum('inbox','sent') NOT NULL,
      `starmark`     tinyint(1) NOT NULL DEFAULT '0',
      `unread`       tinyint(1) NOT NULL DEFAULT '1',
      `deleted`      enum('none','trash','deleted') NOT NULL DEFAULT 'none',
      PRIMARY KEY (`id`),
      CONSTRAINT `message_user_user_fk_1` FOREIGN KEY (`message_id`)   REFERENCES `message` (`id`) ON UPDATE CASCADE,
      CONSTRAINT `message_user_user_fk_2` FOREIGN KEY (`user_id`)      REFERENCES `user`    (`id`) ON UPDATE CASCADE,
      CONSTRAINT `message_user_user_fk_3` FOREIGN KEY (`interlocutor`) REFERENCES `user`    (`id`) ON UPDATE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    

    我认为它可以解决您的所有问题,因为消息用户彼此分开

    因此,对于一条消息,我们必须像这样创建 3 个插入:

    public static function createMessage($subject, $body, $source, $sender_id, $receiver_id)
    {
        // save DATA to message table      ($subject, $body, $source)
        // save DATA to message_user table ($message_id, $sender_id, $receiver_id, 'sent')
        // save DATA to message_user table ($message_id, $receiver_id, $sender_id, 'inbox')
    }
    

    在这种情况下,我们在表message_user 中为每个用户创建单独的行。因此,当 user_1 删除此收件箱文件夹中的邮件时,我们将其标记为“已删除”,并且对第二个用户没有影响。

    因此,要获取所有用户消息,我们必须像这样运行简单的 SELECT:

    SELECT *
    FROM message m
        JOIN message_user mu
        ON m.id = mu.message_id
    WHERE mu.deleted = 'none'
        AND mu.user_id = :user_id
    

    【讨论】:

    • 我相信它对你有用,但这可能很不清楚。它使用只有您的系统知道的类和消息。而且给列名加上前缀感觉又脏又没用。
    • @HugoDelsing 谢谢你的评论。我更新了我的答案并修复了您的所有评论。我希望现在一切都更清楚了
    • 我删除了我的反对票,因为它有效,你解释得更好。我仍然认为 Josh 的回答更好地解释了这种方法,因此他得到了我的支持,
    【解决方案4】:

    不要从数据库中删除消息,而是使用该特定消息的状态
    作为 SHOWtoSenderSHOWtoReciverSHOWtoBoth SHOWtoNONE
    使用数据类型 ENUM,默认为 SHOWtoBoth)。
    在您的表中进行更改:
    id 发送者接收者状态时间

    【讨论】:

    • 好的,我该怎么做?你能发布一个示例代码吗?谢谢
    • 您使用的是准备好的语句还是存储的语句?
    • $query="更新表 SET table.status=?WHERE $user=?LIMIT 1";现在根据您需要的更改将参数传递给 table.status - SHOWtoSender/SHOWtoReceiver/SHOWtoBOTH/SHOtoNONE 并根据发送者/接收者为 $user 提供字符串值
    【解决方案5】:
    id   message    sentby   sentto    created deteled_from_inbox deteled_from_outbox
    

    在您的表格中,我添加了 2 个字段,两个字段的值都是 YES 和 NO。起初两个字段都是 NO

    $you=$_COOKIE['username'];     
    $st= "SELECT* FROM mbox WHERE sentto='$you' AND deteled_from_inbox='NO' ORDER BY ID DESC LIMIT 10";
    
    $you=$_COOKIE['username'];     
    $st= "SELECT* FROM mbox WHERE sentto='$you' AND deteled_from_outbox='NO' ORDER BY ID DESC LIMIT 10";
    

    当用户从收件箱中删除数据时,您实际上将使用YES 更新deteled_from_inbox,因此它不会显示在收件箱部分。由于我们没有触摸deteled_from_outbox,它将显示在发件箱一侧。

    【讨论】:

      【解决方案6】:

      添加一个像has_mail 这样的列,它的默认值像AB 这意味着两个用户都有邮件。现在,如果有人从他们的输入/输出框中删除,那么特定的 A/B 将被删除。

      $st= "SELECT* FROM mbox 
            WHERE sentto='$you' and has_mail LIKE '%". $you . "' ORDER BY ID DESC LIMIT 10";
      
      $st= "SELECT* FROM mbox 
            WHERE sentby='$you' and has_mail LIKE '". $you . "%' ORDER BY ID DESC LIMIT 10";
      

      现在您可以在两个字段都为空时从数据库中删除消息:

      DELETE FROM mbox WHERE LENGTH(has_mail) < 1 
      

      【讨论】:

      • 那么如果两个用户都删除了该消息,则数据库中的记录不会被删除。
      • 数据库记录需要删除吗?我知道 OP 希望删除它,但如果它不仅仅是希望最终用户假设删除,因为他们看不到它,如果数据的实际破坏很重要,那么可以运行清理脚本来删除 has_mail 字段的消息是空的。
      • 将这种逻辑隐藏在“愚蠢”的数据列中可能非常危险。
      【解决方案7】:

      我认为使用多个表(每个用户一个表)可能是最好的选择,以便将其存档。如果你只用一张桌子,那么超时就会变得非常大。


      我建议的解决方案是您将表结构编辑为:

      id    owner    message    sentby    sentto    created
      

      这样,当用户创建消息时,将创建两条记录:发送者的副本和接收者的副本

      当用户A发送用户B消息“Good Job”时,查询将是:

      sendmessage.php

      $you=$_COOKIE['username'];
      $recipient="UserB";
      $st1="INSERT INTO tbl_msg VALUES ($id,'$you','Good Job','$you','$recipient','$time)";
      $st2="INSERT INTO tbl_msg VALUES ($id,'$recipient','Good Job','$you','$recipient','$time)";
      

      inbox.php

      $you=$_COOKIE['username'];
      $st= "SELECT * FROM mbox WHERE sentto='$you' AND owner='$you' ORDER BY ID DESC LIMIT 10";
      

      outbox.php

      $you=$_COOKIE['username'];
      $st= "SELECT * FROM mbox WHERE sentby='$you' AND owner='$you' ORDER BY ID DESC LIMIT 10";
      

      删除.php

      只需删除 owner='$you' 的那个 DELETE FROM mbox WHERE condition1=value1 AND owner='$you'


      基本上,我的解决方法是:当用户发送消息时,我们将两条消息插入数据库(一份用于收件人的收件箱,另一份用于发件人的发件箱)

      当用户删除他/她的消息时,它不会从其他人的收件箱/发件箱中删除,因为每个用户都有自己的消息副本

      【讨论】:

      • 虽然它会起作用,但当我们存储冗余数据时我讨厌它。在这种情况下它可能会起作用,但如果您决定有多个收件人,那就太糟糕了。此外,如果您想添加附件等内容,您还会多次存储这些内容吗?或者如果您允许编辑?我知道,一切都可以解决。但我只是觉得相同的数据应该只在数据库中出现一次。
      【解决方案8】:

      您可以在 mbox 表中添加“状态”之类的列,

      然后;如果 UserB 删除消息,您可以将状态更改为 1 或 UserA 删除消息,您可以将状态更改为 2。

      收件箱:

      $you=$_COOKIE['username'];
      $st= "SELECT* FROM mbox WHERE sentto='$you' AND status <> '1' ORDER BY ID DESC LIMIT 10";
      

      发件箱:

      $you=$_COOKIE['username'];
      $st= "SELECT* FROM mbox WHERE sentby='$you' AND status <> '2' ORDER BY ID DESC LIMIT 10";
      

      祝你好运。

      【讨论】:

      • 如果两个用户都删除了消息会发生什么?
      • @Kristian 您可以在这种情况下使用状态 3。
      • 呃!数据库中的位图字段?第一条规范化规则发生了什么?
      • 那么旧消息会永久存储在系统中吗?或者,可能每个计划的系统维护所有状态为 3 的消息都会被删除。
      • 除了一旦有多个接收者就永远无法完成这项工作之外,它几乎总是会导致使用STATUS=THIS OR STATUS=that 进行查询,并且即使使用正确的索引也会大大减慢速度。
      【解决方案9】:

      这可能不是最强大的解决方案,但它是一个相当实用的解决方案,并且不需要您对数据库结构进行任何更改。

      更改您的删除功能。不要删除数据库中的行,而是进行一些检查。弄清楚是发件人还是收件人进行删除。如果发件人正在删除,请检查是否为sentto == null。如果是,请删除该行。否则,设置sentby = null。反之亦然。

      我假设您在用户按下删除键时发布消息 ID。还假设您正在使用 PDO。让我知道这个假设是否错误。

      删除.php

      $link = new \PDO... // blah blah connection stuff
      $id = $_POST['id'];
      $messageSELECT = $link->prepare("SELECT `sentby`,`sentto` FROM `mbox` WHERE ID = :id");
      $messageSELECT->bindValue(':id',$id,\PDO::PARAM_INT);
      $messageSELECT->execute();
      $msgInfo = $messageSELECT->fetchAll();
      
      $msgDELETE = null;
      if($you == $msgInfo['sentby'] && empty($msgInfo['sentto'])){
        $msgDELETE = $link->prepare("DELETE FROM `mbox` WHERE ID = :id");
      } elseif($you == $msgInfo['sentby'] && !empty($msgInfo['sentto'])){
        $msgDELETE = $link->prepare("UPDATE `mbox` SET `sentby` = NULL WHERE ID = :id");
      } elseif($you == $msgInfo['sentto'] && empty($msgInfo['sentby'])){
        $msgDELETE = $link->prepare("DELETE FROM `mbox` WHERE ID = :id");
      } elseif($you == $msgInfo['sentto'] && !empty($msgInfo['sentby'])){
        $msgDELETE = $link->prepare("UPDATE `mbox` SET `sentto` = NULL WHERE ID = :id");
      } else {
        // Shouldn't happen
      }
      $msgDELETE->bindValue(':id',$id,\PDO::PARAM_INT);
      $msgDelete->execute();
      

      【讨论】:

      • 将 sentto 或 sentby 字段设置为 null 不是一种选择,因为此表由发送者和发送消息的对象共享。发件人,如果他或她“删除”一条消息,并且“sentby”字段设置为空,那么该消息被发送到的人将在他/她的收件箱中看到一个空的“sentby”字段,这不是一个选项为该用户
      【解决方案10】:

      以您当前的数据库结构,不,您不能这样做。让我们从改变你的一些结构来实现你想要的开始。

      1。添加删除字段

      首先要做的是在 ENUM(Y, N) 的位置添加一个已删除的字段。您的表格结构将如下所示。

      tblMessage(id, message, sentby, sentto, created, deleted)
      

      现在,使用已删除字段,它允许接收者删除他们的消息,而发送者仍然保留他们的消息。问题是它不允许发件人从他们的发件箱中删除他们的邮件。

      发件箱

      SELECT * FROM message WHERE sentby = $you
      

      收件箱

      SELECT * FROM message WHERE sentto = $you AND deleted = 'N'
      

      2。制作两张桌子

      为了使其更加灵活 (1) 让发送者可以从他们的发件箱中删除邮件,但接收者仍然可以将邮件保留在他们的收件箱中 (2) 以便接收者可以从他们的收件箱中删除邮件,而发件人仍然在他们的发件箱中。

       tblInbox(id, sendby, message, created, deleted)
       tblOutbox(id, sendto, message, created, deleted)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-02
        • 2013-06-20
        • 2013-01-19
        • 1970-01-01
        • 2013-08-13
        • 2013-11-11
        • 1970-01-01
        相关资源
        最近更新 更多