<?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;
}
}