/** * Converts an XML url or string to a PHP array format * * @static * @access public * @param string $data Either an url to an xml file, or a raw XML string. Peachy will autodetect which is which. * @return array Parsed XML * @throws BadEntryError * @throws DependencyError * @throws HookError * @throws XMLError */ public static function load($data) { $http = HTTP::getDefaultInstance(); if (!function_exists('simplexml_load_string')) { throw new DependencyError("SimpleXML", "http://us.php.net/manual/en/book.simplexml.php"); } libxml_use_internal_errors(true); if (in_string("<?xml", $data)) { $xmlout = $data; } else { $xmlout = $http->get($data); } Hooks::runHook('PreSimpleXMLLoad', array(&$xmlout)); $xml = simplexml_load_string($xmlout); Hooks::runHook('PostSimpleXMLLoad', array(&$xml)); if (!$xml) { foreach (libxml_get_errors() as $error) { throw new XMLError($error); } } $outArr = array(); $namespaces = $xml->getNamespaces(true); $namespaces['default'] = ''; self::recurse($xml, $outArr, $namespaces); libxml_clear_errors(); return $outArr; }
/** * Performs various checks and settings * Checks if MW version is at least {@link MINMW} * * @static * @access public * @param string $base_url URL to api.php * @throws DependencyError * @return array Installed extensions */ public static function wikiChecks($base_url) { $http = HTTP::getDefaultInstance(); $siteinfo = unserialize($http->get($base_url, array('action' => 'query', 'meta' => 'siteinfo', 'format' => 'php', 'siprop' => 'extensions|general'))); if (isset($siteinfo['error']) && $siteinfo['error']['code'] == 'readapidenied') { global $pgHooks; $pgHooks['PostLogin'][] = array('Peachy::wikiChecks', $base_url); return array(MINMW, array()); } $version = preg_replace('/[^0-9\\.]/', '', $siteinfo['query']['general']['generator']); if (version_compare($version, MINMW) < 0) { throw new DependencyError("MediaWiki " . MINMW, "http://mediawiki.org"); } $extensions = array(); foreach ($siteinfo['query']['extensions'] as $ext) { if (isset($ext['version'])) { $extensions[$ext['name']] = $ext['version']; } else { $extensions[$ext['name']] = ''; } } return array($version, $extensions); }
/** * Construct function for the wiki. Handles login and related functions. * * @access public * @see Peachy::newWiki() * @param array $configuration Array with configuration data. At least needs username, password, and base_url. * @param array $extensions Array of names of extensions installed on the wiki and their versions (default: array()) * @param int $recursed Is the function recursing itself? Used internally, don't use (default: 0) * @param mixed $token Token if the wiki needs a token. Used internally, don't use (default: null) * @throws LoginError */ public function __construct($configuration, $extensions = array(), $recursed = 0, $token = null) { global $pgProxy, $pgVerbose, $pgUseSSH, $pgHost, $pgPort, $pgUsername, $pgPrikey, $pgPassphrase, $pgProtocol, $pgTimeout; $this->cached_config['config'] = $configuration; $this->cached_config['extensions'] = $extensions; if (!array_key_exists('encodedparams', $configuration)) { $configuration['encodedparams'] = rawurlencode(serialize($configuration)); } $this->base_url = $configuration['baseurl']; $this->username = $configuration['username']; $this->extensions = $extensions; $this->generatorvalues = array('allcategories', 'allimages', 'alllinks', 'allpages', 'alltransclusions', 'backlinks', 'categories', 'categorymembers', 'duplicatefiles', 'embeddedin', 'exturlusage', 'geosearch', 'images', 'imageusage', 'iwbacklinks', 'langbacklinks', 'links', 'oldreviewedpages', 'protectedtitles', 'querypage', 'random', 'recentchanges', 'search', 'templates', 'watchlist', 'watchlistraw'); if (isset($configuration['editwhileloggedout'])) { $this->allowLoggedOutEditing = true; } if (isset($configuration['requirebotflag'])) { $this->requiresFlag = true; } if (isset($configuration['editsperminute']) && $configuration['editsperminute'] != 0) { $this->edit_rate = $configuration['editsperminute']; } if (isset($configuration['proxyaddr'])) { $pgProxy['addr'] = $configuration['proxyaddr']; if (isset($configuration['proxytype'])) { $pgProxy['type'] = $configuration['proxytype']; } if (isset($configuration['proxyport'])) { $pgProxy['port'] = $configuration['proxyport']; } if (isset($configuration['proxyuser']) && isset($configuration['proxypass'])) { $pgProxy['userpass'] = $configuration['proxyuser'] . ':' . $configuration['proxypass']; } } $http_echo = isset($configuration['httpecho']) && $configuration['httpecho'] === "true"; if (is_null($this->http)) { $this->http = HTTP::getDefaultInstance($http_echo); } if ($pgUseSSH) { if (!$this->SSH) { $this->SSH = new SSH($pgHost, $pgPort, $pgUsername, $pgPassphrase, $pgPrikey, $pgProtocol, $pgTimeout, $this->http); } if (!$this->SSH->connected) { $this->SSH = null; } } else { $this->SSH = null; } if (isset($configuration['runpage'])) { $this->runpage = $configuration['runpage']; } if (isset($configuration['useragent'])) { $this->http->setUserAgent($configuration['useragent']); } $use_cookie_login = false; if (isset($configuration['cookiejar'])) { $this->http->setCookieJar($configuration['cookiejar']); } else { $this->http->setCookieJar(sys_get_temp_dir() . '/PeachyCookieSite' . sha1($configuration['encodedparams'])); if ($this->is_logged_in()) { $use_cookie_login = true; } } if (isset($configuration['optout'])) { $this->optout = $configuration['optout']; } if (isset($configuration['stoponnewmessages'])) { $this->stoponnewmessages = true; } if (isset($configuration['verbose'])) { $pgVerbose = array(); $tmp = explode('|', $configuration['verbose']); foreach ($tmp as $setting) { if ($setting == "ALL") { $pgVerbose = array(PECHO_NORMAL, PECHO_NOTICE, PECHO_WARN, PECHO_ERROR, PECHO_FATAL); break; } else { switch ($setting) { case 'NORMAL': $pgVerbose[] = PECHO_NORMAL; break; case 'NOTICE': $pgVerbose[] = PECHO_NOTICE; break; case 'WARN': $pgVerbose[] = PECHO_WARN; break; case 'ERROR': $pgVerbose[] = PECHO_ERROR; break; case 'FATAL': $pgVerbose[] = PECHO_FATAL; break; case 'VERBOSE': $pgVerbose[] = PECHO_VERBOSE; break; } } } unset($tmp); } if (isset($configuration['nobots']) && $configuration['nobots'] == 'false' || strpos($configuration['baseurl'], '//en.wikipedia.org/w/api.php') === false) { $this->nobots = false; } $lgarray = array('lgname' => $this->username, 'lgpassword' => $configuration['password'], 'action' => 'login'); if (isset($configuration['maxlag']) && $configuration['maxlag'] != "0") { $this->maxlag = $configuration['maxlag']; $lgarray['maxlag'] = $this->maxlag; } if (!is_null($token)) { $lgarray['lgtoken'] = $token; } // FIXME: Why is there a return in a constructor? Should an error be thrown? if (isset($configuration['nologin'])) { $this->nologin = true; return; } if ($use_cookie_login) { pecho("Logging in to {$this->base_url} as {$this->username}, using a saved login cookie\n\n", PECHO_NORMAL); $this->runSuccess($configuration); } elseif (!$this->nologin) { Hooks::runHook('PreLogin', array(&$lgarray)); if (!$recursed) { pecho("Logging in to {$this->base_url}...\n\n", PECHO_NOTICE); } $loginRes = $this->apiQuery($lgarray, true, true, false, false); Hooks::runHook('PostLogin', array(&$loginRes)); } if (isset($loginRes['login']['result'])) { switch ($loginRes['login']['result']) { case 'NoName': throw new LoginError(array('NoName', 'Username not specified')); case 'Illegal': throw new LoginError(array('Illegal', 'Username with illegal characters specified')); case 'NotExists': throw new LoginError(array('NotExists', 'Username specified does not exist')); case 'EmptyPass': throw new LoginError(array('EmptyPass', 'Password not specified')); case 'WrongPass': throw new LoginError(array('WrongPass', 'Incorrect password specified')); case 'WrongPluginPass': throw new LoginError(array('WrongPluginPass', 'Incorrect password specified')); case 'CreateBlocked': throw new LoginError(array('CreateBlocked', 'IP address has been blocked')); case 'Throttled': if ($recursed > 2) { throw new LoginError(array('Throttled', 'Login attempts have been throttled')); } $wait = $loginRes['login']['wait']; pecho("Login throttled, waiting {$wait} seconds.\n\n", PECHO_NOTICE); sleep($wait); $recres = $this->__construct($configuration, $this->extensions, $recursed + 1); return $recres; case 'Blocked': throw new LoginError(array('Blocked', 'User specified has been blocked')); case 'NeedToken': if ($recursed > 2) { throw new LoginError(array('NeedToken', 'Token was not specified')); } $token = $loginRes['login']['token']; $recres = $this->__construct($configuration, $this->extensions, $recursed + 1, $token); return $recres; case 'Success': pecho("Successfully logged in to {$this->base_url} as {$this->username}\n\n", PECHO_NORMAL); $this->runSuccess($configuration); } } }