对于个人项目,我需要使用PHP和MySQL建立一个论坛。我不可能使用已经构建的论坛包(如phpBB)。
我目前正在通过构建这样一个应用程序所需的逻辑工作,但是这是漫长的一天,我正在努力为用户处理未读帖子的概念。我的一个解决方案是使用一个单独的表来保存所有的post id和user id,以确定它们是否已被读取:
tbl_userReadPosts: user_id, post_id, read_timestamp
显然,如果用户的ID出现在这个表中,我们就知道他们已经阅读了这篇文章。这很好,除非我们每天有成千上万的帖子(这在正在提议的系统中是超过可能的),以及成千上万的用户。这个表在几天之内就会变得很大,如果不是几个小时的话。
另一个选项是将用户的最后一个活动作为时间戳跟踪,然后检索在他们的最后一个活动更新之后发布的所有帖子。这在理论上是可行的,但是让我们假设一个用户正在写一个非常长的帖子,同时几个成员也开始新的线程或回复其他线程中的帖子。当用户提交他的新帖子时,他的最后一个活动将被更新,因此与同时进行的活动不匹配。
有没有人有过这样的经历,你是如何处理的?
我已经检查了phpBB,似乎系统分配一个自定义会话给每个用户,并在此基础上工作,但文档是相当稀疏的,如何处理未读的帖子。
一如既往地感谢您的想法和意见。
很抱歉回答得太快,但我只有一秒钟的时间。您肯定不希望将读取信息存储在数据库中,正如您已经推断的那样,这个表将变得非常庞大。
介于你已经建议的两者之间:存储用户最近的活动,并结合存储他们在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的实现相当简单。它只显示上次登录后的所有帖子。这样,您就不需要存储任何关于用户实际看到或阅读的信息。