Подтвердить что ты не робот

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

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

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

tbl_userReadPosts: user_id, post_id, read_timestamp

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

Что-то, что не было предложено, было использование Big Data для хранения такой информации, а именно NoSQL. Это эффективно сделано специально для обработки данных такого типа.

Я использую MongoDB, но вы можете найти приложение NoSQL в соответствии с вашими потребностями. http://nosql.findthebest.com/

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

Другое предложение состоит в том, что вы можете альтернативно хранить данные в виде "Метаданных", аналогично предложению csv, но предоставляя ему более гибкую и сохраняемую структуру, используя сериализацию для сжатия данных для вашего объекта для загрузки и нессериализации при запуске время. Таким образом, работает как сеанс, который не истекает, который связан с user_id, а не session_id, который может быть загружен по требованию и изолирован, как вам нравится. Например, когда страница форума загружается для определенного пользователя.

например:

(сухие кодированные примеры - настройте в соответствии с вашей собственной схемой)

<?php
/**
array(
    "form_id1" => array( "post_id1", "post_id2", ),
    "form_id2" => array( "post_id1", "post_id2", )
);
*/

$this->user->metadata = unserialize( file_get_contents( '/metadata/forums/' . $this->user->id ) );

if( !isset($this->user->metadata[$this->forum->id]) ){
    $this->user->metadata[$this->forum-id] = array();
}
if(!in_array($this->post->id, $this->user->metadata[$this->forum->id]) ){
   $this->user->metadata[$this->forum-id][] = $this->post->id;
}
file_put_contents( '/metadata/forums/' . $this->user->id, serialize( $this->metadata); );

Вы можете поменять файловую систему с файлами____контента на свои РСУБД - например:

<?php
$getMetadata = "SELECT forums FROM user_metadata WHERE user_id = $this->user->id";
$dbrs = mysqli_query( $getMetadata );
$this->user->metadata = unserialize( $dbrs['forums'] );
$dbrs->close();

$metadata = serialize($this->user->metadata);
$saveMetadata = "UPDATE user_metadata SET forums = '$metadata' WHERE user_id = '$this->user->id'";
mysqli_query( $saveMetadata );

Вы также можете выполнять другие действия, такие как поиск через регулярное выражение, дополнительно отделить его (тему, категорию и т.д.) или изменить метод, основанный на пользователях, читающих сообщения на форуме (forum- > post- > playbackby) вместо сообщений на форуме пользователь читает (user- > metadata- > forums). Особенно, если у вас уже есть рабочий "Total Views", но это будет сложнее получить сообщения, которые/не были прочитаны конкретным пользователем, в то время как обратное истинно с другим методом или даже использует оба метода в сочетании.