Extension:UserPageViewTracker

From MediaWiki.org

Jump to: navigation, search

               

Manual on MediaWiki Extensions
List of MediaWiki Extensions
Crystal Clear action run.png
UserPageViewTracker

Release status: beta

Userpageviewtracker.png
Implementation  Page action, Special page, Database
Description Tracks user page hits
Author(s)  Kimon Andreou (KimonTalk)
Last Version  1.0.0.1 (2007-11-07)
MediaWiki  Tested on 1.10
License GPL
Download See below

check usage (experimental)

Contents

[edit] Description

This extension allows users who have the right "userpagehits" to track usage of the site. It will display the pages visited per users, # of visits, and last visit.

Every time a user visits a page, a table in the database gets updated with the hit count for the user on that page. In other words, for every page & user combination, there is a hitcount.

The special page displays this information and allows the filtering of users to either include only or exclude. A list of users can be provided by using the pipe symbol (|) as a delimiter.

[edit] Installation

  1. Execute the SQL scripts below to create the table and view needed by the extension. Make sure to set the appropriate prefix.
  2. Copy & paste the PHP code below into a new file called "UserPageViewTracker.php" located in your extensions directory.
  3. Add the lines to the end of your LocalSettings.php file:
require_once( "$IP/extensions/UserPageViewTracker.php" );
$wgGroupPermissions['userpagehits']['userpagehits'] = true;
$wgGroupPermissions['sysop'       ]['userpagehits'] = true;

You will now have a new security group called "userpagehits" you can assign users to.

[edit] Source

[edit] UserPageViewTracker.php

<?php
# The UserPageViewTracker extension, an extension for providing a view into user activity
 
# @addtogroup Extensions
# @author Kimon Andreou
# @copyright © 2007 by Kimon Andreou
# @licence GNU General Public Licence 2.0 or later

if ( !defined( 'MEDIAWIKI' ) ) {
       	die( 'This file is a MediaWiki extension, it is not a valid entry point' );
}
 
#credit the extension
$wgExtensionCredits['parserhook'][] = array(
	'name'=>'User Page View Tracker',
	'url'=>'http://www.mediawiki.org/wiki/Extension:UserPageViewTracker',
	'author'=>'Kimon Andreou',
	'description'=>'Tracks page views by user',
);
#register with a hook
$wgHooks['ParserAfterTidy'][]  = 'wfUserPageViewTracker';
 
#function that updates the table containing the hits
function wfUserPageViewTracker(&$parser, &$text) {
	global $wgDBprefix, $wgDBname, $wgUser, $wgOut;
 
	$wgOut->enableClientCache(false);
	$wgOut->addMeta("http:Pragma", "no-cache");
 
	$title = $parser->getTitle();
	$artID = $title->getArticleID();
	$db = &wfGetDB(DB_SLAVE);
 
	#check to see if the user has visited this page before
	$query = "SELECT hits, last FROM ".$wgDBprefix."user_page_views WHERE user_id = ".$wgUser->getID();
	$query .= " AND page_id = $artID";
	if($result = $db->doQuery($query)) {
		$row = $db->fetchRow($result);
		$last = $row["last"];
 
		#due to multiple calls, don't double count if we've been here within the last 5 seconds
		if($last < (wfTimestampNow() - 5)) {
			$hits = $row["hits"];
			if($hits > 0) {
				$query = "UPDATE ".$wgDBprefix."user_page_views ";
				$query .= "SET hits = ".($hits + 1);
				$query .= ", last='".wfTimestampNow()."'";
				$query .= " WHERE user_id = ".$wgUser->getID();
				$query .= " AND page_id = ".$artID;
			}
			else
			{
				#looks like this is our first visit, create the record
				$query = "INSERT INTO ".$wgDBprefix."user_page_views(user_id, page_id, hits, last)";
				$query .= " VALUES(".$wgUser->getID().",".$artID.",1,'".wfTimestampNow()."')";
			}
			$db->doQuery($query);
		}
	}
	return true;
}
 
 
###################################################################
###
###
### Special page section
###
###
###################################################################
$wgSpecialPages['SpecialUserpagehits'] = 'SpecialUserpagehits';
$wgExtensionCredits['specialpage'][] = array(
						'name' => 'User Page Hits',
						'description' => 'Displays the user hits per page',
						'url' => 'http://www.mediawiki.org/wiki/Extension:UserPageViewTracker',
						'author' => 'Kimon Andreou');
 
#bring in the specialpage stuff
require_once("$IP/includes/SpecialPage.php");
 
#our special page class
class SpecialUserpagehits extends SpecialPage
{
	#constructor
	function SpecialUserpagehits() {
		global $wgMessageCache;
		$wgMessageCache->addMessage('specialuserpagehits', 'User page hits');
		$wgMessageCache->addMessage('userpagehits', 'User page hits');
		SpecialPage::SpecialPage('SpecialUserpagehits', 'userpagehits');
	}
	#do your stuff
	function execute( $par = null ) {
	        global $wgRequest, $wgOut;
		$wgOut->setPageTitle('User page hits');
 
        	list( $limit, $offset ) = wfCheckLimits();
 
	        $userTarget = isset($par) ? $par : $wgRequest->getVal( 'username' );
 
        	$up = new UserPageHitsPager($user);
 
	        # getBody() first to check, if empty
	        $usersbody = $up->getBody();
	        $s = $up->getPageHeader();
 
	        if( $usersbody ) {
	                $s .=   $up->getNavigationBar();
	                $s .= '<table class="wikitable" width="100%" cellspacing="0" cellpadding="0">';
	                $s .= '<tr><th>#</th><th>User Name</th><th>Real Name</th><th>Page</th><th>Hits</th>';
			$s .= '<th>Last</th></tr>';
                	$s .= $usersbody . '</table>';
        	        $s .=   $up->getNavigationBar() ;
      	  	} else {
	                $s .=   '<p>' . wfMsgHTML('listusers-noresult') . '</p>';
	        };
 
        	$wgOut->addHTML( $s );
	}
}
 
 
require_once("$IP/includes/Pager.php");
 
#create a custom pager
class UserPageHitsPager extends AlphabeticPager 
{
	protected $rowCount = 0;
 
	function __construct($username=null) {
		global $wgRequest;
		$this->filterUsers = $filterUsers != "" ? $filterUsers : $wgRequest->getVal( 'filterusers' );
		$this->filterUserList = explode("|", $this->filterUsers);
 
		$this->ignoreUsers = $ignoreUsers != "" ? $ignoreUsers : $wgRequest->getVal( 'ignoreusers' );
		$this->ignoreUserList = explode("|", $this->ignoreUsers);
		parent::__construct();
	}
 
 
	function getIndexField() {
		return "rownum";
	}
 
	function getQueryInfo() {
		list ($userpagehits) = wfGetDB()->tableNamesN('user_page_hits');
		$conds = array();
		if($this->filterUsers) {
			$includeUsers = "user_name in ( '";
			$includeUsers .= implode("', '", $this->filterUserList)."')";
			$conds[] = $includeUsers;
			#$conds[] = "user_name = ".wfGetDB()->addQuotes($this->requestedUser); 
		}
		if($this->ignoreUsers) {
			$excludeUsers = "user_name not in ( '";
			$excludeUsers .= implode("', '", $this->ignoreUserList)."')";
			$conds[] = $excludeUsers;
		}
		$table = "(select @rownum:=@rownum+1 as rownum,";
		$table .= "user_name, user_real_name, page_namespace, page_title,hits, last ";
		$table .= "from (select @rownum:=0) r, ";
		$table .= "(select user_name, user_real_name, page_namespace, page_title,hits,";
		$table .= "last from user_page_hits) p) results";
		return array(
			'tables' => " $table ",
			'fields' => array( 'rownum',
				'user_name',
				'user_real_name',
				'page_namespace',
				'page_title',
				'hits',
				"concat(substr(last, 1, 4),'-',substr(last,5,2),'-',substr(last,7,2),' ',substr(last,9,2),':',substr(last,11,2),':',substr(last,13,2)) AS last"),
			'conds' => $conds
		);
 
	}
 
	function formatRow( $row ) {
		$userPage = Title::makeTitle( NS_USER, $row->user_name );
		$name = $this->getSkin()->makeLinkObj( $userPage, htmlspecialchars( $userPage->getText() ) );
		$pageTitle = Title::makeTitle( $row->page_namespace, $row->page_title );
		if($row->page_namespace > 0) {
			$pageFullName = $pageTitle->getNsText().":".htmlspecialchars($pageTitle->getText() );
		} else {
			$pageFullName = htmlspecialchars( $pageTitle->getText());
		}
		$page = $this->getSkin()->makeLinkObj( $pageTitle, $pageFullName );
 
		$this->rowCount += 1;
 
		$res = '<tr>';
		$res .= "<td style=\"text-align:center\">$this->rowCount</td>";	
		$res .= '<td>'.$name.'</td><td>';
		if ($row->user_real_name)
		{
			$res .= $row->user_real_name.'</td><td>';
		}
		else
		{
			$res .= '&nbsp;</td><td>';
		}
		$res .= "$page</td>";
		$res .= "<td style=\"text-align:right\">$row->hits</td>";
		$res .= "<td style=\"text-align:center\">$row->last</td>";
		$res .= "</tr>\n";
		return $res;
	}
 
	function getBody() {
		if (!$this->mQueryDone) {
			$this->doQuery();
		}
		$batch = new LinkBatch;
		$db = $this->mDb;
 
		$this->mResult->rewind();
 
		$this->rowCount = 0;
 
		while ( $row = $this->mResult->fetchObject() ) {
			$batch->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) );
		}
		$batch->execute();
		$this->mResult->rewind();
		return parent::getBody();
	}
 
	#this is where we set up the form at the top of the special page to be able to set filters
	function getPageHeader() {
		$out = "<form name=\"filteruser\" id=\"filteruser\" method=\"post\">\n";
		$out .="Usernames: <input type=\"text\" name=\"filterusers\" value=\"".$this->filterUsers."\">";
                $out .="<input type=\"submit\" value=\"Filter\">";
                $out .="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
                $out .="Usernames: <input type=\"text\" name=\"ignoreusers\" value=\"".$this->ignoreUsers."\">";
		$out .="<input type=\"submit\" value=\"Exclude\">";
		$out .="</form>\n<hr>\n";
 
		return $out;
	}
 
	/**
	 * Preserve filter offset parameters when paging
	 * @return array
	 */
	function getDefaultQuery() {
		$query = parent::getDefaultQuery();
		if( $this->filterUsers != '' )
			$query['filterusers'] = $this->filterUsers;
		if( $this->ignoreUsers != '' )
			$query['ignoreusers'] = $this->ignoreUsers;
		return $query;
	}
 
}

[edit] UserPageViews.sql

CREATE TABLE  `user_page_views` (
  `user_id` int(5) UNSIGNED NOT NULL,
  `page_id` int(8) UNSIGNED NOT NULL,
  `hits` int(10) UNSIGNED NOT NULL,
  `last` char(14) DEFAULT NULL,
  PRIMARY KEY  (`user_id`,`page_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

[edit] UserPageHits.sql

CREATE VIEW  `user_page_hits` AS 
SELECT `u`.`user_name` AS `user_name`,
       `u`.`user_real_name` AS `user_real_name`,
       `p`.`page_namespace` AS `page_namespace`,
       `p`.`page_title` AS `page_title`,
       `v`.`hits` AS `hits`,
       `v`.`last` AS `last` 
FROM ((`user` `u` JOIN `page` `p`) JOIN `user_page_views` `v`) 
WHERE ((`u`.`user_id` = `v`.`user_id`) AND (`p`.`page_id` = `v`.`page_id`)) 
ORDER BY `u`.`user_id`,`v`.`hits` DESC;

[edit] See also