В форуме задали вопрос, как средствами Битрикса определить, находится ли зарегистрированный посетитель сайта он-лайн и при этом контролировать его нахождение на сайте, даже если им не выполняются хиты в течение всей активности сессии. [spoiler]
Задача, в принципе не сложная, но с одним нюансом, о нем в конце.
Начнем с простого. Для того чтобы определить активность пользователя нужно сначала эту активность где-то зарегистрировать. К счастью в БУСе есть нужный нам метод, но его нет в документации (надеюсь, что пока): CUser::SetLastActivityDate(). Этот метод сохраняет текущую серверную дату и время в записи пользователя (поле LAST_ACTIVITY_DATE). Вызывается в ядре, но только если установлен модуль социальных сетей, поэтому чтобы выполнить задачу и без установленного модуля соцсетей, нужно в файле /bitrix/php_interface/init.php добавить код:
// регистрируем последнюю активность пользователя, если модуль соцсетей не установлен
if(!IsModuleInstalled('socialnetwork')) {
AddEventHandler('main', 'OnBeforeProlog', 'CustomSetLastActivityDate');
function CustomSetLastActivityDate() {
if($GLOBALS['USER']->IsAuthorized()) {
CUser::SetLastActivityDate($GLOBALS['USER']->GetID());
}
}
}
Все, теперь у нас всегда на каждом хите авторизованного пользователя будет производиться запись даты и времени.
Определить, находится ли пользователь на сайте, можно методом CUser::IsOnLine() Т.к. полного описания для него пока нет, то прокомментирую здесь: первым параметром передается ID пользователя, вторым параметром задается интервал времени в секундах, за которое считается, что пользователь находится на сайте. Второй параметр необязателен, по умолчанию равен двум минутам. Метод возвращает булево значение.
if(CUser::IsOnLine($iUserId, $iIntervalSec)) {
// пользователь на сайте, что-то делаем, показываем
}
Одна часть готова, перейдем к той части задачи, где необходимо добавить возможность контроля активности пользователя, когда он не делает хитов. Например, просто открыто окно и просматривается видеоролик.
Я решил сделать это через ajax, т.к. серверная часть ajax-запроса будет элементарной:
Да, тут достаточно только одного подключения пролога, т.к. регистрация активности пользователя у нас выполняется на событии OnBeforeProlog. Этот код сохраняем в файле /ajax_user_activity_update.php (в корне сайта).
Теперь реализуем клиентскую часть ajax. Клиентская часть должна с требуемым интервалом запрашивать страницу /ajax_user_activity_update.php, отдавая которую на стороне сервера и будет производиться регистрация активности пользователя. Т.е. по сути, нужно делать за пользователя "холостые" хиты. Но вот здесь и кроется тот самый нюанс. У пользователя может быть одновременно открыто несколько окон сайта и это нужно учесть, чтобы все эти окна не долбили сервер "холостыми" хитами больше чем нам нужно, а нужно нам, чтобы только одно окно посылало запросы. Разобраться с этой проблемой нам помогут печеньки (cookies) При каждом запросе мы будем сохранять в куках метку времени отправки, а перед выполнением запроса эту метку будем проверять, если последний запрос выполнялся слишком давно или время последнего запроса намного больше текущего (куки изменили вручную, например), то отправим запрос, иначе пропустим его отправку.
Ну и сам код клиентской ajax-части (его необходимо разместить в футере шаблона сайта, как можно ближе к закрывающему тегу body или вынести в отдельный файл и подключить в head-области):
<?
// подключать скрипт будем только залогиненным пользователям
if($GLOBALS['USER']->isAuthorized()) {
?><script type="text/javascript"><!--
// <этот кусок можно вынести в отдельный файл>
var CActivityUpdate = function(sActivityUrl, iActivityTime) {
var _this = this;
this.sActivityUrl = sActivityUrl;
this.iActivityTime = iActivityTime;
// определение ajax-функции
if(typeof(window['jQuery']['get']) == 'function') {
// jQuery
this.funcAjax = jQuery.get;
} else if(typeof(window['BX']['ajax']['get']) == 'function') {
// Bitrix
this.funcAjax = BX.ajax.get;
}
// получение значения cookie
this.getCookie = function(name) {
var cookie = " " + document.cookie;
var search = " " + name + "=";
var setStr = null;
var offset = 0;
var end = 0;
if(cookie.length > 0) {
offset = cookie.indexOf(search);
if(offset != -1) {
offset += search.length;
end = cookie.indexOf(";", offset)
if(end == -1) {
end = cookie.length;
}
setStr = unescape(cookie.substring(offset, end));
}
}
return(setStr);
};
// установка значения cookie
this.setCookie = function(sName, sValue, sExpires, sPath, sDomain, bSecure) {
var sCookie = '';
sCookie += sName + '=' + escape(sValue);
sCookie += sExpires ? '; expires=' + sExpires : '';
sCookie += sPath ? '; path=' + sPath : '';
sCookie += sDomain ? '; domain=' + sDomain : '';
sCookie += bSecure ? '; secure' : '';
document.cookie = sCookie;
};
// выполнение "холостого" хита для обновления даты активности пользователя
this.updateActivity = function() {
var funcAjax = _this.funcAjax;
if(funcAjax && typeof(funcAjax) == 'function') {
var iLastActivity = _this.getCookie('BX_activity');
iLastActivity = iLastActivity ? parseInt(iLastActivity) : 0;
var oDate = new Date();
var iCurTime = oDate.getTime();
var bNeedUpdate = iCurTime >= (iLastActivity + _this.iActivityTime) || iCurTime < (iLastActivity - _this.iActivityTime);
if(bNeedUpdate) {
var sExpires = false; //'Mon, 01-Jan-2018 00:00:00 GMT'
_this.setCookie('BX_activity', iCurTime, sExpires, '/');
funcAjax(_this.sActivityUrl);
}
}
};
// запуск обновления даты активности пользователя с заданным интервалом
this.startUpdating = function() {
if(_this.funcAjax && typeof(_this.funcAjax) == 'function') {
setInterval(_this.updateActivity, _this.iActivityTime);
}
};
};
// </этот кусок можно вынести в отдельный файл>
// запрашиваемая страница - /ajax_user_activity_update.php
// интервал обновления - две минуты (в миллисекундах)
var appActivityUpdate = new CActivityUpdate('/ajax_user_activity_update.php', (1000*60*2));
appActivityUpdate.startUpdating();
//--></script><?
}
?>
Для работы js-скрипта необходима подключенная библиотека jQuery или родная БУСовская библиотека (новая).
Поскольку в настройках главного модуля имеется флаг "Продлевать сессию при активности посетителя в окне браузера", то вторая часть становится излишней.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».