处理未读的帖子在PHP / MySQL



对于个人项目,我需要使用PHP和MySQL建立一个论坛。我不可能使用已经构建的论坛包(如phpBB)。

我目前正在通过构建这样一个应用程序所需的逻辑工作,但是这是漫长的一天,我正在努力为用户处理未读帖子的概念。我的一个解决方案是使用一个单独的表来保存所有的post id和user id,以确定它们是否已被读取:

tbl_userReadPosts: user_id, post_id, read_timestamp

显然,如果用户的ID出现在这个表中,我们就知道他们已经阅读了这篇文章。这很好,除非我们每天有成千上万的帖子(这在正在提议的系统中是超过可能的),以及成千上万的用户。这个表在几天之内就会变得很大,如果不是几个小时的话。

另一个选项是将用户的最后一个活动作为时间戳跟踪,然后检索在他们的最后一个活动更新之后发布的所有帖子。这在理论上是可行的,但是让我们假设一个用户正在写一个非常长的帖子,同时几个成员也开始新的线程或回复其他线程中的帖子。当用户提交他的新帖子时,他的最后一个活动将被更新,因此与同时进行的活动不匹配。

有没有人有过这样的经历,你是如何处理的?

我已经检查了phpBB,似乎系统分配一个自定义会话给每个用户,并在此基础上工作,但文档是相当稀疏的,如何处理未读的帖子。

一如既往地感谢您的想法和意见。

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

介于你已经建议的两者之间:存储用户最近的活动,并结合存储他们在cookie中看到的信息,以确定他们已经阅读了哪些线程/帖子。

这将把存储空间转移到客户端cookie,这将更加高效。

保存所有user_ids和post_ids的表是一个坏主意,因为它呈指数级增长。想象一下,如果您的论坛解决方案增长到100万个帖子和50,000个用户。现在你有500亿条记录。那就麻烦了。

技巧是使用表,但它只保存自本次登录以来已读取的帖子,以及在上次登录和本次登录之间发布的帖子。

在上次登录之前发布的所有帖子都被视为已读。

IE,我上次登录是2011年4月3日,然后我今天登录。所有在2011年4月3日之前发布的帖子都被认为是已读的(对我来说不是新的)。2011年4月3日到现在的所有帖子都是未读的,除非它们出现在阅读表中。每次登录时都会刷新读表。

这样,你的read posts表中每个成员的记录就不会超过几百条。

不需要为每个post*用户创建一个新行,而可以在用户表中创建一个字段,该字段包含一个逗号分隔的字符串,其中包含用户已阅读的post- id。

显然,用户不需要知道2年前的未读帖子,所以您只显示最近24小时内发布的帖子的"新帖子",而不是在逗号分隔的字符串中。

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

该方法为每个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;
?>

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

Phpbb2的实现相当简单。它只显示上次登录后的所有帖子。这样,您就不需要存储任何关于用户实际看到或阅读的信息。

最新更新