179 lines
4.9 KiB
Text
179 lines
4.9 KiB
Text
|
<?php namespace ProcessWire;
|
||
|
|
||
|
/**
|
||
|
* ProcessWire Session Viewer
|
||
|
*
|
||
|
* This module accompanies installation of the SessionHandlerDB module
|
||
|
*
|
||
|
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer
|
||
|
* https://processwire.com
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
class ProcessSessionDB extends Process {
|
||
|
|
||
|
public static function getModuleInfo() {
|
||
|
return array(
|
||
|
'title' => __('Sessions', __FILE__), // getModuleInfo title
|
||
|
'summary' => __('Enables you to browse active database sessions.', __FILE__), // getModuleInfo summary
|
||
|
'version' => 5,
|
||
|
'permanent' => false,
|
||
|
'icon' => 'dashboard',
|
||
|
'requires' => array('SessionHandlerDB'),
|
||
|
'page' => array(
|
||
|
'name' => self::pageName,
|
||
|
'parent' => 'access',
|
||
|
'title' => 'Sessions',
|
||
|
));
|
||
|
}
|
||
|
|
||
|
const pageName = 'sessions-db';
|
||
|
|
||
|
/**
|
||
|
* Execute display of sessions
|
||
|
*
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
public function ___execute() {
|
||
|
|
||
|
// clean out any stray sessions that may have not yet hit the gc probability
|
||
|
// because we don't want them in the list that we display
|
||
|
|
||
|
$modules = $this->wire()->modules;
|
||
|
$config = $this->wire()->config;
|
||
|
$session = $this->wire()->session;
|
||
|
$database = $this->wire()->database;
|
||
|
$input = $this->wire()->input;
|
||
|
$pages = $this->wire()->pages;
|
||
|
$users = $this->wire()->users;
|
||
|
|
||
|
/** @var SessionHandlerDB $sessionHandlerDB */
|
||
|
$sessionHandlerDB = $this->modules->get('SessionHandlerDB');
|
||
|
$sessionHandlerDB->gc($config->sessionExpireSeconds);
|
||
|
|
||
|
$useIP = $sessionHandlerDB->useIP;
|
||
|
$useUA = $sessionHandlerDB->useUA;
|
||
|
|
||
|
$mins = (int) $input->post('mins');
|
||
|
if(!$mins) $mins = (int) $session->get('ProcessSessionDB_mins');
|
||
|
if(!$mins) $mins = 5;
|
||
|
$session->set('ProcessSessionDB_mins', $mins);
|
||
|
|
||
|
/** @var InputfieldForm $form */
|
||
|
$form = $modules->get('InputfieldForm');
|
||
|
|
||
|
/** @var InputfieldInteger $field */
|
||
|
$field = $modules->get('InputfieldInteger');
|
||
|
$field->attr('name', 'mins');
|
||
|
$field->attr('value', $mins);
|
||
|
$field->label = sprintf($this->_n('Sessions active in last minute', 'Sessions active in last %d minutes', $mins), $mins);
|
||
|
$field->description = $this->_('Number of minutes');
|
||
|
$field->collapsed = Inputfield::collapsedYes;
|
||
|
$form->add($field);
|
||
|
|
||
|
$pagePaths = array();
|
||
|
$userNames = array();
|
||
|
$table = SessionHandlerDB::dbTableName;
|
||
|
$limit = 500;
|
||
|
$seconds = $mins * 60;
|
||
|
|
||
|
$sql = "SELECT user_id, pages_id, ip, ua, UNIX_TIMESTAMP(ts) " .
|
||
|
"FROM `$table` " .
|
||
|
"WHERE ts > DATE_SUB(NOW(), INTERVAL $seconds SECOND) " .
|
||
|
"ORDER BY ts DESC LIMIT $limit";
|
||
|
|
||
|
$query = $database->prepare($sql);
|
||
|
$query->execute();
|
||
|
$numRows = $query->rowCount();
|
||
|
|
||
|
if($numRows) {
|
||
|
if($numRows == $limit) {
|
||
|
// if more than 500, get an accurate count
|
||
|
$numRows = $sessionHandlerDB->getNumSessions($mins * 60);
|
||
|
}
|
||
|
|
||
|
/** @var MarkupAdminDataTable $table */
|
||
|
$table = $modules->get('MarkupAdminDataTable');
|
||
|
$table->setSortable(false);
|
||
|
$header = array(
|
||
|
$this->_('Time'),
|
||
|
$this->_('User'),
|
||
|
$this->_('Page'),
|
||
|
);
|
||
|
if($useIP) $header[] = $this->_('IP Addr');
|
||
|
if($useUA) $header[] = $this->_('User Agent');
|
||
|
$table->headerRow($header);
|
||
|
|
||
|
// for first iteration
|
||
|
$row = $query->fetch(\PDO::FETCH_NUM);
|
||
|
|
||
|
while($row) {
|
||
|
|
||
|
list($user_id, $pages_id, $ip, $ua, $ts) = $row;
|
||
|
|
||
|
$pages_id = (int) $pages_id;
|
||
|
$user_id = (int) $user_id;
|
||
|
|
||
|
if(isset($userNames[$user_id])) {
|
||
|
$userName = $userNames[$user_id];
|
||
|
|
||
|
} else {
|
||
|
$user = $users->get($user_id);
|
||
|
$userName = $user && $user->id ? $user->name : '.';
|
||
|
if($userName !== '.') $userNames[$user_id] = $userName;
|
||
|
}
|
||
|
|
||
|
if(isset($pagePaths[$pages_id])) {
|
||
|
$pagePath = $pagePaths[$pages_id];
|
||
|
|
||
|
} else {
|
||
|
$page = $pages->get($pages_id);
|
||
|
$pagePath = $page->id ? $page->path : '.';
|
||
|
if($pagePath !== '.') $pagePaths[$pages_id] = $pagePath;
|
||
|
}
|
||
|
|
||
|
$tr = array(wireRelativeTimeStr($ts), $userName, $pagePath);
|
||
|
if($useIP) $tr[] = long2ip($ip);
|
||
|
if($useUA) $tr[] = strip_tags($ua); // note MarkupAdminDataTable already entity encodes all output
|
||
|
|
||
|
$table->row($tr);
|
||
|
|
||
|
// for next iteration
|
||
|
$row = $query->fetch(\PDO::FETCH_NUM);
|
||
|
}
|
||
|
|
||
|
$tableOut = $table->render();
|
||
|
|
||
|
} else {
|
||
|
$tableOut = "<p class='description'>" . $this->_('No active sessions') . "</p>";
|
||
|
}
|
||
|
|
||
|
$query->closeCursor();
|
||
|
|
||
|
$out =
|
||
|
"<h2>" .
|
||
|
"<i id='SessionListIcon' class='fa fa-2x fa-fw fa-dashboard ui-priority-secondary'></i> " .
|
||
|
sprintf($this->_n('%d active session', '%d active sessions', $numRows), $numRows) .
|
||
|
"</h2>" .
|
||
|
$tableOut;
|
||
|
|
||
|
if($config->ajax) return $out;
|
||
|
|
||
|
/** @var InputfieldMarkup $markup */
|
||
|
$markup = $modules->get('InputfieldMarkup');
|
||
|
$markup->value = "<div id='SessionList'>$out</div>";
|
||
|
$form->add($markup);
|
||
|
|
||
|
/** @var InputfieldSubmit $submit */
|
||
|
$submit = $modules->get('InputfieldSubmit');
|
||
|
$submit->attr('value', $this->_('Refresh'));
|
||
|
$submit->icon = 'refresh';
|
||
|
$submit->attr('id+name', 'submit_session');
|
||
|
$submit->showInHeader();
|
||
|
$form->add($submit);
|
||
|
|
||
|
return $form->render();
|
||
|
}
|
||
|
}
|