2

我想制作一个PHP if 条件代码,用于检查用户阅读文章的最后 10 篇文章或 10 分钟是否已经过去。

例如

用户打开id = 235的页面(此 id 值在 url localhost/article/235 中)

并且这个id值将保存在会话中,带有当前时间戳,可能还有他的 IP 地址

然后他读了另一篇文章,同样的事情也会发生。

我需要记住点击的东西再点击十次,然后只为第一行重置。例如,在第 10 次点击之后,id 和时间戳不会变成第 11 行,而是会替换列表中的第 1 行。

CodeIgniter 中的 php 条件将检查这些值并更新文章表和列计数器中的文章命中计数器值,如下所示:

   $this->db->where('id', $id);
   $this->db->set('counter', 'counter+1', FALSE);
   $this->db->update('articles');

但在调用此代码之前,我需要从会话中进行此检查吗?

怎么做?

我认为在会话中存储例如 10 个条目以及每个用户的时间戳就足够了。

只是不要在会话中保存相同的页面两次。

并且条件将使用保存的时间戳检查当前时间戳,如果超过例如 10 分钟或者用户已经阅读/点击了另外 10 篇文章,它将允许更新计数器 php 代码。

我不需要这个防弹。只是使用浏览器的刷新按钮禁用增量。

因此,如果他想增加计数器,他将需要等待十分钟或再阅读 10 篇文章;)

4

5 回答 5

4

你绝对应该去参加会议。它可以节省您的带宽消耗,并且更容易处理。当然,除非您需要客户端的数据,根据您的解释,我认为您不需要。假设您参加了会议,您所要做的就是将您拥有的数据存储在一个数组中。下面的代码应该做到这一点:

$aClicks = $this->session
                ->userdata('article_clicks');

// Initialize the array, if it's not already initialized
if ($aClicks == false) {
    $aClicks = array();
}

// Now, we clean our array for the articles that have been clicked longer than
// 10 minutes ago.
$aClicks = array_filter(
    $aClicks,
    function($click) {
        return (time() - $click['time']) < 600; // Less than 10 minutes elapsed
    }
);

// We check if the article clicked is already in the list
$found = false;
foreach ($aClicks as $click) {
    if ($click['article'] === $id) { // Assuming $id holds the article id
        $found = true;
        break;
    }
}

// If it's not, we add it
if (!$found) {
    $aClicks[] = array(
        'article' => $id, // Assuming $id holds the article id
        'time'    => time()
    );
}

// Store the clicks back to the session
$this->session
     ->set_userdata('article_clicks', $aClicks);


// If we meet all conditions
if (count($aClicks) < 10) {
    // Do something
}
于 2012-12-18T19:57:10.767 回答
2

我假设 $clicks 是一个包含最多十篇访问文章的数组。id 用作键,时间戳用作值。$id 是新文章的id。

$clicks = $this->session->userdata('article_clicks');

//default value
$clicks = ($clicks)? $clicks : array();

//could be loaded from config
$maxItemCount = 10;
$timwToLive= 600;

//helpers
$time = time();
$deadline = $time - $timeToLive;

//add if not in list
if(! isset($clicks[$id]) ){
  $clicks[$id] = $time;
}
//remove old values
$clicks = array_filter($clicks, function($value){ $value >= $deadline;});

//sort newest to oldest
arsort($clicks);

//limit items, oldest will be removed first because we sorted the array
$clicks = array_slice($clicks, 0, $maxItemCount);

//save to session
$this->session->>set_userdata('article_clicks',$clicks)

用法:

//print how mch time has passed since the last visit
if(isset($clicks[$id]){
  echo "visited ".($time-$clicks[$id]). "seconds ago." ;
} else {
  echo "first visit";
}

编辑:你必须使用 arsort 而不是 rsort 否则钥匙会丢失,对不起

于 2012-12-22T14:42:31.023 回答
1

根据 Raphael_ 代码和您的问题,您可以尝试以下操作:

    <?php
            $aClicks = $this->session
                ->userdata('article_clicks');
        $nextId = $this->session->userdata('nextId');
        // Initialize the array, if it's not already initialized
        if ($aClicks == false) {
            $aClicks = array();
            $nextId = 0;
        }
        // Now, we clean our array for the articles that have been clicked longer than
       // 10 minutes ago.
        $aClicks = array_filter($aClicks, function($click) {
                    return (time() - $click['time']) < 600; // Less than 10 minutes elapsed
                }
        );
// We check if the article clicked is already in the list
        $found = false;
        foreach ($aClicks as $click) {
            if ($click['article'] === $id) { // Assuming $id holds the article id
                $found = true;
                break;
            }
        }
// If it's not, we add it
        if (!$found) {
            $aClicks[$nextId] = array(
                'article' => $id, // Assuming $id holds the article id
                'time' => time()
            );
            $nextId++;
            $this->session->set_userdata('nextId', $nextId);
        }
        $this->session->set_userdata('article_clicks', $aClicks);
        if (count($aClicks) > 10 && $nextId > 9) {
            $this->session->set_userdata('nextId', 0);
            echo "OK!";

        }
    ?>
于 2012-12-21T09:19:47.993 回答
1

我希望我正确理解了您的需求。

用法:

$this->load->library('click');
$this->click->add($id, time());  

类 API 很简单,代码加了注释。您还可以检查一个项目expired(),如果exists()您可以get()节省时间。

请记住:

  • 每个项目将在 10 分钟后过期(请参阅$ttl
  • 会话中仅保存 10 个项目(请参阅$max_entries

    class Click
    {
        /**
         * CI instance
         * @var object
         */
        private $CI;
    
        /**
         * Click data holder
         * @var array
         */
        protected $clicks = array();
    
        /**
         * Time until an entry will expire
         * @var int
         */
        protected $ttl = 600;
    
        /**
         * How much entries do we store ?
         * @var int
         */
        protected $max_entries = 10;
    
        // -------------------------------------------------------------------------
    
        public function __construct()
        {
            $this->CI =& get_instance();
    
            if (!class_exists('CI_Session')) {
                $this->CI->load->library('session');
            }
    
            // load existing data from user's session
            $this->fetch();
        }
    
        // -------------------------------------------------------------------------
    
        /**
         * Add a new page
         *
         * @access  public
         * @param   int     $id     Page ID
         * @param   int     $time   Added time (optional)
         * @return  bool
         */
        public function add($id, $time = null)
        {
            // If page ID does not exist and limit has been reached, stop here
            if (!$this->exist($id) AND (count($this->clicks) == $this->max_entries)) {
                return false;
            }
    
            $time = !is_null($time) ? $time : time();
    
            if ($this->expired($id)) {
                $this->clicks[$id] = $time;
                return true;
            }
    
            return false;
        }
    
        /**
         * Get specified page ID data
         *
         * @access  public
         * @param   int     $id     Page ID
         * @return  int|bool        Added time or `false` on error
         */
        public function get($id)
        {
            return ($this->exist($id)) ? $this->clicks[$id] : false;
        }
    
        /**
         * Check if specified page ID exists
         *
         * @access  public
         * @param   int     $id Page ID
         * @return  bool
         */
        public function exist($id)
        {
            return isset($this->clicks[$id]);
        }
    
        /**
         * Check if specified page ID expired
         *
         * @access  public
         * @param   int     $id Page ID
         * @return  bool
         */
        public function expired($id)
        {
            // id does not exist, return `true` so it can added
            if (!$this->exist($id)) {
                return true;
            }
    
            return ((time() - $this->clicks[$id]) >= $this->ttl) ? true : false;
        }
    
        /**
         * Store current clicks data in session
         *
         * @access  public
         * @return  object  Click
         */
        public function save()
        {
            $this->CI->session->set_userdata('article_clicks', serialize($this->clicks));
    
            return $this;
        }
    
        /**
         * Load data from user's session
         *
         * @access  public
         * @return  object  Click
         */
        public function fetch()
        {
            if ($data = $this->CI->session->userdata('article_clicks')) {
                $this->clicks = unserialize($data);
            }
    
            return $this;
        }
    
        public function __destruct()
        {
            $this->save();
        }
    }
    
于 2012-12-26T15:28:07.660 回答
1

您可以轻松地将其包装到它自己的类中,该类将信息序列化为字符串并能够操作数据,例如添加另一个值,同时注意最多包含十个元素。

一个潜在的用法可能看起来像,让我们假设最后一个cookie在开始时包含 256:

echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(10), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(20), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(30), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(40), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(50), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(60), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(70), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(80), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(90), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(100), "\n";

和输出(演示):

10,256
20,10,256
30,20,10,256
40,30,20,10,256
50,40,30,20,10,256
60,50,40,30,20,10,256
70,60,50,40,30,20,10,256
80,70,60,50,40,30,20,10,256
90,80,70,60,50,40,30,20,10,256
100,90,80,70,60,50,40,30,20,10

一个粗略的实现:

class StringQueue implements Countable
{
    private $size = 10;
    private $separator = ',';
    private $values;

    public function __construct($string) {
        $this->values = $this->parseString($string);
    }

    private function parseString($string) {
        $values = explode($this->separator, $string, $this->size + 1);
        if (isset($values[$this->size])) {
            unset($values[$this->size]);
        }
        return $values;
    }

    public function add($value) {
        $this->values = $this->parseString($value . $this->separator . $this);
        return $this;
    }

    public function __toString() {
        return implode(',', $this->values);
    }

    public function count() {
        return count($this->values);
    }
}

这只是一些基本的字符串操作,这里用implodeand explode

于 2012-12-27T12:47:08.823 回答