Subversion Repositories web.creative

Rev

Blame | Last modification | View Log | Download

<?php namespace ProcessWire;

/**
 * ProcessWire Session Viewer
 *
 * This module accompanies installation of the SessionHandlerDB module
 *
 * ProcessWire 3.x, Copyright 2020 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' => 4, 
      '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
    
    /** @var SessionHandlerDB $sessionHandlerDB */
    $sessionHandlerDB = $this->modules->get('SessionHandlerDB'); 
    $sessionHandlerDB->gc($this->wire('config')->sessionExpireSeconds); 
    
    $useIP = $sessionHandlerDB->useIP; 
    $useUA = $sessionHandlerDB->useUA; 

    $mins = (int) $this->input->post('mins');
    if(!$mins) $mins = (int) $this->session->get('ProcessSessionDB_mins'); 
    if(!$mins) $mins = 5; 
    $this->session->set('ProcessSessionDB_mins', $mins);

    /** @var InputfieldForm $form */
    $form = $this->wire('modules')->get('InputfieldForm');
  
    /** @var InputfieldInteger $field */
    $field = $this->wire('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;
    $database = $this->wire('database');
    $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);     
      }

      $table = $this->wire('modules')->get('MarkupAdminDataTable');
      $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 = $this->wire('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 = $this->wire('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($this->wire('config')->ajax) return $out;

    /** @var InputfieldMarkup $markup */
    $markup = $this->wire('modules')->get('InputfieldMarkup');
    $markup->value = "<div id='SessionList'>$out</div>";
    $form->add($markup);

    /** @var InputfieldSubmit $submit */
    $submit = $this->wire('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();
  } 
}