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

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

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

tbl_userReadPosts: user_id, post_id, read_timestamp

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Что-то, что не было предложено, было использование 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); ); 

Вы можете поменять файлы file_x_contents на вашу RDBMS – например:

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

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