__('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 = "

" . $this->_('No active sessions') . "

"; } $query->closeCursor(); $out = "

" . " " . sprintf($this->_n('%d active session', '%d active sessions', $numRows), $numRows) . "

" . $tableOut; if($config->ajax) return $out; /** @var InputfieldMarkup $markup */ $markup = $modules->get('InputfieldMarkup'); $markup->value = "
$out
"; $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(); } }