【问题标题】:custom php forum - showing new/unread posts自定义 php 论坛 - 显示新的/未读的帖子
【发布时间】:2011-09-16 12:37:43
【问题描述】:

我已经使用 php 为自己编写了一个自定义论坛脚本。我决定不使用 phpbb 和其他工具,因为我想要 100% 的灵活性。

我遇到了一个问题:

如果帖子是新的/未读的,我如何向用户显示。

想到了两个解决方案:

1) Cookie 2) 数据库

我不想使用 cookie,因为它们可以被用户删除,而 Firefox 方面的东西意味着它们会被自动删除。无论哪种方式,我都不想使用 cookie。

数据库给我带来了问题,因为我似乎无法在脑海中对数据库结构进行排序!我能想到的第一个解决方案是:

  • 当用户加载论坛时,检查他们上次加载论坛的时间
  • 检查自上次查看论坛以来发布的所有帖子
  • 在包含字段(user_id、post_id)的表中将这些值输入到数据库中。
  • 当他们查看帖子时,该值会从数据库中删除

我认为这是一个巨大的数据库消耗问题。看起来效率太低了。我确信字段中有数组的方法,但我对数组并不是那么好。

谁能告诉我一个好的数据库设计以及与之相关的任何代码?这让我发疯,因为我想不出一个对服务器来说既好又高效的解决方案。

非常感谢您的帮助和帮助,

詹姆斯。

【问题讨论】:

  • 只需在 post 表中添加一列可以是布尔值,如果已查看则设置为 true,如果尚未查看则设置为 false
  • 您可以比较现有的板卡软件如何做到这一点。例如 PHPBB 或 MyBB 或其他各种代码可免费获得。然后选择适合您的需求。
  • 我犹豫是否要发布这个建议,但我正在考虑和你一样做,然后我发现了香草论坛,它提供的内容非常精简,你可以在其中插入你需要的各种位和什么时候。就像 hakre 建议的那样,即使您不采用它,您也可以比检查他们的工作方式更糟糕。

标签: php mysql database forum


【解决方案1】:

这是一个很好的问题,我以前从未经历过,所以我只能建议你一个想法,我不能保证它的正确性。

我的想法基本上是:

  1. 在主题表中创建一个名为 is_new 的新字段。此字段包含字符串形式的值列表,遵循特定模式。例如:5|6|12|110|2|45| 之间的每个值都代表一个用户的 ID,该用户已经阅读了该主题。

  2. 每次用户跳转到论坛时,在获取返回主题列表时,您将检查该用户是否阅读了每个主题,简单的方法是:

    • 使用explode('|', $row['is_new']); 分解is_new 中的字符串
    • 现在你有一个包含值的数组,只需要检查in_array($user['id'], $list_of_ids);
  3. 如果false,则标记主题unread,否则将其标记为read,并将该用户的ID更新到is_new列表中。

这种方法似乎没有您原来的方法那么“痛苦”,因为它只检查比普通方法更多的内容,并且在您获取主题列表的同时。如果您有大量用户,我认为它会影响更多。

注意:你不必担心归一化的问题,因为is_new包含多个值,你只用它来检查和更新,不需要选择。

此外,您还可以使用时间比较来检查主题是否为新主题。例如,如果一个主题持续 4 周并且用户没有阅读它,那么即使它没有阅读它也会返回旧的(这很有意义,不是吗?就像报纸一样)。我认为您将能够做到这一点,确实很容易。

这种方法特别适用于很多论坛软件,因为它快速且更有意义。请记住,浏览器最初支持您确定已读/未读主题,即如果主题被访问,超链接的颜色将发生变化。现在它回到 Cookies 解决方案。我不会担心用户删除他们的 cookie。这种情况很少发生,用户不会因为删除 cookie 后 read 主题变为 unread 而死。

这是一个非常开放的话题,不是吗?希望这会有所帮助(:

【讨论】:

  • @BeingSimpler,加一!不错的答案!
  • 这当然是一个有效的方法,但是 is_new 列让我觉得有点脏。虽然您关于规范化的观点在技术上是正确的,但仍有充分的理由将此信息拆分到另一个表中:与 JOIN 相比,执行字符串爆炸、数组遍历和可能的数组更新非常慢。关系数据库旨在快速有效地关联此类信息,为什么不利用它呢?
  • 贾斯汀,好点(:但我仍然认为在这种情况下它不会有太大影响,因为更新新 ID 就像将新字符串附加到当前字符串中一样,例如“UPDATE topic SET is_new = CONCAT(is_new,'|$id')"。正如我所说,这个字段作为匹配值的独立存储,它不需要与任何其他字段相关,也不需要任何特定的选择。你的方法是正确的,这对我来说甚至听起来是正确的,但它与我的想法和方法不同。我的可能需要 2 行代码,并且与使用原始 RDB 方法相比并没有减慢那么多。
  • 非常感谢您的回复。尽管我确实同意贾斯汀的观点,但无论如何,我目前使用该网站的人数相对较少(我认为每天的页面浏览量约为 10-20k 次),而且论坛上的人数也较少。我会暂时坚持这种方法,当我的网站开始扩展时,我会研究另一种方法。我有一个非常紧凑的开发计划,所以有一些效率稍低但在很短的时间内完成的东西是非常重要的。非常感谢所有在这个问题上发帖的人。谢谢。
  • 我已经成功地将这个功能添加到网站上,而且效果很好。我决定添加一个“新帖子”按钮,以便人们单击该按钮并查看新帖子,而不是通过突出显示列表中的单个帖子来增加服务器上的任何消耗。再次感谢您的帮助
【解决方案2】:

许多大型论坛软件使用跟踪表来跟上谁读过什么,像这样(高度简化):

CREATE TABLE topic_tracking (
    user_id INT NOT NULL,
    topic_id INT NOT NULL,
    last_visit DATETIME NOT NULL,
    PRIMARY KEY (user_id, topic_id)
)

然后,您可以在此表上使用连接来检查您正在显示的帖子是否已阅读。由于您将分页您的线程,这应该会产生相对较少的额外查询(取决于您每页显示的帖子数)。

当用户访问线程时,使用他们访问的时间戳更新此跟踪表。然后在显示您的线程链接时,检查此表以查看他们的 last_visit 是否早于线程中的最后一个帖子。这也让您可以显示“更新的”线程,而不仅仅是“新”线程。

【讨论】:

    【解决方案3】:

    嗯,好问题。

    我会在如何处理这个问题上投入两分钱,这可能不是最有效的解决方案,但这里是:

    我会使用数据库来解决这个问题。如果可能,在数据库中创建一个附加到特定用户的字段。在此字段(或列或表,如果您愿意)中存储按文章 ID 列出的“已查看”文章列表。

    在为用户呈现页面时,检索他们“已查看”文章的列表以及所有可用文章 ID 的列表。

    遍历您的文章/论坛/主题结果集,查看该 ID 是否与任何“已查看”ID 匹配。对于没有相应“已查看”匹配项的每个文章/论坛/主题条目,那么对于该用户来说,这将是一篇“新”文章。

    这是处理器/数据库/网络密集型的,并且每次加载包含文章引用的页面时都需要查找数据库。尽管通过一些巧妙的查询设计,我认为您可以将这种操作几乎完全卸载到数据库中。

    另一个使用数据库的潜在解决方案是,当用户首次登录网站时,您会在第一个加载点获取已阅读文章/论坛的列表并将其添加到 cookie 或会话中,这样您只需访问该列表的数据库一次(在第一次加载时),并将其存储在 session/cookie/hidden 字段中,以便在后续请求中您只需转到该 cookie/session/hidden 字段而不是执行 Db 查找每次用户查看包含文章/论坛/主题列表的页面时。每次用户单击链接时,将其捕获并存储在数据库中,并将该文章/论坛 ID 存储在您的 cookie/会话/隐藏字段中。再一次,也许不是最有效的方法,但有一些老式的进取心,我相信你会占上风。 :)

    祝你好运!

    H

    【讨论】:

      【解决方案4】:

      会话将是存储它的好地方。我想你只想存储用户查看的最后“n”个线程的数据,或者只存储最后“n”天的线程数据。

      正如有人在其中一个 cmet 中建议的那样,值得查看一些现有的论坛,看看他们是如何实现这一点的。

      虽然我认为编写自己的论坛软件是一个很好的学习机会,但就自己构建它的效率而言,我认为你在某种程度上是在重新发明轮子。

      【讨论】:

      • 会话的问题是我必须使用数组来做到这一点,不是吗?那么,如果这个人关闭浏览器会发生什么?他们仍然会有以前没有阅读过的新帖子,即使它们是,它们也不会再显示为“新”。使用数据库的优点是即使关闭浏览器,帖子也将始终保持“新”状态,因为在他们阅读之前该值保持“未读”状态。我同意可以说我是在“重新发明轮子”,但我厌倦了试图修改其他人的编码以使其对我有用。它只是不工作..
      • 无法使用数组将真正限制您构建功能的能力。我真的建议花一些时间来学习它。那里有很多很好的教程,只需在 Google 上搜索“php 数组”
      • 感谢您的建议。不过,关于我对会议的观点,您对此有何建议?如果他们在查看新帖子的过程中关闭了浏览器,如果他们稍后再回来会发生什么?我现在将尝试加载 phpbb 论坛代码,看看他们如何显示新帖子。我不确定是否有可能找到它..但我会努力的! :) 如果您对数据库方面有任何想法,请务必告诉我 :) 谢谢
      • @James,James C 说得对,不能有效地使用数组真的会限制你的编程能力。至于如何处理将帖子标记为新的或非新的,请在页面上列出您的文章并为每篇文章提供锚链接,然后将 javascript/jQuery 函数绑定到执行 AJAX 调用的链接“onclick”事件返回服务器通知服务器用户刚刚点击了一篇文章链接并记录该文章的 ID 号。用户下次查看该页面时,数据库中存储的值表明该页面已被查看。
      【解决方案5】:

      我的方法是保存特定用户在数据库中看到的每个主题的最后一个帖子 ID:

      user_id   topic_id   post_id
      1         2          3
      

      所以,在这里你知道用户 1 访问了第二个主题的第三个帖子,但根本没有看第一个主题。

      要检查用户是否有新的/未读的主题,您可以首先检查该用户不在此表中的 topic_id。要检查已知主题是否有新消息,您可以将 post_id 与每个主题的最后一个 post_id 进行比较。如果它们不相等,则有新消息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-18
        • 1970-01-01
        • 2016-05-17
        • 1970-01-01
        • 2011-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多