Обработка непрочитанных сообщений в PHP/MySQL

Для личного проекта мне нужно создать форум с использованием PHP и MySQL. Я не могу использовать уже готовый пакет форума (например, phpBB).

В настоящее время я работаю над логикой, необходимой для создания такого приложения, но это был долгий день, и я борюсь с концепцией обработки непрочитанных сообщений для пользователей. Одно из решений, которое у меня было, состояло в том, чтобы иметь отдельную таблицу, которая по существу содержит все идентификаторы сообщений и идентификаторы пользователей, чтобы определить, были ли они прочитаны:

tbl_userReadPosts: user_id, post_id, read_timestamp

Очевидно, что если идентификатор пользователя появляется в этой таблице, мы знаем, что он прочитал сообщение. Это здорово, если только у нас не тысячи постов в день (что более чем возможно в предлагаемой системе) и тысячи пользователей. Эта таблица станет огромной за считанные дни, если не часы.

Другим вариантом может быть отслеживание последней активности пользователя в виде метки времени, а затем извлечение всех сообщений, сделанных после того, как их последняя активность была обновлена. Теоретически это работает, но предположим, что пользователь пишет очень длинный пост, а в это время несколько участников также начинают новые темы или отвечают на сообщения в других темах. Когда пользователь отправляет свой новый пост, его последняя активность будет обновлена ​​и, таким образом, не будет совпадать с теми, что были сделаны в это время.

Есть ли у кого-нибудь опыт в этом, и как вы с этим боролись?

Я проверил на phpBB, и кажется, что система назначает индивидуальный сеанс каждому пользователю и работает на этой основе, но документация относительно того, как это работает с непрочитанными сообщениями, довольно скудна.

Мысли и мнения с благодарностью приняты, как всегда.


person BenM    schedule 05.04.2011    source источник


Ответы (5)


Извините за быстрый ответ, но у меня есть только секунда. Вы определенно не хотите хранить прочитанную информацию в базе данных, как вы уже поняли, эта таблица станет гигантской.

Что-то среднее между тем, что вы уже предложили: сохранить последнюю активность пользователей и в сочетании с сохранением информации о том, что они видели в файле cookie, чтобы определить, какие темы/сообщения они уже прочитали.

Это разгружает хранилище в файл cookie на стороне клиента, что намного эффективнее.

person John Cartwright    schedule 05.04.2011
comment
Я дал всем ответившим +1 за их вклад. Мне нравится твое предложение, Джон. Я поэкспериментирую с этим методом (или, скорее, с комбинацией). Спасибо! - person BenM; 06.04.2011

Таблица, содержащая все user_id и post_id — плохая идея, так как она растет в геометрической прогрессии. Представьте, что ваше решение для форума выросло до миллиона сообщений и 50 000 пользователей. Теперь у вас есть 50 миллиардов записей. Это будет проблемой.

Хитрость заключается в том, чтобы использовать таблицу, как вы сказали, но она содержит только сообщения, которые были прочитаны с момента входа в систему, сообщения, которые были опубликованы между последним входом в систему и этим входом в систему.

Все сообщения, сделанные до последнего входа в систему, считаются прочитанными.

IE, последний раз я входил в систему 03.04.2011, а затем я вхожу сегодня. Все сообщения, сделанные до 03.04.2011, считаются прочитанными (для меня они не новы). Все сообщения в период с 03.04.2011 по настоящее время считаются непрочитанными, если только они не отображаются в таблице прочитанного. Таблица чтения очищается каждый раз, когда я вхожу в систему.

Таким образом, ваша таблица прочитанных сообщений никогда не должна содержать более пары сотен записей для каждого участника.

person smdrager    schedule 05.04.2011

Вместо того, чтобы иметь новую строку для каждого пользователя post*, вы можете иметь поле в пользовательской таблице, которое содержит разделенную запятыми строку с идентификаторами сообщений, которые прочитал пользователь.

Очевидно, что пользователю не нужно знать, что есть непрочитанные сообщения двухлетней давности, поэтому вы отображаете «Новое сообщение» только для сообщений, сделанных за последние 24 часа, а не в строке, разделенной запятыми.

Вы также можете решить эту проблему с помощью переменной сеанса или файла cookie.

person OMGKurtNilsen    schedule 05.04.2011

Этот метод сохраняет последний доступ к 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;
?>

Примечание. Очевидно, что этот пример предназначен только для демонстрационных целей. Некоторую часть структуры и логики может потребоваться изменить при работе с реальной базой данных.

person drudge    schedule 05.04.2011

Phpbb2 реализовал это довольно просто. Он просто показывает вам все сообщения с момента вашего последнего входа в систему. Таким образом, вам не нужно хранить какую-либо информацию о том, что пользователь действительно видел или читал.

person Kdeveloper    schedule 07.04.2011