XF 2.0 Increase Online status timeout

Hi guys, first post so go gentle, I've ported over from VB and am just having a little trouble increasing this option above the limited 60 minutes.

I found online how you do it on older version but not on ZF2?

Any help appreciated.

Matt
 
If you want to do this without editing any code you can do it via the inspect console.

 
@imno007

PHP:
class SessionActivity extends Repository
{
    public function getOnlineCounts($onlineCutOff = null)
    {
        if ($onlineCutOff === null)
        {
            $onlineCutOff = \XF::$time - $this->options()->onlineStatusTimeout * 43200;
        }

        return $this->db()->fetchRow("
            SELECT
                SUM(IF(user_id >= 0 AND robot_key = '', 1, 0)) AS total,
                SUM(IF(user_id > 0, 1, 0)) AS members,
                SUM(IF(user_id = 0 AND robot_key = '', 1, 0)) AS members
            FROM xf_session_activity
            WHERE view_date >= ?
        ", $onlineCutOff);
    }

I set as 43200 minute at above.

PHP:
public function pruneExpiredActivityRecords($cutOff = null)
    {
        if ($cutOff === null)
        {
            $expiration = $this->getDefaultSessionActivityExpiration();
            if (!$expiration)
            {
                return;
            }

            $cutOff = \XF::$time - $expiration;
        }

        $this->db()->delete('xf_session_activity', 'view_date < ?', $cutOff);
    }

How should I update here?


You'll have to update the value in the final line:


public function pruneExpiredActivityRecords($cutOff = null)
{
if ($cutOff === null)
{
$cutOff = \XF::$time - 86400; (seconds to hours= 24 hours)
 
For whatever reason, you still can't do this with XF's default settings. You'll have to edit src/XF/Repository/SessionActivity.php, look for this line and change the value there:

$cutOff = \XF::$time - 3600;

You might also have to put the forum in dev mode and edit the value in your admin - I can't remember offhand if this is really necessary, but just in case. (Or maybe you could just do that and not actually have to edit the sessions file.) You'll get an error every time XF does a file health check, but you can ignore it.

I changed this line. What do I have to do now? Just activate dev mode? How do I do this exactly?

Thanks in advance.

Best regards,
Chris
 
Ok, I already figured it out myself and the changes worked.

Add the following line to config.php:

Code:
$config['development']['enabled'] = true;
Should I remove/delete the line with Dev mode activated after changing the online-status-session?
 
I changed this line. What do I have to do now? Just activate dev mode? How do I do this exactly?

Thanks in advance.

Best regards,
Chris

Ok, I already figured it out myself and the changes worked.

Add the following line to config.php:

Code:
$config['development']['enabled'] = true;
Should I remove/delete the line with Dev mode activated after changing the online-status-session?
Since I made the changes, I have received the following error message in the ACP:

Code:
Check completed on 4,939 files. The files listed below have contents different from those originally downloaded.

If you have edited these files yourself, you may ignore this message, otherwise you should investigate further as this may be evidence of corrupted or altered files.
XenForo
src/XF/Repository/SessionActivity.php Unexpected contents

What could that be about?

Best regards,
Chris
 
~~~ contents different from those originally downloaded.
If you have edited these files yourself, you may ignore this message, otherwise you should investigate further as this may be evidence of corrupted or altered files.
XenForo
src/XF/Repository/SessionActivity.php Unexpected contents
You changed a core XF file. It's an alert.
 
Hi Brogan...oops...I mean Paul B! ;)

That means this error message will remain as long as I keep this change...but it won't have any negative impact?!

OK! You Got Me! I am convinced and, above all, can I be reassured? ^^

Best regards,
Chris
 
I know. That's what this thread is about and many others have done it before me.

Just apparently without getting this error?!

Maybe this has something to do with the latest version?
If it really annoys you the hash must be regenerated.
 
I guess we have to make the same changes at SessionActivityRepository.php for XF2.3. However, the online members widget is disappearing once we uploaded the amended SessionActivityRepository.php

Is there anything else we should do for 2.3?
 
I guess we have to make the same changes at SessionActivityRepository.php for XF2.3. However, the online members widget is disappearing once we uploaded the amended SessionActivityRepository.php

Is there anything else we should do for 2.3?

SUM(IF(user_id >= 0 AND robot_key = '', 1, 0)) AS guests

This line should remain the same. If we change as members, then the online members widget will disappear.
 
SUM(IF(user_id >= 0 AND robot_key = '', 1, 0)) AS guests

This line should remain the same. If we change as members, then the online members widget will disappear.
Yeah, I think I experienced that as well at one point, while experimenting with this and that. I just wanted to get the guests count set to zero, but couldn't figure out at the time how to do it without it messing up the total member count, so ended up just leaving it alone. Better to have a bunch of bots as "guests," I guess. I'll eventually get back around to taking another look at it, but it's not the end of the world.
 
Last edited:
SUM(IF(user_id >= 0 AND robot_key = '', 1, 0)) AS guests

This line should remain the same. If we change as members, then the online members widget will disappear.

I finally cared enough to look at this again, and all you have to do is change the '1' to another '0' and you won't get a guest tally. I find it hard to believe that wasn't one of the first things I would have tried when I first edited it, but maybe I didn't get enough sleep that day or had a few drinks.:whistle:

Here's my entire edited "SessionActivityRepository.php" file for anyone interested in copying and pasting (edited for a 72 hour cut-off, so you will have to change those values if you want something else):

Code:
<?php

namespace XF\Repository;

use XF\Entity\SessionActivity;
use XF\Finder\SessionActivityFinder;
use XF\Mvc\Entity\Repository;
use XF\Util\Ip;

use function call_user_func, intval, is_array, is_scalar, strlen;

class SessionActivityRepository extends Repository
{
    public function getOnlineCounts($onlineCutOff = null)
    {
        if ($onlineCutOff === null)
        {
            $onlineCutOff = \XF::$time - $this->options()->onlineStatusTimeout * 4320;
        }

        return $this->db()->fetchRow("
            SELECT
                SUM(IF(user_id >= 1 AND robot_key = '', 1, 0)) AS total,
                SUM(IF(user_id > 0 AND robot_key = '', 1, 0)) AS members,
                SUM(IF(user_id = 0 AND robot_key = '', 0, 0)) AS guests
            FROM xf_session_activity
            WHERE view_date >= ?
        ", $onlineCutOff);
    }

    public function getOnlineUsersList($limit)
    {
        /** @var SessionActivityFinder $finder */
        $finder = $this->finder(SessionActivityFinder::class);
        $finder->restrictType('member')
            ->applyMemberVisibilityRestriction()
            ->activeOnly()
            ->with('User')
            ->order('view_date', 'DESC');

        if ($limit)
        {
            $finder->limit($limit);
        }

        return $finder->fetch()->pluckNamed('User', 'user_id');
    }

    public function getOnlineStaffList()
    {
        /** @var SessionActivityFinder $finder */
        $finder = $this->finder(SessionActivityFinder::class);
        $finder->restrictType('member')
            ->applyMemberVisibilityRestriction()
            ->activeOnly()
            ->with('User')
            ->where('User.is_staff', 1)
            ->order('view_date', 'DESC');

        return $finder->fetch()->pluckNamed('User', 'user_id');
    }

    public function getOnlineStatsBlockData($forceIncludeVisitor, $userLimit, $staffQuery = false)
    {
        $counts = $this->getOnlineCounts();
        $users = $this->getOnlineUsersList($userLimit)->toArray();

        if ($forceIncludeVisitor)
        {
            $visitor = \XF::visitor();
            if ($visitor->user_id && !isset($users[$visitor->user_id]))
            {
                $users = [$visitor->user_id => $visitor] + $users;
                $counts['members']++;
                $counts['total']++;
            }
        }

        // run extra query to show all online staff
        if ($staffQuery)
        {
            $users += $this->getOnlineStaffList()->toArray();
        }

        $counts['unseen'] = ($userLimit ? max($counts['members'] - $userLimit, 0) : 0);

        return [
            'counts' => $counts,
            'users' => $users,
        ];
    }

    public function isTypeRestrictionValid($type)
    {
        switch ($type)
        {
            case 'member':
            case 'guest':
            case 'robot':
            case '':
                return true;

            default:
                return false;
        }
    }

    public function findForOnlineList($typeLimit)
    {
        /** @var SessionActivityFinder $finder */
        $finder = $this->finder(SessionActivityFinder::class);
        $finder->activeOnly()
            ->restrictType($typeLimit)
            ->withFullUser()
            ->order('view_date', 'DESC');

        return $finder;
    }

    public function updateSessionActivity($userId, $ip, $controller, $action, array $params, $viewState, $robotKey)
    {
        $userId = intval($userId);
        $binaryIp = Ip::stringToBinary($ip);
        $uniqueKey = $userId ?: $binaryIp;

        // TODO: swallow errors if upgrade is pending
        // work-around MySQL locking issues (https://bugs.mysql.com/bug.php?id=98324)
        $optimizationEnabled = (bool) $this->app()->config('sessionActivityOptimized');
        $expiration = $this->getDefaultSessionActivityExpiration();

        if ($optimizationEnabled)
        {
            $viewDate = $this->db()->fetchOne(
                'SELECT view_date
                    FROM xf_session_activity
                    WHERE user_id = ? AND unique_key = ?',
                [$userId, $uniqueKey]
            );
        }
        else
        {
            // we'll replace the record either way, so avoid an extra query
            $viewDate = 0;
        }

        if ($viewDate === false)
        {
            // the record did not exist, insert ignore it in case it has been created
            $operation = 'INSERT IGNORE';
        }
        else if (!$optimizationEnabled || $viewDate <= \XF::$time - $expiration + 4320)
        {
            // optimization has been disabled, or the record was close to expiration
            // replace it in case it has been pruned
            $operation = 'REPLACE';
        }
        else if ($viewDate <= \XF::$time - 1)
        {
            // the record was not close to expiration, update it normally
            $operation = 'UPDATE';
        }
        else
        {
            // the record was already updated within the last second, skip updating
            return;
        }

        if ($operation === 'UPDATE')
        {
            $query = '-- XFDB=noForceAllWrite
                UPDATE xf_session_activity
                SET
                    ip = ?,
                    controller_name = ?,
                    controller_action = ?,
                    view_state = ?,
                    params = ?,
                    view_date = ?,
                    robot_key = ?
                WHERE user_id = ? AND unique_key = ?';
        }
        else
        {
            $query = "-- XFDB=noForceAllWrite
                {$operation} INTO xf_session_activity (
                    ip,
                    controller_name,
                    controller_action,
                    view_state,
                    params,
                    view_date,
                    robot_key,
                    user_id,
                    unique_key
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            ";
        }

        if ($userId)
        {
            $robotKey = '';
        }

        $logParams = [];
        foreach ($params AS $paramKey => $paramValue)
        {
            if (!strlen($paramKey) || !is_scalar($paramValue))
            {
                continue;
            }

            $logParams[] = "$paramKey=" . urlencode($paramValue);
        }
        $paramList = implode('&', $logParams);

        $controller = substr($controller, 0, 100);
        $action = substr($action, 0, 75);
        $paramList = substr($paramList, 0, 100);
        $robotKey = substr($robotKey, 0, 25);

        $this->db()->query($query, [
            $binaryIp,
            $controller,
            $action,
            $viewState,
            $paramList,
            \XF::$time,
            $robotKey,
            $userId,
            $uniqueKey,
        ]);
    }

    public function updateUserLastActivityFromSession()
    {
        $this->db()->query("
            UPDATE xf_user AS u
            INNER JOIN xf_session_activity AS a ON (a.user_id > 0 AND a.user_id = u.user_id)
            SET u.last_activity = a.view_date
        ");
    }

    public function pruneExpiredActivityRecords($cutOff = null)
    {
         if ($cutOff === null)
    {
        $cutOff = \XF::$time - 259200;
    }


        $this->db()->delete('xf_session_activity', 'view_date < ?', $cutOff);
    }

    public function getDefaultSessionActivityExpiration(): int
    {
        return $this->app()->config()['sessionActivityExpiration'];
    }

    public function clearUserActivity($userId, $ip)
    {
        $userId = intval($userId);
        $binaryIp = Ip::stringToBinary($ip);
        $uniqueKey = ($userId ?: $binaryIp);

        $this->db()->delete(
            'xf_session_activity',
            'user_id = ? AND unique_key = ?',
            [$userId, $uniqueKey]
        );
    }

    public function applyActivityDetails($activities)
    {
        if ($activities instanceof SessionActivity)
        {
            $activities = [$activities];
        }

        $controllers = [];
        foreach ($activities AS $key => $activity)
        {
            $controllers[$activity->controller_name][$key] = $activity;
        }

        foreach ($controllers AS $controller => $entries)
        {
            $controller = $this->app()->extension()->extendClass($controller);
            try
            {
                $valid = (
                    $controller
                    && class_exists($controller)
                    && is_callable([$controller, 'getActivityDetails'])
                );
            }
            catch (\Throwable $e)
            {
                // don't let a class load error (XFCP) error
                $valid = false;
            }

            if ($valid)
            {
                $controllerOutput = call_user_func([$controller, 'getActivityDetails'], $entries);
            }
            else
            {
                $controllerOutput = false;
            }

            if (is_array($controllerOutput))
            {
                foreach ($controllerOutput AS $key => $info)
                {
                    if (!isset($entries[$key]))
                    {
                        continue;
                    }

                    /** @var SessionActivity $activity */
                    $activity = $entries[$key];

                    if (is_array($info))
                    {
                        $activity->setItemDetails($info['description'], $info['title'], $info['url']);
                    }
                    else
                    {
                        $activity->setItemDetails($info);
                    }
                }
            }
            else
            {
                foreach ($entries AS $key => $activity)
                {
                    $activity->setItemDetails($controllerOutput);
                }
            }
        }
    }
}
 
Back
Top Bottom