function getFacebookHTML($showimages = false) { global $wgParser, $wgServer; $feeds = FeaturedArticles::getFeaturedArticles(1); $html = "<fb:title>The How-to Article of the Day</fb:title>\n\t\t\t\t<fb:subtitle><a href='http://www.wikihow.com'>from wikiHow</a></fb:subtitle>\n\t\t"; $now = time(); $dbr = wfGetDB(DB_SLAVE); foreach ($feeds as $f) { $url = $f[0]; $d = $f[1]; if ($d > $now) { continue; } $url = str_replace("http://www.wikihow.com/", "", $url); $url = str_replace("{$wgServer}/", "", $url); $title = Title::newFromURL(urldecode($url)); // get last safe id $res = $dbr->select('revision', array('rev_user', 'rev_id', 'rev_user_text'), array('rev_page' => $title->getArticleId(), 'rev_user>0'), "wfGetFacebookHTML", array('ORDER BY' => 'rev_id desc')); $rev_id = 0; while ($row = $dbr->fetchObject($res)) { $num_edits = $dbr->selectField('revision', 'count(*)', array("rev_user={$row->rev_user}")); if ($num_edits > 300) { $rev_id = $row->rev_id; break; } } $dbr->freeResult($res); $revision = null; if ($rev_id > 0) { $revision = Revision::newFromID($rev_id); } else { $revision = Revision::newFromTitle($title); } $summary = Article::getSection($revision->getText(), 0); $summary = ereg_replace("\\{\\{.*\\}\\}", "", $summary); if (!$showimages) { $summary = preg_replace("/\\[\\[Image[^\\]]*\\]\\]/", "", $summary); } // strip images $output = $wgParser->parse($summary, $title, new ParserOptions()); $summary = strip_tags($output->getText(), '<img>'); $img = ""; $style = 'style="float:right;margin-left:10px;margin-bottom:10px;"'; if (strpos($summary, "<img") !== false && $showimages) { $re = '/<img[^>]*>/'; preg_match_all($re, $summary, $matches); $summary = preg_replace($re, '', $summary); $img = $matches[0][0]; preg_match_all('/width="[0-9]*"/', $img, $matches); $width = 200; if (sizeof($matches[0]) > 0) { $s_width = str_replace('width=', '', $matches[0][0]); $s_width = str_replace('"', '', $s_width); $s_width = intval($s_width); if ($s_width < $width) { $width = $s_width; } } $src = ""; preg_match_all('/src="[^"]*"/', $img, $matches); if (sizeof($matches[0]) > 0) { $src = str_replace("src=", "", $matches[0][0]); $src = str_replace('"', "", $src); if (strpos($src, "http://www.wikihow.com") === false) { $src = "http://www.wikihow.com" . $src; } } $img = "<img src=\"{$src}\" {$style} width=\"{$width}\">"; } else { $img = "<img src=\"http://www.wikihow.com/skins/WikiHow/wikiHow.gif\" {$style} width=\"100\"/>"; } $html .= "<p style=\"font-size:1.2em;margin:2px 0;\"><a href='{$title->getFullURL()}' style=\"font-weight:bold\">" . wfMsg('howto', $title->getText()) . '</a></p>'; $html .= "<p>\n\t\t\t\t{$img} \n\t\t\t\t{$summary}\n\t\t\t\t</p>\n\t\t\t\t<p><a href='{$title->getFullURL()}'>Read more...</a></p>"; $html .= '<table style="clear:both;margin:0 auto;"><tr><td>Do you want to do this? | </td><td >' . "<fb:share-button class='url' href='{$title->getFullURL()}'/> </td></tr></table>"; break; } $html .= '<fb:if-is-own-profile> <fb:else><br/><div style="text-align:right;"><a href="http://apps.facebook.com/howtooftheday">Put this on my profile</a></div></fb:else></fb:if-is-own-profile>'; return $html; }
public function execute() { // The data is hot but user-dependent, like page views, so we set vary cookies $this->getMain()->setCacheMode('anon-public-user-private'); // Get parameters $params = $this->extractRequestParams(); $text = $params['text']; $title = $params['title']; $page = $params['page']; $pageid = $params['pageid']; $oldid = $params['oldid']; $model = $params['contentmodel']; $format = $params['contentformat']; if (!is_null($page) && (!is_null($text) || $title != 'API')) { $this->dieUsage('The page parameter cannot be used together with the text and title parameters', 'params'); } $prop = array_flip($params['prop']); if (isset($params['section'])) { $this->section = $params['section']; } else { $this->section = false; } // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* // TODO: Does this still need $wgTitle? global $wgParser, $wgTitle; // Currently unnecessary, code to act as a safeguard against any change in current behaviour of uselang breaks $oldLang = null; if (isset($params['uselang']) && $params['uselang'] != $this->getContext()->getLanguage()->getCode()) { $oldLang = $this->getContext()->getLanguage(); // Backup language $this->getContext()->setLanguage(Language::factory($params['uselang'])); } $redirValues = null; // Return result $result = $this->getResult(); if (!is_null($oldid) || !is_null($pageid) || !is_null($page)) { if (!is_null($oldid)) { // Don't use the parser cache $rev = Revision::newFromID($oldid); if (!$rev) { $this->dieUsage("There is no revision ID {$oldid}", 'missingrev'); } if (!$rev->userCan(Revision::DELETED_TEXT, $this->getUser())) { $this->dieUsage("You don't have permission to view deleted revisions", 'permissiondenied'); } $titleObj = $rev->getTitle(); $wgTitle = $titleObj; $pageObj = WikiPage::factory($titleObj); $popts = $pageObj->makeParserOptions($this->getContext()); $popts->enableLimitReport(!$params['disablepp']); // If for some reason the "oldid" is actually the current revision, it may be cached if ($rev->isCurrent()) { // May get from/save to parser cache $p_result = $this->getParsedContent($pageObj, $popts, $pageid, isset($prop['wikitext'])); } else { // This is an old revision, so get the text differently $this->content = $rev->getContent(Revision::FOR_THIS_USER, $this->getUser()); if ($this->section !== false) { $this->content = $this->getSectionContent($this->content, 'r' . $rev->getId()); } // Should we save old revision parses to the parser cache? $p_result = $this->content->getParserOutput($titleObj, $rev->getId(), $popts); } } else { // Not $oldid, but $pageid or $page if ($params['redirects']) { $reqParams = array('action' => 'query', 'redirects' => ''); if (!is_null($pageid)) { $reqParams['pageids'] = $pageid; } else { // $page $reqParams['titles'] = $page; } $req = new FauxRequest($reqParams); $main = new ApiMain($req); $main->execute(); $data = $main->getResultData(); $redirValues = isset($data['query']['redirects']) ? $data['query']['redirects'] : array(); $to = $page; foreach ((array) $redirValues as $r) { $to = $r['to']; } $pageParams = array('title' => $to); } elseif (!is_null($pageid)) { $pageParams = array('pageid' => $pageid); } else { // $page $pageParams = array('title' => $page); } $pageObj = $this->getTitleOrPageId($pageParams, 'fromdb'); $titleObj = $pageObj->getTitle(); if (!$titleObj || !$titleObj->exists()) { $this->dieUsage("The page you specified doesn't exist", 'missingtitle'); } $wgTitle = $titleObj; if (isset($prop['revid'])) { $oldid = $pageObj->getLatest(); } $popts = $pageObj->makeParserOptions($this->getContext()); $popts->enableLimitReport(!$params['disablepp']); // Potentially cached $p_result = $this->getParsedContent($pageObj, $popts, $pageid, isset($prop['wikitext'])); } } else { // Not $oldid, $pageid, $page. Hence based on $text $titleObj = Title::newFromText($title); if (!$titleObj) { $this->dieUsageMsg(array('invalidtitle', $title)); } if (!$titleObj->canExist()) { $this->dieUsage("Namespace doesn't allow actual pages", 'pagecannotexist'); } $wgTitle = $titleObj; $pageObj = WikiPage::factory($titleObj); $popts = $pageObj->makeParserOptions($this->getContext()); $popts->enableLimitReport(!$params['disablepp']); if (is_null($text)) { $this->dieUsage('The text parameter should be passed with the title parameter. Should you be using the "page" parameter instead?', 'params'); } try { $this->content = ContentHandler::makeContent($text, $titleObj, $model, $format); } catch (MWContentSerializationException $ex) { $this->dieUsage($ex->getMessage(), 'parseerror'); } if ($this->section !== false) { $this->content = $this->getSectionContent($this->content, $titleObj->getText()); } if ($params['pst'] || $params['onlypst']) { $this->pstContent = $this->content->preSaveTransform($titleObj, $this->getUser(), $popts); } if ($params['onlypst']) { // Build a result and bail out $result_array = array(); $result_array['text'] = array(); $result->setContent($result_array['text'], $this->pstContent->serialize($format)); if (isset($prop['wikitext'])) { $result_array['wikitext'] = array(); $result->setContent($result_array['wikitext'], $this->content->serialize($format)); } $result->addValue(null, $this->getModuleName(), $result_array); return; } // Not cached (save or load) if ($params['pst']) { $p_result = $this->pstContent->getParserOutput($titleObj, null, $popts); } else { $p_result = $this->content->getParserOutput($titleObj, null, $popts); } } $result_array = array(); $result_array['title'] = $titleObj->getPrefixedText(); if (!is_null($oldid)) { $result_array['revid'] = intval($oldid); } if ($params['redirects'] && !is_null($redirValues)) { $result_array['redirects'] = $redirValues; } if (isset($prop['text'])) { $result_array['text'] = array(); $result->setContent($result_array['text'], $p_result->getText()); } if (!is_null($params['summary'])) { $result_array['parsedsummary'] = array(); $result->setContent($result_array['parsedsummary'], Linker::formatComment($params['summary'], $titleObj)); } if (isset($prop['langlinks'])) { $result_array['langlinks'] = $this->formatLangLinks($p_result->getLanguageLinks()); } if (isset($prop['languageshtml'])) { $languagesHtml = $this->languagesHtml($p_result->getLanguageLinks()); $result_array['languageshtml'] = array(); $result->setContent($result_array['languageshtml'], $languagesHtml); } if (isset($prop['categories'])) { $result_array['categories'] = $this->formatCategoryLinks($p_result->getCategories()); } if (isset($prop['categorieshtml'])) { $categoriesHtml = $this->categoriesHtml($p_result->getCategories()); $result_array['categorieshtml'] = array(); $result->setContent($result_array['categorieshtml'], $categoriesHtml); } if (isset($prop['links'])) { $result_array['links'] = $this->formatLinks($p_result->getLinks()); } if (isset($prop['templates'])) { $result_array['templates'] = $this->formatLinks($p_result->getTemplates()); } if (isset($prop['images'])) { $result_array['images'] = array_keys($p_result->getImages()); } if (isset($prop['externallinks'])) { $result_array['externallinks'] = array_keys($p_result->getExternalLinks()); } if (isset($prop['sections'])) { $result_array['sections'] = $p_result->getSections(); } if (isset($prop['displaytitle'])) { $result_array['displaytitle'] = $p_result->getDisplayTitle() ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText(); } if (isset($prop['headitems']) || isset($prop['headhtml'])) { $context = $this->getContext(); $context->setTitle($titleObj); $context->getOutput()->addParserOutputNoText($p_result); if (isset($prop['headitems'])) { $headItems = $this->formatHeadItems($p_result->getHeadItems()); $css = $this->formatCss($context->getOutput()->buildCssLinksArray()); $scripts = array($context->getOutput()->getHeadScripts()); $result_array['headitems'] = array_merge($headItems, $css, $scripts); } if (isset($prop['headhtml'])) { $result_array['headhtml'] = array(); $result->setContent($result_array['headhtml'], $context->getOutput()->headElement($context->getSkin())); } } if (isset($prop['iwlinks'])) { $result_array['iwlinks'] = $this->formatIWLinks($p_result->getInterwikiLinks()); } if (isset($prop['wikitext'])) { $result_array['wikitext'] = array(); $result->setContent($result_array['wikitext'], $this->content->serialize($format)); if (!is_null($this->pstContent)) { $result_array['psttext'] = array(); $result->setContent($result_array['psttext'], $this->pstContent->serialize($format)); } } if (isset($prop['properties'])) { $result_array['properties'] = $this->formatProperties($p_result->getProperties()); } if ($params['generatexml']) { if ($this->content->getModel() != CONTENT_MODEL_WIKITEXT) { $this->dieUsage("generatexml is only supported for wikitext content", "notwikitext"); } $wgParser->startExternalParse($titleObj, $popts, OT_PREPROCESS); $dom = $wgParser->preprocessToDom($this->content->getNativeData()); if (is_callable(array($dom, 'saveXML'))) { $xml = $dom->saveXML(); } else { $xml = $dom->__toString(); } $result_array['parsetree'] = array(); $result->setContent($result_array['parsetree'], $xml); } $result_mapping = array('redirects' => 'r', 'langlinks' => 'll', 'categories' => 'cl', 'links' => 'pl', 'templates' => 'tl', 'images' => 'img', 'externallinks' => 'el', 'iwlinks' => 'iw', 'sections' => 's', 'headitems' => 'hi', 'properties' => 'pp'); $this->setIndexedTagNames($result_array, $result_mapping); $result->addValue(null, $this->getModuleName(), $result_array); if (!is_null($oldLang)) { $this->getContext()->setLanguage($oldLang); // Reset language to $oldLang } }
public function execute() { global $wgUser; $params = $this->extractRequestParams(); if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) { $this->dieUsageMsg(array('missingtext')); } $titleObj = Title::newFromText($params['title']); if (!$titleObj || $titleObj->isExternal()) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } if ($params['redirect']) { if ($titleObj->isRedirect()) { $oldTitle = $titleObj; $titles = Title::newFromRedirectArray(Revision::newFromTitle($oldTitle)->getText(Revision::FOR_THIS_USER)); $redirValues = array(); foreach ($titles as $id => $newTitle) { if (!isset($titles[$id - 1])) { $titles[$id - 1] = $oldTitle; } $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText()); $titleObj = $newTitle; } $this->getResult()->setIndexedTagName($redirValues, 'r'); $this->getResult()->addValue(null, 'redirects', $redirValues); } } // Some functions depend on $wgTitle == $ep->mTitle global $wgTitle; $wgTitle = $titleObj; if ($params['createonly'] && $titleObj->exists()) { $this->dieUsageMsg(array('createonly-exists')); } if ($params['nocreate'] && !$titleObj->exists()) { $this->dieUsageMsg(array('nocreate-missing')); } // Now let's check whether we're even allowed to do this $errors = $titleObj->getUserPermissionsErrors('edit', $wgUser); if (!$titleObj->exists()) { $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $wgUser)); } if (count($errors)) { $this->dieUsageMsg($errors[0]); } $articleObj = new Article($titleObj); $toMD5 = $params['text']; if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) { // For non-existent pages, Article::getContent() // returns an interface message rather than '' // We do want getContent()'s behavior for non-existent // MediaWiki: pages, though if ($articleObj->getID() == 0 && $titleObj->getNamespace() != NS_MEDIAWIKI) { $content = ''; } else { $content = $articleObj->getContent(); } if (!is_null($params['section'])) { // Process the content for section edits global $wgParser; $section = intval($params['section']); $content = $wgParser->getSection($content, $section, false); if ($content === false) { $this->dieUsage("There is no section {$section}.", 'nosuchsection'); } } $params['text'] = $params['prependtext'] . $content . $params['appendtext']; $toMD5 = $params['prependtext'] . $params['appendtext']; } if ($params['undo'] > 0) { if ($params['undoafter'] > 0) { if ($params['undo'] < $params['undoafter']) { list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']); } $undoafterRev = Revision::newFromID($params['undoafter']); } $undoRev = Revision::newFromID($params['undo']); if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['undo'])); } if ($params['undoafter'] == 0) { $undoafterRev = $undoRev->getPrevious(); } if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['undoafter'])); } if ($undoRev->getPage() != $articleObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText())); } if ($undoafterRev->getPage() != $articleObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText())); } $newtext = $articleObj->getUndoText($undoRev, $undoafterRev); if ($newtext === false) { $this->dieUsageMsg(array('undo-failure')); } $params['text'] = $newtext; // If no summary was given and we only undid one rev, // use an autosummary if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) { $params['summary'] = wfMsgForContent('undo-summary', $params['undo'], $undoRev->getUserText()); } } // See if the MD5 hash checks out if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) { $this->dieUsageMsg(array('hashcheckfailed')); } $ep = new EditPage($articleObj); // EditPage wants to parse its stuff from a WebRequest // That interface kind of sucks, but it's workable $reqArr = array('wpTextbox1' => $params['text'], 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => ''); if (!is_null($params['summary'])) { $reqArr['wpSummary'] = $params['summary']; } // Watch out for basetimestamp == '' // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') { $reqArr['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']); } else { $reqArr['wpEdittime'] = $articleObj->getTimestamp(); } if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') { $reqArr['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']); } else { $reqArr['wpStarttime'] = wfTimestampNow(); // Fake wpStartime } if ($params['minor'] || !$params['notminor'] && $wgUser->getOption('minordefault')) { $reqArr['wpMinoredit'] = ''; } if ($params['recreate']) { $reqArr['wpRecreate'] = ''; } if (!is_null($params['section'])) { $section = intval($params['section']); if ($section == 0 && $params['section'] != '0' && $params['section'] != 'new') { $this->dieUsage("The section parameter must be set to an integer or 'new'", "invalidsection"); } $reqArr['wpSection'] = $params['section']; } else { $reqArr['wpSection'] = ''; } $watch = $this->getWatchlistValue($params['watchlist'], $titleObj); // Deprecated parameters if ($params['watch']) { $watch = true; } elseif ($params['unwatch']) { $watch = false; } if ($watch) { $reqArr['wpWatchthis'] = ''; } $req = new FauxRequest($reqArr, true); $ep->importFormData($req); // Run hooks // Handle CAPTCHA parameters global $wgRequest; if (!is_null($params['captchaid'])) { $wgRequest->setVal('wpCaptchaId', $params['captchaid']); } if (!is_null($params['captchaword'])) { $wgRequest->setVal('wpCaptchaWord', $params['captchaword']); } $r = array(); if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) { if (count($r)) { $r['result'] = 'Failure'; $this->getResult()->addValue(null, $this->getModuleName(), $r); return; } else { $this->dieUsageMsg(array('hookaborted')); } } // Do the actual save $oldRevId = $articleObj->getRevIdFetched(); $result = null; // Fake $wgRequest for some hooks inside EditPage // FIXME: This interface SUCKS $oldRequest = $wgRequest; $wgRequest = $req; $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']); $wgRequest = $oldRequest; global $wgMaxArticleSize; switch ($retval) { case EditPage::AS_HOOK_ERROR: case EditPage::AS_HOOK_ERROR_EXPECTED: $this->dieUsageMsg(array('hookaborted')); case EditPage::AS_IMAGE_REDIRECT_ANON: $this->dieUsageMsg(array('noimageredirect-anon')); case EditPage::AS_IMAGE_REDIRECT_LOGGED: $this->dieUsageMsg(array('noimageredirect-logged')); case EditPage::AS_SPAM_ERROR: $this->dieUsageMsg(array('spamdetected', $result['spam'])); case EditPage::AS_FILTERING: $this->dieUsageMsg(array('filtered')); case EditPage::AS_BLOCKED_PAGE_FOR_USER: $this->dieUsageMsg(array('blockedtext')); case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: case EditPage::AS_CONTENT_TOO_BIG: $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize)); case EditPage::AS_READ_ONLY_PAGE_ANON: $this->dieUsageMsg(array('noedit-anon')); case EditPage::AS_READ_ONLY_PAGE_LOGGED: $this->dieUsageMsg(array('noedit')); case EditPage::AS_READ_ONLY_PAGE: $this->dieReadOnly(); case EditPage::AS_RATE_LIMITED: $this->dieUsageMsg(array('actionthrottledtext')); case EditPage::AS_ARTICLE_WAS_DELETED: $this->dieUsageMsg(array('wasdeleted')); case EditPage::AS_NO_CREATE_PERMISSION: $this->dieUsageMsg(array('nocreate-loggedin')); case EditPage::AS_BLANK_ARTICLE: $this->dieUsageMsg(array('blankpage')); case EditPage::AS_CONFLICT_DETECTED: $this->dieUsageMsg(array('editconflict')); // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary case EditPage::AS_TEXTBOX_EMPTY: $this->dieUsageMsg(array('emptynewsection')); case EditPage::AS_SUCCESS_NEW_ARTICLE: $r['new'] = ''; case EditPage::AS_SUCCESS_UPDATE: $r['result'] = 'Success'; $r['pageid'] = intval($titleObj->getArticleID()); $r['title'] = $titleObj->getPrefixedText(); // HACK: We create a new Article object here because getRevIdFetched() // refuses to be run twice, and because Title::getLatestRevId() // won't fetch from the master unless we select for update, which we // don't want to do. $newArticle = new Article($titleObj); $newRevId = $newArticle->getRevIdFetched(); if ($newRevId == $oldRevId) { $r['nochange'] = ''; } else { $r['oldrevid'] = intval($oldRevId); $r['newrevid'] = intval($newRevId); $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $newArticle->getTimestamp()); } break; case EditPage::AS_SUMMARY_NEEDED: $this->dieUsageMsg(array('summaryrequired')); case EditPage::AS_END: // This usually means some kind of race condition // or DB weirdness occurred. Fall through to throw an unknown // error. // This needs fixing higher up, as Article::doEdit should be // used rather than Article::updateArticle, so that specific // error conditions can be returned // This usually means some kind of race condition // or DB weirdness occurred. Fall through to throw an unknown // error. // This needs fixing higher up, as Article::doEdit should be // used rather than Article::updateArticle, so that specific // error conditions can be returned default: $this->dieUsageMsg(array('unknownerror', $retval)); } $this->getResult()->addValue(null, $this->getModuleName(), $r); }
public function execute() { // The data is hot but user-dependent, like page views, so we set vary cookies $this->getMain()->setCacheMode('anon-public-user-private'); // Get parameters $params = $this->extractRequestParams(); $text = $params['text']; $title = $params['title']; $page = $params['page']; $oldid = $params['oldid']; if (!is_null($page) && (!is_null($text) || $title != "API")) { $this->dieUsage("The page parameter cannot be used together with the text and title parameters", 'params'); } $prop = array_flip($params['prop']); $revid = false; // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* global $wgParser, $wgUser, $wgTitle, $wgEnableParserCache; $popts = new ParserOptions(); $popts->setTidy(true); $popts->enableLimitReport(); $redirValues = null; if (!is_null($oldid) || !is_null($page)) { if (!is_null($oldid)) { // Don't use the parser cache $rev = Revision::newFromID($oldid); if (!$rev) { $this->dieUsage("There is no revision ID {$oldid}", 'missingrev'); } if (!$rev->userCan(Revision::DELETED_TEXT)) { $this->dieUsage("You don't have permission to view deleted revisions", 'permissiondenied'); } $text = $rev->getText(Revision::FOR_THIS_USER); $titleObj = $rev->getTitle(); $wgTitle = $titleObj; $p_result = $wgParser->parse($text, $titleObj, $popts); } else { if ($params['redirects']) { $req = new FauxRequest(array('action' => 'query', 'redirects' => '', 'titles' => $page)); $main = new ApiMain($req); $main->execute(); $data = $main->getResultData(); $redirValues = @$data['query']['redirects']; $to = $page; foreach ((array) $redirValues as $r) { $to = $r['to']; } } else { $to = $page; } $titleObj = Title::newFromText($to); if (!$titleObj) { $this->dieUsage("The page you specified doesn't exist", 'missingtitle'); } $articleObj = new Article($titleObj); if (isset($prop['revid'])) { $oldid = $articleObj->getRevIdFetched(); } // Try the parser cache first $p_result = false; $pcache = ParserCache::singleton(); if ($wgEnableParserCache) { $p_result = $pcache->get($articleObj, $wgUser); } if (!$p_result) { $p_result = $wgParser->parse($articleObj->getContent(), $titleObj, $popts); if ($wgEnableParserCache) { $pcache->save($p_result, $articleObj, $popts); } } } } else { $titleObj = Title::newFromText($title); if (!$titleObj) { $titleObj = Title::newFromText("API"); } $wgTitle = $titleObj; if ($params['pst'] || $params['onlypst']) { $text = $wgParser->preSaveTransform($text, $titleObj, $wgUser, $popts); } if ($params['onlypst']) { // Build a result and bail out $result_array['text'] = array(); $this->getResult()->setContent($result_array['text'], $text); $this->getResult()->addValue(null, $this->getModuleName(), $result_array); return; } $p_result = $wgParser->parse($text, $titleObj, $popts); } // Return result $result = $this->getResult(); $result_array = array(); if ($params['redirects'] && !is_null($redirValues)) { $result_array['redirects'] = $redirValues; } if (isset($prop['text'])) { $result_array['text'] = array(); $result->setContent($result_array['text'], $p_result->getText()); } if (!is_null($params['summary'])) { $result_array['parsedsummary'] = array(); $result->setContent($result_array['parsedsummary'], $wgUser->getSkin()->formatComment($params['summary'], $titleObj)); } if (isset($prop['langlinks'])) { $result_array['langlinks'] = $this->formatLangLinks($p_result->getLanguageLinks()); } if (isset($prop['categories'])) { $result_array['categories'] = $this->formatCategoryLinks($p_result->getCategories()); } if (isset($prop['links'])) { $result_array['links'] = $this->formatLinks($p_result->getLinks()); } if (isset($prop['templates'])) { $result_array['templates'] = $this->formatLinks($p_result->getTemplates()); } if (isset($prop['images'])) { $result_array['images'] = array_keys($p_result->getImages()); } if (isset($prop['externallinks'])) { $result_array['externallinks'] = array_keys($p_result->getExternalLinks()); } if (isset($prop['sections'])) { $result_array['sections'] = $p_result->getSections(); } if (isset($prop['displaytitle'])) { $result_array['displaytitle'] = $p_result->getDisplayTitle() ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText(); } if (isset($prop['headitems'])) { $result_array['headitems'] = $this->formatHeadItems($p_result->getHeadItems()); } if (isset($prop['headhtml'])) { $out = new OutputPage(); $out->addParserOutputNoText($p_result); $result_array['headhtml'] = array(); $result->setContent($result_array['headhtml'], $out->headElement($wgUser->getSkin())); } if (!is_null($oldid)) { $result_array['revid'] = intval($oldid); } $result_mapping = array('redirects' => 'r', 'langlinks' => 'll', 'categories' => 'cl', 'links' => 'pl', 'templates' => 'tl', 'images' => 'img', 'externallinks' => 'el', 'sections' => 's', 'headitems' => 'hi'); $this->setIndexedTagNames($result_array, $result_mapping); $result->addValue(null, $this->getModuleName(), $result_array); }
/** * Parse what can be a revision ID or an article name * @param $str Mixed: revision ID or an article name * @return Title or Revision object, or NULL */ private function parseTitleOrRevID($str) { $retval = false; if (is_numeric($str)) { $retval = Revision::newFromID($str); } if (!$retval) { $retval = Title::newFromURL($str); } return $retval; }
public function execute() { $params = $this->extractRequestParams(false); // If any of those parameters are used, work in 'enumeration' mode. // Enum mode can only be used when exactly one page is provided. // Enumerating revisions on multiple pages make it extremely // difficult to manage continuations and require additional SQL indexes $enumRevMode = !is_null($params['user']) || !is_null($params['excludeuser']) || !is_null($params['limit']) || !is_null($params['startid']) || !is_null($params['endid']) || $params['dir'] === 'newer' || !is_null($params['start']) || !is_null($params['end']); $pageSet = $this->getPageSet(); $pageCount = $pageSet->getGoodTitleCount(); $revCount = $pageSet->getRevisionCount(); // Optimization -- nothing to do if ($revCount === 0 && $pageCount === 0) { return; } if ($revCount > 0 && $enumRevMode) { $this->dieUsage('The revids= parameter may not be used with the list options (limit, startid, endid, dirNewer, start, end).', 'revids'); } if ($pageCount > 1 && $enumRevMode) { $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the limit, startid, endid, dirNewer, user, excludeuser, start and end parameters may only be used on a single page.', 'multpages'); } if (!is_null($params['difftotext'])) { $this->difftotext = $params['difftotext']; } elseif (!is_null($params['diffto'])) { if ($params['diffto'] == 'cur') { $params['diffto'] = 0; } if ((!ctype_digit($params['diffto']) || $params['diffto'] < 0) && $params['diffto'] != 'prev' && $params['diffto'] != 'next') { $this->dieUsage('rvdiffto must be set to a non-negative number, "prev", "next" or "cur"', 'diffto'); } // Check whether the revision exists and is readable, // DifferenceEngine returns a rather ambiguous empty // string if that's not the case if ($params['diffto'] != 0) { $difftoRev = Revision::newFromID($params['diffto']); if (!$difftoRev) { $this->dieUsageMsg(array('nosuchrevid', $params['diffto'])); } if ($difftoRev->isDeleted(Revision::DELETED_TEXT)) { $this->setWarning("Couldn't diff to r{$difftoRev->getID()}: content is hidden"); $params['diffto'] = null; } } $this->diffto = $params['diffto']; } $db = $this->getDB(); $this->addTables('page'); $this->addFields(Revision::selectFields()); $this->addWhere('page_id = rev_page'); $prop = array_flip($params['prop']); // Optional fields $this->fld_ids = isset($prop['ids']); // $this->addFieldsIf('rev_text_id', $this->fld_ids); // should this be exposed? $this->fld_flags = isset($prop['flags']); $this->fld_timestamp = isset($prop['timestamp']); $this->fld_comment = isset($prop['comment']); $this->fld_parsedcomment = isset($prop['parsedcomment']); $this->fld_size = isset($prop['size']); $this->fld_sha1 = isset($prop['sha1']); $this->fld_userid = isset($prop['userid']); $this->fld_user = isset($prop['user']); $this->token = $params['token']; // Possible indexes used $index = array(); $userMax = $this->fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1; $botMax = $this->fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2; $limit = $params['limit']; if ($limit == 'max') { $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $this->getResult()->setParsedLimit($this->getModuleName(), $limit); } if (!is_null($this->token) || $pageCount > 0) { $this->addFields(Revision::selectPageFields()); } if (isset($prop['tags'])) { $this->fld_tags = true; $this->addTables('tag_summary'); $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', array('rev_id=ts_rev_id')))); $this->addFields('ts_tags'); } if (!is_null($params['tag'])) { $this->addTables('change_tag'); $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('rev_id=ct_rev_id')))); $this->addWhereFld('ct_tag', $params['tag']); global $wgOldChangeTagsIndex; $index['change_tag'] = $wgOldChangeTagsIndex ? 'ct_tag' : 'change_tag_tag_id'; } if (isset($prop['content']) || !is_null($this->difftotext)) { // For each page we will request, the user must have read rights for that page foreach ($pageSet->getGoodTitles() as $title) { if (!$title->userCan('read')) { $this->dieUsage('The current user is not allowed to read ' . $title->getPrefixedText(), 'accessdenied'); } } $this->addTables('text'); $this->addWhere('rev_text_id=old_id'); $this->addFields('old_id'); $this->addFields(Revision::selectTextFields()); $this->fld_content = isset($prop['content']); $this->expandTemplates = $params['expandtemplates']; $this->generateXML = $params['generatexml']; $this->parseContent = $params['parse']; if ($this->parseContent) { // Must manually initialize unset limit if (is_null($limit)) { $limit = 1; } // We are only going to parse 1 revision per request $this->validateLimit('limit', $limit, 1, 1, 1); } if (isset($params['section'])) { $this->section = $params['section']; } else { $this->section = false; } } // add user name, if needed if ($this->fld_user) { $this->addTables('user'); $this->addJoinConds(array('user' => Revision::userJoinCond())); $this->addFields(Revision::selectUserFields()); } // Bug 24166 - API error when using rvprop=tags $this->addTables('revision'); if ($enumRevMode) { // This is mostly to prevent parameter errors (and optimize SQL?) if (!is_null($params['startid']) && !is_null($params['start'])) { $this->dieUsage('start and startid cannot be used together', 'badparams'); } if (!is_null($params['endid']) && !is_null($params['end'])) { $this->dieUsage('end and endid cannot be used together', 'badparams'); } if (!is_null($params['user']) && !is_null($params['excludeuser'])) { $this->dieUsage('user and excludeuser cannot be used together', 'badparams'); } // Continuing effectively uses startid. But we can't use rvstartid // directly, because there is no way to tell the client to ''not'' // send rvstart if it sent it in the original query. So instead we // send the continuation startid as rvcontinue, and ignore both // rvstart and rvstartid when that is supplied. if (!is_null($params['continue'])) { $params['startid'] = $params['continue']; unset($params['start']); } // This code makes an assumption that sorting by rev_id and rev_timestamp produces // the same result. This way users may request revisions starting at a given time, // but to page through results use the rev_id returned after each page. // Switching to rev_id removes the potential problem of having more than // one row with the same timestamp for the same page. // The order needs to be the same as start parameter to avoid SQL filesort. if (is_null($params['startid']) && is_null($params['endid'])) { $this->addTimestampWhereRange('rev_timestamp', $params['dir'], $params['start'], $params['end']); } else { $this->addWhereRange('rev_id', $params['dir'], $params['startid'], $params['endid']); // One of start and end can be set // If neither is set, this does nothing $this->addTimestampWhereRange('rev_timestamp', $params['dir'], $params['start'], $params['end'], false); } // must manually initialize unset limit if (is_null($limit)) { $limit = 10; } $this->validateLimit('limit', $limit, 1, $userMax, $botMax); // There is only one ID, use it $ids = array_keys($pageSet->getGoodTitles()); $this->addWhereFld('rev_page', reset($ids)); if (!is_null($params['user'])) { $this->addWhereFld('rev_user_text', $params['user']); } elseif (!is_null($params['excludeuser'])) { $this->addWhere('rev_user_text != ' . $db->addQuotes($params['excludeuser'])); } if (!is_null($params['user']) || !is_null($params['excludeuser'])) { // Paranoia: avoid brute force searches (bug 17342) $this->addWhere($db->bitAnd('rev_deleted', Revision::DELETED_USER) . ' = 0'); } } elseif ($revCount > 0) { $max = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $revs = $pageSet->getRevisionIDs(); if (self::truncateArray($revs, $max)) { $this->setWarning("Too many values supplied for parameter 'revids': the limit is {$max}"); } // Get all revision IDs $this->addWhereFld('rev_id', array_keys($revs)); if (!is_null($params['continue'])) { $this->addWhere('rev_id >= ' . intval($params['continue'])); } $this->addOption('ORDER BY', 'rev_id'); // assumption testing -- we should never get more then $revCount rows. $limit = $revCount; } elseif ($pageCount > 0) { $max = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $titles = $pageSet->getGoodTitles(); if (self::truncateArray($titles, $max)) { $this->setWarning("Too many values supplied for parameter 'titles': the limit is {$max}"); } // When working in multi-page non-enumeration mode, // limit to the latest revision only $this->addWhere('page_id=rev_page'); $this->addWhere('page_latest=rev_id'); // Get all page IDs $this->addWhereFld('page_id', array_keys($titles)); // Every time someone relies on equality propagation, god kills a kitten :) $this->addWhereFld('rev_page', array_keys($titles)); if (!is_null($params['continue'])) { $cont = explode('|', $params['continue']); if (count($cont) != 2) { $this->dieUsage('Invalid continue param. You should pass the original ' . 'value returned by the previous query', '_badcontinue'); } $pageid = intval($cont[0]); $revid = intval($cont[1]); $this->addWhere("rev_page > {$pageid} OR " . "(rev_page = {$pageid} AND " . "rev_id >= {$revid})"); } $this->addOption('ORDER BY', array('rev_page', 'rev_id')); // assumption testing -- we should never get more then $pageCount rows. $limit = $pageCount; } else { ApiBase::dieDebug(__METHOD__, 'param validation?'); } $this->addOption('LIMIT', $limit + 1); $this->addOption('USE INDEX', $index); $count = 0; $res = $this->select(__METHOD__); foreach ($res as $row) { if (++$count > $limit) { // We've reached the one extra which shows that there are additional pages to be had. Stop here... if (!$enumRevMode) { ApiBase::dieDebug(__METHOD__, 'Got more rows then expected'); // bug report } $this->setContinueEnumParameter('continue', intval($row->rev_id)); break; } $fit = $this->addPageSubItem($row->rev_page, $this->extractRowInfo($row), 'rev'); if (!$fit) { if ($enumRevMode) { $this->setContinueEnumParameter('continue', intval($row->rev_id)); } elseif ($revCount > 0) { $this->setContinueEnumParameter('continue', intval($row->rev_id)); } else { $this->setContinueEnumParameter('continue', intval($row->rev_page) . '|' . intval($row->rev_id)); } break; } } }
function execute($par) { global $wgRequest, $wgOut, $wgUser; $target = isset($par) ? $par : $wgRequest->getVal('target'); if (!in_array('sysop', $wgUser->getGroups())) { $wgOut->setArticleRelated(false); $wgOut->setRobotpolicy('noindex,nofollow'); $wgOut->showErrorPage('nosuchspecialpage', 'nospecialpagetext'); return; } if ($target) { if (preg_match("@[^0-9]@", $target)) { $t = Title::newFromURL($target); } else { $r = Revision::newFromID($target); if ($wgRequest->getVal('popup')) { $wgOut->setArticleBodyOnly(true); $wgOut->addHTML("<style type='text/css'>\n\t\t\t\t\t\ttable.diff {\n\t\t\t\t\t\t\tmargin-left: auto; margin-right: auto;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttable.diff td {\n\t\t\t\t\t\t\tmax-width: 400px;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t</style>"); } $wgOut->addHTML("Revid: {$r->mId}\n"); $d = self::getDiffToMeasure($r); $de = new DifferenceEngine($r->mTitle, $d['revlo']->mId, $d['revhi']->mId); self::getPoints($r, $d, $de, true); if (!$d['revlo']) { $de->mOldRev = null; $de->mOldid = null; } $de->showDiffPage(); return; } } else { $rp = new RandomPage(); $t = $rp->getRandomTitle(); } $wgOut->addHTML("<script type='text/javascript'>\nfunction getPoints(rev) {\n\t\$('#img-box').load('/Special:Points/' + rev + '?popup=true', function() {\n\t\t\t\$('#img-box').dialog({\n\t\t\t width: 750,\n\t\t\t modal: true,\n\t\t\t\ttitle: 'Points', \n\t\t\t show: 'slide',\n\t\t\t\tcloseOnEscape: true,\n\t\t\t\tposition: 'center'\n\t\t\t});\n\t});\n\treturn false;\n}\n</script>\n"); // get the groups of edits $group = self::getEditGroups($t); $wgOut->addHTML("Title: <a href='{$t->getFullURL()}?action=history' target='new'>{$t->getFullText()}</a><br/><br/>"); $wgOut->addHTML("<table width='100%'><tr><td><u>User</u></td><td><u># Edits</u></td>"); $wgOut->addHTML("<td><u>Date</u></td><td><u>Points</u></td></tr>"); foreach ($group as $g) { $r = Revision::newFromID($g['max_revid']); $d = self::getDiffToMeasure($r); $de = new DifferenceEngine($r->mTitle, $d['revlo']->mId, $d['revhi']->mId); $points = self::getPoints($r, $d, $de); $date = date("Y-m-d", wfTimestamp(TS_UNIX, $g['max_revtimestamp'])); $wgOut->addHTML("<tr><td>{$g['user_text']}</td><td>{$g['edits']}</td><td>{$date}</td>"); $wgOut->addHTML("<td><a href='#' onclick='return getPoints({$g['max_revid']});'>{$points}</a></td></tr>"); } $wgOut->addHTML("</table>"); }
public function execute() { // The data is hot but user-dependent, like page views, so we set vary cookies $this->getMain()->setCacheMode('anon-public-user-private'); // Get parameters $params = $this->extractRequestParams(); $text = $params['text']; $title = $params['title']; $page = $params['page']; $pageid = $params['pageid']; $oldid = $params['oldid']; if (!is_null($page) && (!is_null($text) || $title != 'API')) { $this->dieUsage('The page parameter cannot be used together with the text and title parameters', 'params'); } $prop = array_flip($params['prop']); if (isset($params['section'])) { $this->section = $params['section']; } else { $this->section = false; } // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* // TODO: Does this still need $wgTitle? global $wgParser, $wgTitle, $wgLang; // Currently unnecessary, code to act as a safeguard against any change in current behaviour of uselang breaks $oldLang = null; if (isset($params['uselang']) && $params['uselang'] != $wgLang->getCode()) { $oldLang = $wgLang; // Backup wgLang $wgLang = Language::factory($params['uselang']); } $popts = ParserOptions::newFromContext($this->getContext()); $popts->setTidy(true); $popts->enableLimitReport(!$params['disablepp']); $redirValues = null; // Return result $result = $this->getResult(); if (!is_null($oldid) || !is_null($pageid) || !is_null($page)) { if (!is_null($oldid)) { // Don't use the parser cache $rev = Revision::newFromID($oldid); if (!$rev) { $this->dieUsage("There is no revision ID {$oldid}", 'missingrev'); } if (!$rev->userCan(Revision::DELETED_TEXT, $this->getUser())) { $this->dieUsage("You don't have permission to view deleted revisions", 'permissiondenied'); } $titleObj = $rev->getTitle(); $wgTitle = $titleObj; // If for some reason the "oldid" is actually the current revision, it may be cached if ($titleObj->getLatestRevID() === intval($oldid)) { // May get from/save to parser cache $p_result = $this->getParsedSectionOrText($titleObj, $popts, $pageid, isset($prop['wikitext'])); } else { // This is an old revision, so get the text differently $this->text = $rev->getText(Revision::FOR_THIS_USER, $this->getUser()); if ($this->section !== false) { $this->text = $this->getSectionText($this->text, 'r' . $rev->getId()); } // Should we save old revision parses to the parser cache? $p_result = $wgParser->parse($this->text, $titleObj, $popts); } } else { // Not $oldid, but $pageid or $page if ($params['redirects']) { $reqParams = array('action' => 'query', 'redirects' => ''); if (!is_null($pageid)) { $reqParams['pageids'] = $pageid; } else { // $page $reqParams['titles'] = $page; } $req = new FauxRequest($reqParams); $main = new ApiMain($req); $main->execute(); $data = $main->getResultData(); $redirValues = isset($data['query']['redirects']) ? $data['query']['redirects'] : array(); $to = $page; foreach ((array) $redirValues as $r) { $to = $r['to']; } $titleObj = Title::newFromText($to); } else { if (!is_null($pageid)) { $reqParams['pageids'] = $pageid; $titleObj = Title::newFromID($pageid); } else { // $page $to = $page; $titleObj = Title::newFromText($to); } } if (!is_null($pageid)) { if (!$titleObj) { // Still throw nosuchpageid error if pageid was provided $this->dieUsageMsg(array('nosuchpageid', $pageid)); } } elseif (!$titleObj || !$titleObj->exists()) { $this->dieUsage("The page you specified doesn't exist", 'missingtitle'); } $wgTitle = $titleObj; if (isset($prop['revid'])) { $oldid = $titleObj->getLatestRevID(); } // Potentially cached $p_result = $this->getParsedSectionOrText($titleObj, $popts, $pageid, isset($prop['wikitext'])); } } else { // Not $oldid, $pageid, $page. Hence based on $text if (is_null($text)) { $this->dieUsage('The text parameter should be passed with the title parameter. Should you be using the "page" parameter instead?', 'params'); } $this->text = $text; $titleObj = Title::newFromText($title); if (!$titleObj) { $this->dieUsageMsg(array('invalidtitle', $title)); } $wgTitle = $titleObj; if ($this->section !== false) { $this->text = $this->getSectionText($this->text, $titleObj->getText()); } if ($params['pst'] || $params['onlypst']) { $this->pstText = $wgParser->preSaveTransform($this->text, $titleObj, $this->getUser(), $popts); } if ($params['onlypst']) { // Build a result and bail out $result_array = array(); $result_array['text'] = array(); $result->setContent($result_array['text'], $this->pstText); if (isset($prop['wikitext'])) { $result_array['wikitext'] = array(); $result->setContent($result_array['wikitext'], $this->text); } $result->addValue(null, $this->getModuleName(), $result_array); return; } // Not cached (save or load) $p_result = $wgParser->parse($params['pst'] ? $this->pstText : $this->text, $titleObj, $popts); } $result_array = array(); $result_array['title'] = $titleObj->getPrefixedText(); if (!is_null($oldid)) { $result_array['revid'] = intval($oldid); } if ($params['redirects'] && !is_null($redirValues)) { $result_array['redirects'] = $redirValues; } if (isset($prop['text'])) { $result_array['text'] = array(); $result->setContent($result_array['text'], $p_result->getText()); } if (!is_null($params['summary'])) { $result_array['parsedsummary'] = array(); $result->setContent($result_array['parsedsummary'], Linker::formatComment($params['summary'], $titleObj)); } if (isset($prop['langlinks'])) { $result_array['langlinks'] = $this->formatLangLinks($p_result->getLanguageLinks()); } if (isset($prop['languageshtml'])) { $languagesHtml = $this->languagesHtml($p_result->getLanguageLinks()); $result_array['languageshtml'] = array(); $result->setContent($result_array['languageshtml'], $languagesHtml); } if (isset($prop['categories'])) { $result_array['categories'] = $this->formatCategoryLinks($p_result->getCategories()); } if (isset($prop['categorieshtml'])) { $categoriesHtml = $this->categoriesHtml($p_result->getCategories()); $result_array['categorieshtml'] = array(); $result->setContent($result_array['categorieshtml'], $categoriesHtml); } if (isset($prop['links'])) { $result_array['links'] = $this->formatLinks($p_result->getLinks()); } if (isset($prop['templates'])) { $result_array['templates'] = $this->formatLinks($p_result->getTemplates()); } if (isset($prop['images'])) { $result_array['images'] = array_keys($p_result->getImages()); } if (isset($prop['externallinks'])) { $result_array['externallinks'] = array_keys($p_result->getExternalLinks()); } if (isset($prop['sections'])) { $result_array['sections'] = $p_result->getSections(); } if (isset($prop['displaytitle'])) { $result_array['displaytitle'] = $p_result->getDisplayTitle() ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText(); } if (isset($prop['headitems']) || isset($prop['headhtml'])) { $context = $this->getContext(); $context->setTitle($titleObj); $context->getOutput()->addParserOutputNoText($p_result); if (isset($prop['headitems'])) { $headItems = $this->formatHeadItems($p_result->getHeadItems()); $css = $this->formatCss($context->getOutput()->buildCssLinksArray()); $scripts = array($context->getOutput()->getHeadScripts()); $result_array['headitems'] = array_merge($headItems, $css, $scripts); } if (isset($prop['headhtml'])) { $result_array['headhtml'] = array(); $result->setContent($result_array['headhtml'], $context->getOutput()->headElement($context->getSkin())); } } if (isset($prop['iwlinks'])) { $result_array['iwlinks'] = $this->formatIWLinks($p_result->getInterwikiLinks()); } if (isset($prop['wikitext'])) { $result_array['wikitext'] = array(); $result->setContent($result_array['wikitext'], $this->text); if (!is_null($this->pstText)) { $result_array['psttext'] = array(); $result->setContent($result_array['psttext'], $this->pstText); } } $result_mapping = array('redirects' => 'r', 'langlinks' => 'll', 'categories' => 'cl', 'links' => 'pl', 'templates' => 'tl', 'images' => 'img', 'externallinks' => 'el', 'iwlinks' => 'iw', 'sections' => 's', 'headitems' => 'hi'); $this->setIndexedTagNames($result_array, $result_mapping); $result->addValue(null, $this->getModuleName(), $result_array); if (!is_null($oldLang)) { $wgLang = $oldLang; // Reset $wgLang to $oldLang } }
private function parseTitleOrRevID($str) { // Parse what can be a revision ID or an article name // Returns: Title or Revision object, or NULL $retval = false; if (is_numeric($str)) { $retval = Revision::newFromID($str); } if (!$retval) { $retval = Title::newFromURL($str); } return $retval; }
public function execute() { $user = $this->getUser(); $params = $this->extractRequestParams(); if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) { $this->dieUsageMsg('missingtext'); } $pageObj = $this->getTitleOrPageId($params); $titleObj = $pageObj->getTitle(); $apiResult = $this->getResult(); if ($params['redirect']) { if ($params['prependtext'] === null && $params['appendtext'] === null && $params['section'] !== 'new') { $this->dieUsage('You have attempted to edit using the "redirect"-following mode, which must be used in conjuction with section=new, prependtext, or appendtext.', 'redirect-appendonly'); } if ($titleObj->isRedirect()) { $oldTitle = $titleObj; $titles = Revision::newFromTitle($oldTitle, false, Revision::READ_LATEST)->getContent(Revision::FOR_THIS_USER, $user)->getRedirectChain(); // array_shift( $titles ); $redirValues = array(); /** @var $newTitle Title */ foreach ($titles as $id => $newTitle) { if (!isset($titles[$id - 1])) { $titles[$id - 1] = $oldTitle; } $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText()); $titleObj = $newTitle; } $apiResult->setIndexedTagName($redirValues, 'r'); $apiResult->addValue(null, 'redirects', $redirValues); // Since the page changed, update $pageObj $pageObj = WikiPage::factory($titleObj); } } if (!isset($params['contentmodel']) || $params['contentmodel'] == '') { $contentHandler = $pageObj->getContentHandler(); } else { $contentHandler = ContentHandler::getForModelID($params['contentmodel']); } // @todo Ask handler whether direct editing is supported at all! make // allowFlatEdit() method or some such if (!isset($params['contentformat']) || $params['contentformat'] == '') { $params['contentformat'] = $contentHandler->getDefaultFormat(); } $contentFormat = $params['contentformat']; if (!$contentHandler->isSupportedFormat($contentFormat)) { $name = $titleObj->getPrefixedDBkey(); $model = $contentHandler->getModelID(); $this->dieUsage("The requested format {$contentFormat} is not supported for content model " . " {$model} used by {$name}", 'badformat'); } if ($params['createonly'] && $titleObj->exists()) { $this->dieUsageMsg('createonly-exists'); } if ($params['nocreate'] && !$titleObj->exists()) { $this->dieUsageMsg('nocreate-missing'); } // Now let's check whether we're even allowed to do this $errors = $titleObj->getUserPermissionsErrors('edit', $user); if (!$titleObj->exists()) { $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $user)); } if (count($errors)) { $this->dieUsageMsg($errors[0]); } $toMD5 = $params['text']; if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) { $content = $pageObj->getContent(); if (!$content) { if ($titleObj->getNamespace() == NS_MEDIAWIKI) { # If this is a MediaWiki:x message, then load the messages # and return the message value for x. $text = $titleObj->getDefaultMessageText(); if ($text === false) { $text = ''; } try { $content = ContentHandler::makeContent($text, $this->getTitle()); } catch (MWContentSerializationException $ex) { $this->dieUsage($ex->getMessage(), 'parseerror'); return; } } else { # Otherwise, make a new empty content. $content = $contentHandler->makeEmptyContent(); } } // @todo Add support for appending/prepending to the Content interface if (!$content instanceof TextContent) { $mode = $contentHandler->getModelID(); $this->dieUsage("Can't append to pages using content model {$mode}", 'appendnotsupported'); } if (!is_null($params['section'])) { if (!$contentHandler->supportsSections()) { $modelName = $contentHandler->getModelID(); $this->dieUsage("Sections are not supported for this content model: {$modelName}.", 'sectionsnotsupported'); } if ($params['section'] == 'new') { // DWIM if they're trying to prepend/append to a new section. $content = null; } else { // Process the content for section edits $section = $params['section']; $content = $content->getSection($section); if (!$content) { $this->dieUsage("There is no section {$section}.", 'nosuchsection'); } } } if (!$content) { $text = ''; } else { $text = $content->serialize($contentFormat); } $params['text'] = $params['prependtext'] . $text . $params['appendtext']; $toMD5 = $params['prependtext'] . $params['appendtext']; } if ($params['undo'] > 0) { if ($params['undoafter'] > 0) { if ($params['undo'] < $params['undoafter']) { list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']); } $undoafterRev = Revision::newFromID($params['undoafter']); } $undoRev = Revision::newFromID($params['undo']); if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['undo'])); } if ($params['undoafter'] == 0) { $undoafterRev = $undoRev->getPrevious(); } if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['undoafter'])); } if ($undoRev->getPage() != $pageObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText())); } if ($undoafterRev->getPage() != $pageObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText())); } $newContent = $contentHandler->getUndoContent($pageObj->getRevision(), $undoRev, $undoafterRev); if (!$newContent) { $this->dieUsageMsg('undo-failure'); } $params['text'] = $newContent->serialize($params['contentformat']); // If no summary was given and we only undid one rev, // use an autosummary if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) { $params['summary'] = wfMessage('undo-summary')->params($params['undo'], $undoRev->getUserText())->inContentLanguage()->text(); } } // See if the MD5 hash checks out if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) { $this->dieUsageMsg('hashcheckfailed'); } // EditPage wants to parse its stuff from a WebRequest // That interface kind of sucks, but it's workable $requestArray = array('wpTextbox1' => $params['text'], 'format' => $contentFormat, 'model' => $contentHandler->getModelID(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '', 'wpIgnoreBlankArticle' => true); if (!is_null($params['summary'])) { $requestArray['wpSummary'] = $params['summary']; } if (!is_null($params['sectiontitle'])) { $requestArray['wpSectionTitle'] = $params['sectiontitle']; } // TODO: Pass along information from 'undoafter' as well if ($params['undo'] > 0) { $requestArray['wpUndidRevision'] = $params['undo']; } // Watch out for basetimestamp == '' // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') { $requestArray['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']); } else { $requestArray['wpEdittime'] = $pageObj->getTimestamp(); } if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') { $requestArray['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']); } else { $requestArray['wpStarttime'] = wfTimestampNow(); // Fake wpStartime } if ($params['minor'] || !$params['notminor'] && $user->getOption('minordefault')) { $requestArray['wpMinoredit'] = ''; } if ($params['recreate']) { $requestArray['wpRecreate'] = ''; } if (!is_null($params['section'])) { $section = $params['section']; if (!preg_match('/^((T-)?\\d+|new)$/', $section)) { $this->dieUsage("The section parameter must be a valid section id or 'new'", "invalidsection"); } $content = $pageObj->getContent(); if ($section !== '0' && $section != 'new' && (!$content || !$content->getSection($section))) { $this->dieUsage("There is no section {$section}.", 'nosuchsection'); } $requestArray['wpSection'] = $params['section']; } else { $requestArray['wpSection'] = ''; } $watch = $this->getWatchlistValue($params['watchlist'], $titleObj); // Deprecated parameters if ($params['watch']) { $this->logFeatureUsage('action=edit&watch'); $watch = true; } elseif ($params['unwatch']) { $this->logFeatureUsage('action=edit&unwatch'); $watch = false; } if ($watch) { $requestArray['wpWatchthis'] = ''; } // Pass through anything else we might have been given, to support extensions // This is kind of a hack but it's the best we can do to make extensions work $requestArray += $this->getRequest()->getValues(); global $wgTitle, $wgRequest; $req = new DerivativeRequest($this->getRequest(), $requestArray, true); // Some functions depend on $wgTitle == $ep->mTitle // TODO: Make them not or check if they still do $wgTitle = $titleObj; $articleContext = new RequestContext(); $articleContext->setRequest($req); $articleContext->setWikiPage($pageObj); $articleContext->setUser($this->getUser()); /** @var $articleObject Article */ $articleObject = Article::newFromWikiPage($pageObj, $articleContext); $ep = new EditPage($articleObject); // allow editing of non-textual content. $ep->allowNonTextContent = true; $ep->setContextTitle($titleObj); $ep->importFormData($req); $content = $ep->textbox1; // The following is needed to give the hook the full content of the // new revision rather than just the current section. (Bug 52077) if (!is_null($params['section']) && $contentHandler->supportsSections() && $titleObj->exists()) { // If sectiontitle is set, use it, otherwise use the summary as the section title (for // backwards compatibility with old forms/bots). if ($ep->sectiontitle !== '') { $sectionTitle = $ep->sectiontitle; } else { $sectionTitle = $ep->summary; } $contentObj = $contentHandler->unserializeContent($content, $contentFormat); $fullContentObj = $articleObject->replaceSectionContent($params['section'], $contentObj, $sectionTitle); if ($fullContentObj) { $content = $fullContentObj->serialize($contentFormat); } else { // This most likely means we have an edit conflict which means that the edit // wont succeed anyway. $this->dieUsageMsg('editconflict'); } } // Run hooks // Handle APIEditBeforeSave parameters $r = array(); if (!wfRunHooks('APIEditBeforeSave', array($ep, $content, &$r))) { if (count($r)) { $r['result'] = 'Failure'; $apiResult->addValue(null, $this->getModuleName(), $r); return; } $this->dieUsageMsg('hookaborted'); } // Do the actual save $oldRevId = $articleObject->getRevIdFetched(); $result = null; // Fake $wgRequest for some hooks inside EditPage // @todo FIXME: This interface SUCKS $oldRequest = $wgRequest; $wgRequest = $req; $status = $ep->internalAttemptSave($result, $user->isAllowed('bot') && $params['bot']); $wgRequest = $oldRequest; switch ($status->value) { case EditPage::AS_HOOK_ERROR: case EditPage::AS_HOOK_ERROR_EXPECTED: $this->dieUsageMsg('hookaborted'); case EditPage::AS_PARSE_ERROR: $this->dieUsage($status->getMessage(), 'parseerror'); case EditPage::AS_IMAGE_REDIRECT_ANON: $this->dieUsageMsg('noimageredirect-anon'); case EditPage::AS_IMAGE_REDIRECT_LOGGED: $this->dieUsageMsg('noimageredirect-logged'); case EditPage::AS_SPAM_ERROR: $this->dieUsageMsg(array('spamdetected', $result['spam'])); case EditPage::AS_BLOCKED_PAGE_FOR_USER: $this->dieUsageMsg('blockedtext'); case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: case EditPage::AS_CONTENT_TOO_BIG: $this->dieUsageMsg(array('contenttoobig', $this->getConfig()->get('MaxArticleSize'))); case EditPage::AS_READ_ONLY_PAGE_ANON: $this->dieUsageMsg('noedit-anon'); case EditPage::AS_READ_ONLY_PAGE_LOGGED: $this->dieUsageMsg('noedit'); case EditPage::AS_READ_ONLY_PAGE: $this->dieReadOnly(); case EditPage::AS_RATE_LIMITED: $this->dieUsageMsg('actionthrottledtext'); case EditPage::AS_ARTICLE_WAS_DELETED: $this->dieUsageMsg('wasdeleted'); case EditPage::AS_NO_CREATE_PERMISSION: $this->dieUsageMsg('nocreate-loggedin'); case EditPage::AS_BLANK_ARTICLE: $this->dieUsageMsg('blankpage'); case EditPage::AS_CONFLICT_DETECTED: $this->dieUsageMsg('editconflict'); // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary case EditPage::AS_TEXTBOX_EMPTY: $this->dieUsageMsg('emptynewsection'); case EditPage::AS_SUCCESS_NEW_ARTICLE: $r['new'] = ''; // fall-through // fall-through case EditPage::AS_SUCCESS_UPDATE: $r['result'] = 'Success'; $r['pageid'] = intval($titleObj->getArticleID()); $r['title'] = $titleObj->getPrefixedText(); $r['contentmodel'] = $titleObj->getContentModel(); $newRevId = $articleObject->getLatest(); if ($newRevId == $oldRevId) { $r['nochange'] = ''; } else { $r['oldrevid'] = intval($oldRevId); $r['newrevid'] = intval($newRevId); $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $pageObj->getTimestamp()); } break; case EditPage::AS_SUMMARY_NEEDED: $this->dieUsageMsg('summaryrequired'); case EditPage::AS_END: default: // $status came from WikiPage::doEdit() $errors = $status->getErrorsArray(); $this->dieUsageMsg($errors[0]); // TODO: Add new errors to message map break; } $apiResult->addValue(null, $this->getModuleName(), $r); }
/** * Handler for EchoGetNotificationTypes hook, Adjust the notify types (e.g. web, email) which * are applicable to this event and user based on various user options. In other words, allow * certain non-echo user options to override the echo notification options. * @param $user User * @param $event EchoEvent * @param $notifyTypes * @return bool */ public static function getNotificationTypes($user, $event, &$notifyTypes) { $type = $event->getType(); if (!$user->getOption('enotifminoredits')) { $extra = $event->getExtra(); if (!empty($extra['revid'])) { $rev = Revision::newFromID($extra['revid']); if ($rev->isMinor()) { $notifyTypes = array_diff($notifyTypes, array('email')); } } } return true; }
$dbw->update("imageadder", array("imageadder_hasimage" => 0, "imageadder_skip" => 0), array("imageadder_page" => $t->getArticleID())); // last revision comment? $row = $dbr->selectRow('revision', '*', array('rev_page' => $t->getArticleID()), "fix intro adder", array("ORDER BY" => "rev_id desc", "LIMIT" => 1)); if ($row->rev_comment == "Added Image using ImageAdder Tool") { $a = new Article($t); $a->commitRollback($row->rev_user_text, "Rolling back bug", false, &$results); echo "{$t->getFullURL()} rolled back \n"; continue; } // how many sections? $r = Revision::newFromTitle($t); if (!$r) { echo "Can't make revision out of {$row->rc_title}\n"; continue; } $text = $r->getText(); preg_match_all("@^==.*==@m", $text, $matches); if (sizeof($matches[0]) == 0) { echo "{$t->getFullURL()} has no sections\n"; // get the last edit $lastgood_rev = $dbr->selectRow("revision", "*", array('rev_page' => $t->getArticleID(), 'rev_comment != "Added Image using ImageAdder Tool"', "rev_id < {$row->rev_id}"), "fix intro adder", array("ORDER BY" => "rev_id desc", "LIMIT" => 1)); $rev = Revision::newFromID($lastgood_rev->rev_id); if (!$rev) { // ? continue; } $text = $rev->getText(); $a = new Article($t); $a->doEdit($text, "Rolling back bug going back to rev {$lastgood_rev->rev_id} by {$lastgood_rev->rev_user_text}"); } }
function getLastRevisionText() { $lastrev = $this->getLastRevID(); $r = Revision::newFromID($lastrev); if (!$r) { return null; } return $r->getText(); }
protected function statusInterface() { global $wgOut, $wgUser, $wgPremoderationStrict; $params = $this->mParams; if( !isset( $params['id'] ) ) { $wgOut->setPageTitle( wfMsg( 'premoderation-manager-invalidaction' ) ); $wgOut->addWikiMsg( 'premoderation-invalidaction' ); return; } $id = intval( $params['id'] ); $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'pm_queue', '*', "pmq_id = '$id'", __METHOD__, array( 'LIMIT' => 1 ) ); $row = $dbr->fetchRow( $res ); if( !$row ) { $wgOut->setPageTitle( wfMsg( 'premoderation-manager-invalidaction' ) ); $wgOut->addWikiMsg( 'premoderation-notexists-id' ); return; } $wgOut->setPageTitle( wfMsg( 'premoderation-manager-status' ) ); $wgOut->addWikiMsg( 'premoderation-status-intro' ); $wgOut->addHTML( '<h2>' . wfMsg( 'premoderation-status-info' ) . '</h2>' . $this->getListTableHeader( 'status' ) . $this->formatListTableRow( $row ) . Xml::closeElement( 'table' ) ); if( $wgUser->isAllowed( 'premoderation-viewip' ) ) { $wgOut->addWikiMsg( 'premoderation-private-ip', $row['pmq_ip'] ); } $rev = Revision::newFromID( $row['pmq_page_last_id'] ); $diff = new DifferenceEngine(); $diff->showDiffStyle(); $formattedDiff = $diff->generateDiffBody( isset( $rev ) ? $rev->getText() : '', $row['pmq_text'] ); $wgOut->addHTML( '<h2>' . wfMsg( 'premoderation-diff-h2' ) . '</h2>' . "<table class='mw-abusefilter-diff-multiline'><col class='diff-marker' />" . "<col class='diff-content' /><col class='diff-marker' /><col class='diff-content' />" . "<tbody>" . $formattedDiff . "</tbody></table>" ); if( $row['pmq_status'] == 'approved' ) { return; } $externalConflicts = $this->checkExternalConflicts( $row['pmq_page_last_id'], $row['pmq_page_ns'], $row['pmq_page_title'] ); if( $externalConflicts ) { $wgOut->addHTML( '<h2>' . wfMsg( 'premoderation-external-conflicts-h2' ) . '</h2>' ); if( $wgPremoderationStrict ) { $wgOut->addWikiMsg( 'premoderation-error-externals' ); return; } $wgOut->addWikiMsg( 'premoderation-external-edits' ); } $this->checkInternalConflicts( $dbr, $id, $row['pmq_page_ns'], $row['pmq_page_title'] ); $final = Xml::fieldset( wfMsg( 'premoderation-status-fieldset' ) ) . Xml::openElement( 'form', array( 'id' => 'prem-status-form', 'method' => 'post' ) ) . $this->getStatusForm( $row['pmq_status'] ) . '<input type="hidden" name="id" value="' . $id . '" />' . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' ); $wgOut->addHTML( $final ); }
public function execute() { global $wgUser; $params = $this->extractRequestParams(); if (is_null($params['title'])) { $this->dieUsageMsg(array('missingparam', 'title')); } if (is_null($params['xpath'])) { $this->dieUsage(array('missingparam', 'xpath')); } $titleObj = Title::newFromText($params['title']); if (!$titleObj || $titleObj->isExternal()) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } // Some functions depend on $wgTitle == $ep->mTitle global $wgTitle; $wgTitle = $titleObj; if ($params['nocreate'] && !$titleObj->exists()) { $this->dieUsageMsg(array('nocreate-missing')); } // Now let's check whether we're even allowed to do this $errors = $titleObj->getUserPermissionsErrors('edit', $wgUser); if (!$titleObj->exists()) { $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $wgUser)); } if (count($errors)) { $this->dieUsageMsg($errors[0]); } $articleObj = new Article($titleObj); if (!is_null($params['rid'])) { $revObj = Revision::newFromID($params['rid']); if (is_null($revObj) || $revObj->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['rid'])); } if ($revObj->getPage() != $articleObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $revObj->getID(), $titleObj->getPrefixedText())); } if (!$params['force_update'] && !$revObj->isCurrent()) { $this->dieUsage("Page revision id is not current '{$titleObj->getPrefixedText()} ({$params['rid']})'", 'revnotcurrent'); } } else { $params['rid'] = 0; } $verb = $params['verb']; $xpath = $params['xpath']; try { $wom = WOMProcessor::getPageObject($titleObj, $params['rid']); $obj_ids = WOMProcessor::getObjIdByXPath2($wom, $xpath); $obj_id = null; foreach ($obj_ids as $id) { if ($id != '') { $obj_id = $id; break; } } if ($obj_id == null) { throw new MWException(__METHOD__ . ": object does not found, xpath: {$xpath}"); } if ($verb == 'remove') { $wom->removePageObject($obj_id); } elseif ($verb == 'removeall') { foreach ($obj_ids as $id) { if ($id == '') { continue; } $wom->removePageObject($id); } } else { if (is_null($params['text'])) { $this->dieUsageMsg(array('missingparam', 'text')); } $toMD5 = $params['text']; // See if the MD5 hash checks out if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) { $this->dieUsageMsg(array('hashcheckfailed')); } $text = $params['text']; if ($verb == 'insert') { $text = WOMProcessor::getValidText($text, $wom->getObject($obj_id)->getParent(), $wom); // no need to parse or merge object model but use text $wom->insertPageObject(new WOMTextModel($text), $obj_id); } elseif ($verb == 'update') { $text = WOMProcessor::getValidText($text, $wom->getObject($obj_id)->getParent(), $wom); $wom->updatePageObject(new WOMTextModel($text), $obj_id); } elseif ($verb == 'append') { $parent = $wom->getObject($obj_id); if (!$parent instanceof WikiObjectModelCollection) { throw new MWException(__METHOD__ . ": Object is not a collection object '{$title} ({$revision_id}) - {$obj_id}'"); } $text = WOMProcessor::getValidText($text, $parent, $wom); $wom->appendChildObject(new WOMTextModel($text), $obj_id); } elseif ($verb == 'attribute') { $obj = $wom->getObject($obj_id); $kv = explode('=', $text, 2); if (count($kv) != 2) { throw new MWException(__METHOD__ . ": value should be 'key=value' in attribute mode"); } $obj->setXMLAttribute(trim($kv[0]), trim($kv[1])); } } $ep = new EditPage($articleObj); // EditPage wants to parse its stuff from a WebRequest // That interface kind of sucks, but it's workable $reqArr = array('wpTextbox1' => $wom->getWikiText(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '', 'wpSection' => ''); if (!is_null($params['summary'])) { $reqArr['wpSummary'] = $params['summary']; } // Watch out for basetimestamp == '' // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') { $reqArr['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']); } else { $reqArr['wpEdittime'] = $articleObj->getTimestamp(); } if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') { $reqArr['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']); } else { $reqArr['wpStarttime'] = $reqArr['wpEdittime']; } // Fake wpStartime if ($params['minor'] || !$params['notminor'] && $wgUser->getOption('minordefault')) { $reqArr['wpMinoredit'] = ''; } // Handle watchlist settings switch ($params['watchlist']) { case 'watch': $watch = true; break; case 'unwatch': $watch = false; break; case 'preferences': if ($titleObj->exists()) { $watch = $wgUser->getOption('watchdefault') || $titleObj->userIsWatching(); } else { $watch = $wgUser->getOption('watchcreations'); } break; case 'nochange': default: $watch = $titleObj->userIsWatching(); } // Deprecated parameters if ($params['watch']) { $watch = true; } elseif ($params['unwatch']) { $watch = false; } if ($watch) { $reqArr['wpWatchthis'] = ''; } $req = new FauxRequest($reqArr, true); $ep->importFormData($req); // Run hooks // Handle CAPTCHA parameters global $wgRequest; if (!is_null($params['captchaid'])) { $wgRequest->setVal('wpCaptchaId', $params['captchaid']); } if (!is_null($params['captchaword'])) { $wgRequest->setVal('wpCaptchaWord', $params['captchaword']); } $r = array(); if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) { if (count($r)) { $r['result'] = "Failure"; $this->getResult()->addValue(null, $this->getModuleName(), $r); return; } else { $this->dieUsageMsg(array('hookaborted')); } } // Do the actual save $oldRevId = $articleObj->getRevIdFetched(); $result = null; // Fake $wgRequest for some hooks inside EditPage // FIXME: This interface SUCKS $oldRequest = $wgRequest; $wgRequest = $req; $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']); $wgRequest = $oldRequest; switch ($retval) { case EditPage::AS_HOOK_ERROR: case EditPage::AS_HOOK_ERROR_EXPECTED: $this->dieUsageMsg(array('hookaborted')); case EditPage::AS_IMAGE_REDIRECT_ANON: $this->dieUsageMsg(array('noimageredirect-anon')); case EditPage::AS_IMAGE_REDIRECT_LOGGED: $this->dieUsageMsg(array('noimageredirect-logged')); case EditPage::AS_SPAM_ERROR: $this->dieUsageMsg(array('spamdetected', $result['spam'])); case EditPage::AS_FILTERING: $this->dieUsageMsg(array('filtered')); case EditPage::AS_BLOCKED_PAGE_FOR_USER: $this->dieUsageMsg(array('blockedtext')); case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: case EditPage::AS_CONTENT_TOO_BIG: global $wgMaxArticleSize; $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize)); case EditPage::AS_READ_ONLY_PAGE_ANON: $this->dieUsageMsg(array('noedit-anon')); case EditPage::AS_READ_ONLY_PAGE_LOGGED: $this->dieUsageMsg(array('noedit')); case EditPage::AS_READ_ONLY_PAGE: $this->dieReadOnly(); case EditPage::AS_RATE_LIMITED: $this->dieUsageMsg(array('actionthrottledtext')); case EditPage::AS_ARTICLE_WAS_DELETED: $this->dieUsageMsg(array('wasdeleted')); case EditPage::AS_NO_CREATE_PERMISSION: $this->dieUsageMsg(array('nocreate-loggedin')); case EditPage::AS_BLANK_ARTICLE: $this->dieUsageMsg(array('blankpage')); case EditPage::AS_CONFLICT_DETECTED: $this->dieUsageMsg(array('editconflict')); // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary case EditPage::AS_TEXTBOX_EMPTY: $this->dieUsageMsg(array('emptynewsection')); case EditPage::AS_SUCCESS_NEW_ARTICLE: $r['new'] = ''; case EditPage::AS_SUCCESS_UPDATE: $r['result'] = "Success"; $r['pageid'] = intval($titleObj->getArticleID()); $r['title'] = $titleObj->getPrefixedText(); // HACK: We create a new Article object here because getRevIdFetched() // refuses to be run twice, and because Title::getLatestRevId() // won't fetch from the master unless we select for update, which we // don't want to do. $newArticle = new Article($titleObj); $newRevId = $newArticle->getRevIdFetched(); if ($newRevId == $oldRevId) { $r['nochange'] = ''; } else { $r['oldrevid'] = intval($oldRevId); $r['newrevid'] = intval($newRevId); $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $newArticle->getTimestamp()); } break; case EditPage::AS_END: // This usually means some kind of race condition // or DB weirdness occurred. Fall through to throw an unknown // error. // This needs fixing higher up, as Article::doEdit should be // used rather than Article::updateArticle, so that specific // error conditions can be returned // This usually means some kind of race condition // or DB weirdness occurred. Fall through to throw an unknown // error. // This needs fixing higher up, as Article::doEdit should be // used rather than Article::updateArticle, so that specific // error conditions can be returned default: $this->dieUsageMsg(array('unknownerror', $retval)); } $this->getResult()->addValue(null, $this->getModuleName(), $r); } catch (Exception $e) { $this->dieUsage($e->getMessage(), 'WOM error'); } }