PHP/MySQL中未读帖子的处理

16

为了完成一个个人项目,我需要使用PHP和MySQL构建论坛。我不能使用已经构建好的论坛包(例如phpBB)。

目前,我正在研究构建这种应用所需的逻辑,但今天已经很长时间了,我正在苦苦思考如何处理用户未读的帖子。我想到的一个解决方案是创建一个单独的表,该表基本上保存所有帖子ID和用户ID,以确定它们是否已被阅读:

tbl_userReadPosts:user_id,post_id,read_timestamp

显然,如果用户ID出现在此表中,我们就知道他们已经阅读了该帖子。这很好,但如果每天有成千上万的帖子(在提议的系统中完全可能),并且有成千上万的用户,则此表将在几天内甚至几小时内变得非常庞大。

另一种选择是跟踪用户的上次活动时间戳,然后检索在其上次活动更新之后发布的所有帖子。理论上,这种方法可行,但假设一个用户正在撰写一篇极长的帖子,而同时还有其他成员开始新线程或回复其他线程中的帖子。当用户提交新帖子时,他的最后活动时间戳将被更新,因此不会匹配其间的时间。

有没有人有这方面的经验?你是如何解决的?

我已经在phpBB中检查过了,似乎该系统为每个用户分配一个自定义会话,并且基于此进行操作,但是关于如何处理未读帖子的文档非常简洁。

欢迎分享你的想法和意见。

5个回答

7

抱歉回答得很快,但我只有一点时间。您肯定不希望将读取信息存储在数据库中,正如您已经推断的那样,这个表会变得巨大。

建议采用您已经提出的方案之间的某种方式:存储用户的最新活动,并与存储在cookie中的已读线程/帖子信息结合使用,以确定他们已经阅读了哪些线程/帖子。

这将把存储转移到客户端cookie上,效率更高。


我为所有回答者的贡献点赞。约翰,我喜欢你的建议。我会试着使用这种方法(或组合)进行尝试。谢谢! - BenM

7
一个包含所有用户ID和帖子ID的表是一个不好的主意,因为它会呈指数级增长。想象一下,如果您的论坛解决方案增长到了一百万篇帖子和五万个用户,那么现在就有500亿条记录了。这将是一个问题。
诀窍是像你说的那样使用一个表,但它只保存自上次登录以来已阅读的帖子,这些帖子是在上次登录和本次登录之间发布的。
所有在上次登录之前发布的帖子都被认为是已读的。
例如,我上次登录是在2011年4月3日,然后我今天登录。所有在2011年4月3日之前发布的帖子都被认为是已读的(对我来说它们不是新的)。所有在2011年4月3日至今之间发布的帖子,除非在已读表中看到,否则都是未读的。已读表在每次登录时都会被清空。
这样,您的已读帖子表应该永远不会对每个成员有超过几百条记录。

3

不必为每个帖子*用户创建新行,您可以在用户表中拥有一个字段,其中包含用户阅读过的以逗号分隔的帖子ID字符串。

显然,用户不需要知道两年前还有未读帖子,因此,您只显示在最近24小时内发布的帖子为“新帖”,并且不在逗号分隔的字符串中。

您也可以使用会话变量或cookie来解决这个问题。


2

这种方法为每个 forumID 单独存储最近访问的 postID

它不像针对每个帖子单独跟踪的解决方案那样精细,但它可以减少需要为每个用户存储的数据量,并仍然提供了一种不错的方式来跟踪用户的浏览历史。

<?php
    session_start();
    //error_reporting(E_ALL);

    // debug: clear session
    if (isset($_GET['reset'])) { unset($_SESSION['activity']); }

    // sample data: db table with your forum ids
    $forums = array(
        //  forumID     forumTitle
            '1'     =>  'Public Chat',
            '2'     =>  'Member Area',
            '3'     =>  'Moderator Mayhem'
    );

    // sample data: db table with your forum posts
    $posts = array(
        //  postID                  forumID     postTitle
            '12345' =>  array(  'fID'=>'1', 'title'=>'Hello World'),
            '12346' =>  array(  'fID'=>'3', 'title'=>'I hate you all'),
            '12347' =>  array(  'fID'=>'1', 'title'=>'Greetings!'),
            '12348' =>  array(  'fID'=>'2', 'title'=>'Car thread'),
            '12349' =>  array(  'fID'=>'1', 'title'=>'I like turtles!'),
            '12350' =>  array(  'fID'=>'2', 'title'=>'Food thread'),
            '12351' =>  array(  'fID'=>'3', 'title'=>'FR33 V1AGR4'),
            '12352' =>  array(  'fID'=>'3', 'title'=>'CAPSLOCK IS AWESOME!!!!!!!!'),
            '12353' =>  array(  'fID'=>'2', 'title'=>'Funny pictures thread'),
    );

    // sample data: db table with the last read post from each forum
    $userhist = array(
        //  forumID     postID
            '1'     =>  '12344',
            '2'     =>  '12350',
            '3'     =>  '12346'
    );

    // reference for shorter code
    $s = &$_SESSION['activity'];

    // store user's history into session
    if (!isset($s)) { $s = $userhist; }

    // mark forum as read
    if (isset($_GET['mark'])) {
        $mid = (int)$_GET['mark'];
        if (array_key_exists($mid, $forums)) {
            // sets the last read post to the last entry in $posts
            $s[$mid] = array_search(end($posts), $posts);
        }
        // mark all forums as read
        elseif ($mid == 0) {
            foreach ($forums as $fid=>$finfo) {
                // sets the last read post to the last entry in $posts
                $s[$fid] = array_search(end($posts), $posts);
            }
        }
    }

    // mark post as read
    if (isset($_GET['post'])) {
        $pid = (int)$_GET['post'];
        if (array_key_exists($pid, $posts)) {
            // update activity if $pid is newer
            $hist = &$s[$posts[$pid]['fID']];
            if ($pid > $hist) {
                $hist = $pid;
            }
        }
    }

    // link to mark all as read
    echo '<p>[<a href="?mark=all">Read All</a>]</p>' . PHP_EOL;

    // display forum/post info
    foreach ($forums as $fid=>$finfo) {
        echo '<p>Forum: ' . $finfo;
        echo ' [<a href="?mark=' . $fid . '">Mark as Read</a>]<br>' . PHP_EOL;
        foreach ($posts as $pid=>$pinfo) {
            if ($pinfo['fID'] == $fid) {
                echo '- Post: <a href="?post=' . $pid . '">' . $pid . '</a>';
                echo ' - ' . ($s[$fid] < $pid ? 'NEW' : 'old');
                echo ' - "' . $pinfo['title'] . '"<br>' . PHP_EOL;
            }
        }
        echo '</p>' . PHP_EOL;
    }

    // debug: display session value and reset link
    echo '<hr><pre>$_SESSION = '; print_r($_SESSION); echo '</pre>' . PHP_EOL;
    echo '<hr>[<a href="?reset">Reset Session</a>]' . PHP_EOL;
?>

注意: 显然,这个例子仅供演示目的。在处理实际数据库时,一些结构和逻辑可能需要更改。


1

Phpbb2已经实现了这个相当简单的功能。它只会显示自上次登录以来的所有帖子。这样,您就不需要存储有关用户实际上看到或阅读了什么信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接