User:Full-date unlinking bot/code

/** 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.org/wiki/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. 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 = '(?: | |
)*'; // 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\}\}'

. ')';

$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";

}

}

}

}

?>