User:Full-date unlinking bot/code

<?php
/** fulldateunlinker.php -- Removes link tags from dates
 *  Final Version
 *
 *  Modifications:
 *  08 November 2009 - Tcncv - Change lower case months to proper case
 *  14 November 2009 - Harej - Replaced edit conflict detection system
 *  19 November 2009 - Harej - Bugfixes and reducing sleep time from 10 seconds to 6 seconds.
 *  03 December 2009 - Harej - Progress tracking, resume points
 *  24 December 2009 - Harej - Fix in title-matching regex, reliance on maxlag instead of arbitrary throttle
 *
 *  (c) 2009 James Hare (Harej) and others - http://en.wikipedia.orgview_html.php?sq=&lang=&q=User:Harej
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *   
 *	  Developers (add your self here if you worked on the code):
 *    [[User:Harej]]   - Initial code
 *    [[User:Tcncv]]   - Date-parsing regular expressions, unlinker()
 *    [[User:Chris G]] - MediaWiki API and database interfacing
 **/
ini_set("display_errors", 1);
error_reporting(E_ALL ^ E_NOTICE);
include("./public_html/botclasses.php");  // Botclasses.php was written by User:Chris_G and is available under the GNU General Public License
include("fdublogin.php");
 
// For the purposes of unambiguous documentation, the Month-Day-Year style of writing dates will be referred to as "American" and the Day-Month-Year style "British".
// I understand how not-right this is but I felt it was necessary to use two terms that could not be confused with each other.
// ("International" would be a good replacement for "British", but "i" could be confused for "1", plus "int" means "integer".)
 
// I'm sorry, Chris, but I had to ditch the toolserver DB interfacing in favor of API interfacing.
// The database parts were not working, and there was no way to tell how to fix it because no errors were being put out.
// So I did the easy thing and put the old method, which works, back in.
 
echo "Logging in...";
$objwiki = new wikipedia();
$objwiki->login($botuser, $botpass);
echo " done.\n";
 
$contents = "";
 
/* Connect to the database */
echo "Retrieving database login credentials...";
$toolserver_mycnf = parse_ini_file("/home/messedrocker/.my.cnf");
$toolserver_username = $toolserver_mycnf['user'];
$toolserver_password = $toolserver_mycnf['password'];
unset($toolserver_mycnf);
echo " done.\n";
 
echo "Logging into database...";
mysql_connect("sql",$toolserver_username,$toolserver_password);
@mysql_select_db('u_messedrocker_reqs') or die(mysql_error());
echo " done.\n";
 
function query($query) {
	// we need to use this function in case our MySQL connection times out
	global $toolserver_username;
	global $toolserver_password;
	if (!mysql_ping()) {
		mysql_connect("sql",$toolserver_username,$toolserver_password);
		@mysql_select_db('u_messedrocker_reqs') or die(mysql_error());
	}
	return mysql_query($query) or die(mysql_error());
}
 
 
function overridecheck() {
	// This checks to see if [[User:Full-date unlinking bot/Manual override]] has been triggered by the placement of the string "Joe Biden" anywhere on the page.
	// I chose the Vice President of the United States as the "safety word" because it can't be triggered accidentally. And because I'm nuts.
 
 	global $objwiki;
	$overridepage = $objwiki->getpage("User:Full-date unlinking bot/manual override");
 
	if (strpos($overridepage, "Joe Biden") !== false) {
		die("Manual override has been triggered. Shutting down.");
	}
}
 
function checktoprocess($page) {
	// checktoprocess checks if $page should be processed.
	// First, it checks if the page has already been processed based on a comment that is left by the bot after each page is processed.
	// Checks are then performed based on the exclusion criteria on the bot's user page
	// If any of these tests fail, "false" is returned; otherwise, "true" is returned.
 
	$regex1 = "/^(January|February|March|April|May|June|July|August|September|October|November|December)$/"; // matches Month
	$regex1b = "/^(January|February|March|April|May|June|July|August|September|October|November|December) \d{1,4}/"; // matches Month-Date or Month-Year
	$regex2 = "/^\d{1,4}(st|rd|th|nd|s)?\s?(century|millennium)?( BC)?/i"; // matches year, century, and millennium articles, BC and AD
	$regex3 = "/^List of \d{1,4}(st|rd|th|nd|s)?\s?(century|millennium)?( BC)?/i"; // List of (year or year range) Xs
	$regex4 = "/^List of .* in (the )?\d{1,4}(st|rd|th|nd|s)?\s?(century|millennium)?( BC)?/i"; // List of Xs in the (year or year range)
	if (preg_match($regex1, $page) || preg_match($regex1b, $page) || preg_match($regex2, $page) || preg_match($regex3, $page) || preg_match($regex4, $page)) {
		return false;
	}
 
 	global $objwiki;
	global $contents;
 
	do {
	$contents = $objwiki->getpage($page,null,true);
	} while ($contents == "");
 
	global $botuser;
	if (!$objwiki->nobots($page,$botuser,$contents)) {
		return false;
	}
 
 	$check = mysql_query("select * from `unlinked` where `name`=\"" . mysql_real_escape_string($page) . "\"");
 	$row = mysql_fetch_assoc($check);
	if ($row['name'] == $page) {
		return false;
	}
	else {
		return true;
	}
	/* President Clinton called. He wants his era's shitty way of storing data back. */
}
 
function unlinker($link) {
	global $objwiki;
	global $contents;
	$contents_archive = $contents; // this is to maintain an unchanged version for comparison purposes. if there is no change, the bot will not send the API request to edit the page
	$editsummary = "Unlinking full-dates. [[User:Full-date unlinking bot|Details here]]. Codes: ";
 
	//==========  Define regular expression date building blocks
	// Key: m=month, d=day, y=year, s = ordinal suffix, n = ordinal day (1st, 2nd, ...),
	// x = day with optional ordinal suffix (1, 1st, 2, 2nd, etc.), o = "of"
	//
 
	// Root date components
	$part_m = '(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|'
		. 'July?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)';
	$part_d = '\d{1,2}';
	$part_s = '(?:st|nd|rd|th)';        // Ordinal suffix
	$part_n = $part_d . $part_s;        // Day with ordinal suffix
	$part_x = $part_d . $part_s . '?';  // Day with optional ordinal suffix
	$part_y = '\d{1,4}(?:[ _]BC)?';
 
	// Captured date components
	$part_c_m = '(' . $part_m . ')';
	$part_c_d = '(' . $part_d . ')';
	$part_c_n = '(' . $part_n . ')';
	$part_c_x = '(' . $part_x . ')';
	$part_c_y = '(' . $part_y . ')';
 
	// The following "Nth of Month" dates are not redirects to standard day articles, so are not to be unlinked
	$excl_nom = '(?!1st[ _]of[ _]May|5th[ _]of[ _]May|4th[ _]of[ _]July|6th[ _]of[ _]October|8th[ _]of[ _]November)';
 
	// Linked captured date components
	$part_lc_md  = '\[\[' . $part_c_m . '[ _]' . $part_c_d . '\]\]';  // [[month day]]
	$part_lc_dm  = '\[\[' . $part_c_d . '[ _]' . $part_c_m . '\]\]';  // [[day month]]
	$part_lc_mn  = '\[\[' . $part_c_m . '[ _]' . $part_c_n . '\]\]';  // [[month Nth]]
	$part_lc_nm  = '\[\[' . $part_c_n . '[ _]' . $part_c_m . '\]\]';  // [[Nth month]]
	$part_lc_nom = '\[\[' . $excl_nom . $part_c_n . '[ _]of[ _]' . $part_c_m . '\]\]';  // [[Nth of month]], excluding select dates
	$part_lc_y   = '\[\[' . $part_c_y . '\]\]';  // [[year]]
 
	// Generalized piped date components
	$part_mx = $part_m . '[ _]' . $part_x;  // Month day(th)
	$part_xm = $part_x . '[ _]' . $part_m;  // day(th) Month
	$part_nom = $excl_nom . $part_n . '[ _]of[ _]' . $part_m;  // Nth of Month, excluding select dates
	$part_gen_link = '(?:' . $part_mx . '|' . $part_xm . '|' . $part_nom . ')';                  // m-d(th), d(th)-m, or d(th)-of-m
	$part_gen_pipe = '(?:' . $part_x . '|' . $part_mx . '|' . $part_xm . '|' . $part_nom . ')';  // d(th), m-d(th), d(th)-m, or d(th)-of-m
	$part_lc_piped = '\[\[' . $part_gen_link . '\|' . '(' . $part_gen_pipe . ')' . '\]\]';  // Only the piped text is captured
 
	// Punctuation 
	$part_AMreg_punct = ', ';
	$part_BRreg_punct = ' ';
	$part_AModd_punct = '(?!, \[)(?: *(?:, *)?)';  // spaces and optional comma, excluding comma + single space
	$part_BRodd_punct = '(?! \[)(?: *(?:, *)?)';   // spaces and optional comma, excluding single space
	$part_c_gen_punct = '( *(?:, *)?)';            // spaces and optional comma (any form) - captured
	$part_YMD_punct   = ' *';                      // Recognize only spaces (zero or more) between year and month-day
 
	// Define words and punctuation that may appear between items of a date range or list.
	// Optional comma + whitespace + separator punctuation or word + more whitespace
	$part_list_commaopt = ',?';
	$part_list_spacing = '(?: |&nbsp;|<br */?>)*'; // Zero or more: Space, symbolic nb-space, line break
	$part_list_word =
		'(?:-|–|—|−|~'      // hyphen, en dash, em dash, minus, tilda
		. '|/|&|[+]|×|x|,|;'  // slash, ampersand, plus, times, letter x, comma, semicolon
		. '|to|and|or|until|till|til|through|thru|into'
		. '|&ndash;|&mdash;|\{\{ndash\}\}'
		. ')';
	$part_c_list_separator = '(' . $part_list_commaopt . $part_list_spacing . '(?:' . $part_list_word . $part_list_spacing . ')?)';
 
	// Final search expressions 
	$regex_AMreg = '/' . $part_lc_md  . $part_AMreg_punct . $part_lc_y  . '/i';
	$regex_BRreg = '/' . $part_lc_dm  . $part_BRreg_punct . $part_lc_y  . '/i';
	$regex_AModd = '/' . $part_lc_md  . $part_AModd_punct . $part_lc_y  . '/i';
	$regex_BRodd = '/' . $part_lc_dm  . $part_BRodd_punct . $part_lc_y  . '/i';
	$regex_AMord = '/' . $part_lc_mn  . $part_c_gen_punct . $part_lc_y  . '/i';
	$regex_BRord = '/' . $part_lc_nm  . $part_c_gen_punct . $part_lc_y  . '/i';
	$regex_ordOf = '/' . $part_lc_nom . $part_c_gen_punct . $part_lc_y  . '/i';
	$regex_piped = '/' . $part_lc_piped . $part_c_gen_punct . $part_lc_y . '/i';
	$regex_YMD   = '/' . $part_lc_y   . $part_YMD_punct   . $part_lc_md . '/i';
	$regex_ISO1  = '/' . '\[\[(-?\d{4}-\d{2}-\d{2})\]\]' . '/i';            // [[yyyy-mm-dd]] or [[-yyyy-mm-dd]]
	$regex_ISO2  = '/' . '\[\[(-?\d{4})\]\]-\[\[(\d{2}-\d{2})\]\]' . '/i';  // [[yyyy]]-[[mm-dd]] or [[-yyyy]]-[[mm-dd]]
	// Note:  Negative year forms are also recognized in the above patterns for ISO-8601-like dates, but
	// will likely never be encountered.  Technically,  ISO 8601 dates are only valid for years 1583 through
	// 9999 of the Gregorian calendar, but we will not enforce those rules here.
 
	// Final replace expressions ("§~§" is a marker, deleted later, that supports date list processing)
	$replace_AM    = '§~§$1 $2, $3';
	$replace_BR    = '§~§$1 $2 $3';
	$replace_AMord = '§~§$1 $2$3$4';     // "(month) (dayth)(punct)(year)"
	$replace_BRord = '§~§$1 $2$3$4';     // "(dayth) (month)(punct)(year)"
	$replace_ordOf = '§~§$1 of $2$3$4';  // "(dayth) of (month)(punct)(year)"
	$replace_piped = '§~§$1$2$3';        // (piped-text)(punc)(year)
	$replace_YMD   = '$1 $2 $3';
	$replace_ISO1  = '$1';
	$replace_ISO2  = '$1-$2';
 
	// Date list search ("@" is used as a regex delimiter, since "/" is used in the eexpressions)
	$regex_AMlist    = '@' . $part_lc_md    . $part_c_list_separator . '(?=§~§)' . '@i';
	$regex_BRlist    = '@' . $part_lc_dm    . $part_c_list_separator . '(?=§~§)' . '@i';
	$regex_AMordList = '@' . $part_lc_mn    . $part_c_list_separator . '(?=§~§)' . '@i';
	$regex_BRordList = '@' . $part_lc_nm    . $part_c_list_separator . '(?=§~§)' . '@i';
	$regex_ordOfList = '@' . $part_lc_nom   . $part_c_list_separator . '(?=§~§)' . '@i';
	$regex_pipedList = '@' . $part_lc_piped . $part_c_list_separator . '(?=§~§)' . '@i';
 
	// Date list replace
	$replace_AMlist    = '§~§$1 $2$3';     // "(month) (day)(punct)..."  
	$replace_BRlist    = '§~§$1 $2$3';     // "(day) (month)(punct)..."
	$replace_AMordList = '§~§$1 $2$3';     // "(month) (dayth)(punct)..."
	$replace_BRordList = '§~§$1 $2$3';     // "(dayth) (month)(punct)..."
	$replace_ordOfList = '§~§$1 of $2$3';  // "(dayth) of (month)(punct)..."
	$replace_pipedList = '§~§$1$2';        // "(pipetext)(punct)..."
 
	// For information and review purposes, the above expressions are equivalent to:
	// $regex_AMreg = '/\[\[(Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|July?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)[ _](\d{1,2})\]\], \[\[(\d{1,4}(?:[ _]BC)?)\]\]/i'
	// $regex_BRreg = '/\[\[(\d{1,2})[ _](Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|July?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\]\] \[\[(\d{1,4}(?:[ _]BC)?)\]\]/i'
	// $regex_AModd = '/\[\[(Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|July?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)[ _](\d{1,2})\]\](?!, \[)(?: *(?:, *)?)\[\[(\d{1,4}(?:[ _]BC)?)\]\]/i'
	// $regex_BRodd = '/\[\[(\d{1,2})[ _](Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|July?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\]\](?! \[)(?: *(?:, *)?)\[\[(\d{1,4}(?:[ _]BC)?)\]\]/i'
	// $regex_YMD   = '/\[\[(\d{1,4}(?:[ _]BC)?)\]\] *\[\[(Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|July?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)[ _](\d{1,2})\]\]/i'
 
	// Define regex to change delinked all-lower-case months to proper case (leading cap)
	// Note that only the first few characters of the month are matched and replaced.  This handles full month names too.
	$part_c_opt_day_forms = '(' . $part_x . ' (?:of )?)?';  // empty, "d ", "dth ", or "dth of " (with trailing space)
	$proper_case_months = array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
	$regex_proper   = array();
	$replace_proper = array();
	for ($i = 0; $i < count($proper_case_months); $i++) {
		$proper_case_month = $proper_case_months[$i];
		$lower_case_month = strtolower($proper_case_month);
		$regex_proper[$i]   = '/(?<=§~§)' . $part_c_opt_day_forms . $lower_case_month . '/';  // Case sensitive regex
		$replace_proper[$i] = '$1' . $proper_case_month;   // $1 may be empty for month-day forms
	}
 
	// Remove any remaining placeholders.
	$regex_cleanup_final = '/' . '§~§' . '/i';
	$replace_cleanup_final = '';
 
	//==========  Begin search and replace ordinary dates
 
	$match_count = 0;
	$contents = preg_replace($regex_AMreg, $replace_AM, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "AMreg(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_BRreg, $replace_BR, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "BRreg(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_AModd, $replace_AM, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "AModd(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_BRodd, $replace_BR, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "BRodd(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_AMord, $replace_AMord, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "AMord(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_BRord, $replace_BRord, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "BRord(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_ordOf, $replace_ordOf, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "ordOf(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_piped, $replace_piped, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "piped(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_YMD, $replace_YMD, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "YMD(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_ISO1, $replace_ISO1, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "ISO1(×" . $match_count . "), ";
	}
 
	$match_count = 0;
	$contents = preg_replace($regex_ISO2, $replace_ISO2, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "ISO2(×" . $match_count . "), ";
	}
 
	//==========  Begin search and replace date lists
 
	$AMlist_count = 0;
	$BRlist_count = 0;
	$AMordList_count = 0;
	$BRordList_count = 0;
	$ordOfList_count = 0;
	$pipedList_count = 0;
 
	// Process additional date parts to the left of a previously identified date or list.
	// Loop for a maximum or 10 iterations or until no more matches are found
	for ($i = 0; $i < 10; $i++) {
		$current_iteration_match_count = 0; 
 
		$match_count = 0;
		$contents = preg_replace($regex_AMlist, $replace_AMlist, $contents, -1, &$match_count);
		$AMlist_count += $match_count;
		$current_iteration_match_count += $match_count;
 
		$match_count = 0;
		$contents = preg_replace($regex_BRlist, $replace_BRlist, $contents, -1, &$match_count);
		$BRlist_count += $match_count;
		$current_iteration_match_count += $match_count;
 
		$match_count = 0;
		$contents = preg_replace($regex_AMordList, $replace_AMordList, $contents, -1, &$match_count);
		$AMordList_count += $match_count;
		$current_iteration_match_count += $match_count;
 
		$match_count = 0;
		$contents = preg_replace($regex_BRordList, $replace_BRordList, $contents, -1, &$match_count);
		$BRordList_count += $match_count;
		$current_iteration_match_count += $match_count;
 
		$match_count = 0;
		$contents = preg_replace($regex_ordOfList, $replace_ordOfList, $contents, -1, &$match_count);
		$ordOfList_count += $match_count;
		$current_iteration_match_count += $match_count;
 
		$match_count = 0;
		$contents = preg_replace($regex_pipedList, $replace_pipedList, $contents, -1, &$match_count);
		$pipedList_count += $match_count;
		$current_iteration_match_count += $match_count;
 
		if ($current_iteration_match_count == 0) break;  // No more list extensions found
	}
 
	// Add list extension counts to summary
	if ($AMlist_count > 0) {
		$editsummary .= "AMlist(×" . $AMlist_count . "), ";
	}
 
	if ($BRlist_count > 0) {
		$editsummary .= "BRlist(×" . $BRlist_count . "), ";
	}
 
	if ($AMordList_count > 0) {
		$editsummary .= "AMordList(×" . $AMordList_count . "), ";
	}
 
	if ($BRordList_count > 0) {
		$editsummary .= "BRordList(×" . $BRordList_count . "), ";
	}
 
	if ($ordOfList_count > 0) {
		$editsummary .= "ordOfList(×" . $ordOfList_count . "), ";
	}
 
	if ($pipedList_count > 0) {
		$editsummary .= "pipedList(×" . $pipedList_count . "), ";
	}
 
	// Change delinked all-lower-case months to proper case (leading cap)
	$match_count = 0;
	$contents = preg_replace($regex_proper, $replace_proper, $contents, -1, &$match_count);
	if ($match_count > 0) {
		$editsummary .= "proper(×" . $match_count . "), ";
	}
 
	// Finalize date list item format and remove any remaining marker strings ("§~§")
	$contents = preg_replace($regex_cleanup_final, $replace_cleanup_final, $contents);
 
	//==========  Postprocessing
 
	$editsummary = substr($editsummary, 0, -2); // to get rid of superfluous comma and space
 
	// In extreme cases where the edit summary is too long, trim the fat but keep the beef
	if (strlen($editsummary) > 200) $editsummary = preg_replace('/\(×1\)/',  '',  $editsummary);  // Remove "(×1)"
	if (strlen($editsummary) > 200) $editsummary = preg_replace('/\, /',     ',', $editsummary);  // Remove spaces after commas
	if (strlen($editsummary) > 200) $editsummary = preg_replace('/\(×/',     '(', $editsummary);  // Remove "×" from all counts
	if (strlen($editsummary) > 200) $editsummary = preg_replace('/\..*:/',   ':', $editsummary);  // Remove most of lead-in
	if (strlen($editsummary) > 200) $editsummary = preg_replace('/\(\d*\)/', ',', $editsummary);  // Remove all remaining counts
 
	if (strlen($contents) == 0) {
		echo "Contents blanked during processing of article \"$link\".  Skipping save step.";
	}
 	else if ($contents != $contents_archive) {
		overridecheck(); // checks if the manual override has been triggered
		while (1 < 2) {
			do {
				$return_code = $objwiki->edit($link,$contents,$editsummary,true,true,null,true,5); // posts the change. The two "true" parameters indicate that this is a bot edit and it is a minor edit
			} while ($return_code['error']['code'] == "maxlag"); // more like "maxbaucus"
			if ($return_code['error']['code'] == "protectedpage") {
				break;
			}
			if (isset($return_code['error']['code'])) {
				die("Error code: " . $return_code['error']['code'] . "\n");
			}
			elseif (!isset($return_code['error']['code'])) {
				break;
			}
		}
		$sqlquery = query("INSERT INTO `unlinked` (`name`) VALUES (\"".mysql_real_escape_string($link)."\")");
		#sleep(6);
 	}
}
 
$months = array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");

$userpage = $objwiki->getpage("User:Full-date unlinking bot");
preg_match("/\/currently\|.*/i", $userpage, $statusbox);
$statusbox = str_replace("/currently|", "", $statusbox[0]);
$statusbox = str_replace("}}", "", $statusbox);
$md = explode(" ", $statusbox); // isolates the month and the date, since they are separated by a space

switch ($md[0]) {
	case "January":
		$md[0] = 0;
		break;
	case "February":
		$md[0] = 1;
		break;
	case "March":
		$md[0] = 2;
		break;
	case "April":
		$md[0] = 3;
		break;
	case "May":
		$md[0] = 4;
		break;
	case "June":
		$md[0] = 5;
		break;
	case "July":
		$md[0] = 6;
		break;
	case "August":
		$md[0] = 7;
		break;
	case "September":
		$md[0] = 8;
		break;
	case "October":
		$md[0] = 9;
		break;
	case "November":
		$md[0] = 10;
		break;
	case "December":
		$md[0] = 11;
		break;
	default:
		die("\n\nSomething went wrong. Raw input: " . $md[0] . "\n");
		break;
}

$firstiteration = true;

for ($i = 0; $i < count($months); $i++) { // for each month
	for ($d = 1; $d < 32; $d++) { // This is like the above, except with different date combinations
		if ($firstiteration == true) {
			$i = $md[0];
			$d = $md[1];
			$firstiteration = false;
		}
		
		echo "Checking backlinks to " . $months[$i] . " " . $d . "\n";
		
		$userpage = $objwiki->getpage("User:Full-date unlinking bot");
		$userpage = preg_replace("/\/currently\|.*/i", "/currently|" . $months[$i] . " " . $d . "}}", $userpage);
		$objwiki->edit("User:Full-date unlinking bot",$userpage,"Now processing: " . $months[$i] . " " . $d,true,true);
		unset($userpage);
		
		$links = $objwiki->whatlinkshere($months[$i] . " " . $d, "&blnamespace=0");
		for ($j = 0; $j < count($links); $j++) {
			echo "Checking " . $links[$j] . "\n";
			if (checktoprocess($links[$j])) {
				echo $links[$j] . " shall be processed.\n";
				do {
					$conflict_check = unlinker($links[$j]);
				} while ($conflict_check === true);
				unset($conflict_check);
			}
			else {
				echo $links[$j] . " shall NOT be processed.\n";
			}
		}
	}
}
?>