【问题标题】:View counter - how to only count up once per user? - PHP / Laravel 4查看计数器 - 如何每个用户只计数一次? - PHP / Laravel 4
【发布时间】:2013-07-04 20:59:13
【问题描述】:

我正在为博客计划一个用 PHP 编码的视图计数。计数器的目的是指示阅读博客文章的频率,例如 StackOverflow 在问题页面上显示“查看了 n 次”。

首先,我想将计数器数据存储在文件中,但通过研究,我改变了主意,将 MySQL 与多个 InnoDB 表一起使用,因为这些表的执行速度比 HDD 查找快,从长远来看更不费力,并且原生提供有用的功能。

我遇到的问题是如何只计算每个用户一次?

限制 IP 不是解决方案,因为动态 IP 和网络大多有一个 IP 与所有连接的设备(例如学校、办公室、公共接入点)共享连接。

编辑:

fideloper’s answer 启发,我正在研究基于会话的解决方案。

我已经在为会话使用单独的数据库表,因此我将按照建议将其合并到解决方案中。

这是我目前所得到的(使用Laravel 4Eloquent ORM):

SQL 表设置:

-- 
-- Sessions Table
-- 
CREATE TABLE sessions (
    id VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
    payload TEXT NOT NULL COLLATE 'utf8_unicode_ci',
    last_activity INT(11) NOT NULL,

    UNIQUE INDEX sessions_id_unique (id)
) COLLATE='utf8_unicode_ci' ENGINE=InnoDB;

-- 
-- Views Table
-- 
CREATE TABLE post_views (
    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    post_id INT(11) UNSIGNED NOT NULL,
    sess_id VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
    viewed_at TIMESTAMP NULL DEFAULT NULL,

    PRIMARY KEY (id)
) COLLATE='utf8_unicode_ci' ENGINE=InnoDB;

-- 
-- Posts Table
-- 
CREATE TABLE posts (
    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    user_id INT(11) UNSIGNED NOT NULL,
    title VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
    excerpt TEXT NOT NULL COLLATE 'utf8_unicode_ci',
    slug VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
    content LONGTEXT NOT NULL COLLATE 'utf8_unicode_ci',
    ...

    views INT(10) UNSIGNED NOT NULL DEFAULT '0',

    PRIMARY KEY (id)
) COLLATE='utf8_unicode_ci' ENGINE=InnoDB;


PHP Views Counter 类:

<?php namespace Services\Posts;
/**
 * Blog Post Views Counter
 *
 * Using Laravel 4 with Eloquent ORM
 */

class ViewsCounter {

    public $post_id;

    /**
     * Sets the post id
     * 
     * @param  int $id
     * @return void
     */
    public function setPostID($id)
    {
        $this->post_id = $id;
    }

    /**
     * Handles the view count
     * 
     * @return bool  True or false on failure
     */
    public function countView()
    {
        // Get the post data from the db
        try
        {
            $post = \Post::findOrFail($this->post_id);
        }
        catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e)
        {
            return false;
        }

        // Get the current session id
        $sess_id = session_id();

        // Check if this view was already counted by 
        // looking up the session id in the views table
        $post_views = \PostViews::where('sess_id', '=', $sess_id)
                            ->where('post_id', '=', $this->post_id)
                            ->remember(10)
                            ->first();

        // The sess_id was not found so count the view
        if (empty($post_views))
        {
            $post_views->post_id = $this->post_id;
            $post_views->sess_id = $sess_id;
            $post_views->viewed_at = date('Y-m-d H:i:s');
            $post_views->save();

            // A cronjob is run every 24 hours to count the views per 
            // post and update the count values in the posts table.
            // The post_views table will be truncated when done.
        }

        return true;
    }

}

建议表示赞赏。

【问题讨论】:

  • 只是你试过什么?!简单来说就是显示一些代码!
  • 从数据库中获取当前计数,将其加1并将增加的值保存回数据库。
  • found quite a lot. But unfortunately the data is ancient。你有知识。 I'm using the Laravel Framework version 4你有技术....把代码拿来适应Laravel?
  • 我知道我的问题需要澄清!

标签: php mysql laravel laravel-4


【解决方案1】:

每位用户计算 +1 观看次数的问题是一个有趣的问题,因为您需要将会话考虑在内。

您确实需要对每个会话 ID 进行 +1 计数(因为它会为每个用户重新生成,但更有可能让您每次访问每个用户 +1 视图计数...取决于您的代码)。请注意,这意味着在新会话中再次访问该网站的用户将再次获得查看计数。

如果您需要跟踪会话 ID,您可能需要执行以下操作:

  1. 为每个视图添加一个新的数据库行(相对于增加单个值)。通过这种方式,您可以跟踪会话 ID 以及查看次数(这也意味着最终的表格很大!)
  2. 仅在未找到会话 ID 时添加新行(如果找到,则用户在此次访问中的查看次数已 +1)。
  3. 对于一些可扩展性:添加第二个表来跟踪每个视图的访问次数。使用 CRON 或类似工具定期更新此内容。然后,您始终可以写入一个表(针对写入优化表)并从另一个表读取(针对读取进行优化)。
  4. 为了获得额外的可扩展性,请使用第二个表来计算每 24 小时的查看次数。然后您可以从视图计数表中删除视图。这样一来,您的观看次数表就不会被填满,而是节省了每 24 小时的总观看次数。

您也可以随意缩短这 24 小时的时间。您可能(将会)在更新查看次数时计算一些额外的查看次数,并且要与之比较的会话 ID 被删除。

希望能激发您的灵感。

【讨论】:

  • 这是我一直在寻找的答案!非常感谢@fideloper。你肯定引发了一些想法:P BTW。我以前曾使用您的一些博客文章作为自己编码实现的灵感。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-19
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多