Open main menu

User:Diploid/ATS (Article Tagging System)/ATS Body.php

<?php
 /* Copyright (c) 2007 MediaWiki.org User: Diploid
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal 
 * in the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 
 * the Software, and to permit persons to whom the Software is furnished to do 
 * so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
 * OTHER DEALINGS IN THE SOFTWARE. 
 * -----------------------------------------------------------------------
 */

#
# The ATS ajax response (Article Tagging System) class
#

# used for producing tag clouds and all interactions with the ATS table
class ATSajaxresponse
{	
	##=========Configuration Variables=========

	#The Maximum Font Size of the Tag Cloud in the units selected bellow
	private $MaxFontSize = 21;
	private $MinFontSize = 12;
	#Units for the font size
	private $FontUnit = "px";
	
	#Definate the default number of tags per tag cloud
	private $DefaultNofTags = 9;
	
	##Defines the CSS Classes of various html elements of the Tag Cloud
	#Wrapper div for the tag cloud section
	private $cssClass_TagCloud = "tagcloud";
	#Each individual tag's span element
	private $cssClass_Tag = "tag";
	#Wrapper div for the add a tag section
	private $cssClass_AddTag = "addtag";
	#The text input area for typing the name of your tag
	private $cssClass_Add_Text = "addtaginput";
	#The button for adding your tag
	private $cssClass_Add_Button = "addtagbutton";
	
	#The Add Tag and Tag Cloud titles
	private $HTMLtagCloudTitle = "<h2>Tags</h2>";
	private $HTMLaddTagTitle = "<h2>Add Tag</h2>";


	#Set the dbuser and dbpassword variables to give this script table create 
	#permision for the wiki's database so that it can create the ATSTags table.
	private $dbuser="";
	private $dbpassword="";
	
	#database server name
	private $dbserver = "localhost";
	#database name
	private $dbname = "wikidb";
	#database mediawiki table prefix
	private $dbprefix = ""; //(make it the same as $wgDBprefix in local settings)
	

	
	private $MediaWikiInstallDirectory = "";
	
	#Sets the default setting for tag clouds:
	# If true every page will have a tag cloud by default that can be removed
	#with {{#ATS: disable}}
	# If false pages will not have tag clouds by default but must be added
	#with {{#ATS: enable}}
	public $TagCloudEnable = true;
	
	#The Hash Key used for all ATS form data, set this to some random
	#characters for increased security
	public $FormHashData = '';
	
	##=====End of Configuration Variables=====
	
	##Everything beyond this point should probably not be touched unless you wish
	#to modify the extension
	private $TagTableName = "atstags";
	private $TagCountAlias = "NoOfTags";
	#Time out (in seconds) for Session Data Stored in the atssession Memory Table in mysql
	#Note that this data is not particlularly valuable as it is only used to store a user validation key
	#from the time the user loads a ATS tagcloud to the time they add a tag to that cloud.
	private $SessionDataTimeout = 300; //default is 5 minute timeout
	
####Session Database Related Functions
	private function SessionEntryExists($user)
	{
			$query = "SELECT suser FROM ".$this->dbname.".".$this->dbprefix."atssessions "
					."WHERE suser = '$user'";
			if ($resultdata = $this->DBConnect($query)==false) return false;
			return true;
	}
	public function PostSessionData($sessiondata, $user)
	{
		foreach($sessiondata as $seskey => $sesvalue)
		{
			$query = "DELETE FROM $this->dbname.$this->dbprefix"."atssessions "
				."WHERE suser = '$user' and skey = '$seskey'";
			if ($this->DBConnect($query) == false) echo("ATS Session Deletion Error");
			
			$servertime = time();
			$query = "INSERT INTO ".$this->dbname.".".$this->dbprefix."atssessions"
			." (suser, skey, svalue, timestamp)"
			." VALUES ('$user', '$seskey', '$sesvalue','$servertime');";
			if ($this->DBConnect($query) == false) echo("ATS Session Error");
		}
	}
	public function GetSessionData($sessionkey, $user)
	{
			$query = "SELECT suser, svalue, skey FROM ".$this->dbname.".".$this->dbprefix."atssessions "
					."WHERE skey = '$sessionkey' AND suser = '$user'";
			$resultdata = $this->DBConnect($query);
			if ($resultdata==false) return false;
			$resultarray = $this->getSQLarray($resultdata);
			return $resultarray[(count($resultarray)-1)]['svalue'];
	}
	private function DeleteExpiredSessions()
	{ #Deletes Entries older then the timeout period specified in the $SessionDataTimeout Variable
		$awhileback = time()-$this->SessionDataTimeout;
		$query = "DELETE FROM $this->dbname.$this->dbprefix"."atssessions "
				."WHERE timestamp < $awhileback";
		if ($this->DBConnect($query) == false) echo("ATS Session Deletion Error");
	}
	private function SetupSession()
	{
		$query = "SELECT * FROM ".$this->dbname.".".$this->dbprefix."atssessions";
		if ($this->DBConnect($query)==false)
		{
		$query = "CREATE TABLE ".$this->dbname.".".$this->dbprefix."atssessions"
		."("
		."suser VARCHAR(100) NOT NULL, "
		."skey VARCHAR(100) NOT NULL, "
		."svalue VARCHAR(100) NOT NULL, "
		."timestamp INTEGER UNSIGNED NOT NULL"
		.") ENGINE = MEMORY;";
		if ($this->DBConnect($query)==false) echo ("ATS Fatal Error: Could Not Set Up Session Data");
		}
		
		#Removing Expired Session Entries
		$this->DeleteExpiredSessions();

	}
	
####Tag Creation Related Functions
	public function AddTag($pagename, $tag, $username, $hashtoken)
	{
		$tag = ucfirst($tag);
		$identicaltagcheck = $this->identicaltagcheck($pagename, $tag, $username);
		//Requires the user to be logged in and authorized (aka has a correct hash)
		if ($this->validateuser($pagename,$username,$hashtoken) == true
		and $identicaltagcheck==false
		and $pagename != null)
		{
			$pagename = ucfirst($pagename);
			######  Adding to ATS Table ####
			
			//Updating the tag table
			$query = "
INSERT INTO `".$this->dbname."`.`".$this->dbprefix.$this->TagTableName."` (Tag, Page, UserName)
VALUES (\"".$tag."\",\"".$pagename."\",\"".$username."\")";
			
			if($this->DBConnect($query)==false)
			{
				echo("Unknown ATS Error Please Try Again");
				exit();
			}
			
			#####  Adding to MediaWiki Tables #####
			
			//Getting the page's number
			$_pagename =  str_replace(" ", "_", $pagename);
			$query =
"SELECT page_id FROM `".$this->dbname."`.`".$this->dbprefix."page`
WHERE page_title = \"".$_pagename."\"";
			
			$pageiddata = $this->DBConnect($query);
			if ($pageiddata ==false)
			{
				echo("ATS Error While Getting Page ID Please Try Again");
				exit();
			}
			$pageidarray = $this->getSQLarray($pageiddata);
			$pageid = $pageidarray[count($pageidarray)-1]["page_id"];

			//Updating the Media Wiki categorylinks table
			//cl_from, cl_to, cl_sortkey, cl_timestamp
			$timestamp = date("Y-m-d H:i:s");
			$tag = str_replace(" ", "_", $tag);
			$query = "
INSERT INTO `$this->dbname`.`$this->dbprefix"."categorylinks` (cl_from, cl_to, cl_sortkey, cl_timestamp)
VALUES (\"".$pageid."\",\"".$tag."\",\"".$pagename."\",\"".$timestamp."\")";
			
			if($this->DBConnect($query)==false)
			{
				echo("ATS Error While Interacting with the MediaWiki Table CategoryLinks Please Try Again");
				exit();
			}
			
			
			//Updating the Job List so that the category page is updated accordingly
			$query = "
insert into ".$this->dbname.".".$this->dbprefix."job (job_cmd,job_namespace,job_title,job_params) 
VALUES ('refreshLinks',0,'".$_pagename."','');
";
			
			if($this->DBConnect($query)==false)
			{
				echo("ATS Error While adding MediaWiki Job");
				exit();
			}
			
		}
		else
		{
			if ($identicaltagcheck == true) {
				echo("You can only tag this page once");
			}
			else {
				echo("Your session has expired, please log in to add a tag");
			}
		}
	}
	
	
	private function identicaltagcheck($page, $tag, $user)
	{
		$query = 
"
SELECT Tag, Page, UserName FROM `".$this->dbname."`.`".$this->dbprefix.$this->TagTableName."`
WHERE Tag = \"".$tag."\" and UserName = \"".$user."\" and Page = \"".$page."\"
";
		$result = $this->DBConnect($query);
		if ($result == false) return true;
		$resultarray = $this->getSQLarray($result);
		if (count($resultarray) == 1)
		{
		return false;
		}
		return true;
	}

####Tag Querying Functions
	private function QueryPageTags($page, $arg="orderbytagcount")
	{
		$orderby="";
		if ($arg == "textonly" || $arg="orderbytagcount")
			$orderby = "ORDER BY Count(UserName) DESC";
		
		//Querying the Database
		$query = 
"
SELECT Tag, Count(UserName) AS ".$this->TagCountAlias." FROM `".$this->dbname."`.`".$this->dbprefix.$this->TagTableName."`
WHERE Page = \"".$page."\"
GROUP BY Tag
".$orderby;
		return $this->DBConnect($query);
	}
	public function GetTags_CommaSeperatedText($page)
	{
		$result = $this->QueryPageTags($page);
		if ($result == false) return false;
		return $this->getSQLcolumntext_CommaSeperated($result,"Tag");
	}
	public function GetTags($page)
	{
		$result = $this->QueryPageTags($page);
		if ($result == false) return false;
		$resultarray = $this->getSQLarray($result);
		#Deleting the first, and for some reason always empty first row
		array_splice($resultarray, 0, 1);
		return $resultarray;
	}
	public function GetTaggedPages($tag)
	{
		$query = 
"
SELECT Page, Count(UserName) AS tagcount FROM `".$this->dbname."`.`".$this->dbprefix.$this->TagTableName."`
WHERE Tag = \"".$tag."\"
GROUP BY Page
ORDER BY Count(UserName) DESC
"
;
		$result = $this->DBConnect($query);
		if ($result == false) return false;
		$resultarray = $this->getSQLarray($result);
		#Deleting the first, and for some reason always empty first row
		array_splice($resultarray, 0, 1);
		return $resultarray;
	}
	
	#This monster of a function generates Tag Clouds in both WikiText and HTML format
	public function MakeTagCloud($page,$NofTags = false, $user=false, $key)
	{
		if ($this->TagCloudEnable == true)
		{
		#Setting the defualt number of tags if it is not definaed here
		if ($NofTags==false) $NofTags = $this->DefaultNofTags;
		#Gets the tag data in array form
		$tagdata = $this->GetTags($page);

		$Path = $this->MediaWikiInstallDirectory;

		#Initializing the returned tag cloud HTML: $tagcloud var
		$tagcloud =$this->HTMLtagCloudTitle
		."<div class=\"".$this->cssClass_TagCloud."\">";
		
		#Getting the Size of the tagdata array
		$size = count($tagdata);

		#Checking that there are actually any tags returned for the page
		#before creating the tag cloud
		if ($tagdata!=false && $size != 0)
		{
		#Initializing a variety of variables
		if ($size < $NofTags) $NofTags = $size;
		
		$mosttags = $tagdata[0][$this->TagCountAlias];
		$leasttags = $tagdata[$NofTags-1][$this->TagCountAlias];

		$fontmultiplier = 1;
		if ($mosttags != $leasttags)
		{
		#Creating the font multiplier used to create the varying font sizes used in
		#the tag cloud to represent tag popularity		
		$fontmultiplier = 1/($mosttags - $leasttags)*
						  ($this->MaxFontSize - $this->MinFontSize);	  
		}
		
		#Get the first N Tags where N = $NofTags 
		if ($size != $NofTags) array_splice($tagdata,$NofTags);
		$size = count($tagdata);
		#Order the first N Tags Alphabetically where N = $NofTags
		$this->OrderRowArrayAlphabetically($tagdata, "Tag");
		#Creating each Tag's HTML
		for ($i=0; $i<$size; $i++)
		{
			#Generating the tag's font size relative to it's popularity and the
			#font multiplier
			$fontsize = 
				(($tagdata[$i][$this->TagCountAlias]-$leasttags)
				*$fontmultiplier) + $this->MinFontSize;

			#Sets the URL of the Tag's Link
			$tagurl = $Path."/index.php?title=Category:".$tagdata[$i]["Tag"];
				
			#Generating the Tag's HTML code and appending it to the output
			$tagcloud .= "<a href=\"".$tagurl."\" class = \"".$this->cssClass_Tag."\""
					   ." style=\"font-size:".$fontsize."".$this->FontUnit.";\">"
					  .$tagdata[$i]["Tag"]
					  ."</a>\n";
			}
		}

		$tagcloud .= "</div>\n"; //End of the TagCloudSpan
		
		$tagcloud .= $this->HTMLaddTagTitle
				  ."<div class = \"".$this->cssClass_AddTag."\">\n";
		if ($this->validateuser($page, $user, $key) ==false)
		{
			$tagcloud .="Please Log in to add a tag";
		}
		else 
		{
		#Creating the Add Tag HTML
		$tagcloud .=""
		."<input id=\"ATSaddtag-tagname\" type=\"text\" />\n"
		."<input id=\"ATSaddtag-submit\" type=\"button\" value=\"Add\""
		."onClick=\"AsyncLoadATS("
		."document.getElementById('ATSaddtag-tagname').value)\"/>\n";
		}
		$tagcloud .= "</div>\n";
		
		
		return $tagcloud;
		}
		return "";
	}
	
	
	private function OrderRowArrayAlphabetically(&$rows, $col)
	{
		$size = count($rows);
		
		for ($i=0; $i<$size; $i++)
		{
		
		#Finding the next row in alphabetical order (temperarorly stored as $alpha)
		$alpha = $i;
		for ($j=$i; $j<$size; $j++)
		{
			if ((strcasecmp($rows[$alpha][$col], $rows[$j][$col]))>0)
			{$alpha =$j;
			}
		}
		
		#Inserting the next row $alpha and moving the previous 
		#entry at that position back into the sorting que
		if ($alpha!= $i)
		{
			$tmprow = $rows[$i];
			$rows[$i] = $rows[$alpha];
			$rows[$alpha] = $tmprow;
		}
		}
	}
	
	
	public function Setup()
	{
		#Checking for Script Specific DB Username and Password otherwise using the
		#mediawiki account
		/*if (!$this->dbuser || !$this->dbpassword)
		{
			$this->dbuser = $wgDBuser;
			$this->dbpassword = $wgDBpassword;
		}*/
		#Checking if MySQL is installed and working properly
		# Test for missing mysql.so
		# First try to load it
		if (!@extension_loaded('mysql')) {
			@dl('mysql.so');
		}
		# Fail now
		# Otherwise we get a suppressed fatal error, which is very hard to track down
		if ( !function_exists( 'mysql_connect' ) )
		{
			echo ("ATS Error: SQL Not properly Installed.");
			exit;
		};
		#Checking if the Tags table has been setup
		$query = "SELECT 1 FROM `".$this->dbprefix.$this->TagTableName."` LIMIT 0";
		$result = $this->DBConnect($query);
		if ($result==false)
		{
			//If the table has not been setup attempt to make it

				$query="
CREATE TABLE `".$this->dbname."`.`".$this->dbprefix.$this->TagTableName."` (
  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  Page VARCHAR(100) NOT NULL,
  UserName VARCHAR(50) NOT NULL,
  Tag VARCHAR(50) NOT NULL,
  PRIMARY KEY (`id`)
);";


			//Returning an error if the table cannot be created
			//Yes I realize this is a shoddy error message, but its 2am and i'm sick
			//so bugger off. (please)
			if (!$this->DBConnect($query))
			{
				echo("ATS Error: Tag Table cannot be created."
					."Please Insert the Following in your Wiki's MySQL Database:"
					."<pre>"
				    .$query
					."</pre>"
					."<br/><b>or</b>"
					."Uncomment \$dbuser and \$dbpassword and set them to those "
					."corresponding to a MySQL account with CREATE privledges for "
					."the media wiki database and reload this page.");
				   //Initialization of the Extension is stopped due to an SQL error
				   exit();
			}
		}
		//Sets up the session table in the RAM to track tagcloud users
		$this->SetupSession();
		
		//All is well so we allow the Magic Word/Hook to be initialized
		return true;
	}
	
	
	//I Realize all functions beyond this point are sql related and techincally
	//should be in their own object but i'm being lazy on this one.
	
	#Private function used to connect to the Tag Table
	public function DBConnect($query)
	{

		$link = mysql_connect ($this->dbserver, $this->dbuser, $this->dbpassword);
		mysql_select_db ($this->dbname, $link);
		$result = mysql_query ($query, $link);
		$link = null;
		return $result;
	}
	private function getSQLarray($queryresults)
	{
		if ($queryresults == false) return false;
		$resultsarray[] = null;
		$num_results = mysql_num_rows($queryresults);
		for ($i=0; $i < $num_results; $i ++)
		{
			$resultsarray[] = mysql_fetch_array($queryresults);
		}
		return $resultsarray;
	}
	private function getSQLcolumntext_CommaSeperated($queryresults, $column)
	{
		if ($queryresults == false) return false;
		
		$resultstext = "";
		$num_results = mysql_num_rows($queryresults);
		for ($i=0; $i < $num_results; $i ++)
		{
			$resultstext .= mysql_result($queryresults,$i,$column) . ",";
		}
		return $resultstext;
	}
	
	
	private function validateuser($pagename, $user, $key)
	{
		#If User is logged in
		if ($user != "" and $this->SessionEntryExists($user)) {
			#If user's credentials check out
			if (
			$this->GetSessionData('ATShash',$user) == sha1($key) and #Checking Encryption Key
			$this->GetSessionData('ATSpage',$user) == $pagename #Checking Page Name
			)
			{
				return true;
			}
		}
		return false;
	}
}