User:QuietBot/src
From TheKolWiki
<? require("Snoopy.class.php"); class wikibot { protected $snoopy; protected $root, $user, $pass; protected $title; protected $loggedin; protected $edittoken; protected $debug; public function __construct ($root, $user, $pass, $debug = FALSE) { $this->snoopy = new Snoopy; $this->root = $root; $this->user = $user; $this->pass = $pass; $this->debug = $debug; $this->title = ''; $this->edittoken = ''; $this->loggedin = FALSE; } public function __destruct () { if ($this->loggedin) $this->logout(); } protected function post ($action, $parms = array()) { if ($this->snoopy->submit($this->root . "/api.php?format=php&action=". $action, $parms)) { $result = unserialize($this->snoopy->results); return $this->checkError($result, $action); } else return 'HTTP request failed'; } protected function checkError ($data, $action) { if (isset($data[$action])) return $data[$action]; if (!isset($data['error'])) return 'unknown error'; return $data['error']['code'] .' ('. $data['error']['info'] .')'; } // Establish session for editing wiki pages public function login () { if ($this->loggedin) return $this->error("ERROR: already logged in!", 1); $login = $this->post('login', array('lgname' => $this->user, 'lgpassword' => $this->pass)); if (!is_array($login)) return $this->error("ERROR: Login failed (1) - $login", 2); if ($login['result'] == 'NeedToken') { $login = $this->post('login', array('lgname' => $this->user, 'lgpassword' => $this->pass, 'lgtoken' => $login['token'])); if (!is_array($login)) return $this->error("FATAL ERROR: Login failed (2) - $login", 3); } if ($login['result'] != 'Success') return $this->error("Login failed: ". $login['result'], 3); $this->loggedin = TRUE; return 0; } // Terminate active session public function logout () { if (!$this->loggedin) return $this->error("ERROR: not logged in!", 1); $logout = $this->post('logout'); $this->loggedin = FALSE; $this->notice("Successfully logged out."); return 0; } // Load page contents. Required for any sort of editing. public function loadPage ($title) { if (!$this->loggedin) return $this->error("ERROR: not logged in!", 1); $query = $this->post('query', array('prop' => 'info|revisions', 'rvprop' => 'content', 'intoken' => 'edit', 'titles' => $title)); if (!is_array($query)) return $this->error("ERROR in loadPage - $query", 2); list($page_id) = array_keys($query['pages']); if (!$page_id) return $this->error("Failed to load page $this->title", 3); $data = $query['pages'][$page_id]['revisions'][0]['*']; $this->edittoken = $query['pages'][$page_id]['edittoken']; $this->title = $title; $this->notice("Successfully loaded page $this->title"); return array('text' => $data); } // Create new page with specified contents and reason. Fails if page already exists public function createPage ($title, $data, $reason, $minor = false) { if (!$this->loggedin) return $this->error("ERROR: not logged in!", 1); $query = $this->post('query', array('prop' => 'info', 'intoken' => 'edit', 'titles' => $title)); if (!is_array($query)) return $this->error("ERROR in createPage (1) - $query", 2); if (!isset($query['pages'][-1])) return $this->error("ERROR: page $title already exists!", 3); $edittoken = $query['pages'][-1]['edittoken']; $edit = $this->post('edit', array('title' => $title, 'text' => $data, 'bot' => 1, 'summary' => $reason, ($minor ? 'minor' : 'notminor') => 1, 'createonly' => 1, 'token' => $edittoken)); if (!is_array($edit)) return $this->error("FATAL ERROR in createPage (2) - $edit", 4); if ($edit['result'] != 'Success') return $this->error("Failed to create page $title: ". $edit['result'], 5); $this->notice("Successfully created page $title"); return 0; } // Saves new data into previously loaded page. Cannot be called twice in a row - must call loadPage() afterwards public function savePage ($data, $reason, $minor = false) { if (!$this->loggedin) return $this->error("ERROR: not logged in!", 1); if (!strlen($this->title) || !strlen($this->edittoken)) return $this->error("ERROR: attempted to save page without first loading one", 2); $edit = $this->post('edit', array('title' => $this->title, 'text' => $data, 'bot' => 1, 'summary' => $reason, ($minor ? 'minor' : 'notminor') => 1, 'token' => $this->edittoken)); if (!is_array($edit)) return $this->error("ERROR in savePage - $edit", 3); if ($edit['result'] != 'Success') return $this->error("Failed to save page $this->title: ". $edit['result'], 4); $this->notice("Successfully saved page $this->title"); $this->title = ''; $this->edittoken = ''; return 0; } // Renames one page to another, suppressing creation of a redirect. // Generally requires sufficient privileges to perform. public function movePage ($old, $new, $reason) { if (!$this->loggedin) return $this->error("ERROR: not logged in!", 1); $query = $this->post('query', array('prop' => 'info', 'intoken' => 'move', 'titles' => $old)); if (!is_array($query)) return $this->error("ERROR: Move failed (1) - $query", 2); list($page_id) = array_keys($query['pages']); $movetoken = $query['pages'][$page_id]['movetoken']; $move = $this->post('move', array('from' => $old, 'to' => $new, 'reason' => $reason, 'token' => $movetoken, 'noredirect' => 1)); if (!is_array($move)) return $this->error("ERROR: Move failed (2) - $move", 3); $this->notice("Successfully moved page $old to $new"); return 0; } // Deletes a page. // Generally requires sufficient privileges to perform. public function deletePage ($title, $reason) { if (!$this->loggedin) return $this->error("ERROR: not logged in!", 1); $query = $this->post('query', array('prop' => 'info', 'intoken' => 'delete', 'titles' => $title)); if (!is_array($query)) return $this->error("ERROR: Delete failed (1) - $query", 2); list($page_id) = array_keys($query['pages']); $deletetoken = $query['pages'][$page_id]['deletetoken']; $delete = $this->post('delete', array('title' => $title, 'reason' => $reason, 'token' => $deletetoken)); if (!is_array($delete)) return $this->error("ERROR: Delete failed (2) - $delete", 3); $this->notice("Successfully deleted page $title"); return 0; } // Clears the cached state of a page, forcing it to be regenerated. public function purgePage ($title) { if (!$this->loggedin) return $this->error("ERROR: not logged in!", 1); $purge = $this->post('purge', array('titles' => $title)); if (!is_array($purge)) return $this->error("ERROR: Purge failed - $purge", 2); if (($purge[0]['title'] == $title) && isset($purge[0]['purged'])) { $this->notice("Successfully purged page $title"); return 0; } return $this->error("Failed to purge page $title", 2); } // Checks if any edits have been made to the bot's User Talk page and aborts execution. // Must be called manually so the bot can be remotely shut down if it runs out of control public function checkAbort ($abort = true) { if (!$this->loggedin) return $this->error("ERROR: not logged in!", 1); $query = $this->post('query', array('meta' => 'userinfo', 'uiprop' => 'hasmsg')); if (!is_array($query)) return $this->fatal("FATAL ERROR: Could not check for new messages - $query"); if (!isset($query['userinfo']['messages'])) return NULL; // Acknowledge it $this->snoopy->fetch($this->root . '/index.php/User_talk:'. $this->user); if ($abort) return $this->fatal("\n\n\n*** Received abort signal!"); else return $this->error("***Received abort signal!", 2); } protected function fatal ($text) { die($text."\n"); // this will never be reached return -1; } protected function error ($text, $errno = 0) { if ($this->debug) echo $text."\n"; return $errno; } protected function notice ($text) { if ($this->debug) echo $text."\n"; } } function pagenum ($num, $max) { return str_pad($num + 1, strlen($max), '0', STR_PAD_LEFT); } ?>
Note that you must also patch Snoopy.class.php (version 1.2.4) as follows:
<? --- Snoopy.class.php 2010-03-07 17:16:14.000000000 +0000 +++ Snoopy.class.php.new 2010-03-07 17:20:27.000000000 +0000 @@ -191,8 +191,10 @@ } else { + $this->_redirectdepth = 0; return false; } + $this->_redirectdepth = 0; return true; break; case "https": @@ -248,14 +250,17 @@ break; } } + $this->_redirectdepth = 0; return true; break; default: // not a valid protocol $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; + $this->_redirectdepth = 0; return false; break; } + $this->_redirectdepth = 0; return true; } @@ -350,8 +355,10 @@ } else { + $this->_redirectdepth = 0; return false; } + $this->_redirectdepth = 0; return true; break; case "https": @@ -413,15 +420,18 @@ break; } } + $this->_redirectdepth = 0; return true; break; default: // not a valid protocol $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; + $this->_redirectdepth = 0; return false; break; } + $this->_redirectdepth = 0; return true; } ?>
If this patch is not applied, this bug will cause the redirect depth to eventually reach its limit (5) and cause all subsequent savePage operations to appear to fail.