protected function castBool($args) { if (count($args) < 1) { throw new AFPUserVisibleException('noparams', $this->mCur->pos, array(__METHOD__)); } $val = $args[0]; return AFPData::castTypes($val, AFPData::DBool); }
/** * @param $vars AbuseFilterVariableHolder * @return AFPData|array|int|mixed|null|string * @throws MWException * @throws AFPException */ function compute($vars) { $parameters = $this->mParameters; $result = null; if (!wfRunHooks('AbuseFilter-interceptVariable', array($this->mMethod, $vars, $parameters, &$result))) { return $result instanceof AFPData ? $result : AFPData::newFromPHPVar($result); } switch ($this->mMethod) { case 'diff': $text1Var = $parameters['oldtext-var']; $text2Var = $parameters['newtext-var']; $text1 = $vars->getVar($text1Var)->toString() . "\n"; $text2 = $vars->getVar($text2Var)->toString() . "\n"; $result = wfDiff($text1, $text2); break; case 'diff-split': $diff = $vars->getVar($parameters['diff-var'])->toString(); $line_prefix = $parameters['line-prefix']; $diff_lines = explode("\n", $diff); $interest_lines = array(); foreach ($diff_lines as $line) { if (substr($line, 0, 1) === $line_prefix) { $interest_lines[] = substr($line, strlen($line_prefix)); } } $result = $interest_lines; break; case 'links-from-wikitext': // This should ONLY be used when sharing a parse operation with the edit. /* @var WikiPage $article */ $article = $parameters['article']; if ($article !== null && (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT)) { $textVar = $parameters['text-var']; // XXX: Use prepareContentForEdit. But we need a Content object for that. $new_text = $vars->getVar($textVar)->toString(); $content = ContentHandler::makeContent($new_text, $article->getTitle()); $editInfo = $article->prepareContentForEdit($content); $links = array_keys($editInfo->output->getExternalLinks()); $result = $links; break; } // Otherwise fall back to database // Otherwise fall back to database case 'links-from-wikitext-nonedit': case 'links-from-wikitext-or-database': // TODO: use Content object instead, if available! In any case, use WikiPage, not Article. $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); if ($vars->getVar('context')->toString() == 'filter') { $links = $this->getLinksFromDB($article); wfDebug("AbuseFilter: loading old links from DB\n"); } elseif (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT) { wfDebug("AbuseFilter: loading old links from Parser\n"); $textVar = $parameters['text-var']; $wikitext = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($wikitext, $article); $links = array_keys($editInfo->output->getExternalLinks()); } else { // TODO: Get links from Content object. But we don't have the content object. // And for non-text content, $wikitext is usually not going to be a valid // serialization, but rather some dummy text for filtering. $links = array(); } $result = $links; break; case 'link-diff-added': case 'link-diff-removed': $oldLinkVar = $parameters['oldlink-var']; $newLinkVar = $parameters['newlink-var']; $oldLinks = $vars->getVar($oldLinkVar)->toString(); $newLinks = $vars->getVar($newLinkVar)->toString(); $oldLinks = explode("\n", $oldLinks); $newLinks = explode("\n", $newLinks); if ($this->mMethod == 'link-diff-added') { $result = array_diff($newLinks, $oldLinks); } if ($this->mMethod == 'link-diff-removed') { $result = array_diff($oldLinks, $newLinks); } break; case 'parse-wikitext': // Should ONLY be used when sharing a parse operation with the edit. $article = $parameters['article']; if ($article !== null && (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT)) { $textVar = $parameters['wikitext-var']; // XXX: Use prepareContentForEdit. But we need a Content object for that. $new_text = $vars->getVar($textVar)->toString(); $editInfo = $article->prepareTextForEdit($new_text); if (isset($parameters['pst']) && $parameters['pst']) { $result = $editInfo->pstContent->serialize($editInfo->format); } else { $newHTML = $editInfo->output->getText(); // Kill the PP limit comments. Ideally we'd just remove these by not setting the // parser option, but then we can't share a parse operation with the edit, which is bad. $result = preg_replace('/<!--\\s*NewPP limit report[^>]*-->\\s*$/si', '', $newHTML); } break; } // Otherwise fall back to database // Otherwise fall back to database case 'parse-wikitext-nonedit': // TODO: use Content object instead, if available! In any case, use WikiPage, not Article. $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); $textVar = $parameters['wikitext-var']; if (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT) { if (isset($parameters['pst']) && $parameters['pst']) { // $textVar is already PSTed when it's not loaded from an ongoing edit. $result = $vars->getVar($textVar)->toString(); } else { $text = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($text, $article); $result = $editInfo->output->getText(); } } else { // TODO: Parser Output from Content object. But we don't have the content object. // And for non-text content, $wikitext is usually not going to be a valid // serialization, but rather some dummy text for filtering. $result = ''; } break; case 'strip-html': $htmlVar = $parameters['html-var']; $html = $vars->getVar($htmlVar)->toString(); $result = StringUtils::delimiterReplace('<', '>', '', $html); break; case 'load-recent-authors': $cutOff = $parameters['cutoff']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); if (!$title->exists()) { $result = ''; break; } $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('revision', 'DISTINCT rev_user_text', array('rev_page' => $title->getArticleID(), 'rev_timestamp<' . $dbr->addQuotes($dbr->timestamp($cutOff))), __METHOD__, array('ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 10)); $users = array(); foreach ($res as $row) { $users[] = $row->rev_user_text; } $result = $users; break; case 'get-page-restrictions': $action = $parameters['action']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $rights = $title->getRestrictions($action); $rights = count($rights) ? $rights : array(); $result = $rights; break; case 'simple-user-accessor': $user = $parameters['user']; $method = $parameters['method']; if (!$user) { throw new MWException('No user parameter given.'); } $obj = self::getUserObject($user); if (!$obj) { throw new MWException("Invalid username {$user}"); } $result = call_user_func(array($obj, $method)); break; case 'user-age': $user = $parameters['user']; $asOf = $parameters['asof']; $obj = self::getUserObject($user); if ($obj->getId() == 0) { $result = 0; break; } $registration = $obj->getRegistration(); $result = wfTimestamp(TS_UNIX, $asOf) - wfTimestampOrNull(TS_UNIX, $registration); break; case 'user-groups': // Deprecated but needed by old log entries $user = $parameters['user']; $obj = self::getUserObject($user); $result = $obj->getEffectiveGroups(); break; case 'length': $s = $vars->getVar($parameters['length-var'])->toString(); $result = strlen($s); break; case 'subtract': $v1 = $vars->getVar($parameters['val1-var'])->toFloat(); $v2 = $vars->getVar($parameters['val2-var'])->toFloat(); $result = $v1 - $v2; break; case 'revision-text-by-id': $rev = Revision::newFromId($parameters['revid']); $result = AbuseFilter::revisionToString($rev); break; case 'revision-text-by-timestamp': $timestamp = $parameters['timestamp']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $dbr = wfGetDB(DB_SLAVE); $rev = Revision::loadFromTimestamp($dbr, $title, $timestamp); $result = AbuseFilter::revisionToString($rev); break; default: if (wfRunHooks('AbuseFilter-computeVariable', array($this->mMethod, $vars, $parameters, &$result))) { throw new AFPException('Unknown variable compute type ' . $this->mMethod); } } return $result instanceof AFPData ? $result : AFPData::newFromPHPVar($result); }
function compute($vars) { $parameters = $this->mParameters; $result = null; switch ($this->mMethod) { case 'diff': $text1Var = $parameters['oldtext-var']; $text2Var = $parameters['newtext-var']; $text1 = $vars->getVar($text1Var)->toString(); $text2 = $vars->getVar($text2Var)->toString(); $result = wfDiff($text1, $text2); $result = trim(preg_replace("/^\\\\ No newline at end of file\n/m", '', $result)); break; case 'diff-split': $diff = $vars->getVar($parameters['diff-var'])->toString(); $line_prefix = $parameters['line-prefix']; $diff_lines = explode("\n", $diff); $interest_lines = array(); foreach ($diff_lines as $line) { if (substr($line, 0, 1) === $line_prefix) { $interest_lines[] = substr($line, strlen($line_prefix)); } } $result = $interest_lines; break; case 'links-from-wikitext': // This should ONLY be used when sharing a parse operation with the edit. $article = $parameters['article']; if ($article) { $textVar = $parameters['text-var']; $new_text = $vars->getVar($textVar)->toString(); $editInfo = $article->prepareTextForEdit($new_text); $links = array_keys($editInfo->output->getExternalLinks()); $result = $links; break; } // Otherwise fall back to database // Otherwise fall back to database case 'links-from-wikitext-nonedit': case 'links-from-wikitext-or-database': $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); if ($vars->getVar('context')->toString() == 'filter') { $links = $this->getLinksFromDB($article); wfDebug("AbuseFilter: loading old links from DB\n"); } else { wfDebug("AbuseFilter: loading old links from Parser\n"); $textVar = $parameters['text-var']; $wikitext = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($wikitext, $article); $links = array_keys($editInfo->output->getExternalLinks()); } $result = $links; break; case 'link-diff-added': case 'link-diff-removed': $oldLinkVar = $parameters['oldlink-var']; $newLinkVar = $parameters['newlink-var']; $oldLinks = $vars->getVar($oldLinkVar)->toString(); $newLinks = $vars->getVar($newLinkVar)->toString(); $oldLinks = explode("\n", $oldLinks); $newLinks = explode("\n", $newLinks); if ($this->mMethod == 'link-diff-added') { $result = array_diff($newLinks, $oldLinks); } if ($this->mMethod == 'link-diff-removed') { $result = array_diff($oldLinks, $newLinks); } break; case 'parse-wikitext': // Should ONLY be used when sharing a parse operation with the edit. $article = $parameters['article']; if ($article) { $textVar = $parameters['wikitext-var']; $new_text = $vars->getVar($textVar)->toString(); $editInfo = $article->prepareTextForEdit($new_text); $newHTML = $editInfo->output->getText(); // Kill the PP limit comments. Ideally we'd just remove these by not setting the // parser option, but then we can't share a parse operation with the edit, which is bad. $result = preg_replace('/<!--\\s*NewPP limit report[^>]*-->\\s*$/si', '', $newHTML); break; } // Otherwise fall back to database // Otherwise fall back to database case 'parse-wikitext-nonedit': $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); $textVar = $parameters['wikitext-var']; $text = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($text, $article); $result = $editInfo->output->getText(); break; case 'strip-html': $htmlVar = $parameters['html-var']; $html = $vars->getVar($htmlVar)->toString(); $result = StringUtils::delimiterReplace('<', '>', '', $html); break; case 'load-recent-authors': $cutOff = $parameters['cutoff']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); if (!$title->exists()) { $result = ''; break; } $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('revision', 'DISTINCT rev_user_text', array('rev_page' => $title->getArticleId(), 'rev_timestamp<' . $dbr->addQuotes($dbr->timestamp($cutOff))), __METHOD__, array('ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 10)); $users = array(); foreach ($res as $row) { $users[] = $row->rev_user_text; } $result = $users; break; case 'get-page-restrictions': $action = $parameters['action']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $rights = $title->getRestrictions($action); $rights = count($rights) ? $rights : array(); $result = $rights; break; case 'simple-user-accessor': $user = $parameters['user']; $method = $parameters['method']; if (!$user) { throw new MWException('No user parameter given.'); } $obj = self::userObjectFromName($user); if (!$obj) { throw new MWException("Invalid username {$user}"); } $result = call_user_func(array($obj, $method)); break; case 'user-age': $user = $parameters['user']; $asOf = $parameters['asof']; $obj = self::userObjectFromName($user); if ($obj->getId() == 0) { $result = 0; break; } $registration = $obj->getRegistration(); $result = wfTimestamp(TS_UNIX, $asOf) - wfTimestampOrNull(TS_UNIX, $registration); break; case 'user-groups': $user = $parameters['user']; $obj = self::userObjectFromName($user); $result = $obj->getEffectiveGroups(); break; case 'length': $s = $vars->getVar($parameters['length-var'])->toString(); $result = strlen($s); break; case 'subtract': $v1 = $vars->getVar($parameters['val1-var'])->toFloat(); $v2 = $vars->getVar($parameters['val2-var'])->toFloat(); $result = $v1 - $v2; break; case 'revision-text-by-id': $rev = Revision::newFromId($parameters['revid']); $result = $rev->getText(); break; case 'revision-text-by-timestamp': $timestamp = $parameters['timestamp']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $dbr = wfGetDB(DB_SLAVE); $rev = Revision::loadFromTimestamp($dbr, $title, $timestamp); if ($rev) { $result = $rev->getText(); } else { $result = ''; } break; default: if (wfRunHooks('AbuseFilter-computeVariable', array($this->mMethod, $vars))) { throw new AFPException('Unknown variable compute type ' . $this->mMethod); } } return $result instanceof AFPData ? $result : AFPData::newFromPHPVar($result); }