public function execute() { global $wgUser; $params = $this->extractRequestParams(); if (is_null($params['title'])) { $this->dieUsage('Must specify page title', 0); } if (is_null($params['xpath'])) { $this->dieUsage('Must specify xpath', 1); } $page_name = $params['title']; $xpath = $params['xpath']; $type = $params['type']; $rid = $params['rid']; $articleTitle = Title::newFromText($page_name); if (!$articleTitle) { $this->dieUsage("Can't create title object ({$page_name})", 2); } $article = new Article($articleTitle); if (!$article->exists()) { $this->dieUsage("Article doesn't exist ({$page_name})", 3); } $page_obj = WOMOutputProcessor::getOutputData($articleTitle, $rid); try { $objs = WOMProcessor::getObjIdByXPath2($page_obj, $xpath); } catch (Exception $e) { $err = $e->getMessage(); } $result = array(); if (isset($err)) { $result = array('result' => 'Failure', 'message' => array()); $this->getResult()->setContent($result['message'], $err); } else { $result['result'] = 'Success'; // pay attention to special xml tag, e.g., <property><value>...</value></property> $result['return'] = array(); if ($type == 'count') { $count = 0; foreach ($objs as $id) { if ($id == '') { continue; } ++$count; } $this->getResult()->setContent($result['return'], $count); } else { $xml = ''; foreach ($objs as $id) { if ($id == '') { continue; } $wobj = $page_obj->getObject($id); $result['return'][$id] = array(); if ($type == 'xml') { $xml .= "<{$id} xml:space=\"preserve\">{$wobj->toXML()}</{$id}>"; } else { $this->getResult()->setContent($result['return'][$id], $wobj->getWikiText()); } } if ($type == 'xml') { header("Content-Type: application/rdf+xml"); echo <<<OUTPUT <?xml version="1.0" encoding="UTF-8" ?> <api><womoutput result="Success"><return> {$xml} </return></womoutput></api> OUTPUT; exit(1); } } } $this->getResult()->addValue(null, $this->getModuleName(), $result); }
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'); } }