16

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

我目前正在研究构建这样一个应用程序所需的逻辑,但这是漫长的一天,我正在为处理用户未读帖子的概念而苦苦挣扎。我有一个解决方案是有一个单独的表,它基本上包含所有帖子 ID 和用户 ID,以确定它们是否已被阅读:

tbl_userReadPosts: user_id, post_id, read_timestamp

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

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

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

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

一如既往地感激地接受思想和意见。

4

5 回答 5

7

很抱歉快速回答,但我只有一秒钟。您肯定不想将读取的信息存储在数据库中,正如您已经推断的那样,该表将变得巨大。

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

这会将存储卸载到客户端 cookie,效率更高。

于 2011-04-05T15:52:12.487 回答
7

包含所有 user_ids 和 post_ids 的表是一个坏主意,因为它呈指数增长。想象一下,如果您的论坛解决方案增长到一百万个帖子和 50,000 个用户。现在您有 500 亿条记录。那会是个问题。

诀窍是使用您所说的表格,但它仅包含自此登录以来已阅读的帖子,以及在上次登录和此登录之间发布的帖子。

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

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

这样,您的阅读帖子表中每个成员的记录不应超过几百条。

于 2011-04-05T15:53:48.107 回答
3

您可以在用户表中拥有一个字段,该字段包含一个逗号分隔的字符串,其中包含用户已阅读的 post-ID,而不是为每个 post*user 设置一个新行。

显然,用户不需要知道有 2 年前的未读帖子,因此您只显示过去 24 小时内发布的帖子的“新帖子”,而不是逗号分隔的字符串。

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

于 2011-04-05T16:32:29.257 回答
2

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

它不像单独跟踪每个帖子的解决方案那样精细,但它减少了您需要为每个用户存储的数据量,并且仍然提供了一种体面的方式来跟踪用户的查看历史记录。

<?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;
?>

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

于 2011-04-05T21:38:57.617 回答
1

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

于 2011-04-07T18:28:43.843 回答