User:ClueBot/Source

The following is automatically generated by ClueBot.

Classes (wikibot.classes.php)
&lt;?PHP /**	 * @author Cobi Carter **/	/**	 * This class is designed to provide a simplified interface to cURL which maintains cookies. * @author Cobi **/	class http { private $ch; private $uid; public $postfollowredirs; public $getfollowredirs;

/**		 * Our constructor function. This just does basic cURL initialization. * @return void **/		function __construct { global $proxyhost, $proxyport, $proxytype; $this-&gt;ch = curl_init; $this-&gt;uid = dechex(rand(0,99999999)); curl_setopt($this-&gt;ch,CURLOPT_COOKIEJAR,'/tmp/cluewikibot.cookies.'.$this-&gt;uid.'.dat'); curl_setopt($this-&gt;ch,CURLOPT_COOKIEFILE,'/tmp/cluewikibot.cookies.'.$this-&gt;uid.'.dat'); curl_setopt($this-&gt;ch,CURLOPT_MAXCONNECTS,100); curl_setopt($this-&gt;ch,CURLOPT_CLOSEPOLICY,CURLCLOSEPOLICY_LEAST_RECENTLY_USED); curl_setopt($this-&gt;ch,CURLOPT_USERAGENT,'ClueBot/1.1'); if (isset($proxyhost) and isset($proxyport) and ($proxyport != null) and ($proxyhost != null)) { curl_setopt($this-&gt;ch,CURLOPT_PROXYTYPE,isset( $proxytype ) ? $proxytype : CURLPROXY_HTTP); curl_setopt($this-&gt;ch,CURLOPT_PROXY,$proxyhost); curl_setopt($this-&gt;ch,CURLOPT_PROXYPORT,$proxyport); }			$this-&gt;postfollowredirs = 0; $this-&gt;getfollowredirs = 1; }

/**		 * Post to a URL. * @param $url The URL to post to. * @param $data The post-data to post, should be an array of key =&gt; value pairs. * @return Data retrieved from the POST request. **/		function post ($url,$data) { $time = microtime(1); curl_setopt($this-&gt;ch,CURLOPT_URL,$url); curl_setopt($this-&gt;ch,CURLOPT_FOLLOWLOCATION,$this-&gt;postfollowredirs); curl_setopt($this-&gt;ch,CURLOPT_MAXREDIRS,10); curl_setopt($this-&gt;ch,CURLOPT_HEADER,0); curl_setopt($this-&gt;ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($this-&gt;ch,CURLOPT_TIMEOUT,30); curl_setopt($this-&gt;ch,CURLOPT_CONNECTTIMEOUT,10); curl_setopt($this-&gt;ch,CURLOPT_POST,1); curl_setopt($this-&gt;ch,CURLOPT_POSTFIELDS, $data); curl_setopt($this-&gt;ch,CURLOPT_HTTPHEADER, array('Expect:')); $data = curl_exec($this-&gt;ch); global $logfd; if (!is_resource($logfd)) $logfd = fopen('php://stderr','w'); fwrite($logfd,'POST: '.$url.' ('.(microtime(1) - $time).' s) ('.strlen($data).&quot; b)\n&quot;); return $data; }

/**		 * Get a URL. * @param $url The URL to get. * @return Data retrieved from the GET request. **/		function get ($url) { $time = microtime(1); curl_setopt($this-&gt;ch,CURLOPT_URL,$url); curl_setopt($this-&gt;ch,CURLOPT_FOLLOWLOCATION,$this-&gt;getfollowredirs); curl_setopt($this-&gt;ch,CURLOPT_MAXREDIRS,10); curl_setopt($this-&gt;ch,CURLOPT_HEADER,0); curl_setopt($this-&gt;ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($this-&gt;ch,CURLOPT_TIMEOUT,30); curl_setopt($this-&gt;ch,CURLOPT_CONNECTTIMEOUT,10); curl_setopt($this-&gt;ch,CURLOPT_HTTPGET,1); $data = curl_exec($this-&gt;ch); global $logfd; if (!is_resource($logfd)) $logfd = fopen('php://stderr','w'); fwrite($logfd,'GET: '.$url.' ('.(microtime(1) - $time).' s) ('.strlen($data).&quot; b)\n&quot;); return $data; }

/**		 * Our destructor. Cleans up cURL and unlinks temporary files. **/		function __destruct { curl_close($this-&gt;ch); @unlink('/tmp/cluewikibot.cookies.'.$this-&gt;uid.'.dat'); }	}

/**	 * This class is a deprecated wrapper class which allows legacy code written for Wikipedia's query.php API to still work with wikipediaapi::. **/	class wikipediaquery { private $http; private $api; public $queryurl = 'http://en.wikipedia.org/w/query.php'; //Obsolete, but kept for compatibility purposes.

/**		 * This is our constructor. * @return void **/		function __construct { global $__wp__http; if (!isset($__wp__http)) { $__wp__http = new http; }			$this-&gt;http = &amp;$__wp__http; $this-&gt;api = new wikipediaapi; }

/**		 * Reinitializes the queryurl. * @private * @return void **/		private function checkurl { $this-&gt;api-&gt;apiurl = str_replace('query.php','api.php',$this-&gt;queryurl); }

/**		 * Gets the content of a page. * @param $page The wikipedia page to fetch. * @return The wikitext for the page. **/		function getpage ($page) { $this-&gt;checkurl; $ret = $this-&gt;api-&gt;revisions($page,1,'older',true,null,true,false,false,false); return $ret[0]['*']; }

/**		 * Gets the page id for a page. * @param $page The wikipedia page to get the id for. * @return The page id of the page. **/		function getpageid ($page) { $this-&gt;checkurl; $ret = $this-&gt;api-&gt;revisions($page,1,'older',false,null,true,false,false,false); return $ret['pageid']; }

/**		 * Gets the number of contributions a user has. * @param $user The username for which to get the edit count. * @return The number of contributions the user has. **/		function contribcount ($user) { $this-&gt;checkurl; $ret = $this-&gt;api-&gt;users($user,1,null,true); if ($ret !== false) return $ret[0]['editcount']; return false; }	}

/**	 * This class is for interacting with Wikipedia's api.php API. **/	class wikipediaapi { private $http; private $edittoken; private $tokencache; private $user, $pass; public $apiurl = 'http://en.wikipedia.org/w/api.php';

/**		 * This is our constructor. * @return void **/		function __construct { global $__wp__http; if (!isset($__wp__http)) { $__wp__http = new http; }			$this-&gt;http = &amp;$__wp__http; }

/**		 * This function takes a username and password and logs you into wikipedia. * @param $user Username to login as. * @param $pass Password that corrisponds to the username. * @return void **/		function login ($user,$pass) { $this-&gt;user = $user; $this-&gt;pass = $pass; $x = unserialize($this-&gt;http-&gt;post($this-&gt;apiurl.'?action=login&amp;format=php',array('lgname' =&gt; $user, 'lgpassword' =&gt; $pass))); if($x['login']['result'] == 'Success') return true; if($x['login']['result'] == 'NeedToken') { $x = unserialize($this-&gt;http-&gt;post($this-&gt;apiurl.'?action=login&amp;format=php',array('lgname' =&gt; $user, 'lgpassword' =&gt; $pass, 'lgtoken' =&gt; $x['login']['token']))); if($x['login']['result'] == 'Success') return true; }			return false; }

/**		 * This function returns the edit token. * @return Edit token. **/		function getedittoken { $tokens = $this-&gt;gettokens('Main Page'); if ($tokens['edittoken'] == '') $tokens = $this-&gt;gettokens('Main Page',true); $this-&gt;edittoken = $tokens['edittoken']; return $tokens['edittoken']; }

/**		 * This function returns the various tokens for a certain page. * @param $title Page to get the tokens for. * @param $flush Optional - internal use only. Flushes the token cache. * @return An associative array of tokens for the page. **/		function gettokens ($title,$flush = false) { if (!is_array($this-&gt;tokencache)) $this-&gt;tokencache = array; foreach ($this-&gt;tokencache as $t =&gt; $data) if (time - $data['timestamp'] &gt; 6*60*60) unset($this-&gt;tokencache[$t]); if (isset($this-&gt;tokencache[$title]) &amp;&amp; (!$flush)) { return $this-&gt;tokencache[$title]['tokens']; } else { $tokens = array; $x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;format=php&amp;prop=info&amp;intoken=edit|delete|protect|move|block|unblock|email&amp;titles='.urlencode($title)); $x = unserialize($x); foreach ($x['query']['pages'] as $y) { $tokens['edittoken'] = $y['edittoken']; $tokens['deletetoken'] = $y['deletetoken']; $tokens['protecttoken'] = $y['protecttoken']; $tokens['movetoken'] = $y['movetoken']; $tokens['blocktoken'] = $y['blocktoken']; $tokens['unblocktoken'] = $y['unblocktoken']; $tokens['emailtoken'] = $y['emailtoken']; $this-&gt;tokencache[$title] = array(							'timestamp' =&gt; time,							'tokens' =&gt; $tokens									 ); return $tokens; }			}		}

/**		 * This function returns the recent changes for the wiki. * @param $count The number of items to return. (Default 10) * @param $namespace The namespace ID to filter items on. Null for no filtering. (Default null) * @param $dir The direction to pull items. &quot;older&quot; or &quot;newer&quot;. (Default 'older') * @param $ts The timestamp to start at. Null for the beginning/end (depending on direction). (Default null) * @return Associative array of recent changes metadata. **/		function recentchanges ($count = 10,$namespace = null,$dir = 'older',$ts = null) { $append = ''; if ($ts !== null) { $append .= '&amp;rcstart='.urlencode($ts); } $append .= '&amp;rcdir='.urlencode($dir); if ($namespace !== null) { $append .= '&amp;rcnamespace='.urlencode($namespace); } $x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;list=recentchanges&amp;rcprop=user|comment|flags|timestamp|title|ids|sizes&amp;format=php&amp;rclimit='.$count.$append); $x = unserialize($x); return $x['query']['recentchanges']; }

/**		 * This function returns search results from Wikipedia's internal search engine. * @param $search The query string to search for. * @param $limit The number of results to return. (Default 10) * @param $offset The number to start at. (Default 0) * @param $namespace The namespace ID to filter by. Null means no filtering. (Default 0) * @param $what What to search, 'text' or 'title'. (Default 'text') * @param $redirs Whether or not to list redirects. (Default false) * @return Associative array of search result metadata. **/		function search ($search,$limit = 10,$offset = 0,$namespace = 0,$what = 'text',$redirs = false) { $append = ''; if ($limit != null) $append .= '&amp;srlimit='.urlencode($limit); if ($offset != null) $append .= '&amp;sroffset='.urlencode($offset); if ($namespace != null) $append .= '&amp;srnamespace='.urlencode($namespace); if ($what != null) $append .= '&amp;srwhat='.urlencode($what); if ($redirs == true) $append .= '&amp;srredirects=1'; else $append .= '&amp;srredirects=0'; $x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;list=search&amp;format=php&amp;srsearch='.urlencode($search).$append); $x = unserialize($x); return $x['query']['search']; }

/**		 * Retrieve entries from the WikiLog. * @param $user Username who caused the entry. Null means anyone. (Default null) * @param $title Object to which the entry refers. Null means anything. (Default null) * @param $limit Number of entries to return. (Default 50) * @param $type Type of logs. Null means any type. (Default null) * @param $start Date to start enumerating logs. Null means beginning/end depending on $dir. (Default null) * @param $end Where to stop enumerating logs. Null means whenever limit is satisfied or there are no more logs. (Default null) * @param $dir Direction to enumerate logs. &quot;older&quot; or &quot;newer&quot;. (Default 'older') * @return Associative array of logs metadata. **/		function logs ($user = null,$title = null,$limit = 50,$type = null,$start = null,$end = null,$dir = 'older') { $append = ''; if ($user != null) $append.= '&amp;leuser='.urlencode($user); if ($title != null) $append.= '&amp;letitle='.urlencode($title); if ($limit != null) $append.= '&amp;lelimit='.urlencode($limit); if ($type != null) $append.= '&amp;letype='.urlencode($type); if ($start != null) $append.= '&amp;lestart='.urlencode($start); if ($end != null) $append.= '&amp;leend='.urlencode($end); if ($dir != null) $append.= '&amp;ledir='.urlencode($dir); $x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;format=php&amp;list=logevents&amp;leprop=ids|title|type|user|timestamp|comment|details'.$append); $x = unserialize($x); return $x['query']['logevents']; }

/**		 * Retrieves metadata about a user's contributions. * @param $user Username whose contributions we want to retrieve. * @param $count Number of entries to return. (Default 50) * @param[in,out] $continue Where to continue enumerating if part of a larger, split request. This is filled with the next logical continuation value. (Default null) * @param $dir Which direction to enumerate from, &quot;older&quot; or &quot;newer&quot;. (Default 'older') * @return Associative array of contributions metadata. **/		function usercontribs ($user,$count = 50,&amp;$continue = null,$dir = 'older') { if ($continue != null) { $append = '&amp;ucstart='.urlencode($continue); } else { $append = ''; }			$x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;format=php&amp;list=usercontribs&amp;ucuser='.urlencode($user).'&amp;uclimit='.urlencode($count).'&amp;ucdir='.urlencode($dir).$append); $x = unserialize($x); $continue = $x['query-continue']['usercontribs']['ucstart']; return $x['query']['usercontribs']; }

/**		 * Returns revision data (meta and/or actual). * @param $page Page for which to return revision data for. * @param $count Number of revisions to return. (Default 1) * @param $dir Direction to start enumerating multiple revisions from, &quot;older&quot; or &quot;newer&quot;. (Default 'older') * @param $content Whether to return actual revision content, true or false. (Default false) * @param $revid Revision ID to start at. (Default null) * @param $wait Whether or not to wait a few seconds for the specific revision to become available. (Default true) * @param $getrbtok Whether or not to retrieve a rollback token for the revision. (Default false) * @param $dieonerror Whether or not to kill the process with an error if an error occurs. (Default false) * @param $redirects Whether or not to follow redirects. (Default false) * @return Associative array of revision data. **/		function revisions ($page,$count = 1,$dir = 'older',$content = false,$revid = null,$wait = true,$getrbtok = false,$dieonerror = true,$redirects = false) { $x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;prop=revisions&amp;titles='.urlencode($page).'&amp;rvlimit='.urlencode($count).'&amp;rvprop=timestamp|ids|user|comment'.(($content)?'|content':).'&amp;format=php&amp;meta=userinfo&amp;rvdir='.urlencode($dir).(($revid !== null)?'&amp;rvstartid='.urlencode($revid):).(($getrbtok == true)?'&amp;rvtoken=rollback':).(($redirects == true)?'&amp;redirects':)); $x = unserialize($x); if ($revid !== null) { $found = false; if (!isset($x['query']['pages']) or !is_array($x['query']['pages'])) { if ($dieonerror == true) die('No such page.'.&quot;\n&quot;); else return false; }				foreach ($x['query']['pages'] as $data) { if (!isset($data['revisions']) or !is_array($data['revisions'])) { if ($dieonerror == true) die('No such page.'.&quot;\n&quot;); else return false; }					foreach ($data['revisions'] as $data2) if ($data2['revid'] == $revid) $found = true; unset($data,$data2); break; }

if ($found == false) { if ($wait == true) { sleep(1); return $this-&gt;revisions($page,$count,$dir,$content,$revid,false,$getrbtok,$dieonerror); } else { if ($dieonerror == true) die('Revision error.'.&quot;\n&quot;); }				}			}			foreach ($x['query']['pages'] as $key =&gt; $data) { $data['revisions']['ns'] = $data['ns']; $data['revisions']['title'] = $data['title']; $data['revisions']['currentuser'] = $x['query']['userinfo']['name']; //				$data['revisions']['currentuser'] = $x['query']['userinfo']['currentuser']['name']; $data['revisions']['continue'] = $x['query-continue']['revisions']['rvstartid']; $data['revisions']['pageid'] = $key; return $data['revisions']; }		}

/**		 * Enumerates user metadata. * @param $start The username to start enumerating from. Null means from the beginning. (Default null) * @param $limit The number of users to enumerate. (Default 1) * @param $group The usergroup to filter by. Null means no filtering. (Default null) * @param $requirestart Whether or not to require that $start be a valid username. (Default false) * @param[out] $continue This is filled with the name to continue from next query. (Default null) * @return Associative array of user metadata. **/		function users ($start = null,$limit = 1,$group = null,$requirestart = false,&amp;$continue = null) { $append = ''; if ($start != null) $append .= '&amp;aufrom='.urlencode($start); if ($group != null) $append .= '&amp;augroup='.urlencode($group); $x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;list=allusers&amp;format=php&amp;auprop=blockinfo|editcount|registration|groups&amp;aulimit='.urlencode($limit).$append); $x = unserialize($x); $continue = $x['query-continue']['allusers']['aufrom']; if (($requirestart == true) and ($x['query']['allusers'][0]['name'] != $start)) return false; return $x['query']['allusers']; }

/**		 * Get members of a category. * @param $category Category to enumerate from. * @param $count Number of members to enumerate. (Default 500) * @param[in,out] $continue Where to continue enumerating from. This is automatically filled in when run. (Default null) * @return Associative array of category member metadata. **/		function categorymembers ($category,$count = 500,&amp;$continue = null) { if ($continue != null) { $append = '&amp;cmcontinue='.urlencode($continue); } else { $append = ''; }			$category = 'Category:'.str_ireplace('category:','',$category); $x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;list=categorymembers&amp;cmtitle='.urlencode($category).'&amp;format=php&amp;cmlimit='.$count.$append); $x = unserialize($x); $continue = $x['query-continue']['categorymembers']['cmcontinue']; return $x['query']['categorymembers']; }

/**		 * Enumerate all categories. * @param[in,out] $start Where to start enumerating. This is updated automatically with the value to continue from. (Default null) * @param $limit Number of categories to enumerate. (Default 50) * @param $dir Direction to enumerate in. 'ascending' or 'descending'. (Default 'ascending') * @param $prefix Only enumerate categories with this prefix. (Default null) * @return Associative array of category list metadata. **/		function listcategories (&amp;$start = null,$limit = 50,$dir = 'ascending',$prefix = null) { $append = ''; if ($start != null) $append .= '&amp;acfrom='.urlencode($start); if ($limit != null) $append .= '&amp;aclimit='.urlencode($limit); if ($dir != null) $append .= '&amp;acdir='.urlencode($dir); if ($prefix != null) $append .= '&amp;acprefix='.urlencode($prefix);

$x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;list=allcategories&amp;acprop=size&amp;format=php'.$append); $x = unserialize($x);

$start = $x['query-continue']['allcategories']['acfrom'];

return $x['query']['allcategories']; }

/**		 * Enumerate all backlinks to a page. * @param $page Page to search for backlinks to. * @param $count Number of backlinks to list. (Default 500) * @param[in,out] $continue Where to start enumerating from. This is automatically filled in. (Default null) * @param $filter Whether or not to include redirects. Acceptible values are 'all', 'redirects', and 'nonredirects'. (Default null) * @return Associative array of backlink metadata. **/		function backlinks ($page,$count = 500,&amp;$continue = null,$filter = null) { if ($continue != null) { $append = '&amp;blcontinue='.urlencode($continue); } else { $append = ''; }			if ($filter != null) { $append .= '&amp;blfilterredir='.urlencode($filter); }

$x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;list=backlinks&amp;bltitle='.urlencode($page).'&amp;format=php&amp;bllimit='.$count.$append); $x = unserialize($x); $continue = $x['query-continue']['backlinks']['blcontinue']; return $x['query']['backlinks']; }

/**		 * Gets a list of transcludes embedded in a page. * @param $page Page to look for transcludes in. * @param $count Number of transcludes to list. (Default 500) * @param[in,out] $continue Where to start enumerating from. This is automatically filled in. (Default null) * @return Associative array of transclude metadata. **/		function embeddedin ($page,$count = 500,&amp;$continue = null) { if ($continue != null) { $append = '&amp;eicontinue='.urlencode($continue); } else { $append = ''; }			$x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;list=embeddedin&amp;eititle='.urlencode($page).'&amp;format=php&amp;eilimit='.$count.$append); $x = unserialize($x); $continue = $x['query-continue']['embeddedin']['eicontinue']; return $x['query']['embeddedin']; }

/**		 * Gets a list of pages with a common prefix. * @param $prefix Common prefix to search for. * @param $namespace Numeric namespace to filter on. (Default 0) * @param $count Number of pages to list. (Default 500) * @param[in,out] $continue Where to start enumerating from. This is automatically filled in. (Default null) * @return Associative array of page metadata. **/		function listprefix ($prefix,$namespace = 0,$count = 500,&amp;$continue = null) { $append = '&amp;apnamespace='.urlencode($namespace); if ($continue != null) { $append .= '&amp;apfrom='.urlencode($continue); }			$x = $this-&gt;http-&gt;get($this-&gt;apiurl.'?action=query&amp;list=allpages&amp;apprefix='.urlencode($prefix).'&amp;format=php&amp;aplimit='.$count.$append); $x = unserialize($x); $continue = $x['query-continue']['allpages']['apfrom']; return $x['query']['allpages']; }

/**		 * Edits a page. * @param $page Page name to edit. * @param $data Data to post to page. * @param $summary Edit summary to use. * @param $minor Whether or not to mark edit as minor. (Default false) * @param $bot Whether or not to mark edit as a bot edit. (Default true) * @param $wpStarttime Time in MW TS format of beginning of edit. (Default now) * @param $wpEdittime Time in MW TS format of last edit to that page. (Default correct) * @return boolean True on success, false on failure. **/		function edit ($page,$data,$summary = '',$minor = false,$bot = true,$wpStarttime = null,$wpEdittime = null,$checkrun = true) { global $run, $user;

$wpq = new wikipediaquery; $wpq-&gt;queryurl = str_replace('api.php','query.php',$this-&gt;apiurl);

if ($checkrun == true) if (!preg_match('/(yes|enable|true)/iS',((isset($run))?$run:$wpq-&gt;getpage('User:'.$user.'/Run')))) return false; /* Check /Run page */

$params = Array(				'action' =&gt; 'edit',				'format' =&gt; 'php',				'assert' =&gt; 'bot',				'title' =&gt; $page,				'text' =&gt; $data,				'token' =&gt; $this-&gt;getedittoken,				'summary' =&gt; $summary,				($minor?'minor':'notminor') =&gt; '1',				($bot?'bot':'notbot') =&gt; '1'			);

if ($wpStarttime !== null) $params['starttimestamp'] = $wpStarttime; if ($wpEdittime !== null) $params['basetimestamp'] = $wpEdittime;

$x = $this-&gt;http-&gt;post($this-&gt;apiurl,$params); $x = unserialize($x); var_export($x); if ($x['edit']['result'] == 'Success') return true; if ($x['error']['code'] == 'badtoken') { if($this-&gt;login($this-&gt;user,$this-&gt;pass)) { $this-&gt;gettokens('Main Page',true); return $this-&gt;edit($page,$data,$summary,$minor,$bot,$wpStarttime,$wpEdittime,$checkrun); } else return false; }			else return false; }

/**		 * Moves a page. * @param $old Name of page to move. * @param $new New page title. * @param $reason Move summary to use. * @return void **/		function move ($old,$new,$reason) { $tokens = $this-&gt;gettokens($old); $params = array(				'action' =&gt; 'move',				'format' =&gt; 'php',				'from' =&gt; $old,				'to' =&gt; $new,				'token' =&gt; $tokens['movetoken'],				'reason' =&gt; $reason			);

$x = $this-&gt;http-&gt;post($this-&gt;apiurl,$params); $x = unserialize($x); var_export($x); }

/**		 * Rollback an edit. * @param $title Title of page to rollback. * @param $user Username of last edit to the page to rollback. * @param $reason Edit summary to use for rollback. * @param $token Rollback token. If not given, it will be fetched. (Default null) * @return void **/		function rollback ($title,$user,$reason,$token = null) { if (($token == null) or ($token == '')) { $token = $this-&gt;revisions($title,1,'older',false,null,true,true); print_r($token); if ($token[0]['user'] == $user) { $token = $token[0]['rollbacktoken']; } else { return false; }			}			$params = array(				'action' =&gt; 'rollback',				'format' =&gt; 'php',				'title' =&gt; $title,				'user' =&gt; $user,				'summary' =&gt; $reason,				'token' =&gt; $token,				'markbot' =&gt; 0			);

echo 'Posting to API: '; var_export($params); $x = $this-&gt;http-&gt;post($this-&gt;apiurl,$params); $x = unserialize($x); var_export($x); return ( isset($x['rollback']['summary']) and isset( $x[ 'rollback' ][ 'revid' ] ) and $x[ 'rollback' ][ 'revid' ] ) ? true : false; }	}

/**	 * This class is for interacting with Wikipedia's browser interface, index.php. * Many of these functions are deprecated. **/	class wikipediaindex { private $http; public $indexurl = 'http://en.wikipedia.org/w/index.php'; private $postinterval = 0; private $lastpost; private $edittoken;

/**		 * This is our constructor. * @return void **/		function __construct { global $__wp__http; if (!isset($__wp__http)) { $__wp__http = new http; }			$this-&gt;http = &amp;$__wp__http; }

/**		 * Post data to a page, nicely. * @param $page Page title. * @param $data Data to post to page. * @param $summery Edit summary. (Default '') * @param $minor Whether to mark edit as minor. (Default false) * @param $rv Revision data. If not given, it will be fetched. (Default null) * @param $bot Whether to mark edit as bot. (Default true) * @return HTML data from the page. * @deprecated * @see wikipediaapi::edit **/		function post ($page,$data,$summery = '',$minor = false,$rv = null,$bot = true) { global $user; global $maxlag; global $irc; global $irctechchannel; global $run; global $maxlagkeepgoing;

$wpq = new wikipediaquery; $wpq-&gt;queryurl = str_replace('index.php','query.php',$this-&gt;indexurl); $wpapi = new wikipediaapi; $wpapi-&gt;apiurl = str_replace('index.php','api.php',$this-&gt;indexurl);

if ((!$this-&gt;edittoken) or ($this-&gt;edittoken == '')) $this-&gt;edittoken = $wpapi-&gt;getedittoken; if ($rv == null) $rv = $wpapi-&gt;revisions($page,1,'older',true); if (!$rv[0]['*']) $rv[0]['*'] = $wpq-&gt;getpage($page);

//Fake the edit form. $now = gmdate('YmdHis', time); $token = htmlspecialchars($this-&gt;edittoken); $tmp = date_parse($rv[0]['timestamp']); $edittime = gmdate('YmdHis', gmmktime($tmp['hour'],$tmp['minute'],$tmp['second'],$tmp['month'],$tmp['day'],$tmp['year'])); $html = &quot;&lt;input type='hidden' value=\&quot;{$now}\&quot; name=\&quot;wpStarttime\&quot; /&gt;\n&quot;; $html.= &quot;&lt;input type='hidden' value=\&quot;{$edittime}\&quot; name=\&quot;wpEdittime\&quot; /&gt;\n&quot;; $html.= &quot;&lt;input type='hidden' value=\&quot;{$token}\&quot; name=\&quot;wpEditToken\&quot; /&gt;\n&quot;; $html.= '&lt;input name=&quot;wpAutoSummary&quot; type=&quot;hidden&quot; value=&quot;'.md5('').'&quot; /&gt;'.&quot;\n&quot;;

if (preg_match('/'.preg_quote('','/').'/iS',$rv[0]['*'])) { return false; }		/* Honor the bots flags */ if (preg_match('/'.preg_quote('','/').'/iS',$rv[0]['*'])) { return false; } if (preg_match('/'.preg_quote('','/').'/iS',$rv[0]['*'])) { return false; } if (preg_match('/'.preg_quote('','/').'/iS',$rv[0]['*'],$m)) { if (in_array(explode(',',$m[1]),$user)) { return false; } } /* /Honor the bots flags */ if (!preg_match('/'.preg_quote($user,'/').'/iS',$rv['currentuser'])) { return false; } /* We need to be logged in */ //			if (preg_match('/'.preg_quote('You have new messages','/').'/iS',$rv[0]['*'])) { return false; } /* Check talk page */ if (!preg_match('/(yes|enable|true)/iS',((isset($run))?$run:$wpq-&gt;getpage('User:'.$user.'/Run')))) { return false; } /* Check /Run page */

$x = $this-&gt;forcepost($page,$data,$summery,$minor,$html,$maxlag,$maxlagkeepgoing,$bot); /* Go ahead and post. */			$this-&gt;lastpost = time; return $x; }

/**		 * Post data to a page. * @param $page Page title. * @param $data Data to post to page. * @param $summery Edit summary. (Default '') * @param $minor Whether to mark edit as minor. (Default false) * @param $edithtml HTML from the edit form. If not given, it will be fetched. (Default null) * @param $maxlag Maxlag for posting. (Default null) * @param $mlkg Whether to keep going after encountering a maxlag error and sleeping or not. (Default null) * @param $bot Whether to mark edit as bot. (Default true) * @return HTML data from the page. * @deprecated * @see wikipediaapi::edit **/		function forcepost ($page,$data,$summery = '',$minor = false,$edithtml = null,$maxlag = null,$mlkg = null,$bot = true) { $post['wpSection'] = ''; $post['wpScrolltop'] = ''; if ($minor == true) { $post['wpMinoredit'] = 1; } $post['wpTextbox1'] = $data; $post['wpSummary'] = $summery; if ($edithtml == null) { $html = $this-&gt;http-&gt;get($this-&gt;indexurl.'?title='.urlencode($page).'&amp;action=edit'); } else { $html = $edithtml; }			preg_match('|\&lt;input type\=\\\'hidden\\\' value\=\&quot;(.*)\&quot; name\=\&quot;wpStarttime\&quot; /\&gt;|U',$html,$m); $post['wpStarttime'] = $m[1]; preg_match('|\&lt;input type\=\\\'hidden\\\' value\=\&quot;(.*)\&quot; name\=\&quot;wpEdittime\&quot; /\&gt;|U',$html,$m); $post['wpEdittime'] = $m[1]; preg_match('|\&lt;input type\=\\\'hidden\\\' value\=\&quot;(.*)\&quot; name\=\&quot;wpEditToken\&quot; /\&gt;|U',$html,$m); $post['wpEditToken'] = $m[1]; preg_match('|\&lt;input name\=\&quot;wpAutoSummary\&quot; type\=\&quot;hidden\&quot; value\=\&quot;(.*)\&quot; /\&gt;|U',$html,$m); $post['wpAutoSummary'] = $m[1]; if ($maxlag != null) { $x = $this-&gt;http-&gt;post($this-&gt;indexurl.'?title='.urlencode($page).'&amp;action=submit&amp;maxlag='.urlencode($maxlag).'&amp;bot='.(($bot == true)?'1':'0'),$post); if (preg_match('/Waiting for ([^ ]*): ([0-9.-]+) seconds lagged/S',$x,$lagged)) { global $irc; if (is_resource($irc)) { global $irctechchannel; foreach(explode(',',$irctechchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :'.$lagged[1].' is lagged out by '.$lagged[2].' seconds. ('.$lagged[0].')'.&quot;\n&quot;); }					}					sleep(10); if ($mlkg != true) { return false; } else { $x = $this-&gt;http-&gt;post($this-&gt;indexurl.'?title='.urlencode($page).'&amp;action=submit&amp;bot='.(($bot == true)?'1':'0'),$post); } }				return $x; } else { return $this-&gt;http-&gt;post($this-&gt;indexurl.'?title='.urlencode($page).'&amp;action=submit&amp;bot='.(($bot == true)?'1':'0'),$post); }		}

/**		 * Get a diff. * @param $title Page title to get the diff of. * @param $oldid Old revision ID. * @param $id New revision ID. * @param $wait Whether or not to wait for the diff to become available. (Default true) * @return Array of added data, removed data, and a rollback token if one was fetchable. **/		function diff ($title,$oldid,$id,$wait = true) { $deleted = ''; $added = '';

$html = $this-&gt;http-&gt;get($this-&gt;indexurl.'?title='.urlencode($title).'&amp;action=render&amp;diff='.urlencode($id).'&amp;oldid='.urlencode($oldid).'&amp;diffonly=1');

if (preg_match_all('/\&amp;amp\;(oldid\=)(\d*)\\\'\&gt;(Revision as of|Current revision as of)/USs', $html, $m, PREG_SET_ORDER)) { //print_r($m); if ((($oldid != $m[0][2]) and (is_numeric($oldid))) or (($id != $m[1][2]) and (is_numeric($id)))) { if ($wait == true) { sleep(1); return $this-&gt;diff($title,$oldid,$id,false); } else { echo 'OLDID as detected: '.$m[0][2].' Wanted: '.$oldid.&quot;\n&quot;; echo 'NEWID as detected: '.$m[1][2].' Wanted: '.$id.&quot;\n&quot;; echo $html; die('Revision error.'.&quot;\n&quot;); }				}			}			if (preg_match_all('/\&lt;td class\=(\&quot;|\\\')diff-addedline\1\&gt;\&lt;div\&gt;(.*)\&lt;\/div\&gt;\&lt;\/td\&gt;/USs', $html, $m, PREG_SET_ORDER)) { //print_r($m); foreach ($m as $x) { $added .= htmlspecialchars_decode(strip_tags($x[2])).&quot;\n&quot;; }			}

if (preg_match_all('/\&lt;td class\=(\&quot;|\\\')diff-deletedline\1\&gt;\&lt;div\&gt;(.*)\&lt;\/div\&gt;\&lt;\/td\&gt;/USs', $html, $m, PREG_SET_ORDER)) { //print_r($m); foreach ($m as $x) { $deleted .= htmlspecialchars_decode(strip_tags($x[2])).&quot;\n&quot;; }			}

//echo $added.&quot;\n&quot;.$deleted.&quot;\n&quot;;

if (preg_match('/action\=rollback\&amp;amp\;from\=.*\&amp;amp\;token\=(.*)\&quot;/US', $html, $m)) { $rbtoken = $m[1]; $rbtoken = urldecode($rbtoken); //				echo 'rbtoken: '.$rbtoken.' -- '; print_r($m); echo &quot;\n\n&quot;; return array($added,$deleted,$rbtoken); }

return array($added,$deleted); }

/**		 * Rollback an edit. * @param $title Page title to rollback. * @param $user Username of last edit to the page to rollback. * @param $reason Reason to rollback. If null, default is generated. (Default null) * @param $token Rollback token to use. If null, it is fetched. (Default null) * @param $bot Whether or not to mark as bot. (Default true) * @return HTML or false if failure. * @deprecated * @see wikipediaapi::rollback **/		function rollback ($title,$user,$reason = null,$token = null,$bot = true) { if (($token == null) or (!$token)) { $wpapi = new wikipediaapi; $wpapi-&gt;apiurl = str_replace('index.php','api.php',$this-&gt;indexurl); $token = $wpapi-&gt;revisions($title,1,'older',false,null,true,true); if ($token[0]['user'] == $user) { //					echo 'Token: '; print_r($token); echo &quot;\n\n&quot;; $token = $token[0]['rollbacktoken']; } else { return false; }			}			$x = $this-&gt;http-&gt;get($this-&gt;indexurl.'?title='.urlencode($title).'&amp;action=rollback&amp;from='.urlencode($user).'&amp;token='.urlencode($token).(($reason != null)?'&amp;summary='.urlencode($reason):'').'&amp;bot='.(($bot == true)?'1':'0')); global $logfd; if (!is_resource($logfd)) $logfd = fopen('php://stderr','w'); fwrite($logfd,'Rollback return: '.$x.&quot;\n&quot;); if (!preg_match('/action complete/iS',$x)) return false; return $x; }

/**		 * Move a page. * @param $old Page title to move. * @param $new New title to move to. * @param $reason Move page summary. * @return HTML page. * @deprecated * @see wikipediaapi::move **/		function move ($old,$new,$reason) { $wpapi = new wikipediaapi; $wpapi-&gt;apiurl = str_replace('index.php','api.php',$this-&gt;indexurl); if ((!$this-&gt;edittoken) or ($this-&gt;edittoken == '')) $this-&gt;edittoken = $wpapi-&gt;getedittoken;

$token = htmlspecialchars($this-&gt;edittoken);

$post = array (					'wpOldTitle'	=&gt; $old,					'wpNewTitle'	=&gt; $new,					'wpReason'	=&gt; $reason,					'wpWatch'	=&gt; '0',					'wpEditToken'	=&gt; $token,					'wpMove'	=&gt; 'Move page'				); return $this-&gt;http-&gt;post($this-&gt;indexurl.'?title=Special:Movepage&amp;action=submit',$post); }

/**		 * Uploads a file. * @param $page Name of page on the wiki to upload as. * @param $file Name of local file to upload. * @param $desc Content of the file description page. * @return HTML content. **/		function upload ($page,$file,$desc) { $post = array (					'wpUploadFile'		=&gt; '@'.$file,					'wpSourceType'		=&gt; 'file',					'wpDestFile'		=&gt; $page,					'wpUploadDescription'	=&gt; $desc,					'wpLicense'		=&gt; '',					'wpWatchthis'		=&gt; '0',					'wpIgnoreWarning'	=&gt; '1',					'wpUpload'		=&gt; 'Upload file'				); return $this-&gt;http-&gt;post($this-&gt;indexurl.'?title=Special:Upload&amp;action=submit',$post); }

/**		 * Check if a user has email enabled. * @param $user Username to check whether or not the user has email enabled. * @return True or false depending on whether or not the user has email enabled. **/		function hasemail ($user) { $tmp = $this-&gt;http-&gt;get($this-&gt;indexurl.'?title=Special:EmailUser&amp;target='.urlencode($user)); if (stripos($tmp,&quot;No e-mail address&quot;) !== false) return false; return true; }

/**		 * Sends an email to a user. * @param $user Username to send email to. * @param $subject Subject of email to send. * @param $body Body of email to send. * @return HTML content. **/		function email ($user,$subject,$body) { $wpapi = new wikipediaapi; $wpapi-&gt;apiurl = str_replace('index.php','api.php',$this-&gt;indexurl); if ((!$this-&gt;edittoken) or ($this-&gt;edittoken == '')) $this-&gt;edittoken = $wpapi-&gt;getedittoken;

$post = array (					'wpSubject'	=&gt; $subject,					'wpText'	=&gt; $body,					'wpCCMe'	=&gt; 0,					'wpSend'	=&gt; 'Send',					'wpEditToken'	=&gt; $this-&gt;edittoken				);

return $this-&gt;http-&gt;post($this-&gt;indexurl.'?title=Special:EmailUser&amp;target='.urlencode($user).'&amp;action=submit',$post); }	} ?&gt;

Diff function (diff.function.php)
&lt;?PHP function diff ($old,$new,$nret = true,$inline = false) { //		if ($inline) { //			return str_replace(array(&quot;\n&quot;,chr(92).chr(92),'\n'),array(' ',chr(92),&quot;\n&quot;),diff(implode(&quot;\n&quot;,explode(' ',str_replace(array(chr(92),&quot;\n&quot;),array(chr(92).chr(92),'\n'),$old))),implode(&quot;\n&quot;,explode(' ',str_replace(array(chr(92),&quot;\n&quot;),array(chr(92).chr(92),'\n'),$new))),$nret,false)); //		}		$file1 = tempnam('/tmp','diff_'); $file2 = tempnam('/tmp','diff_'); file_put_contents($file1,$old); file_put_contents($file2,$new); $out = array; if ($inline) { //			echo 'EXEC: wdiff -3'.(($nret)?'1':'2').' '.escapeshellarg($file1).' '.escapeshellarg($file2).&quot;\n&quot;; @exec('wdiff -3'.(($nret)?'1':'2').' '.escapeshellarg($file1).' '.escapeshellarg($file2),$out); foreach ($out as $key =&gt; $line) { if ($line == '======================================================================') unset($out[$key]); elseif ($nret) $out[$key] = '&gt; '.$line; else $out[$key] = '&lt; '.$line; }		} else { @exec('diff -d --suppress-common-lines '.escapeshellarg($file1).' '.escapeshellarg($file2),$out); }		$out2 = array; foreach ($out as $line) { if (				( ($nret) and (preg_match('/^\&gt; .*$/',$line)) )				or ( (!$nret) and (preg_match('/^\&lt; .*$/',$line)) )			) {				$out2[] = substr($line,2); }		}		$out = $out2; unset($out2); unlink($file1); unlink($file2); return implode(&quot;\n&quot;,$out); } ?&gt;

Source to ClueBot
&lt;?PHP declare(ticks = 1);

function sig_handler($signo) { switch ($signo) { case SIGCHLD: while (($x = pcntl_waitpid(0, $status, WNOHANG)) != -1) { if ($x == 0) break; $status = pcntl_wexitstatus($status); }				break; }	}

pcntl_signal(SIGCHLD,  &quot;sig_handler&quot;);

function score ($list,$data,&amp;$matches = null) { $ret = 0; foreach ($list as $preg =&gt; $pts) { if ($x = preg_match_all($preg.'S',$data,$m)) { //				echo $x.'*'.$pts.' ('.$preg.')'.&quot;\n&quot;; $matches[$preg] = $x; $ret += $pts * $x; }		} //		echo 'Score: '.$ret.&quot;\n&quot;; return $ret; }

function myfnmatch ($pattern,$string) { if (strlen($string) &lt; 4000) { return fnmatch($pattern,$string); } else { $pattern = strtr(preg_quote($pattern, '#'), array('\*' =&gt; '.*', '\?' =&gt; '.', '\[' =&gt; '[', '\]' =&gt; ']')); if (preg_match('#^'.$pattern.'$#',$string)) return true; return false; }	}

include '../diff.function.php'; /* The diff function. */	include '../wikibot.classes.php'; /* The wikipedia classes. */	include 'cluebot.config.php'; /* This file is very simple, but it contains sensitive information, we just define $user, $ircserver, $ircport, $ircchannel, $pass, $owner, and $status. */	include 'cluebot.scorelist.php'; /* This file is uploaded as well as the main file. */

$wpapi	= new wikipediaapi; $wpq	= new wikipediaquery; $wpi	= new wikipediaindex; var_export($wpapi-&gt;login($user,$pass));

$mysql = mysql_pconnect($mysqlhost.':'.$mysqlport,$mysqluser,$mysqlpass); if (!$mysql) { die('Could not connect: ' . mysql_error); } if (!mysql_select_db($mysqldb, $mysql)) { die ('Can\'t use database : ' . mysql_error); }

$ircconfig = explode(&quot;\n&quot;,$wpq-&gt;getpage('User:'.$owner.'/CBChannels.js')); $tmp = array; foreach($ircconfig as $tmpline) { if (substr($tmpline,0,1) != '#') { $tmpline = explode('=',$tmpline,2); $tmp[trim($tmpline[0])] = trim($tmpline[1]); } }

$ircchannel = $tmp['ircchannel']; $ircdebugchannel = $tmp['ircdebugchannel']; $ircreportchannel = $tmp['ircreportchannel']; $ircvandalismchannel = $tmp['ircvandalismchannel']; $ircaivchannel = $tmp['ircaivchannel']; $irctechchannel = $tmp['irctechchannel']; $ircproxychannels = $tmp['ircproxychannels']; $ircunrevertedchannels = $tmp['ircunrevertedchannels']; $ircbagtrialchannels = $tmp['ircbagtrialchannels']; $ircotherchannels = $tmp['ircotherchannels'];

unset($tmp,$tmpline);

$stalkbots = array; $trialbots = explode(&quot;\n&quot;,$wpq-&gt;getpage('Wikipedia:Bots/Requests for approval')); foreach ($trialbots as $trialbot) if (preg_match('/\{\{BRFA\|(.*)\|.*\|Trial\}\}/',str_replace(array(&quot;\n&quot;,&quot;\r&quot;),'',$trialbot),$m)) $stalkbots[$m[1]] = 1;

$irc = fsockopen($ircserver,$ircport,$ircerrno,$ircerrstr,15); $ircpid = pcntl_fork; if ($ircpid == 0) { fwrite($irc,'PASS '.$ircpass.&quot;\n&quot;); fwrite($irc,'USER '.$user.' &quot;1&quot; &quot;1&quot; :ClueBot Wikipedia Bot.'.&quot;\n&quot;); fwrite($irc,'NICK '.$user.&quot;\n&quot;); while (!feof($irc)) { $data = str_replace(array(&quot;\n&quot;,&quot;\r&quot;),'',fgets($irc,1024)); //			echo 'IRC: '.$data.&quot;\n&quot;; $d = explode(' ',$data); if (strtolower($d[0]) == 'ping') { fwrite($irc,'PONG '.$d[1].&quot;\n&quot;); } elseif (($d[1] == '376') or ($d[1] == '422')) { //				fwrite($irc,'PRIVMSG NickServ :identify '.$pass.&quot;\n&quot;); //				sleep(2); fwrite($irc,'JOIN '.$ircchannel.','.$ircdebugchannel.','.$ircreportchannel.','.$ircvandalismchannel.','.$ircaivchannel.','.$irctechchannel.','.$ircproxychannels.','.$ircunrevertedchannels.','.$ircbagtrialchannels.','.$ircotherchannels.&quot;\n&quot;); foreach (explode(',',$ircchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :IRC logging enabled.'.&quot;\n&quot;); }			} elseif (strtolower($d[1]) == 'privmsg') { if (substr($d[3],0,2) == ':!') { if (strtolower($d[2]) == '#wikipedia-en') { $tmp = explode('!',substr($d[0],1)); $cmd = 'NOTICE '.$tmp[0]; } elseif (strtolower($d[2]) == strtolower($user)) { $tmp = explode('!',substr($d[0],1)); $cmd = 'NOTICE '.$tmp[0]; } else { $cmd = 'PRIVMSG '.$d[2]; } switch (substr(strtolower($d[3]),2)) { case 'edit': if (preg_match(&quot;/\[\[(.*)\]\]/&quot;,$data,$m)) { $rv = $wpapi-&gt;revisions($m[1],1,'older'); fwrite($irc,$cmd.' :'.$m[1].' http://en.wikipedia.org/w/index.php?title='.urlencode($m[1]).'&amp;diff=prev' .									'&amp;oldid='.urlencode($rv[0]['revid']).' * '.$rv[0]['user'].' * '.$rv[0]['comment'].&quot;\n&quot;); } else { fwrite($irc,$cmd.' :Couldn\'t find link.'.&quot;\n&quot;); }							break; case 'stalk': if (preg_match(&quot;/\[\[User:(.*)\]\]/&quot;,$data,$m)) { $uc = $wpapi-&gt;usercontribs($m[1],1); fwrite($irc,$cmd.' :'.$uc[0]['title'].' http://en.wikipedia.org/w/index.php?title='.urlencode($uc[0]['title']).'&amp;diff=prev' .									'&amp;oldid='.urlencode($uc[0]['revid']).' * '.$m[1].' * '.$uc[0]['comment'].&quot;\n&quot;); } else { fwrite($irc,$cmd.' :Couldn\'t find link.'.&quot;\n&quot;); }							break; case 'beaten': if (preg_match(&quot;/\[\[User:(.*)\]\]/&quot;,$data,$m)) { if (!mysql_ping($mysql)) { $mysql = mysql_pconnect($mysqlhost.':'.$mysqlport,$mysqluser,$mysqlpass); mysql_select_db($mysqldb, $mysql); } $x = mysql_fetch_assoc(mysql_query('SELECT COUNT(`id`) AS `count` FROM `beaten` WHERE `user` = \''.mysql_real_escape_string($m[1]).'\' GROUP BY `user`')); $y = mysql_fetch_assoc(mysql_query('SELECT SQL_CALC_FOUND_ROWS COUNT(`id`) AS `count2` FROM `beaten` GROUP BY `user` HAVING `count2` &gt; \''.mysql_real_escape_string($x['count']).'\' LIMIT 1')); $z = mysql_fetch_assoc(mysql_query('SELECT FOUND_ROWS as `ahead`')); fwrite($irc,$cmd.' :User:'.$m[1].' has beaten me '.(($x['count'] != '')?$x['count']:'0').' times. There are '.$z['ahead'].' users who have beaten me more times.'.&quot;\n&quot;); unset($x,$y); } else { fwrite($irc,$cmd.' :Couldn\'t find link.'.&quot;\n&quot;); }							break; case 'vandalcount': if (preg_match(&quot;/\[\[(.*)\]\]/&quot;,$data,$m)) { $tmp = unserialize(file_get_contents('oftenvandalized.txt')); if (isset($tmp[$m[1]])) { fwrite($irc,$cmd.' :'.$m[1].' has been vandalized '.count($tmp[$m[1]]).' time(s) in the last 48 hours.'.&quot;\n&quot;); } else { fwrite($irc,$cmd.' :'.$m[1].' has not been vandalized in the last 48 hours.'.&quot;\n&quot;); }							} else { fwrite($irc,$cmd.' :Couldn\'t find link.'.&quot;\n&quot;); }							break; case 'heuristics': include 'cluebot.heuristics.config.php'; $stats = unserialize(file_get_contents('cluebot.heuristics.stats.txt')); fwrite($irc,$cmd.' :I have the following heuristics enabled: '.implode(', ',$heuristics).&quot;.\n&quot;); foreach ($stats as $heuristic =&gt; $count) { fwrite($irc,$cmd.' :The '.$heuristic.' heuristic has been matched '.$count.' times.'.&quot;\n&quot;); }							unset($count,$heuristic,$stats,$heuristics); break; case 'status': $ov = unserialize(file_get_contents('oftenvandalized.txt')); foreach ($ov as $title =&gt; $array) { if (count($array) == 0) unset($ov[$title]); }							file_put_contents('oftenvandalized.txt',serialize($ov)); $count = count($ov);

$titles = unserialize(file_get_contents('titles.txt')); foreach ($titles as $title =&gt; $time) { if ((time - $time) &gt; (24*60*60)) { unset($titles[$title]); }							}							file_put_contents('titles.txt',serialize($titles)); $tcount = count($titles);

foreach ($ov as $x =&gt; $y) { $ocount[$x] = count($y); }							arsort($ocount); foreach ($ocount as $x =&gt; $y) { $mova = $x; $movacount = $y; break; }

preg_match('/\(\'\'\'\[\[([^|]*)\|more...\]\]\'\'\'\)/iU',$wpq-&gt;getpage('Wikipedia:Today\'s featured article/'.date('F j, Y')),$tfa); $tfa = $tfa[1]; if (!preg_match('/(yes|enable|true)/i',$wpq-&gt;getpage('User:'.$user.'/Run'))) { $run = false; } else { $run = true; }

$top5beat = array;

if (!mysql_ping($mysql)) { $mysql = mysql_pconnect($mysqlhost.':'.$mysqlport,$mysqluser,$mysqlpass); mysql_select_db($mysqldb, $mysql); } $q = mysql_query('SELECT `user`,COUNT(`id`) AS `count` FROM `cluebot_enwiki`.`beaten` WHERE `user` != \'\' GROUP BY `user` HAVING `count` &gt; 1 ORDER BY `count` DESC LIMIT 5'); while ($x = mysql_fetch_assoc($q)) { $top5beat[] = $x['user'].' ('.$x['count'].')'; }							unset($x,$q); $top5beat = implode(' - ',$top5beat);

fwrite($irc,$cmd.' :I am '.$user.'. I am currently '.($run?'enabled':'disabled').'.  I currently have '.$wpq-&gt;contribcount($user).' contributions.'.&quot;\n&quot;);

fwrite($irc,$cmd.' :I have attempted to revert '.$tcount.' unique article/user combinations in the last 24 hours. ' .								'I know of '.$count.' different articles that have been vandalized in the last 48 hours.'.&quot;\n&quot;								);

fwrite($irc,$cmd.' :'.$mova.' is the most vandalized page with a total of '.$movacount.' vandalisms in the last 48 hours. ' .								'Today\'s featured article is: '.$tfa.'.'.&quot;\n&quot;								);

fwrite($irc,$cmd.' :The following users have beat me to the revert the most: '.$top5beat.&quot;\n&quot;);

fwrite($irc,$cmd.' :I log all information to '.$ircchannel.'. This channel is '.$d[2].'.'.&quot;\n&quot;);

unset($x,$y,$count,$ov,$tcount,$ocount,$mova,$movacount,$tfa,$run,$title,$titles,$time,$top5beat); break; case 'warninglevel': if (preg_match(&quot;/\[\[User:(.*)\]\]/&quot;,$data,$n)) { $warning = 0; if (preg_match_all('/&lt;!-- Template:(uw-[a-z]*(\d)(im)?|Blatantvandal \(serious warning\)) --&gt;.*(\d{2}):(\d{2}), (\d+) ([a-zA-Z]+) (\d{4}) \(UTC\)/iU', $wpq-&gt;getpage('User talk:'.$n[1]), $match,PREG_SET_ORDER)								) { foreach ($match as $m) { $month = array('January' =&gt; 1, 'February' =&gt; 2, 'March' =&gt; 3,											'April' =&gt; 4, 'May' =&gt; 5, 'June' =&gt; 6, 'July' =&gt; 7,											'August' =&gt; 8, 'September' =&gt; 9, 'October' =&gt; 10,											'November' =&gt; 11, 'December' =&gt; 12										); if ($m[1] == 'Blatantvandal (serious warning)') $m[2] = 4; if ((time - gmmktime($m[4],$m[5],0,$month[$m[7]],$m[6],$m[8])) &lt;= (2*24*60*60)) { if ($m[2] &gt; $warning) { $warning = $m[2]; } }									}								}								fwrite($irc,$cmd.' :User:'.$n[1].' is at warning level '.$warning.&quot;.\n&quot;); } else { fwrite($irc,$cmd.' :Couldn\'t find link.'.&quot;\n&quot;); }							break; case 'count': if (preg_match(&quot;/\[\[User:(.*)\]\]/&quot;,$data,$n)) { fwrite($irc,$cmd.' :User:'.$n[1].' has '.$wpq-&gt;contribcount($n[1]).&quot; contributions.\n&quot;); } else { fwrite($irc,$cmd.' :Couldn\'t find link.'.&quot;\n&quot;); }							break; case 'help': fwrite($irc,$cmd.' :Please see User:'.$user.'.'.&quot;\n&quot;); break; case 'eval': $tmp = explode(' ',$data,6); $tmp1 = explode('!',substr($d[0],1)); if ($d[4] == md5($thesecret.$tmp1[0].$tmp[5])) { eval($tmp[5]); } else { fwrite($irc,$cmd.' :Code incorrect.'.&quot;\n&quot;); }							break; case 'cbproxy': $tmp = explode(' ',$data,6); $tmp1 = explode('!',substr($d[0],1)); if ($tmp1[0] == 'ClueBot-Bopm') { foreach (explode(',',$ircproxychannels) as $y) { fwrite($irc,'PRIVMSG '.$y.' :!admin '.$tmp[5].&quot;\n&quot;); }								$data = $wpq-&gt;getpage('Wikipedia:WikiProject on open proxies'); if (strpos($data,$tmp[4]) === false) { $header = explode(' || Example',$data,2); $header[0] .= ' || Example '; $footer = $header[1]; $header = $header[0]; $data = &quot;\n&quot;.' || '.$tmp[5].' ~'.&quot;\n&quot;; $data = $header.$data.$footer; unset($header,$footer); $wpapi-&gt;edit('Wikipedia:WikiProject on open proxies',$data,'Adding '.$tmp[4].'.'); unset($data); }							}							break; }				}			}		}		die; }

$heuristics = &quot;==Heuristics==\n\n===Config (cluebot.heuristics.config.php)===\n\n&lt;pre&gt;&quot;.htmlentities(file_get_contents('cluebot.heuristics.config.php')).&quot;&lt;/pre&gt;\n\n&quot;; foreach (glob('heuristics/cluebot.*.heuristic.php') as $heuristic) $heuristics .= '==='.$heuristic.&quot;===\n\n&lt;pre&gt;&quot;.htmlentities(file_get_contents($heuristic)).&quot;&lt;/pre&gt;\n\n&quot;; unset($heuristic);

$wpapi-&gt;edit('User:'.$user.'/Source',		'The following is automatically generated by '.$user.&quot;.\n\n\n\n==Classes (wikibot.classes.php)==\n\n&lt;pre&gt;&quot; .		htmlentities(file_get_contents('../wikibot.classes.php')).&quot;&lt;/pre&gt;\n\n\n\n==Diff function (diff.function.php)==\n\n&lt;pre&gt;&quot; .		htmlentities(file_get_contents('../diff.function.php')).&quot;&lt;/pre&gt;\n\n\n\n==Source to &quot;.$user .		&quot;==\n\n&quot;.'&lt;pre&gt;'.htmlentities(file_get_contents(__FILE__)).&quot;&lt;/pre&gt;\n\n\n\n&quot; .		$heuristics .		&quot;==Score list==\n\n&quot;.'&lt;pre&gt;'.htmlentities(file_get_contents('cluebot.scorelist.php')).&quot;&lt;/pre&gt;\n\n\n\n~&quot;,		'Automated source upload.'); /* Our source code, we force post this because this is *our* page, and it triggers the nobots. */

unset($heuristics);

$wpapi-&gt;edit('User:'.$user,		&quot;\n&quot;,		'Automated bot userpage set.'); /* Our page, we force post this because this is *our* page. */

$tfas = 0; $pipe = fopen('thepipe','w'); $stdin = fopen('php://stdin','r'); $run = $wpq-&gt;getpage('User:'.$user.'/Run'); $wl = $wpq-&gt;getpage('User:'.$user.'/Whitelist'); $optin = $wpq-&gt;getpage('User:'.$user.'/Optin'); $aoptin = $wpq-&gt;getpage('User:'.$user.'/AngryOptin');

unset($tmp,$tmp2,$tmp3);

$tmp = explode(&quot;\n&quot;,$wpq-&gt;getpage('User:'.$owner.'/CBAutostalk.js')); foreach ($tmp as $tmp2) { if (substr($tmp2,0,1) != '#') { $tmp3 = explode('|',$tmp2,2); $stalk[$tmp3[0]] = trim($tmp3[1]); } } $tmp = explode(&quot;\n&quot;,$wpq-&gt;getpage('User:'.$owner.'/CBAutoedit.js')); foreach ($tmp as $tmp2) { if (substr($tmp2,0,1) != '#') { $tmp3 = explode('|',$tmp2,2); $edit[$tmp3[0]] = trim($tmp3[1]); } } unset($tmp,$tmp2,$tmp3);

print_r($stalk); print_r($edit);

while (1) { $feed = fsockopen($feedhost,$feedport,$feederrno,$feederrstr,30);

if (!$feed) { sleep(10); $feed = fsockopen($feedhost,$feedport,$feederrno,$feederrstr,30); if (!$feed) die($feederrstr.' ('.$feederrno.')'); }

fwrite($feed,'USER '.$user.' &quot;1&quot; &quot;1&quot; :ClueBot Wikipedia Bot.'.&quot;\n&quot;); fwrite($feed,'NICK '.$user.&quot;\n&quot;);

while (!feof($feed)) { $rawline = fgets($feed,1024); $line = str_replace(array(&quot;\n&quot;,&quot;\r&quot;,&quot;\002&quot;),'',$rawline); $line = preg_replace('/\003(\d\d?(,\d\d?)?)?/','',$line); //			echo 'FEED: '.$line.&quot;\n&quot;; if (!$line) { fclose($feed); break; } $linea= explode(' ',$line,4);

if (strtolower($linea[0]) == 'ping') { fwrite($feed,'PONG '.$linea[1].&quot;\n&quot;); } elseif (($linea[1] == '376') or ($linea[1] == '422')) { fwrite($feed,'JOIN '.$feedchannel.&quot;\n&quot;); } elseif ((strtolower($linea[1]) == 'privmsg') and (strtolower($linea[2]) == strtolower($feedchannel))) { $message = substr($linea[3],1); if (preg_match('/^\[\[((Talk|User|Wikipedia|Image|MediaWiki|Template|Help|Category|Portal|Special)(( |_)talk)?:)?([^\x5d]*)\]\] (\S*) (http:\/\/en\.wikipedia\.org\/w\/index\.php\?diff=(\d*)&amp;oldid=(\d*).*|http:\/\/en\.wikipedia\.org\/wiki\/\S+)? \* ([^*]*) \* (\(([^)]*)\))? (.*)$/S',$message,$m)) {					$messagereceived = microtime(1);					$change['namespace'] = $m[1];					$change['title'] = $m[5];					$change['flags'] = $m[6];					$change['url'] = $m[7];					$change['revid'] = $m[8];					$change['old_revid'] = $m[9];					$change['user'] = $m[10];					$change['length'] = $m[12];					$change['comment'] = $m[13];

//					include 'cluebot.stalk.config.php';

$stalkchannel = array; foreach ($stalk as $key =&gt; $value) if (myfnmatch(str_replace('_',' ',$key),str_replace('_',' ',$change['user']))) $stalkchannel = array_merge($stalkchannel,explode(',',$value)); foreach ($stalkbots as $key =&gt; $value) if (myfnmatch(str_replace('_',' ',$key),str_replace('_',' ',$change['user']))) $stalkchannel = array_merge($stalkchannel,explode(',',$ircbagtrialchannels)); foreach ($edit as $key =&gt; $value) if (myfnmatch(str_replace('_',' ',$key),str_replace('_',' ',$change['namespace'].$change['title']))) $stalkchannel = array_merge($stalkchannel,explode(',',$value)); //					if ($change['user'] == $owner) $stalkchannel[] = $ircchannel;

$stalkchannel = array_unique($stalkchannel);

foreach ($stalkchannel as $y) { fwrite($irc,'PRIVMSG '.$y.' :New edit: '.$change['namespace'].$change['title'].' http://en.wikipedia.org/w/index.php?title=' .							urlencode($change['namespace'].$change['title']).'&amp;diff=prev'.'&amp;oldid='.urlencode($change['revid']).' * '.$change['user'] .							' * '.$change['comment'].&quot;\n&quot;); }					if (($change['namespace'] == 'User:') or ($change['namespace'] == 'User talk:')) { if (strtolower($change['title']) == strtolower($user.'/Run')) { $run = $wpq-&gt;getpage('User:'.$user.'/Run'); } if (strtolower($change['title']) == strtolower($user.'/Whitelist')) { $wl = $wpq-&gt;getpage('User:'.$user.'/Whitelist'); } if (strtolower($change['title']) == strtolower($user.'/Optin')) { $optin = $wpq-&gt;getpage('User:'.$user.'/Optin'); } if (strtolower($change['title']) == strtolower($user.'/AngryOptin')) { $aoptin = $wpq-&gt;getpage('User:'.$user.'/AngryOptin'); } if (strtolower($change['title']) == strtolower($owner.'/CBAutostalk.js')) { unset($stalk); $tmp = explode(&quot;\n&quot;,$wpq-&gt;getpage('User:'.$owner.'/CBAutostalk.js')); foreach ($tmp as $tmp2) { if (substr($tmp2,0,1) != '#') { $tmp3 = explode('|',$tmp2,2); $stalk[$tmp3[0]] = trim($tmp3[1]); } } unset($tmp,$tmp2,$tmp3); print_r($stalk); }						if (strtolower($change['title']) == strtolower($owner.'/CBAutoedit.js')) { unset($edit); $tmp = explode(&quot;\n&quot;,$wpq-&gt;getpage('User:'.$owner.'/CBAutoedit.js')); foreach ($tmp as $tmp2) { if (substr($tmp2,0,1) != '#') { $tmp3 = explode('|',$tmp2,2); $edit[$tmp3[0]] = trim($tmp3[1]); } } unset($tmp,$tmp2,$tmp3); print_r($edit); }						if (strtolower($change['title']) == strtolower($owner.'/CBChannels.js')) { $ircconfig = explode(&quot;\n&quot;,$wpq-&gt;getpage('User:'.$owner.'/CBChannels.js')); $tmp = array; foreach($ircconfig as $tmpline) { if (substr($tmpline,0,1) != '#') { $tmpline = explode('=',$tmpline,2); $tmp[trim($tmpline[0])] = trim($tmpline[1]); } } print_r($tmp);

$tmpold = array; $tmpnew = array; foreach ($tmp as $tmp2) foreach (explode(',',$tmp2) as $tmp3) $tmpnew[$tmp3] = 1; foreach (explode(',',$ircchannel.','.$ircdebugchannel.','.$ircreportchannel.','.$ircvandalismchannel.','.$ircaivchannel.','.$irctechchannel.','.$ircproxychannels.','.$ircunrevertedchannels.','.$ircbagtrialchannels.','.$ircotherchannels) as $tmp3) $tmpold[$tmp3] = 1;

foreach ($tmpold as $tmp2 =&gt; $tmp3) if (isset($tmpnew[$tmp2])) unset($tmpold[$tmp2],$tmpnew[$tmp2]); foreach ($tmpnew as $tmp2 =&gt; $tmp3) $tmpnew1[] = $tmp2; foreach ($tmpold as $tmp2 =&gt; $tmp3) $tmpold1[] = $tmp2;

$tmpold = $tmpold1; $tmpnew = $tmpnew1; unset($tmpold1,$tmpnew1);

fwrite($irc,'JOIN '.implode(',',$tmpnew).&quot;\n&quot;); fwrite($irc,'PART '.implode(',',$tmpold).&quot;\n&quot;);

$ircchannel = $tmp['ircchannel']; $ircdebugchannel = $tmp['ircdebugchannel']; $ircreportchannel = $tmp['ircreportchannel']; $ircvandalismchannel = $tmp['ircvandalismchannel']; $ircaivchannel = $tmp['ircaivchannel']; $irctechchannel = $tmp['irctechchannel']; $ircproxychannels = $tmp['ircproxychannels']; $ircunrevertedchannels = $tmp['ircunrevertedchannels']; $ircbagtrialchannels = $tmp['ircbagtrialchannels']; $ircotherchannels = $tmp['ircotherchannels'];

unset($tmp,$tmpline,$tmpold,$tmpnew,$tmp2,$tmp3); }					}					if ($change['namespace'].$change['title'] == 'Wikipedia:Bots/Requests for approval') { $stalkbots = array; $trialbots = explode(&quot;\n&quot;,$wpq-&gt;getpage('Wikipedia:Bots/Requests for approval')); foreach ($trialbots as $trialbot) if (preg_match('/\{\{BRFA\|(.*)\|.*\|Trial\}\}/',str_replace(array(&quot;\n&quot;,&quot;\r&quot;),'',$trialbot),$m)) $stalkbots[$m[1]] = 1; }

if (($change['namespace'] != '') and ((!preg_match('/\* \[\[('.preg_quote($change['namespace'].$change['title'],'/').')\]\] \- .*/i',$optin))) and ($change['flags'] != 'move') and ($change['namespace'] != 'Template:')) continue;

$change['justtitle'] = $change['title']; $change['title'] = $change['namespace'].$change['title'];

if ($change['flags'] == 'move') { if (preg_match('/moved \[\[(.*)\]\] to \[\[(.*)\]\]( over redirect)?: (.*)$/',$change['comment'],$m)) { $change['title'] = $m[1]; $change['newtitle'] = $m[2]; $change['realcomment'] = $change['comment']; $change['comment'] = $m[4]; echo &quot;\n\n\n&quot;.'Move!'.&quot;\n\n\n&quot;; print_r($change); echo &quot;\n\n\n&quot;.'Move!'.&quot;\n\n\n&quot;; }					}

if (						((time - $tfas) &gt;= 1800)						and (preg_match('/\(\'\'\'\[\[([^|]*)\|more...\]\]\'\'\'\)/iU',$wpq-&gt;getpage('Wikipedia:Today\'s featured article/'.date('F j, Y')),$tfam))					) { $tfas = time; $tfa = $tfam[1]; //echo &quot;TFA: &quot;.$tfa.&quot;\n&quot;; }					$s = null; $pid = @pcntl_fork; if ($pid != 0) continue;

$hutime = microtime(1);

include 'cluebot.heuristics.config.php'; foreach ($heuristics as $heuristic) { $heuristicret = false; include 'heuristics/cluebot.'.$heuristic.'.heuristic.php'; if ($heuristicret == true) { $stats = unserialize(file_get_contents('cluebot.heuristics.stats.txt')); $stats[$heuristic]++; print_r($log); file_put_contents('cluebot.heuristics.stats.txt',serialize($stats)); unset($stats); break; }					}

if ($heuristicret == true) { echo 'Heuristics time: '.(microtime(1) - $hutime).&quot;\n&quot;; /*file_put_contents('trainingdata.txt',$change['title'].&quot;\0&quot;.$change['revid'].&quot;\0&quot;.'1'.&quot;\n&quot;,FILE_APPEND);*/ } else { $tmp = explode(' ',$rawline,4); $tmp = $tmp[3]; $udp = fsockopen('udp://localhost',3333); fwrite($udp,substr(str_replace(array(&quot;\n&quot;,&quot;\r&quot;),'',$tmp),1).&quot;\n&quot;); fclose($udp); unset($tmp,$udp); $d = $wpi-&gt;diff($change['title'],$change['old_revid'],$change['revid']); $s = score($obscenelist,$d[0],$log); $s -= score($obscenelist,$d[1],$log); //						if ($s &gt; 15) file_put_contents('trainingdata.txt',$change['title'].&quot;\0&quot;.$change['revid'].&quot;\0&quot;.'0'.&quot;\n&quot;,FILE_APPEND); }					unset($hutime);

if (						($heuristicret == true)					) { if (							( ( /* IP users with 250 contributions are fine .. */									(long2ip(ip2long($change['user'])) == $change['user'])									/* and ($uc = $wpapi-&gt;usercontribs($change['user'],250))									and (!isset($uc[249])) */								) or ( /* Users with 50 contributions are fine .. */									(long2ip(ip2long($change['user'])) != $change['user'])									and ($wpq-&gt;contribcount($change['user']) &lt; 50)								) )							and ( /* Whitelisted users are ok. */								/* ($wl = $wpq-&gt;getpage('User:'.$user.'/Whitelist')) and */ (!preg_match('/^\* \[\[User:('.preg_quote($change['user'],'/').')|\1\]\] \- .*/',$wl)) )						) { //							$vandalpage = $wpq-&gt;getpage('User:'.$user.'/PossibleVandalism'); //							$x = explode(&quot;\n\n&quot;,$vandalpage); //							foreach ($x as $k =&gt; $y) { //								if (preg_match('/(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+)/',$y,$m)) { //									if ((time - gmmktime($m[4],$m[5],$m[6],$m[2],$m[3],$m[1])) &gt; (5*60*60)) { //										unset($x[$k]); //									} //								} //							} //							$vandalpage = implode(&quot;\n\n&quot;,$x); $diff = 'http://en.wikipedia.org/w/index.php'. '?title='.urlencode($change['title']). '&amp;diff='.urlencode($change['revid']). '&amp;oldid='.urlencode($change['old_revid']);

$report = ' was '. (($change['flags'] != 'move')?'['.$diff.' changed] by ':'moved to by '). ''.$change['user'].' '. '(u) '. '(t) '. $reason.' on '.gmdate('c'); //							$datatopost = $vandalpage.&quot;\n\n&quot;.'Possible vandalism: '.$report.&quot; ~\n&quot;;

if ($s == null) { //								$rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid']); //								$s = score($scorelist,diff($rv[1]['*'],$rv[0]['*'])); //								$s += (score($scorelist,diff($rv[1]['*'],$rv[0]['*'],false))) * -1; $s = 'N/A'; }

$tmp = unserialize(file_get_contents('oftenvandalized.txt')); if (rand(1,50) == 2) { foreach ($tmp as $key1 =&gt; $tmp2) { foreach ($tmp2 as $key2 =&gt; $time) { if ((time - $time) &gt; (2*24*60*60)) { unset($tmp[$key1][$key2]); } }								}							}							$tmp[$change['title']][] = time; if (count($tmp[$change['title']]) &gt;= 30) { foreach (explode(',',$ircreportchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :!admin '.$change['title'].' has been vandalized '.(count($tmp[$change['title']])).' times in the last 2 days.'.&quot;\n&quot;); }							}							file_put_contents('oftenvandalized.txt',serialize($tmp));

if (								( ($rv1 = $wpapi-&gt;revisions($change['title'],1,'older')) and ($rv1[0]['revid'] == $change['revid']) )								or ($change['flags'] == 'move')							) { /* No need to continue further if it has been reverted */ echo 'Possible vandalism: '.$change['title'].' changed by '.$change['user'].' '.$reason.' on '.$rv[0]['timestamp'].'('.$s.&quot;).\n&quot;; foreach (explode(',',$ircdebugchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :Possible vandalism: '.$change['title'].' changed by '.$change['user'].' '.$reason.' on '.$rv[0]['timestamp'].'('.$s.&quot;).\n&quot;); fwrite($irc,'PRIVMSG '.$y.' :( http://en.wikipedia.org/w/index.php?title='.urlencode($change['title']).'&amp;action=history | '.$change['url'].' )'.&quot;\n&quot;); }								fwrite($pipe,'http://en.wikipedia.org/w/index.php?title='.urlencode($change['title']).'&amp;action=history'.&quot;\n&quot;); /* Tell owner */

$mqtime = microtime(1);

if (is_array($log)) { $logt = ''; foreach ($log as $k =&gt; $v) { $logt .= '* '.$v.' * &quot;'.$k.'&quot;'.&quot;\n&quot;; }								}

$query = 'INSERT INTO `vandalism` '. '(`id`,`user`,`article`,`heuristic`'.((is_array($log))?',`regex`':'').',`reason`,`diff`,`old_id`,`new_id`,`reverted`) '. 'VALUES '. '(NULL,\.mysql_real_escape_string($change['user']).'\',' .									'\.mysql_real_escape_string($change['title']).'\',' .									'\.mysql_real_escape_string($heuristic).'\',' .									((is_array($log))?'\.mysql_real_escape_string($logt).'\',':) .									'\.mysql_real_escape_string($reason).'\',' .									'\.mysql_real_escape_string($change['url']).'\',' .									'\.mysql_real_escape_string($change['old_revid']).'\',' .									'\''.mysql_real_escape_string($change['revid']).'\',0)'; //echo 'Mysql query: '.$query.&quot;\n&quot;; if (!mysql_ping($mysql)) { $mysql = mysql_pconnect($mysqlhost.':'.$mysqlport,$mysqluser,$mysqlpass); if (!$mysql) { die('Could not connect: ' . mysql_error); } if (!mysql_select_db($mysqldb, $mysql)) { die ('Can\'t use database : ' . mysql_error); } }								mysql_query($query); //echo 'Mysql error: '.mysql_error.&quot;\n&quot;; $mysqlid = mysql_insert_id; echo 'MySQL time: '.(microtime(1) - $mqtime).' MySQL id: '.$mysqlid.&quot;\n&quot;; unset($mqtime);

if (									( (											(preg_match('/(assisted|manual)/iS',$status))											and (print('Revert [y/N]? '))											and (strtolower(substr(fgets($stdin,3),0,1)) == 'y')										) or (											(preg_match('/(read-write|rw|go|approved|trial)/iS',$status))										) )									and ( /*ANGRY MODE*/ false or										(											( ((time - $tfas) &lt; 1800) or (													(preg_match('/\(\'\'\'\[\[([^|]*)\|more...\]\]\'\'\'\)/iU',$wpq-&gt;getpage('Wikipedia:Today\'s featured article/'.date('F j, Y')),$tfam))													and ($tfas = time)													and ($tfa = $tfam[1])													and ((print(&quot;TFA: &quot;.$tfa.&quot;\n&quot;)) or (true))												) )											and ($tfa == $change['title'])										) or (											(preg_match('/\* \[\[('.preg_quote($change['title'],'/').')\]\] \- .*/i',$aoptin))											and ((fwrite($irc,'PRIVMSG '.$ircdebugchannel.' :Angry-reverting '.$change['title'].'.'.&quot;\n&quot;)) or (true))										) or (											(($tmp = unserialize(file_get_contents('titles.txt'))) or true)											and ((!isset($tmp[$change['title'].$change['user']])) or ((time - $tmp[$change['title'].$change['user']]) &gt; (24*60*60)))											and ($tmp[$change['title'].$change['user']] = time)											and ((file_put_contents('titles.txt',serialize($tmp))) or true)										) )								) {									echo 'Reverting ...'.&quot;\n&quot;; if ($change['flags'] != 'move') { $rev = $wpapi-&gt;revisions($change['title'],5,'older',false,null,true,true); $revid = 0; $rbtok = $rev[0]['rollbacktoken']; foreach ($rev as $revdata) { if ($revdata['user'] != $change['user']) { $revid = $revdata['revid']; break; }										}										if (($revdata['user'] == $user) or (in_array($revdata['user'],explode(',',$botfriends)))) { die; /* Do not revert to us. */ }									} //									if ($revid == 0) { die; } foreach (explode(',',$ircdebugchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :Reverting ...'.&quot;\n&quot;); } //									$revisiondata = $wpapi-&gt;revisions($change['title'],1,'older',true,$revid); //									if (!$revisiondata[0]['*']) die; //									if (!$rv1[0]['*']) $rv1[0]['*'] = $rv[0]['*']; //									$wpi-&gt;post( //										$change['title'], //										$revisiondata[0]['*'], //										'Reverting possible vandalism by '.$change['user'].' ' . //										'to version by '.$revisiondata[0]['user'].'. ' . //										'False positive? Report it. '. //										'Thanks, User:'.$user.'. ('.$mysqlid.') (Bot)', //										false, //										$rv1 //									); /* Revert the page */ if ($change['flags'] != 'move') { if (!$rbtok) { $d = $wpi-&gt;diff($change['title'],$change['old_revid'],$change['revid']); $rbtok = $d[2]; }										$rbret = $wpapi-&gt;rollback(											$change['title'],											$change['user'],											'Reverting possible vandalism by '.$change['user'].' ' .											'to '.(($revid == 0)?'older version':'version by '.$revdata['user']).'. ' .											'False positive? Report it. '.											'Thanks, '.$user.'. ('.$mysqlid.') (Bot)',											$rbtok										); } else { $rbret = $wpapi-&gt;move(											$change['newtitle'],											$change['title'],											'Reverting possible vandalism by '.$change['user'].' ' .											'to '.(($revid == 0)?'older version':'version by '.$revdata['user']).'. ' .											'False positive? Report it. '.											'Thanks, '.$user.'. ('.$mysqlid.') (Bot)'										); } // // 									$rv2 = $wpapi-&gt;revisions($change['title'],1); //									if ($rv2[0]['user'] == $user) { if ($rbret !== false) { foreach (explode(',',$ircdebugchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :Reverted. ('.(microtime(1) - $messagereceived).' s)'.&quot;\n&quot;); } 										$warning = 0; $tpcontent = $wpq-&gt;getpage('User talk:'.$change['user']); if (preg_match_all('/&lt;!-- Template:(uw-[a-z]*(\d)(im)?|Blatantvandal \(serious warning\)) --&gt;.*(\d{2}):(\d{2}), (\d+) ([a-zA-Z]+) (\d{4}) \(UTC\)/iU', $tpcontent, $match,PREG_SET_ORDER)										) { foreach ($match as $m) { $month = array('January' =&gt; 1, 'February' =&gt; 2, 'March' =&gt; 3, 													'April' =&gt; 4, 'May' =&gt; 5, 'June' =&gt; 6, 'July' =&gt; 7, 													'August' =&gt; 8, 'September' =&gt; 9, 'October' =&gt; 10, 													'November' =&gt; 11, 'December' =&gt; 12												); if ($m[1] == 'Blatantvandal (serious warning)') $m[2] = 4; if ((time - gmmktime($m[4],$m[5],0,$month[$m[7]],$m[6],$m[8])) &lt;= (2*24*60*60)) { if ($m[2] &gt; $warning) { $warning = $m[2]; } }											}										}										$warning++; if ($warning == 5) { /* Report them if they have been warned 4 times. */											$aivdata = $wpq-&gt;getpage('Wikipedia:Administrator_intervention_against_vandalism/TB2'); if (!preg_match('/'.preg_quote($change['user'],'/').'/i',$aivdata)) { foreach(explode(',',$ircaivchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :!admin Reporting User:'.$change['user'].' to WP:AIV. Contributions: Special:Contributions/'.$change['user'].' Block: Special:Blockip/'.$change['user'].''.&quot;\n&quot;); }												foreach (explode(',',$ircvandalismchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :rcbot bl add '.$change['user'].' x='.(24*$warning).' r=Vandalism to '.$change['title'].' (#'.$warning.&quot;).\n&quot;); }												$wpapi-&gt;edit(													'Wikipedia:Administrator_intervention_against_vandalism/TB2',													$aivdata .													&quot;\n\n* ' .													' - '.$report.&quot; (Automated) ~\n&quot;,													'Automatically reporting Special:Contributions/'.$change['user'].'. (bot)',													false,													false												); } else { foreach (explode(',',$ircreportchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :!admin User:'.$change['user'].' has vandalized at least one time while being listed on WP:AIV. Contributions: Special:Contributions/'.$change['user'].' Block: Special:Blockip/'.$change['user'].''.&quot;\n&quot;); }											}										} elseif ($warning &lt; 5) { /* Warn them if they haven't been warned 4 times. */											foreach (explode(',',$ircvandalismchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :rcbot bl add '.$change['user'].' x='.(24*$warning).' r=Vandalism to '.$change['title'].' (#'.$warning.').'.&quot;\n&quot;); }											$wpapi-&gt;edit(												'User talk:'.$change['user'],												$tpcontent.&quot;\n\n&quot; .												''.$warning.' ~'.&quot;\n&quot;,												'Warning '.$change['user'].' - #'.$warning,												false,												false											); /* Warn the user */ } else { /* They have already been reported ... do nothing */

}										if (!mysql_ping($mysql)) { $mysql = mysql_pconnect($mysqlhost.':'.$mysqlport,$mysqluser,$mysqlpass); if (!$mysql) { die('Could not connect: ' . mysql_error); } if (!mysql_select_db($mysqldb, $mysql)) { die ('Can\'t use database : ' . mysql_error); } }										mysql_query('UPDATE `vandalism` SET `reverted` = 1 WHERE `id` = \.mysql_real_escape_string($mysqlid).'\); } else { $rv2 = $wpapi-&gt;revisions($change['title'],1); if ($change['user'] != $rv2[0]['user']) { echo 'Grr! Beaten by '.$rv2[0]['user'].&quot;.\n&quot;; foreach(explode(',',$ircdebugchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :Grr! Beaten by '.$rv2[0]['user'].&quot;.\n&quot;); }											if (!mysql_ping($mysql)) { $mysql = mysql_pconnect($mysqlhost.':'.$mysqlport,$mysqluser,$mysqlpass); mysql_select_db($mysqldb, $mysql); } mysql_query('INSERT INTO `beaten` (`id`,`article`,`diff`,`user`) VALUES (NULL,\.mysql_real_escape_string($change['title']).'\',\.mysql_real_escape_string($change['url']).'\',\''.mysql_real_escape_string($rv2[0]['user']).'\')'); }									}								} else { foreach (explode(',',$ircunrevertedchannels) as $y) { fwrite($irc,'PRIVMSG '.$y.' :'.&quot;\002\00304Possible ignored vandalism: \002\003\00312&quot;.$change['title'].&quot;\003\00304 changed by \003\00312User:&quot;.$change['user'].&quot;\003 \00303&quot;.$reason.&quot;\00304 on \00307&quot;.$rv[0]['timestamp'].&quot;\003(\002\00313&quot;.$s.&quot;\003).\n&quot;); fwrite($irc,'PRIVMSG '.$y.' :'.&quot;\002(\002\00312 http://en.wikipedia.org/w/index.php?title=&quot;.urlencode($change['title']).&quot;&amp;action=history \003\002|\002\00312 &quot;.$change['url'].&quot; \003\002)\002&quot;.&quot;\n&quot;); }									$vandalpage = $wpq-&gt;getpage('User:'.$user.'/PossibleVandalism'); $x = explode(&quot;\n\n&quot;,$vandalpage); foreach ($x as $k =&gt; $y) { if (preg_match('(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)Z',$y,$m)) { if ((gmtime - gmmktime($m[4],$m[5],$m[6],$m[2],$m[3],$m[1])) &gt; (5*60*60)) { unset($x[$k]); }										}									}									$vandalpage = implode(&quot;\n\n&quot;,$vandalpage); $wpapi-&gt;edit('User:'.$user.'/PossibleVandalism',$vandalpage.&quot;\n\n&quot;.'Possible ignored vandalism: '.$change['title'].' changed by User:'.$change['user'].' '.$reason.' on '.$rv[0]['timestamp'].' ('.$s.')'.' ).'&amp;action=history hist] ['.$change['url'].' diff] ~','Adding possible vandalism',true,true); }

} else { $rev = $wpapi-&gt;revisions($change['title'],1); $rev = $rev[0];

echo 'Possible corrected vandalism: '.$change['title'].' changed by '.$change['user'].' '.$reason.'('.$s.&quot;)\n\tReverted by &quot;.$rev['user'].&quot; before I saw it.\n&quot;; foreach (explode(',',$ircdebugchannel) as $y) { fwrite($irc,'PRIVMSG '.$y.' :Possible corrected vandalism: '.$change['title'].' changed by '.$change['user'].' '.$reason.'('.$s.&quot;)\n&quot;); fwrite($irc,'PRIVMSG '.$y.' :Reverted by '.$rev['user'].&quot; before I saw it.\n&quot;); }								if (($rev['user'] != $user) and ($rev['user'] != $change['user'])) { if (!mysql_ping($mysql)) { $mysql = mysql_pconnect($mysqlhost.':'.$mysqlport,$mysqluser,$mysqlpass); mysql_select_db($mysqldb, $mysql); } mysql_query('INSERT INTO `beaten` (`id`,`article`,`diff`,`user`) VALUES (NULL,\.mysql_real_escape_string($change['title']).'\',\.mysql_real_escape_string($change['url']).'\',\''.mysql_real_escape_string($rev['user']).'\')'); }							}						}					}					die; }			}		}	} ?&gt;

Config (cluebot.heuristics.config.php)
&lt;?PHP $heuristics[] = 'grawp'; $heuristics[] = 'evolution'; $heuristics[] = 'avrillavigne'; $heuristics[] = 'editsummary'; $heuristics[] = 'pagereplace'; $heuristics[] = 'pageblank'; $heuristics[] = 'massdelete'; $heuristics[] = 'massadd'; $heuristics[] = 'tables'; $heuristics[] = 'smallchange'; $heuristics[] = 'claimjumperpete'; $heuristics[] = 'sneaky'; $heuristics[] = 'redirect'; ?&gt;

heuristics/cluebot.avrillavigne.heuristic.php
&lt;?PHP if ( /* The Avril Lavigne vandal */		( (preg_match('/avril\s*lavigne\s*roc*k*[zs]*\s*my\s*soc*k*[zs]*/i',$change['comment'])) or (preg_match('/she\s*(is\s*)*(so\s*)*.*hot\!.*using.*TW/i',$change['comment'])) //			or ( //				($change['namespace'] == 'Template:') //				and (preg_match('/\{\{user((\s|_)talk)?:/i',$wpq-&gt;getpage($change['title']))) //			) )		and ($reason = 'Avril Lavigne vandal?')	) { $heuristicret = true; foreach (explode(',',$ircreportchannel) as $y) fwrite($irc,'PRIVMSG '.$y.' :!admin Avril Lavigne vandal? Special:Contributions/'.$change['user'].&quot; .\n&quot;); } ?&gt;

heuristics/cluebot.claimjumperpete.heuristic.php
&lt;?PHP if ( /* The ClaimJumperPete vandal */		(($change['length'] &gt;= 100) and ($change['length'] &lt;= 400))		and ( ($change['length'] &lt;= 200) or ($d = $wpi-&gt;diff($change['title'],$change['old_revid'],$change['revid'])) )		and ( (fnmatch(&quot;&lt;!--*howdy y'all*--&gt;*&quot;,trim(strtolower($d[0])))) or (fnmatch(&quot;&lt;!--*hello der*--&gt;*&quot;,trim(strtolower($d[0])))) or (fnmatch(&quot;&lt;!--*happy editin' y'all*--&gt;*&quot;,trim(strtolower($d[0])))) )		and ($reason = 'ClaimJumperPete?')	) { $heuristicret = true; foreach (explode(',',$ircreportchannel) as $y) fwrite($irc,'PRIVMSG '.$y.' :!admin ClaimJumperPete vandal? http://en.wikipedia.org/w/index.php?title='.urlencode($change['title']).'&amp;diff=prev'.'&amp;oldid='.urlencode($change['revid']).&quot; .\n&quot;); } ?&gt;

heuristics/cluebot.editsummary.heuristic.php
&lt;?PHP if (		( (fnmatch('*nimp*org*',strtolower($change['comment']))) )		and ($reason = 'obscenities in edit summary')	) { $heuristicret = true; } ?&gt;

heuristics/cluebot.evolution.heuristic.php
&lt;?PHP if ( /* The Evolution vandal */		($change['title'] == 'Evolution')		and (($pagedata = $wpq-&gt;getpage($change['title'])) or true)		and (fnmatch('*Genesis 1*The beginning*',$pagedata))		and ($reason = 'replacing article with the Bible')	) { $heuristicret = true; foreach (explode(',',$ircreportchannel) as $y) fwrite($irc,'PRIVMSG '.$y.' :!admin Evolution vandal? http://en.wikipedia.org/w/index.php?title='.urlencode($change['title']).'&amp;diff=prev'.'&amp;oldid='.urlencode($change['revid']).&quot; .\n&quot;); } ?&gt;

heuristics/cluebot.grawp.heuristic.php
&lt;?PHP if ( /* The Grawp vandal */		( (fnmatch('*epic*lulz*on*nimp*org*',strtolower($change['comment']))) or (fnmatch('*on*nimp*org*epic*lulz*',strtolower($change['comment']))) or (fnmatch('*punishing*wikipedia*',strtolower($change['comment']))) or (fnmatch('*anti*avril*hate*campaign*',strtolower($change['comment']))) or (fnmatch('*HAGGER*',$change['comment'])) or (fnmatch('*H?A?G?G?E?R*',$change['comment'])) or (fnmatch('*h??a??g??g??e??r*',strtolower($change['comment']))) or (fnmatch('*grawp*cock*',strtolower($change['comment']))) or (fnmatch('*massive*cock*',strtolower($change['comment']))) or (fnmatch('*grawp*dick*',strtolower($change['comment']))) or (fnmatch('*massive*dick*',strtolower($change['comment']))) or (fnmatch('*H?A?G?E?R*',$change['comment'])) or (fnmatch('*hgger*',strtolower($change['comment']))) )		and ($reason = 'Grawp?')	) { $heuristicret = true; foreach (explode(',',$ircreportchannel) as $y) fwrite($irc,'PRIVMSG '.$y.' :!admin Grawp vandal? Special:Contributions/'.$change['user'].&quot; .\n&quot;); } ?&gt;

heuristics/cluebot.massadd.heuristic.php
&lt;?PHP if ( /* Massive additions */		($change['length'] &gt;= 7500)		and ($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid']))		and ($pagedata = $wpq-&gt;getpage($change['title']))		and ($s = score($scorelist,$rv[0]['*']))		and ($s += (score($scorelist,$rv[1]['*'])) * -1)		and ($s &lt; -1000)		and ($reason = 'score equals '.$s)	) $heuristicret = true; ?&gt;

heuristics/cluebot.massdelete.heuristic.php
&lt;?PHP if ( /* Massive deletes */		($change['length'] &lt;= -7500)		and ($pagedata = $wpq-&gt;getpage($change['title']))		and (!fnmatch('*#REDIRECT*',strtoupper(substr($pagedata,0,9))))		and ($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid']))		and ($s = score($scorelist,$rv[0]['*']))		and ($s += (score($scorelist,$rv[1]['*'])) * -1)		and ($s &lt; -50) /* There are times when massive deletes are ok. */		and ($reason = 'deleting '.($change['length'] * -1).' characters')	) $heuristicret = true; ?&gt;

heuristics/cluebot.pageblank.heuristic.php
&lt;?PHP if ( /* Page blanks */		(preg_match('/\[\[WP:.*Blanked.*page/',$change['comment'],$m))		and (($pagedata = $wpq-&gt;getpage($change['title'])) or true)		and ($fc = $wpapi-&gt;revisions($change['title'],1,'newer'))		and ($fc[0]['user'] != $change['user']) /* The creator is allowed to blank the page. */		and ($reason = 'blanking the page')	) $heuristicret = true; ?&gt;

heuristics/cluebot.pagereplace.heuristic.php
&lt;?PHP if ( /* Page replaces */		(preg_match('/\[\[WP:.*\]\]Replaced page with (.*)$/',$change['comment'],$m))		and ($pagedata = $wpq-&gt;getpage($change['title']))		and ($fc = $wpapi-&gt;revisions($change['title'],1,'newer'))		and ($fc[0]['user'] != $change['user']) /* The creator is allowed to replace the page. */		and ($reason = 'replacing entire content with something else')	) $heuristicret = true; ?&gt;

heuristics/cluebot.redirect.heuristic.php
&lt;?PHP if ( /* The Redirect vandals */		( ($tfa == $change['title']) and (fnmatch('*#redirect *',strtolower($wpq-&gt;getpage($change['title'])))) and ($reason = 'redirecting featured article to new title') )		or ( ($pagedata = $wpq-&gt;getpage($change['title'])) and (substr(trim(strtolower($pagedata)),0,10) == '#redirect ') and (preg_match('/\[\[(.*)\]\]/',$pagedata,$m)) and (!$wpq-&gt;getpage($m[1])) and ($reason = 'redirecting article to non-existant page') )	) {		$heuristicret = true; //		fwrite($irc,'PRIVMSG #cvn-wp-en :!admin Grawp vandal? http://en.wikipedia.org/wiki/Special:Contributions/'.$change['user'].&quot; .\n&quot;); } ?&gt;

heuristics/cluebot.smallchange.heuristic.php
&lt;?PHP unset($log,$log2); if ( /* Small changes with obscenities. */		(($change['length'] &gt;= -200) and ($change['length'] &lt;= 200))		and (($d = $wpi-&gt;diff($change['title'],$change['old_revid'],$change['revid'])) or true)		and ((($change['title'] == 'User:ClueBot/Sandbox') and print_r($rv)) or true)		and (($s = score($obscenelist,$d[0],$log)) or true)		and (($s -= score($obscenelist,$d[1],$log2)) or true)		and ( (				($s &lt; -5) /* There are times when small changes are ok. */				and (($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid'])) or true)				and (!fnmatch('*#REDIRECT*',strtoupper(substr($rv[0]['*'],0,9))))				and (!fnmatch('*SEX*',strtoupper($rv[1]['*'])))				and (!fnmatch('*BDSM*',strtoupper($rv[1]['*'])))				and (score($obscenelist,$change['title']) &gt;= 0)				and (score($obscenelist,$rv[1]['*']) &gt;= 0)				and (!preg_match('/(^|\s)([a-z]{1,2}(\*+|\-{3,})[a-z]{0,2}|\*{4}|\-{4}|(\&lt;|\?censored(\&gt;|\))?)(ing?|ed)?(\s|$)/iS',$rv[1]['*']))				and ($heuristic .= '/obscenities')				and ($reason = 'making a minor change with obscenities')			) or (				($s &gt; 5)				and (($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid'])) or true)				and (!fnmatch('*#REDIRECT*',strtoupper(substr($rv[0]['*'],0,9))))				and (!preg_match('/(^|\s)([a-z]{1,2}(\*+|\-{3,})[a-z]{0,2}|\*{4}|\-{4}|(\&lt;|\?censored(\&gt;|\))?)(ing?|ed)?(\s|$)/iS',$rv[1]['*']))				and (preg_match('/(^|\s)([a-z]{1,2}(\*+|\-{3,})[a-z]{0,2}|\*{4}|\-{4}|(\&lt;|\?censored(\&gt;|\))?)(ing?|ed)?(\s|$)/iS',$rv[0]['*']))				and ($heuristic .= '/censor')				and ($reason = 'making a minor change censoring content (Wikipedia is not censored)')			) or (				(preg_match('/\!\!\!/S',$d[0]))				and (($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid'])) or true)				and (!preg_match('/\!\!\!/S',$rv[1]['*']))				and (!fnmatch('*#REDIRECT*',strtoupper(substr($rv[0]['*'],0,9))))				and ($heuristic .= '/exclamation')				and ($reason = 'making a minor change adding &quot;!!!&quot;')			) )	) { $heuristicret = true; if (isset($log2) and is_array($log2)) foreach ($log2 as $k =&gt; $v) $log[$k] -= $v; if (isset($log) and is_array($log)) foreach ($log as $k =&gt; $v) if ($v == 0) unset($log[$k]); unset($log2); /* fwrite($irc,'PRIVMSG #wikipedia-BAG/ClueBot :Would revert http://en.wikipedia.org/w/index.php?title='.urlencode($change['namespace'].$change['title']).'&amp;diff=prev'.'&amp;oldid='.urlencode($change['revid']).&quot; .\n&quot;); */ } ?&gt;

heuristics/cluebot.sneaky.heuristic.php
&lt;?PHP unset($log,$log2); if ( /* Small changes with obscenities. */		(($change['length'] &gt;= -200) and ($change['length'] &lt;= 200))		and (($d = $wpi-&gt;diff($change['title'],$change['old_revid'],$change['revid'])) or true)		and ((($change['title'] == 'User:ClueBot/Sandbox') and print_r($rv)) or true)		and (($s = score($obscenelist,$d[0],$log)) or true)		and (($s -= score($obscenelist,$d[1],$log2)) or true)		and ( (				($s &lt; -5) /* There are times when small changes are ok. */				and (($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid'])) or true)				and (!fnmatch('*#REDIRECT*',strtoupper(substr($rv[0]['*'],0,9))))				and (!fnmatch('*SEX*',strtoupper($rv[1]['*'])))				and (!fnmatch('*BDSM*',strtoupper($rv[1]['*'])))				and (score($obscenelist,$change['title']) &gt;= 0)				and (score($obscenelist,$rv[1]['*']) &gt;= 0)				and (!preg_match('/(^|\s)([a-z]{1,2}(\*+|\-{3,})[a-z]{0,2}|\*{4}|\-{4}|(\&lt;|\?censored(\&gt;|\))?)(ing?|ed)?(\s|$)/iS',$rv[1]['*']))				and ($heuristic .= '/obscenities')				and ($reason = 'making a minor change with obscenities')			) or (				($s &gt; 5)				and (($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid'])) or true)				and (!fnmatch('*#REDIRECT*',strtoupper(substr($rv[0]['*'],0,9))))				and (!preg_match('/(^|\s)([a-z]{1,2}(\*+|\-{3,})[a-z]{0,2}|\*{4}|\-{4}|(\&lt;|\?censored(\&gt;|\))?)(ing?|ed)?(\s|$)/iS',$rv[1]['*']))				and (preg_match('/(^|\s)([a-z]{1,2}(\*+|\-{3,})[a-z]{0,2}|\*{4}|\-{4}|(\&lt;|\?censored(\&gt;|\))?)(ing?|ed)?(\s|$)/iS',$rv[0]['*']))				and ($heuristic .= '/censor')				and ($reason = 'making a minor change censoring content (Wikipedia is not censored)')			) or (				(preg_match('/\!\!\!/S',$d[0]))				and (($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid'])) or true)				and (!preg_match('/\!\!\!/S',$rv[1]['*']))				and (!fnmatch('*#REDIRECT*',strtoupper(substr($rv[0]['*'],0,9))))				and ($heuristic .= '/exclamation')				and ($reason = 'making a minor change adding &quot;!!!&quot;')			) )	) { $heuristicret = true; if (isset($log2) and is_array($log2)) foreach ($log2 as $k =&gt; $v) $log[$k] -= $v; if (isset($log) and is_array($log)) foreach ($log as $k =&gt; $v) if ($v == 0) unset($log[$k]); unset($log2); /* fwrite($irc,'PRIVMSG #wikipedia-BAG/ClueBot :Would revert http://en.wikipedia.org/w/index.php?title='.urlencode($change['namespace'].$change['title']).'&amp;diff=prev'.'&amp;oldid='.urlencode($change['revid']).&quot; .\n&quot;); */ } ?&gt;

heuristics/cluebot.tables.heuristic.php
&lt;?PHP if ( /* Massive tables */		($change['length'] &gt;= 7500)		and ($rv = $wpapi-&gt;revisions($change['title'],2,'older',true,$change['revid']))		and (substr_count(strtolower($rv[0]['*']),'&lt;td') &gt; 300)		and ($reason = 'adding huge, browser-crashing tables')	) $heuristicret = true; ?&gt;

Score list
&lt;?PHP /*	 * This page contains bad words out of necessity. * Here is 50 lines of whitespace before the actual list: * (scroll down to see the list) *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 *	 * Here is the list: */	$obscenelist = Array (			/* 'preg'				=&gt; points, */			'/suck/i'				=&gt; -5,  /* Usually bad words */			'/stupid/i'				=&gt; -3,			'/haha/i'				=&gt; -5,			'/\bomg/i'				=&gt; -3,			'/\bpimp\b/i'				=&gt; -7,			'/1337/i'				=&gt; -5,			'/leet/i'				=&gt; -5,			'/dumb/i'				=&gt; -5,			'/\bputa\b/i'				=&gt; -7,			'/\bhomo\b/i'				=&gt; -7,			'/\bGAY\b/'				=&gt; -10,			'/\bslut/i'				=&gt; -5,			'/damn/i'				=&gt; -5,			'/\bass\b/i'				=&gt; -10,			'/\brape\b/i'				=&gt; -7,			'/\bpoop\b/i'				=&gt; -10,			'/\bcock\b/i'				=&gt; -10,			'/\blol\b/i'				=&gt; -7,			'/\bcrap\b/i'				=&gt; -5,			'/\bsex\b/i'				=&gt; -5,			'/noob/i'				=&gt; -5,			'/\bnazi\b/i'				=&gt; -3,			'/\bneo-nazi\b/i'			=&gt; +3,   /* False-positive */			'/fuck/i'				=&gt; -20,  /* Stronger bad words */			'/\[\[Fucked\ Up\]\]/'			=&gt; +20,  /* This one is a false positive */			'/bitch/i'				=&gt; -20,			'/\bpussy\b/i'				=&gt; -20, '/penis/i'				=&gt; -20, '/Penisula/'				=&gt; +20, /* False Positive */ '/vagina/i'				=&gt; -20, '/whore/i'				=&gt; -15, '/\bshit\b/i'				=&gt; -20, '/nigger/i'				=&gt; -20, '/\bnigga\b/i'				=&gt; -20, '/cocksucker/i'				=&gt; -20, '/assrape/i'				=&gt; -15, '/motherfucker/i'			=&gt; -20, '/wanker/i'				=&gt; -20, '/\bcunt\b/i'				=&gt; -20, '/faggot/i'				=&gt; -20, '/fags/i'				=&gt; -20, '/asshole/i'				=&gt; -15, '/fuck ((yo)?u|h(er|im)|them|it)/i'	=&gt; -100, /* This looks like a personal attack */ '/((yo)?u|s?he|we|they|it) sucks?/i'	=&gt; -100, /* This looks like a personal attack */ '/666+\b/i'				=&gt; -50  /* Though this has uses, it is commonly used by vandals */ );	$grammarlist = Array		( '/(.{1,4})\1{30}/'			=&gt; -10, /* Ugg .. the same letter(s) several times in a row. */			'/\b[A-Z].*[.!?]\b/U'			=&gt; +2,  /* This looks to be a correct sentence */ '/\b[A-Z][^a-z]{30,}\b/U'		=&gt; -10, /* All capitals? Looks like vandal activity */ '/\b[^A-Z]{1500,}\b/U'			=&gt; -10, /* No capitals? Looks like vandal activity */ '/!{5,}/i'				=&gt; -10, /* No wikipedia article needs '!!!!!' in it */ '/!!+1+(one)*/i'			=&gt; -30, /* No wikipedia article needs '!!!11one' in it */ '/\[\[.*\]\]/U'				=&gt; +1,  /* Wiki links are good. */			'/\{\{.*\}\}/U'				=&gt; +5,  /* Wiki transcludes are good. */			'/\{\{[iI]nfobox .*\}\}/U'		=&gt; +20, /* Wiki infoboxes are good. */			'/\[\[Category\:.*\]\]/iU'		=&gt; +3   /* Wiki categories are good. */		);	$scorelist = array_merge($obscenelist,$grammarlist); ?&gt;

ClueBot (talk) 13:01, 27 November 2010 (UTC)