function execute($par)
 {
     // Global array containing names of tracking categories
     global $wgTrackingCategories;
     $this->setHeaders();
     $this->outputHeader();
     $this->getOutput()->allowClickjacking();
     $this->getOutput()->addHTML(Html::openElement('table', array('class' => 'mw-datatable TablePager', 'id' => 'mw-trackingcategories-table')) . "\n" . "<thead><tr>\n\t\t\t<th>" . $this->msg('trackingcategories-msg')->escaped() . "\n\t\t\t</th>\n\t\t\t<th>" . $this->msg('trackingcategories-name')->escaped() . "</th>\n\t\t\t<th>" . $this->msg('trackingcategories-desc')->escaped() . "\n\t\t\t</th>\n\t\t\t</tr></thead>");
     foreach ($wgTrackingCategories as $catMsg) {
         /*
          * Check if the tracking category varies by namespace
          * Otherwise only pages in the current namespace will be displayed
          * If it does vary, show pages considering all namespaces
          */
         $msgObj = $this->msg($catMsg)->inContentLanguage();
         $allMsgs = array();
         $catDesc = $catMsg . '-desc';
         $catMsgTitle = Title::makeTitleSafe(NS_MEDIAWIKI, $catMsg);
         $catMsgTitleText = Linker::link($catMsgTitle, htmlspecialchars($catMsg));
         if (strpos($msgObj->plain(), '{{NAMESPACE}}') !== false) {
             $ns = MWNamespace::getValidNamespaces();
             foreach ($ns as $namesp) {
                 $tempTitle = Title::makeTitleSafe($namesp, $catMsg);
                 $catName = $msgObj->title($tempTitle)->text();
                 if (!$msgObj->isDisabled()) {
                     $catTitle = Title::makeTitleSafe(NS_CATEGORY, $catName);
                     $catTitleText = Linker::link($catTitle, htmlspecialchars($catName));
                     $allMsgs[] = $catTitleText;
                 }
             }
         } else {
             $catName = $msgObj->text();
             if (!$msgObj->isDisabled()) {
                 $catTitle = Title::makeTitleSafe(NS_CATEGORY, $catName);
                 $catTitleText = Linker::link($catTitle, htmlspecialchars($catName));
                 $classes = array();
             } else {
                 $catTitleText = $this->msg('trackingcategories-disabled')->parse();
             }
             $allMsgs[] = $catTitleText;
         }
         /*
          * Show category description if it exists as a system message
          * as category-name-desc
          */
         $descMsg = $this->msg($catDesc);
         if ($descMsg->isBlank()) {
             $descMsg = $this->msg('trackingcategories-nodesc');
         }
         $this->getOutput()->addHTML(Html::openElement('tr') . Html::openElement('td', array('class' => 'mw-trackingcategories-name')) . $this->getLanguage()->commaList(array_unique($allMsgs)) . Html::closeElement('td') . Html::openElement('td', array('class' => 'mw-trackingcategories-msg')) . $catMsgTitleText . Html::closeElement('td') . Html::openElement('td', array('class' => 'mw-trackingcategories-desc')) . $descMsg->parse() . Html::closeElement('td') . Html::closeElement('tr'));
     }
     $this->getOutput()->addHTML(Html::closeElement('table'));
 }
示例#2
0
文件: ApiHelp.php 项目: paladox/2
 /**
  * Recursively-called function to actually construct the help
  *
  * @param IContextSource $context
  * @param ApiBase[] $modules
  * @param array $options
  * @param array &$haveModules
  * @return string
  */
 private static function getHelpInternal(IContextSource $context, array $modules, array $options, &$haveModules)
 {
     $out = '';
     $level = empty($options['headerlevel']) ? 2 : $options['headerlevel'];
     if (empty($options['tocnumber'])) {
         $tocnumber = array(2 => 0);
     } else {
         $tocnumber =& $options['tocnumber'];
     }
     foreach ($modules as $module) {
         $tocnumber[$level]++;
         $path = $module->getModulePath();
         $module->setContext($context);
         $help = array('header' => '', 'flags' => '', 'description' => '', 'help-urls' => '', 'parameters' => '', 'examples' => '', 'submodules' => '');
         if (empty($options['noheader']) || !empty($options['toc'])) {
             $anchor = $path;
             $i = 1;
             while (isset($haveModules[$anchor])) {
                 $anchor = $path . '|' . ++$i;
             }
             if ($module->isMain()) {
                 $header = $context->msg('api-help-main-header')->parse();
             } else {
                 $name = $module->getModuleName();
                 $header = $module->getParent()->getModuleManager()->getModuleGroup($name) . "={$name}";
                 if ($module->getModulePrefix() !== '') {
                     $header .= ' ' . $context->msg('parentheses', $module->getModulePrefix())->parse();
                 }
             }
             $haveModules[$anchor] = array('toclevel' => count($tocnumber), 'level' => $level, 'anchor' => $anchor, 'line' => $header, 'number' => join('.', $tocnumber), 'index' => false);
             if (empty($options['noheader'])) {
                 $help['header'] .= Html::element('h' . min(6, $level), array('id' => $anchor, 'class' => 'apihelp-header'), $header);
             }
         } else {
             $haveModules[$path] = true;
         }
         $links = array();
         $any = false;
         for ($m = $module; $m !== null; $m = $m->getParent()) {
             $name = $m->getModuleName();
             if ($name === 'main_int') {
                 $name = 'main';
             }
             if (count($modules) === 1 && $m === $modules[0] && !(!empty($options['submodules']) && $m->getModuleManager())) {
                 $link = Html::element('b', null, $name);
             } else {
                 $link = SpecialPage::getTitleFor('ApiHelp', $m->getModulePath())->getLocalURL();
                 $link = Html::element('a', array('href' => $link, 'class' => 'apihelp-linktrail'), $name);
                 $any = true;
             }
             array_unshift($links, $link);
         }
         if ($any) {
             $help['header'] .= self::wrap($context->msg('parentheses')->rawParams($context->getLanguage()->pipeList($links)), 'apihelp-linktrail', 'div');
         }
         $flags = $module->getHelpFlags();
         $help['flags'] .= Html::openElement('div', array('class' => 'apihelp-block apihelp-flags'));
         $msg = $context->msg('api-help-flags');
         if (!$msg->isDisabled()) {
             $help['flags'] .= self::wrap($msg->numParams(count($flags)), 'apihelp-block-head', 'div');
         }
         $help['flags'] .= Html::openElement('ul');
         foreach ($flags as $flag) {
             $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg("api-help-flag-{$flag}"), "apihelp-flag-{$flag}"));
         }
         $sourceInfo = $module->getModuleSourceInfo();
         if ($sourceInfo) {
             if (isset($sourceInfo['namemsg'])) {
                 $extname = $context->msg($sourceInfo['namemsg'])->text();
             } else {
                 $extname = $sourceInfo['name'];
             }
             $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-source', $extname, $sourceInfo['name']), 'apihelp-source'));
             $link = SpecialPage::getTitleFor('Version', 'License/' . $sourceInfo['name']);
             if (isset($sourceInfo['license-name'])) {
                 $msg = $context->msg('api-help-license', $link, $sourceInfo['license-name']);
             } elseif (SpecialVersion::getExtLicenseFileName(dirname($sourceInfo['path']))) {
                 $msg = $context->msg('api-help-license-noname', $link);
             } else {
                 $msg = $context->msg('api-help-license-unknown');
             }
             $help['flags'] .= Html::rawElement('li', null, self::wrap($msg, 'apihelp-license'));
         } else {
             $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-source-unknown'), 'apihelp-source'));
             $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-license-unknown'), 'apihelp-license'));
         }
         $help['flags'] .= Html::closeElement('ul');
         $help['flags'] .= Html::closeElement('div');
         foreach ($module->getFinalDescription() as $msg) {
             $msg->setContext($context);
             $help['description'] .= $msg->parseAsBlock();
         }
         $urls = $module->getHelpUrls();
         if ($urls) {
             $help['help-urls'] .= Html::openElement('div', array('class' => 'apihelp-block apihelp-help-urls'));
             $msg = $context->msg('api-help-help-urls');
             if (!$msg->isDisabled()) {
                 $help['help-urls'] .= self::wrap($msg->numParams(count($urls)), 'apihelp-block-head', 'div');
             }
             if (!is_array($urls)) {
                 $urls = array($urls);
             }
             $help['help-urls'] .= Html::openElement('ul');
             foreach ($urls as $url) {
                 $help['help-urls'] .= Html::rawElement('li', null, Html::element('a', array('href' => $url), $url));
             }
             $help['help-urls'] .= Html::closeElement('ul');
             $help['help-urls'] .= Html::closeElement('div');
         }
         $params = $module->getFinalParams(ApiBase::GET_VALUES_FOR_HELP);
         $dynamicParams = $module->dynamicParameterDocumentation();
         $groups = array();
         if ($params || $dynamicParams !== null) {
             $help['parameters'] .= Html::openElement('div', array('class' => 'apihelp-block apihelp-parameters'));
             $msg = $context->msg('api-help-parameters');
             if (!$msg->isDisabled()) {
                 $help['parameters'] .= self::wrap($msg->numParams(count($params)), 'apihelp-block-head', 'div');
             }
             $help['parameters'] .= Html::openElement('dl');
             $descriptions = $module->getFinalParamDescription();
             foreach ($params as $name => $settings) {
                 if (!is_array($settings)) {
                     $settings = array(ApiBase::PARAM_DFLT => $settings);
                 }
                 $help['parameters'] .= Html::element('dt', null, $module->encodeParamName($name));
                 // Add description
                 $description = array();
                 if (isset($descriptions[$name])) {
                     foreach ($descriptions[$name] as $msg) {
                         $msg->setContext($context);
                         $description[] = $msg->parseAsBlock();
                     }
                 }
                 // Add usage info
                 $info = array();
                 // Required?
                 if (!empty($settings[ApiBase::PARAM_REQUIRED])) {
                     $info[] = $context->msg('api-help-param-required')->parse();
                 }
                 // Custom info?
                 if (!empty($settings[ApiBase::PARAM_HELP_MSG_INFO])) {
                     foreach ($settings[ApiBase::PARAM_HELP_MSG_INFO] as $i) {
                         $tag = array_shift($i);
                         $info[] = $context->msg("apihelp-{$path}-paraminfo-{$tag}")->numParams(count($i))->params($context->getLanguage()->commaList($i))->params($module->getModulePrefix())->parse();
                     }
                 }
                 // Type documentation
                 if (!isset($settings[ApiBase::PARAM_TYPE])) {
                     $dflt = isset($settings[ApiBase::PARAM_DFLT]) ? $settings[ApiBase::PARAM_DFLT] : null;
                     if (is_bool($dflt)) {
                         $settings[ApiBase::PARAM_TYPE] = 'boolean';
                     } elseif (is_string($dflt) || is_null($dflt)) {
                         $settings[ApiBase::PARAM_TYPE] = 'string';
                     } elseif (is_int($dflt)) {
                         $settings[ApiBase::PARAM_TYPE] = 'integer';
                     }
                 }
                 if (isset($settings[ApiBase::PARAM_TYPE])) {
                     $type = $settings[ApiBase::PARAM_TYPE];
                     $multi = !empty($settings[ApiBase::PARAM_ISMULTI]);
                     $hintPipeSeparated = true;
                     $count = ApiBase::LIMIT_SML2 + 1;
                     if (is_array($type)) {
                         $count = count($type);
                         $links = isset($settings[ApiBase::PARAM_VALUE_LINKS]) ? $settings[ApiBase::PARAM_VALUE_LINKS] : array();
                         $type = array_map(function ($v) use($links) {
                             $ret = wfEscapeWikiText($v);
                             if (isset($links[$v])) {
                                 $ret = "[[{$links[$v]}|{$ret}]]";
                             }
                             return $ret;
                         }, $type);
                         $i = array_search('', $type, true);
                         if ($i === false) {
                             $type = $context->getLanguage()->commaList($type);
                         } else {
                             unset($type[$i]);
                             $type = $context->msg('api-help-param-list-can-be-empty')->numParams(count($type))->params($context->getLanguage()->commaList($type))->parse();
                         }
                         $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($type)->parse();
                         $hintPipeSeparated = false;
                     } else {
                         switch ($type) {
                             case 'submodule':
                                 $groups[] = $name;
                                 if (isset($settings[ApiBase::PARAM_SUBMODULE_MAP])) {
                                     $map = $settings[ApiBase::PARAM_SUBMODULE_MAP];
                                     ksort($map);
                                     $submodules = array();
                                     foreach ($map as $v => $m) {
                                         $submodules[] = "[[Special:ApiHelp/{$m}|{$v}]]";
                                     }
                                 } else {
                                     $submodules = $module->getModuleManager()->getNames($name);
                                     sort($submodules);
                                     $prefix = $module->isMain() ? '' : $module->getModulePath() . '+';
                                     $submodules = array_map(function ($name) use($prefix) {
                                         return "[[Special:ApiHelp/{$prefix}{$name}|{$name}]]";
                                     }, $submodules);
                                 }
                                 $count = count($submodules);
                                 $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($context->getLanguage()->commaList($submodules))->parse();
                                 $hintPipeSeparated = false;
                                 // No type message necessary, we have a list of values.
                                 $type = null;
                                 break;
                             case 'namespace':
                                 $namespaces = MWNamespace::getValidNamespaces();
                                 $count = count($namespaces);
                                 $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($context->getLanguage()->commaList($namespaces))->parse();
                                 $hintPipeSeparated = false;
                                 // No type message necessary, we have a list of values.
                                 $type = null;
                                 break;
                             case 'limit':
                                 if (isset($settings[ApiBase::PARAM_MAX2])) {
                                     $info[] = $context->msg('api-help-param-limit2')->numParams($settings[ApiBase::PARAM_MAX])->numParams($settings[ApiBase::PARAM_MAX2])->parse();
                                 } else {
                                     $info[] = $context->msg('api-help-param-limit')->numParams($settings[ApiBase::PARAM_MAX])->parse();
                                 }
                                 break;
                             case 'integer':
                                 // Possible messages:
                                 // api-help-param-integer-min,
                                 // api-help-param-integer-max,
                                 // api-help-param-integer-minmax
                                 $suffix = '';
                                 $min = $max = 0;
                                 if (isset($settings[ApiBase::PARAM_MIN])) {
                                     $suffix .= 'min';
                                     $min = $settings[ApiBase::PARAM_MIN];
                                 }
                                 if (isset($settings[ApiBase::PARAM_MAX])) {
                                     $suffix .= 'max';
                                     $max = $settings[ApiBase::PARAM_MAX];
                                 }
                                 if ($suffix !== '') {
                                     $info[] = $context->msg("api-help-param-integer-{$suffix}")->params($multi ? 2 : 1)->numParams($min, $max)->parse();
                                 }
                                 break;
                             case 'upload':
                                 $info[] = $context->msg('api-help-param-upload')->parse();
                                 // No type message necessary, api-help-param-upload should handle it.
                                 $type = null;
                                 break;
                             case 'string':
                             case 'text':
                                 // Displaying a type message here would be useless.
                                 $type = null;
                                 break;
                         }
                     }
                     // Add type. Messages for grep: api-help-param-type-limit
                     // api-help-param-type-integer api-help-param-type-boolean
                     // api-help-param-type-timestamp api-help-param-type-user
                     // api-help-param-type-password
                     if (is_string($type)) {
                         $msg = $context->msg("api-help-param-type-{$type}");
                         if (!$msg->isDisabled()) {
                             $info[] = $msg->params($multi ? 2 : 1)->parse();
                         }
                     }
                     if ($multi) {
                         $extra = array();
                         if ($hintPipeSeparated) {
                             $extra[] = $context->msg('api-help-param-multi-separate')->parse();
                         }
                         if ($count > ApiBase::LIMIT_SML1) {
                             $extra[] = $context->msg('api-help-param-multi-max')->numParams(ApiBase::LIMIT_SML1, ApiBase::LIMIT_SML2)->parse();
                         }
                         if ($extra) {
                             $info[] = join(' ', $extra);
                         }
                     }
                 }
                 // Add default
                 $default = isset($settings[ApiBase::PARAM_DFLT]) ? $settings[ApiBase::PARAM_DFLT] : null;
                 if ($default === '') {
                     $info[] = $context->msg('api-help-param-default-empty')->parse();
                 } elseif ($default !== null && $default !== false) {
                     $info[] = $context->msg('api-help-param-default')->params(wfEscapeWikiText($default))->parse();
                 }
                 if (!array_filter($description)) {
                     $description = array(self::wrap($context->msg('api-help-param-no-description'), 'apihelp-empty'));
                 }
                 // Add "deprecated" flag
                 if (!empty($settings[ApiBase::PARAM_DEPRECATED])) {
                     $help['parameters'] .= Html::openElement('dd', array('class' => 'info'));
                     $help['parameters'] .= self::wrap($context->msg('api-help-param-deprecated'), 'apihelp-deprecated', 'strong');
                     $help['parameters'] .= Html::closeElement('dd');
                 }
                 if ($description) {
                     $description = join('', $description);
                     $description = preg_replace('!\\s*</([oud]l)>\\s*<\\1>\\s*!', "\n", $description);
                     $help['parameters'] .= Html::rawElement('dd', array('class' => 'description'), $description);
                 }
                 foreach ($info as $i) {
                     $help['parameters'] .= Html::rawElement('dd', array('class' => 'info'), $i);
                 }
             }
             if ($dynamicParams !== null) {
                 $dynamicParams = ApiBase::makeMessage($dynamicParams, $context, array($module->getModulePrefix(), $module->getModuleName(), $module->getModulePath()));
                 $help['parameters'] .= Html::element('dt', null, '*');
                 $help['parameters'] .= Html::rawElement('dd', array('class' => 'description'), $dynamicParams->parse());
             }
             $help['parameters'] .= Html::closeElement('dl');
             $help['parameters'] .= Html::closeElement('div');
         }
         $examples = $module->getExamplesMessages();
         if ($examples) {
             $help['examples'] .= Html::openElement('div', array('class' => 'apihelp-block apihelp-examples'));
             $msg = $context->msg('api-help-examples');
             if (!$msg->isDisabled()) {
                 $help['examples'] .= self::wrap($msg->numParams(count($examples)), 'apihelp-block-head', 'div');
             }
             $help['examples'] .= Html::openElement('dl');
             foreach ($examples as $qs => $msg) {
                 $msg = ApiBase::makeMessage($msg, $context, array($module->getModulePrefix(), $module->getModuleName(), $module->getModulePath()));
                 $link = wfAppendQuery(wfScript('api'), $qs);
                 $help['examples'] .= Html::rawElement('dt', null, $msg->parse());
                 $help['examples'] .= Html::rawElement('dd', null, Html::element('a', array('href' => $link), "api.php?{$qs}"));
             }
             $help['examples'] .= Html::closeElement('dl');
             $help['examples'] .= Html::closeElement('div');
         }
         $subtocnumber = $tocnumber;
         $subtocnumber[$level + 1] = 0;
         $suboptions = array('submodules' => $options['recursivesubmodules'], 'headerlevel' => $level + 1, 'tocnumber' => &$subtocnumber, 'noheader' => false) + $options;
         if ($options['submodules'] && $module->getModuleManager()) {
             $manager = $module->getModuleManager();
             $submodules = array();
             foreach ($groups as $group) {
                 $names = $manager->getNames($group);
                 sort($names);
                 foreach ($names as $name) {
                     $submodules[] = $manager->getModule($name);
                 }
             }
             $help['submodules'] .= self::getHelpInternal($context, $submodules, $suboptions, $haveModules);
         }
         $module->modifyHelp($help, $suboptions, $haveModules);
         Hooks::run('APIHelpModifyOutput', array($module, &$help, $suboptions, &$haveModules));
         $out .= join("\n", $help);
     }
     return $out;
 }
 /**
  * @param ApiPageSet $resultPageSet
  * @return void
  */
 protected function run(ApiPageSet $resultPageSet = null)
 {
     $db = $this->getDB();
     $params = $this->extractRequestParams(false);
     $result = $this->getResult();
     $this->requireMaxOneParameter($params, 'user', 'excludeuser');
     // Namespace check is likely to be desired, but can't be done
     // efficiently in SQL.
     $miser_ns = null;
     $needPageTable = false;
     if ($params['namespace'] !== null) {
         $params['namespace'] = array_unique($params['namespace']);
         sort($params['namespace']);
         if ($params['namespace'] != MWNamespace::getValidNamespaces()) {
             $needPageTable = true;
             if ($this->getConfig()->get('MiserMode')) {
                 $miser_ns = $params['namespace'];
             } else {
                 $this->addWhere(array('page_namespace' => $params['namespace']));
             }
         }
     }
     $this->addTables('revision');
     if ($resultPageSet === null) {
         $this->parseParameters($params);
         $this->addTables('page');
         $this->addJoinConds(array('page' => array('INNER JOIN', array('rev_page = page_id'))));
         $this->addFields(Revision::selectFields());
         $this->addFields(Revision::selectPageFields());
         // Review this depeneding on the outcome of T113901
         $this->addOption('STRAIGHT_JOIN');
     } else {
         $this->limit = $this->getParameter('limit') ?: 10;
         $this->addFields(array('rev_timestamp', 'rev_id'));
         if ($params['generatetitles']) {
             $this->addFields(array('rev_page'));
         }
         if ($needPageTable) {
             $this->addTables('page');
             $this->addJoinConds(array('page' => array('INNER JOIN', array('rev_page = page_id'))));
             $this->addFieldsIf(array('page_namespace'), (bool) $miser_ns);
             // Review this depeneding on the outcome of T113901
             $this->addOption('STRAIGHT_JOIN');
         }
     }
     if ($this->fld_tags) {
         $this->addTables('tag_summary');
         $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', array('rev_id=ts_rev_id'))));
         $this->addFields('ts_tags');
     }
     if ($this->fetchContent) {
         $this->addTables('text');
         $this->addJoinConds(array('text' => array('INNER JOIN', array('rev_text_id=old_id'))));
         $this->addFields('old_id');
         $this->addFields(Revision::selectTextFields());
     }
     if ($params['user'] !== null) {
         $id = User::idFromName($params['user']);
         if ($id) {
             $this->addWhereFld('rev_user', $id);
         } else {
             $this->addWhereFld('rev_user_text', $params['user']);
         }
     } elseif ($params['excludeuser'] !== null) {
         $id = User::idFromName($params['excludeuser']);
         if ($id) {
             $this->addWhere('rev_user != ' . $id);
         } else {
             $this->addWhere('rev_user_text != ' . $db->addQuotes($params['excludeuser']));
         }
     }
     if ($params['user'] !== null || $params['excludeuser'] !== null) {
         // Paranoia: avoid brute force searches (bug 17342)
         if (!$this->getUser()->isAllowed('deletedhistory')) {
             $bitmask = Revision::DELETED_USER;
         } elseif (!$this->getUser()->isAllowedAny('suppressrevision', 'viewsuppressed')) {
             $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
         } else {
             $bitmask = 0;
         }
         if ($bitmask) {
             $this->addWhere($db->bitAnd('rev_deleted', $bitmask) . " != {$bitmask}");
         }
     }
     $dir = $params['dir'];
     if ($params['continue'] !== null) {
         $op = $dir == 'newer' ? '>' : '<';
         $cont = explode('|', $params['continue']);
         $this->dieContinueUsageIf(count($cont) != 2);
         $ts = $db->addQuotes($db->timestamp($cont[0]));
         $rev_id = (int) $cont[1];
         $this->dieContinueUsageIf(strval($rev_id) !== $cont[1]);
         $this->addWhere("rev_timestamp {$op} {$ts} OR " . "(rev_timestamp = {$ts} AND " . "rev_id {$op}= {$rev_id})");
     }
     $this->addOption('LIMIT', $this->limit + 1);
     $sort = $dir == 'newer' ? '' : ' DESC';
     $orderby = array();
     // Targeting index rev_timestamp, user_timestamp, or usertext_timestamp
     // But 'user' is always constant for the latter two, so it doesn't matter here.
     $orderby[] = "rev_timestamp {$sort}";
     $orderby[] = "rev_id {$sort}";
     $this->addOption('ORDER BY', $orderby);
     $res = $this->select(__METHOD__);
     $pageMap = array();
     // Maps rev_page to array index
     $count = 0;
     $nextIndex = 0;
     $generated = array();
     foreach ($res as $row) {
         if (++$count > $this->limit) {
             // We've had enough
             $this->setContinueEnumParameter('continue', "{$row->rev_timestamp}|{$row->rev_id}");
             break;
         }
         // Miser mode namespace check
         if ($miser_ns !== null && !in_array($row->page_namespace, $miser_ns)) {
             continue;
         }
         if ($resultPageSet !== null) {
             if ($params['generatetitles']) {
                 $generated[$row->rev_page] = $row->rev_page;
             } else {
                 $generated[] = $row->rev_id;
             }
         } else {
             $revision = Revision::newFromRow($row);
             $rev = $this->extractRevisionInfo($revision, $row);
             if (!isset($pageMap[$row->rev_page])) {
                 $index = $nextIndex++;
                 $pageMap[$row->rev_page] = $index;
                 $title = $revision->getTitle();
                 $a = array('pageid' => $title->getArticleID(), 'revisions' => array($rev));
                 ApiResult::setIndexedTagName($a['revisions'], 'rev');
                 ApiQueryBase::addTitleInfo($a, $title);
                 $fit = $result->addValue(array('query', $this->getModuleName()), $index, $a);
             } else {
                 $index = $pageMap[$row->rev_page];
                 $fit = $result->addValue(array('query', $this->getModuleName(), $index, 'revisions'), null, $rev);
             }
             if (!$fit) {
                 $this->setContinueEnumParameter('continue', "{$row->rev_timestamp}|{$row->rev_id}");
                 break;
             }
         }
     }
     if ($resultPageSet !== null) {
         if ($params['generatetitles']) {
             $resultPageSet->populateFromPageIDs($generated);
         } else {
             $resultPageSet->populateFromRevisionIDs($generated);
         }
     } else {
         $result->addIndexedTagName(array('query', $this->getModuleName()), 'page');
     }
 }
 /**
  * @param ApiPageSet $resultPageSet
  * @return void
  */
 protected function run(ApiPageSet $resultPageSet = null)
 {
     $user = $this->getUser();
     // Before doing anything at all, let's check permissions
     if (!$user->isAllowed('deletedhistory')) {
         $this->dieUsage('You don\'t have permission to view deleted revision information', 'permissiondenied');
     }
     $db = $this->getDB();
     $params = $this->extractRequestParams(false);
     $result = $this->getResult();
     // If the user wants no namespaces, they get no pages.
     if ($params['namespace'] === []) {
         if ($resultPageSet === null) {
             $result->addValue('query', $this->getModuleName(), []);
         }
         return;
     }
     // This module operates in two modes:
     // 'user': List deleted revs by a certain user
     // 'all': List all deleted revs in NS
     $mode = 'all';
     if (!is_null($params['user'])) {
         $mode = 'user';
     }
     if ($mode == 'user') {
         foreach (['from', 'to', 'prefix', 'excludeuser'] as $param) {
             if (!is_null($params[$param])) {
                 $p = $this->getModulePrefix();
                 $this->dieUsage("The '{$p}{$param}' parameter cannot be used with '{$p}user'", 'badparams');
             }
         }
     } else {
         foreach (['start', 'end'] as $param) {
             if (!is_null($params[$param])) {
                 $p = $this->getModulePrefix();
                 $this->dieUsage("The '{$p}{$param}' parameter may only be used with '{$p}user'", 'badparams');
             }
         }
     }
     // If we're generating titles only, we can use DISTINCT for a better
     // query. But we can't do that in 'user' mode (wrong index), and we can
     // only do it when sorting ASC (because MySQL apparently can't use an
     // index backwards for grouping even though it can for ORDER BY, WTF?)
     $dir = $params['dir'];
     $optimizeGenerateTitles = false;
     if ($mode === 'all' && $params['generatetitles'] && $resultPageSet !== null) {
         if ($dir === 'newer') {
             $optimizeGenerateTitles = true;
         } else {
             $p = $this->getModulePrefix();
             $this->setWarning("For better performance when generating titles, set {$p}dir=newer");
         }
     }
     $this->addTables('archive');
     if ($resultPageSet === null) {
         $this->parseParameters($params);
         $this->addFields(Revision::selectArchiveFields());
         $this->addFields(['ar_title', 'ar_namespace']);
     } else {
         $this->limit = $this->getParameter('limit') ?: 10;
         $this->addFields(['ar_title', 'ar_namespace']);
         if ($optimizeGenerateTitles) {
             $this->addOption('DISTINCT');
         } else {
             $this->addFields(['ar_timestamp', 'ar_rev_id', 'ar_id']);
         }
     }
     if ($this->fld_tags) {
         $this->addTables('tag_summary');
         $this->addJoinConds(['tag_summary' => ['LEFT JOIN', ['ar_rev_id=ts_rev_id']]]);
         $this->addFields('ts_tags');
     }
     if (!is_null($params['tag'])) {
         $this->addTables('change_tag');
         $this->addJoinConds(['change_tag' => ['INNER JOIN', ['ar_rev_id=ct_rev_id']]]);
         $this->addWhereFld('ct_tag', $params['tag']);
     }
     if ($this->fetchContent) {
         // Modern MediaWiki has the content for deleted revs in the 'text'
         // table using fields old_text and old_flags. But revisions deleted
         // pre-1.5 store the content in the 'archive' table directly using
         // fields ar_text and ar_flags, and no corresponding 'text' row. So
         // we have to LEFT JOIN and fetch all four fields.
         $this->addTables('text');
         $this->addJoinConds(['text' => ['LEFT JOIN', ['ar_text_id=old_id']]]);
         $this->addFields(['ar_text', 'ar_flags', 'old_text', 'old_flags']);
         // This also means stricter restrictions
         if (!$user->isAllowedAny('undelete', 'deletedtext')) {
             $this->dieUsage('You don\'t have permission to view deleted revision content', 'permissiondenied');
         }
     }
     $miser_ns = null;
     if ($mode == 'all') {
         if ($params['namespace'] !== null) {
             $namespaces = $params['namespace'];
         } else {
             $namespaces = MWNamespace::getValidNamespaces();
         }
         $this->addWhereFld('ar_namespace', $namespaces);
         // For from/to/prefix, we have to consider the potential
         // transformations of the title in all specified namespaces.
         // Generally there will be only one transformation, but wikis with
         // some namespaces case-sensitive could have two.
         if ($params['from'] !== null || $params['to'] !== null) {
             $isDirNewer = $dir === 'newer';
             $after = $isDirNewer ? '>=' : '<=';
             $before = $isDirNewer ? '<=' : '>=';
             $where = [];
             foreach ($namespaces as $ns) {
                 $w = [];
                 if ($params['from'] !== null) {
                     $w[] = 'ar_title' . $after . $db->addQuotes($this->titlePartToKey($params['from'], $ns));
                 }
                 if ($params['to'] !== null) {
                     $w[] = 'ar_title' . $before . $db->addQuotes($this->titlePartToKey($params['to'], $ns));
                 }
                 $w = $db->makeList($w, LIST_AND);
                 $where[$w][] = $ns;
             }
             if (count($where) == 1) {
                 $where = key($where);
                 $this->addWhere($where);
             } else {
                 $where2 = [];
                 foreach ($where as $w => $ns) {
                     $where2[] = $db->makeList([$w, 'ar_namespace' => $ns], LIST_AND);
                 }
                 $this->addWhere($db->makeList($where2, LIST_OR));
             }
         }
         if (isset($params['prefix'])) {
             $where = [];
             foreach ($namespaces as $ns) {
                 $w = 'ar_title' . $db->buildLike($this->titlePartToKey($params['prefix'], $ns), $db->anyString());
                 $where[$w][] = $ns;
             }
             if (count($where) == 1) {
                 $where = key($where);
                 $this->addWhere($where);
             } else {
                 $where2 = [];
                 foreach ($where as $w => $ns) {
                     $where2[] = $db->makeList([$w, 'ar_namespace' => $ns], LIST_AND);
                 }
                 $this->addWhere($db->makeList($where2, LIST_OR));
             }
         }
     } else {
         if ($this->getConfig()->get('MiserMode')) {
             $miser_ns = $params['namespace'];
         } else {
             $this->addWhereFld('ar_namespace', $params['namespace']);
         }
         $this->addTimestampWhereRange('ar_timestamp', $dir, $params['start'], $params['end']);
     }
     if (!is_null($params['user'])) {
         $this->addWhereFld('ar_user_text', $params['user']);
     } elseif (!is_null($params['excludeuser'])) {
         $this->addWhere('ar_user_text != ' . $db->addQuotes($params['excludeuser']));
     }
     if (!is_null($params['user']) || !is_null($params['excludeuser'])) {
         // Paranoia: avoid brute force searches (bug 17342)
         // (shouldn't be able to get here without 'deletedhistory', but
         // check it again just in case)
         if (!$user->isAllowed('deletedhistory')) {
             $bitmask = Revision::DELETED_USER;
         } elseif (!$user->isAllowedAny('suppressrevision', 'viewsuppressed')) {
             $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
         } else {
             $bitmask = 0;
         }
         if ($bitmask) {
             $this->addWhere($db->bitAnd('ar_deleted', $bitmask) . " != {$bitmask}");
         }
     }
     if (!is_null($params['continue'])) {
         $cont = explode('|', $params['continue']);
         $op = $dir == 'newer' ? '>' : '<';
         if ($optimizeGenerateTitles) {
             $this->dieContinueUsageIf(count($cont) != 2);
             $ns = intval($cont[0]);
             $this->dieContinueUsageIf(strval($ns) !== $cont[0]);
             $title = $db->addQuotes($cont[1]);
             $this->addWhere("ar_namespace {$op} {$ns} OR " . "(ar_namespace = {$ns} AND ar_title {$op}= {$title})");
         } elseif ($mode == 'all') {
             $this->dieContinueUsageIf(count($cont) != 4);
             $ns = intval($cont[0]);
             $this->dieContinueUsageIf(strval($ns) !== $cont[0]);
             $title = $db->addQuotes($cont[1]);
             $ts = $db->addQuotes($db->timestamp($cont[2]));
             $ar_id = (int) $cont[3];
             $this->dieContinueUsageIf(strval($ar_id) !== $cont[3]);
             $this->addWhere("ar_namespace {$op} {$ns} OR " . "(ar_namespace = {$ns} AND " . "(ar_title {$op} {$title} OR " . "(ar_title = {$title} AND " . "(ar_timestamp {$op} {$ts} OR " . "(ar_timestamp = {$ts} AND " . "ar_id {$op}= {$ar_id})))))");
         } else {
             $this->dieContinueUsageIf(count($cont) != 2);
             $ts = $db->addQuotes($db->timestamp($cont[0]));
             $ar_id = (int) $cont[1];
             $this->dieContinueUsageIf(strval($ar_id) !== $cont[1]);
             $this->addWhere("ar_timestamp {$op} {$ts} OR " . "(ar_timestamp = {$ts} AND " . "ar_id {$op}= {$ar_id})");
         }
     }
     $this->addOption('LIMIT', $this->limit + 1);
     $sort = $dir == 'newer' ? '' : ' DESC';
     $orderby = [];
     if ($optimizeGenerateTitles) {
         // Targeting index name_title_timestamp
         if ($params['namespace'] === null || count(array_unique($params['namespace'])) > 1) {
             $orderby[] = "ar_namespace {$sort}";
         }
         $orderby[] = "ar_title {$sort}";
     } elseif ($mode == 'all') {
         // Targeting index name_title_timestamp
         if ($params['namespace'] === null || count(array_unique($params['namespace'])) > 1) {
             $orderby[] = "ar_namespace {$sort}";
         }
         $orderby[] = "ar_title {$sort}";
         $orderby[] = "ar_timestamp {$sort}";
         $orderby[] = "ar_id {$sort}";
     } else {
         // Targeting index usertext_timestamp
         // 'user' is always constant.
         $orderby[] = "ar_timestamp {$sort}";
         $orderby[] = "ar_id {$sort}";
     }
     $this->addOption('ORDER BY', $orderby);
     $res = $this->select(__METHOD__);
     $pageMap = [];
     // Maps ns&title to array index
     $count = 0;
     $nextIndex = 0;
     $generated = [];
     foreach ($res as $row) {
         if (++$count > $this->limit) {
             // We've had enough
             if ($optimizeGenerateTitles) {
                 $this->setContinueEnumParameter('continue', "{$row->ar_namespace}|{$row->ar_title}");
             } elseif ($mode == 'all') {
                 $this->setContinueEnumParameter('continue', "{$row->ar_namespace}|{$row->ar_title}|{$row->ar_timestamp}|{$row->ar_id}");
             } else {
                 $this->setContinueEnumParameter('continue', "{$row->ar_timestamp}|{$row->ar_id}");
             }
             break;
         }
         // Miser mode namespace check
         if ($miser_ns !== null && !in_array($row->ar_namespace, $miser_ns)) {
             continue;
         }
         if ($resultPageSet !== null) {
             if ($params['generatetitles']) {
                 $key = "{$row->ar_namespace}:{$row->ar_title}";
                 if (!isset($generated[$key])) {
                     $generated[$key] = Title::makeTitle($row->ar_namespace, $row->ar_title);
                 }
             } else {
                 $generated[] = $row->ar_rev_id;
             }
         } else {
             $revision = Revision::newFromArchiveRow($row);
             $rev = $this->extractRevisionInfo($revision, $row);
             if (!isset($pageMap[$row->ar_namespace][$row->ar_title])) {
                 $index = $nextIndex++;
                 $pageMap[$row->ar_namespace][$row->ar_title] = $index;
                 $title = $revision->getTitle();
                 $a = ['pageid' => $title->getArticleID(), 'revisions' => [$rev]];
                 ApiResult::setIndexedTagName($a['revisions'], 'rev');
                 ApiQueryBase::addTitleInfo($a, $title);
                 $fit = $result->addValue(['query', $this->getModuleName()], $index, $a);
             } else {
                 $index = $pageMap[$row->ar_namespace][$row->ar_title];
                 $fit = $result->addValue(['query', $this->getModuleName(), $index, 'revisions'], null, $rev);
             }
             if (!$fit) {
                 if ($mode == 'all') {
                     $this->setContinueEnumParameter('continue', "{$row->ar_namespace}|{$row->ar_title}|{$row->ar_timestamp}|{$row->ar_id}");
                 } else {
                     $this->setContinueEnumParameter('continue', "{$row->ar_timestamp}|{$row->ar_id}");
                 }
                 break;
             }
         }
     }
     if ($resultPageSet !== null) {
         if ($params['generatetitles']) {
             $resultPageSet->populateFromTitles($generated);
         } else {
             $resultPageSet->populateFromRevisionIDs($generated);
         }
     } else {
         $result->addIndexedTagName(['query', $this->getModuleName()], 'page');
     }
 }
示例#5
0
 /**
  * Generates the parameter descriptions for this module, to be displayed in the
  * module's help.
  * @deprecated since 1.25
  * @return string|bool
  */
 public function makeHelpMsgParameters()
 {
     wfDeprecated(__METHOD__, '1.25');
     $params = $this->getFinalParams(ApiBase::GET_VALUES_FOR_HELP);
     if ($params) {
         $paramsDescription = $this->getFinalParamDescription();
         $msg = '';
         $paramPrefix = "\n" . str_repeat(' ', 24);
         $descWordwrap = "\n" . str_repeat(' ', 28);
         foreach ($params as $paramName => $paramSettings) {
             $desc = isset($paramsDescription[$paramName]) ? $paramsDescription[$paramName] : '';
             if (is_array($desc)) {
                 $desc = implode($paramPrefix, $desc);
             }
             // handle shorthand
             if (!is_array($paramSettings)) {
                 $paramSettings = array(self::PARAM_DFLT => $paramSettings);
             }
             // handle missing type
             if (!isset($paramSettings[ApiBase::PARAM_TYPE])) {
                 $dflt = isset($paramSettings[ApiBase::PARAM_DFLT]) ? $paramSettings[ApiBase::PARAM_DFLT] : null;
                 if (is_bool($dflt)) {
                     $paramSettings[ApiBase::PARAM_TYPE] = 'boolean';
                 } elseif (is_string($dflt) || is_null($dflt)) {
                     $paramSettings[ApiBase::PARAM_TYPE] = 'string';
                 } elseif (is_int($dflt)) {
                     $paramSettings[ApiBase::PARAM_TYPE] = 'integer';
                 }
             }
             if (isset($paramSettings[self::PARAM_DEPRECATED]) && $paramSettings[self::PARAM_DEPRECATED]) {
                 $desc = "DEPRECATED! {$desc}";
             }
             if (isset($paramSettings[self::PARAM_REQUIRED]) && $paramSettings[self::PARAM_REQUIRED]) {
                 $desc .= $paramPrefix . "This parameter is required";
             }
             $type = isset($paramSettings[self::PARAM_TYPE]) ? $paramSettings[self::PARAM_TYPE] : null;
             if (isset($type)) {
                 $hintPipeSeparated = true;
                 $multi = isset($paramSettings[self::PARAM_ISMULTI]) ? $paramSettings[self::PARAM_ISMULTI] : false;
                 if ($multi) {
                     $prompt = 'Values (separate with \'|\'): ';
                 } else {
                     $prompt = 'One value: ';
                 }
                 if ($type === 'submodule') {
                     if (isset($paramSettings[self::PARAM_SUBMODULE_MAP])) {
                         $type = array_keys($paramSettings[self::PARAM_SUBMODULE_MAP]);
                     } else {
                         $type = $this->getModuleManager()->getNames($paramName);
                     }
                     sort($type);
                 }
                 if (is_array($type)) {
                     $choices = array();
                     $nothingPrompt = '';
                     foreach ($type as $t) {
                         if ($t === '') {
                             $nothingPrompt = 'Can be empty, or ';
                         } else {
                             $choices[] = $t;
                         }
                     }
                     $desc .= $paramPrefix . $nothingPrompt . $prompt;
                     $choicesstring = implode(', ', $choices);
                     $desc .= wordwrap($choicesstring, 100, $descWordwrap);
                     $hintPipeSeparated = false;
                 } else {
                     switch ($type) {
                         case 'namespace':
                             // Special handling because namespaces are
                             // type-limited, yet they are not given
                             $desc .= $paramPrefix . $prompt;
                             $desc .= wordwrap(implode(', ', MWNamespace::getValidNamespaces()), 100, $descWordwrap);
                             $hintPipeSeparated = false;
                             break;
                         case 'limit':
                             $desc .= $paramPrefix . "No more than {$paramSettings[self::PARAM_MAX]}";
                             if (isset($paramSettings[self::PARAM_MAX2])) {
                                 $desc .= " ({$paramSettings[self::PARAM_MAX2]} for bots)";
                             }
                             $desc .= ' allowed';
                             break;
                         case 'integer':
                             $s = $multi ? 's' : '';
                             $hasMin = isset($paramSettings[self::PARAM_MIN]);
                             $hasMax = isset($paramSettings[self::PARAM_MAX]);
                             if ($hasMin || $hasMax) {
                                 if (!$hasMax) {
                                     $intRangeStr = "The value{$s} must be no less than " . "{$paramSettings[self::PARAM_MIN]}";
                                 } elseif (!$hasMin) {
                                     $intRangeStr = "The value{$s} must be no more than " . "{$paramSettings[self::PARAM_MAX]}";
                                 } else {
                                     $intRangeStr = "The value{$s} must be between " . "{$paramSettings[self::PARAM_MIN]} and {$paramSettings[self::PARAM_MAX]}";
                                 }
                                 $desc .= $paramPrefix . $intRangeStr;
                             }
                             break;
                         case 'upload':
                             $desc .= $paramPrefix . "Must be posted as a file upload using multipart/form-data";
                             break;
                     }
                 }
                 if ($multi) {
                     if ($hintPipeSeparated) {
                         $desc .= $paramPrefix . "Separate values with '|'";
                     }
                     $isArray = is_array($type);
                     if (!$isArray || $isArray && count($type) > self::LIMIT_SML1) {
                         $desc .= $paramPrefix . "Maximum number of values " . self::LIMIT_SML1 . " (" . self::LIMIT_SML2 . " for bots)";
                     }
                 }
             }
             $default = isset($paramSettings[self::PARAM_DFLT]) ? $paramSettings[self::PARAM_DFLT] : null;
             if (!is_null($default) && $default !== false) {
                 $desc .= $paramPrefix . "Default: {$default}";
             }
             $msg .= sprintf("  %-19s - %s\n", $this->encodeParamName($paramName), $desc);
         }
         return $msg;
     }
     return false;
 }
示例#6
0
 /**
  * List all namespace indices which are considered talks, aka not a subject
  * or special namespace. See also MWNamespace::isTalk
  *
  * @return array Array of namespace indices
  */
 public static function getTalkNamespaces()
 {
     return array_filter(MWNamespace::getValidNamespaces(), 'MWNamespace::isTalk');
 }
示例#7
0
 /**
  * Returns the ID of a namespace that defaults to Wikitext.
  *
  * @throws MWException If there is none.
  * @return int The ID of the wikitext Namespace
  * @since 1.21
  */
 protected function getDefaultWikitextNS()
 {
     global $wgNamespaceContentModels;
     static $wikitextNS = null;
     // this is not going to change
     if ($wikitextNS !== null) {
         return $wikitextNS;
     }
     // quickly short out on most common case:
     if (!isset($wgNamespaceContentModels[NS_MAIN])) {
         return NS_MAIN;
     }
     // NOTE: prefer content namespaces
     $namespaces = array_unique(array_merge(MWNamespace::getContentNamespaces(), array(NS_MAIN, NS_HELP, NS_PROJECT), MWNamespace::getValidNamespaces()));
     $namespaces = array_diff($namespaces, array(NS_FILE, NS_CATEGORY, NS_MEDIAWIKI, NS_USER));
     $talk = array_filter($namespaces, function ($ns) {
         return MWNamespace::isTalk($ns);
     });
     // prefer non-talk pages
     $namespaces = array_diff($namespaces, $talk);
     $namespaces = array_merge($namespaces, $talk);
     // check default content model of each namespace
     foreach ($namespaces as $ns) {
         if (!isset($wgNamespaceContentModels[$ns]) || $wgNamespaceContentModels[$ns] === CONTENT_MODEL_WIKITEXT) {
             $wikitextNS = $ns;
             return $wikitextNS;
         }
     }
     // give up
     // @todo Inside a test, we could skip the test as incomplete.
     //        But frequently, this is used in fixture setup.
     throw new MWException("No namespace defaults to wikitext!");
 }
示例#8
0
 /**
  * @param User $user
  * @param IContextSource $context
  * @param array $defaultPreferences
  */
 static function searchPreferences($user, IContextSource $context, &$defaultPreferences)
 {
     foreach (MWNamespace::getValidNamespaces() as $n) {
         $defaultPreferences['searchNs' . $n] = array('type' => 'api');
     }
 }
示例#9
0
 /**
  * Save namespace preferences when we're supposed to
  *
  * @return bool Whether we wrote something
  */
 protected function saveNamespaces()
 {
     $user = $this->getUser();
     $request = $this->getRequest();
     if ($user->isLoggedIn() && $user->matchEditToken($request->getVal('nsRemember'), 'searchnamespace', $request)) {
         // Reset namespace preferences: namespaces are not searched
         // when they're not mentioned in the URL parameters.
         foreach (MWNamespace::getValidNamespaces() as $n) {
             $user->setOption('searchNs' . $n, false);
         }
         // The request parameters include all the namespaces to be searched.
         // Even if they're the same as an existing profile, they're not eaten.
         foreach ($this->namespaces as $n) {
             $user->setOption('searchNs' . $n, true);
         }
         $user->saveSettings();
         return true;
     }
     return false;
 }
示例#10
0
 /**
  * Using the settings determine the value for the given parameter
  *
  * @param $paramName String: parameter name
  * @param $paramSettings array|mixed default value or an array of settings
  *  using PARAM_* constants.
  * @param $parseLimit Boolean: parse limit?
  * @return mixed Parameter value
  */
 protected function getParameterFromSettings($paramName, $paramSettings, $parseLimit)
 {
     // Some classes may decide to change parameter names
     $encParamName = $this->encodeParamName($paramName);
     if (!is_array($paramSettings)) {
         $default = $paramSettings;
         $multi = false;
         $type = gettype($paramSettings);
         $dupes = false;
         $deprecated = false;
         $required = false;
     } else {
         $default = isset($paramSettings[self::PARAM_DFLT]) ? $paramSettings[self::PARAM_DFLT] : null;
         $multi = isset($paramSettings[self::PARAM_ISMULTI]) ? $paramSettings[self::PARAM_ISMULTI] : false;
         $type = isset($paramSettings[self::PARAM_TYPE]) ? $paramSettings[self::PARAM_TYPE] : null;
         $dupes = isset($paramSettings[self::PARAM_ALLOW_DUPLICATES]) ? $paramSettings[self::PARAM_ALLOW_DUPLICATES] : false;
         $deprecated = isset($paramSettings[self::PARAM_DEPRECATED]) ? $paramSettings[self::PARAM_DEPRECATED] : false;
         $required = isset($paramSettings[self::PARAM_REQUIRED]) ? $paramSettings[self::PARAM_REQUIRED] : false;
         // When type is not given, and no choices, the type is the same as $default
         if (!isset($type)) {
             if (isset($default)) {
                 $type = gettype($default);
             } else {
                 $type = 'NULL';
                 // allow everything
             }
         }
     }
     if ($type == 'boolean') {
         if (isset($default) && $default !== false) {
             // Having a default value of anything other than 'false' is not allowed
             ApiBase::dieDebug(__METHOD__, "Boolean param {$encParamName}'s default is set to '{$default}'. Boolean parameters must default to false.");
         }
         $value = $this->getRequest()->getCheck($encParamName);
     } else {
         $value = $this->getRequest()->getVal($encParamName, $default);
         if (isset($value) && $type == 'namespace') {
             $type = MWNamespace::getValidNamespaces();
         }
     }
     if (isset($value) && ($multi || is_array($type))) {
         $value = $this->parseMultiValue($encParamName, $value, $multi, is_array($type) ? $type : null);
     }
     // More validation only when choices were not given
     // choices were validated in parseMultiValue()
     if (isset($value)) {
         if (!is_array($type)) {
             switch ($type) {
                 case 'NULL':
                     // nothing to do
                     break;
                 case 'string':
                     if ($required && $value === '') {
                         $this->dieUsageMsg(array('missingparam', $paramName));
                     }
                     break;
                 case 'integer':
                     // Force everything using intval() and optionally validate limits
                     $min = isset($paramSettings[self::PARAM_MIN]) ? $paramSettings[self::PARAM_MIN] : null;
                     $max = isset($paramSettings[self::PARAM_MAX]) ? $paramSettings[self::PARAM_MAX] : null;
                     $enforceLimits = isset($paramSettings[self::PARAM_RANGE_ENFORCE]) ? $paramSettings[self::PARAM_RANGE_ENFORCE] : false;
                     if (is_array($value)) {
                         $value = array_map('intval', $value);
                         if (!is_null($min) || !is_null($max)) {
                             foreach ($value as &$v) {
                                 $this->validateLimit($paramName, $v, $min, $max, null, $enforceLimits);
                             }
                         }
                     } else {
                         $value = intval($value);
                         if (!is_null($min) || !is_null($max)) {
                             $this->validateLimit($paramName, $value, $min, $max, null, $enforceLimits);
                         }
                     }
                     break;
                 case 'limit':
                     if (!$parseLimit) {
                         // Don't do any validation whatsoever
                         break;
                     }
                     if (!isset($paramSettings[self::PARAM_MAX]) || !isset($paramSettings[self::PARAM_MAX2])) {
                         ApiBase::dieDebug(__METHOD__, "MAX1 or MAX2 are not defined for the limit {$encParamName}");
                     }
                     if ($multi) {
                         ApiBase::dieDebug(__METHOD__, "Multi-values not supported for {$encParamName}");
                     }
                     $min = isset($paramSettings[self::PARAM_MIN]) ? $paramSettings[self::PARAM_MIN] : 0;
                     if ($value == 'max') {
                         $value = $this->getMain()->canApiHighLimits() ? $paramSettings[self::PARAM_MAX2] : $paramSettings[self::PARAM_MAX];
                         $this->getResult()->setParsedLimit($this->getModuleName(), $value);
                     } else {
                         $value = intval($value);
                         $this->validateLimit($paramName, $value, $min, $paramSettings[self::PARAM_MAX], $paramSettings[self::PARAM_MAX2]);
                     }
                     break;
                 case 'boolean':
                     if ($multi) {
                         ApiBase::dieDebug(__METHOD__, "Multi-values not supported for {$encParamName}");
                     }
                     break;
                 case 'timestamp':
                     if (is_array($value)) {
                         foreach ($value as $key => $val) {
                             $value[$key] = $this->validateTimestamp($val, $encParamName);
                         }
                     } else {
                         $value = $this->validateTimestamp($value, $encParamName);
                     }
                     break;
                 case 'user':
                     if (!is_array($value)) {
                         $value = array($value);
                     }
                     foreach ($value as $key => $val) {
                         $title = Title::makeTitleSafe(NS_USER, $val);
                         if (is_null($title)) {
                             $this->dieUsage("Invalid value for user parameter {$encParamName}", "baduser_{$encParamName}");
                         }
                         $value[$key] = $title->getText();
                     }
                     if (!$multi) {
                         $value = $value[0];
                     }
                     break;
                 default:
                     ApiBase::dieDebug(__METHOD__, "Param {$encParamName}'s type is unknown - {$type}");
             }
         }
         // Throw out duplicates if requested
         if (is_array($value) && !$dupes) {
             $value = array_unique($value);
         }
         // Set a warning if a deprecated parameter has been passed
         if ($deprecated && $value !== false) {
             $this->setWarning("The {$encParamName} parameter has been deprecated.");
         }
     } elseif ($required) {
         $this->dieUsageMsg(array('missingparam', $paramName));
     }
     return $value;
 }
 private function outputNamespaceProtectionInfo()
 {
     global $wgParser, $wgContLang;
     $out = $this->getOutput();
     $namespaceProtection = $this->getConfig()->get('NamespaceProtection');
     if (count($namespaceProtection) == 0) {
         return;
     }
     $header = $this->msg('listgrouprights-namespaceprotection-header')->parse();
     $out->addHTML(Html::rawElement('h2', array(), Html::element('span', array('class' => 'mw-headline', 'id' => $wgParser->guessSectionNameFromWikiText($header)), $header)) . Xml::openElement('table', array('class' => 'wikitable')) . Html::element('th', array(), $this->msg('listgrouprights-namespaceprotection-namespace')->text()) . Html::element('th', array(), $this->msg('listgrouprights-namespaceprotection-restrictedto')->text()));
     ksort($namespaceProtection);
     foreach ($namespaceProtection as $namespace => $rights) {
         if (!in_array($namespace, MWNamespace::getValidNamespaces())) {
             continue;
         }
         if ($namespace == NS_MAIN) {
             $namespaceText = $this->msg('blanknamespace')->text();
         } else {
             $namespaceText = $wgContLang->convertNamespace($namespace);
         }
         $out->addHTML(Xml::openElement('tr') . Html::rawElement('td', array(), Linker::link(SpecialPage::getTitleFor('Allpages'), $namespaceText, array(), array('namespace' => $namespace))) . Xml::openElement('td') . Xml::openElement('ul'));
         if (!is_array($rights)) {
             $rights = array($rights);
         }
         foreach ($rights as $right) {
             $out->addHTML(Html::rawElement('li', array(), $this->msg('listgrouprights-right-display', User::getRightDescription($right), Html::element('span', array('class' => 'mw-listgrouprights-right-name'), $right))->parse()));
         }
         $out->addHTML(Xml::closeElement('ul') . Xml::closeElement('td') . Xml::closeElement('tr'));
     }
     $out->addHTML(Xml::closeElement('table'));
 }
 /**
  * Read the global and extract title objects from the corresponding messages
  * @return array Array( 'msg' => Title, 'cats' => Title[] )
  */
 private function prepareTrackingCategoriesData()
 {
     $categories = array_merge(self::$coreTrackingCategories, ExtensionRegistry::getInstance()->getAttribute('TrackingCategories'), $this->getConfig()->get('TrackingCategories'));
     $trackingCategories = [];
     foreach ($categories as $catMsg) {
         /*
          * Check if the tracking category varies by namespace
          * Otherwise only pages in the current namespace will be displayed
          * If it does vary, show pages considering all namespaces
          */
         $msgObj = $this->msg($catMsg)->inContentLanguage();
         $allCats = [];
         $catMsgTitle = Title::makeTitleSafe(NS_MEDIAWIKI, $catMsg);
         if (!$catMsgTitle) {
             continue;
         }
         // Match things like {{NAMESPACE}} and {{NAMESPACENUMBER}}.
         // False positives are ok, this is just an efficiency shortcut
         if (strpos($msgObj->plain(), '{{') !== false) {
             $ns = MWNamespace::getValidNamespaces();
             foreach ($ns as $namesp) {
                 $tempTitle = Title::makeTitleSafe($namesp, $catMsg);
                 if (!$tempTitle) {
                     continue;
                 }
                 $catName = $msgObj->title($tempTitle)->text();
                 # Allow tracking categories to be disabled by setting them to "-"
                 if ($catName !== '-') {
                     $catTitle = Title::makeTitleSafe(NS_CATEGORY, $catName);
                     if ($catTitle) {
                         $allCats[] = $catTitle;
                     }
                 }
             }
         } else {
             $catName = $msgObj->text();
             # Allow tracking categories to be disabled by setting them to "-"
             if ($catName !== '-') {
                 $catTitle = Title::makeTitleSafe(NS_CATEGORY, $catName);
                 if ($catTitle) {
                     $allCats[] = $catTitle;
                 }
             }
         }
         $trackingCategories[$catMsg] = ['cats' => $allCats, 'msg' => $catMsgTitle];
     }
     return $trackingCategories;
 }
示例#13
0
 /**
  * Using the settings determine the value for the given parameter
  *
  * @param string $paramName parameter name
  * @param array|mixed $paramSettings default value or an array of settings
  *  using PARAM_* constants.
  * @param $parseLimit Boolean: parse limit?
  * @return mixed Parameter value
  */
 protected function getParameterFromSettings($paramName, $paramSettings, $parseLimit)
 {
     // Some classes may decide to change parameter names
     $encParamName = $this->encodeParamName($paramName);
     if (!is_array($paramSettings)) {
         $default = $paramSettings;
         $multi = false;
         $type = gettype($paramSettings);
         $dupes = false;
         $deprecated = false;
         $required = false;
     } else {
         $default = isset($paramSettings[self::PARAM_DFLT]) ? $paramSettings[self::PARAM_DFLT] : null;
         $multi = isset($paramSettings[self::PARAM_ISMULTI]) ? $paramSettings[self::PARAM_ISMULTI] : false;
         $type = isset($paramSettings[self::PARAM_TYPE]) ? $paramSettings[self::PARAM_TYPE] : null;
         $dupes = isset($paramSettings[self::PARAM_ALLOW_DUPLICATES]) ? $paramSettings[self::PARAM_ALLOW_DUPLICATES] : false;
         $deprecated = isset($paramSettings[self::PARAM_DEPRECATED]) ? $paramSettings[self::PARAM_DEPRECATED] : false;
         $required = isset($paramSettings[self::PARAM_REQUIRED]) ? $paramSettings[self::PARAM_REQUIRED] : false;
         // When type is not given, and no choices, the type is the same as $default
         if (!isset($type)) {
             if (isset($default)) {
                 $type = gettype($default);
             } else {
                 $type = 'NULL';
                 // allow everything
             }
         }
     }
     if ($type == 'boolean') {
         if (isset($default) && $default !== false) {
             // Having a default value of anything other than 'false' is not allowed
             ApiBase::dieDebug(__METHOD__, "Boolean param {$encParamName}'s default is set to '{$default}'. " . "Boolean parameters must default to false.");
         }
         $value = $this->getMain()->getCheck($encParamName);
     } elseif ($type == 'upload') {
         if (isset($default)) {
             // Having a default value is not allowed
             ApiBase::dieDebug(__METHOD__, "File upload param {$encParamName}'s default is set to " . "'{$default}'. File upload parameters may not have a default.");
         }
         if ($multi) {
             ApiBase::dieDebug(__METHOD__, "Multi-values not supported for {$encParamName}");
         }
         $value = $this->getMain()->getUpload($encParamName);
         if (!$value->exists()) {
             // This will get the value without trying to normalize it
             // (because trying to normalize a large binary file
             // accidentally uploaded as a field fails spectacularly)
             $value = $this->getMain()->getRequest()->unsetVal($encParamName);
             if ($value !== null) {
                 $this->dieUsage("File upload param {$encParamName} is not a file upload; " . "be sure to use multipart/form-data for your POST and include " . "a filename in the Content-Disposition header.", "badupload_{$encParamName}");
             }
         }
     } else {
         $value = $this->getMain()->getVal($encParamName, $default);
         if (isset($value) && $type == 'namespace') {
             $type = MWNamespace::getValidNamespaces();
         }
     }
     if (isset($value) && ($multi || is_array($type))) {
         $value = $this->parseMultiValue($encParamName, $value, $multi, is_array($type) ? $type : null);
     }
     // More validation only when choices were not given
     // choices were validated in parseMultiValue()
     if (isset($value)) {
         if (!is_array($type)) {
             switch ($type) {
                 case 'NULL':
                     // nothing to do
                     break;
                 case 'string':
                     if ($required && $value === '') {
                         $this->dieUsageMsg(array('missingparam', $paramName));
                     }
                     break;
                 case 'integer':
                     // Force everything using intval() and optionally validate limits
                     $min = isset($paramSettings[self::PARAM_MIN]) ? $paramSettings[self::PARAM_MIN] : null;
                     $max = isset($paramSettings[self::PARAM_MAX]) ? $paramSettings[self::PARAM_MAX] : null;
                     $enforceLimits = isset($paramSettings[self::PARAM_RANGE_ENFORCE]) ? $paramSettings[self::PARAM_RANGE_ENFORCE] : false;
                     if (is_array($value)) {
                         $value = array_map('intval', $value);
                         if (!is_null($min) || !is_null($max)) {
                             foreach ($value as &$v) {
                                 $this->validateLimit($paramName, $v, $min, $max, null, $enforceLimits);
                             }
                         }
                     } else {
                         $value = intval($value);
                         if (!is_null($min) || !is_null($max)) {
                             $this->validateLimit($paramName, $value, $min, $max, null, $enforceLimits);
                         }
                     }
                     break;
                 case 'limit':
                     if (!$parseLimit) {
                         // Don't do any validation whatsoever
                         break;
                     }
                     if (!isset($paramSettings[self::PARAM_MAX]) || !isset($paramSettings[self::PARAM_MAX2])) {
                         ApiBase::dieDebug(__METHOD__, "MAX1 or MAX2 are not defined for the limit {$encParamName}");
                     }
                     if ($multi) {
                         ApiBase::dieDebug(__METHOD__, "Multi-values not supported for {$encParamName}");
                     }
                     $min = isset($paramSettings[self::PARAM_MIN]) ? $paramSettings[self::PARAM_MIN] : 0;
                     if ($value == 'max') {
                         $value = $this->getMain()->canApiHighLimits() ? $paramSettings[self::PARAM_MAX2] : $paramSettings[self::PARAM_MAX];
                         $this->getResult()->setParsedLimit($this->getModuleName(), $value);
                     } else {
                         $value = intval($value);
                         $this->validateLimit($paramName, $value, $min, $paramSettings[self::PARAM_MAX], $paramSettings[self::PARAM_MAX2]);
                     }
                     break;
                 case 'boolean':
                     if ($multi) {
                         ApiBase::dieDebug(__METHOD__, "Multi-values not supported for {$encParamName}");
                     }
                     break;
                 case 'timestamp':
                     if (is_array($value)) {
                         foreach ($value as $key => $val) {
                             $value[$key] = $this->validateTimestamp($val, $encParamName);
                         }
                     } else {
                         $value = $this->validateTimestamp($value, $encParamName);
                     }
                     break;
                 case 'user':
                     if (is_array($value)) {
                         foreach ($value as $key => $val) {
                             $value[$key] = $this->validateUser($val, $encParamName);
                         }
                     } else {
                         $value = $this->validateUser($value, $encParamName);
                     }
                     break;
                 case 'upload':
                     // nothing to do
                     break;
                 default:
                     ApiBase::dieDebug(__METHOD__, "Param {$encParamName}'s type is unknown - {$type}");
             }
         }
         // Throw out duplicates if requested
         if (!$dupes && is_array($value)) {
             $value = array_unique($value);
         }
         // Set a warning if a deprecated parameter has been passed
         if ($deprecated && $value !== false) {
             $this->setWarning("The {$encParamName} parameter has been deprecated.");
         }
     } elseif ($required) {
         $this->dieUsageMsg(array('missingparam', $paramName));
     }
     return $value;
 }
示例#14
0
 /**
  * Using the settings determine the value for the given parameter
  *
  * @param string $paramName Parameter name
  * @param array|mixed $paramSettings Default value or an array of settings
  *  using PARAM_* constants.
  * @param bool $parseLimit Parse limit?
  * @return mixed Parameter value
  */
 protected function getParameterFromSettings($paramName, $paramSettings, $parseLimit)
 {
     // Some classes may decide to change parameter names
     $encParamName = $this->encodeParamName($paramName);
     if (!is_array($paramSettings)) {
         $default = $paramSettings;
         $multi = false;
         $type = gettype($paramSettings);
         $dupes = false;
         $deprecated = false;
         $required = false;
     } else {
         $default = isset($paramSettings[self::PARAM_DFLT]) ? $paramSettings[self::PARAM_DFLT] : null;
         $multi = isset($paramSettings[self::PARAM_ISMULTI]) ? $paramSettings[self::PARAM_ISMULTI] : false;
         $type = isset($paramSettings[self::PARAM_TYPE]) ? $paramSettings[self::PARAM_TYPE] : null;
         $dupes = isset($paramSettings[self::PARAM_ALLOW_DUPLICATES]) ? $paramSettings[self::PARAM_ALLOW_DUPLICATES] : false;
         $deprecated = isset($paramSettings[self::PARAM_DEPRECATED]) ? $paramSettings[self::PARAM_DEPRECATED] : false;
         $required = isset($paramSettings[self::PARAM_REQUIRED]) ? $paramSettings[self::PARAM_REQUIRED] : false;
         // When type is not given, and no choices, the type is the same as $default
         if (!isset($type)) {
             if (isset($default)) {
                 $type = gettype($default);
             } else {
                 $type = 'NULL';
                 // allow everything
             }
         }
     }
     if ($type == 'boolean') {
         if (isset($default) && $default !== false) {
             // Having a default value of anything other than 'false' is not allowed
             ApiBase::dieDebug(__METHOD__, "Boolean param {$encParamName}'s default is set to '{$default}'. " . 'Boolean parameters must default to false.');
         }
         $value = $this->getMain()->getCheck($encParamName);
     } elseif ($type == 'upload') {
         if (isset($default)) {
             // Having a default value is not allowed
             ApiBase::dieDebug(__METHOD__, "File upload param {$encParamName}'s default is set to " . "'{$default}'. File upload parameters may not have a default.");
         }
         if ($multi) {
             ApiBase::dieDebug(__METHOD__, "Multi-values not supported for {$encParamName}");
         }
         $value = $this->getMain()->getUpload($encParamName);
         if (!$value->exists()) {
             // This will get the value without trying to normalize it
             // (because trying to normalize a large binary file
             // accidentally uploaded as a field fails spectacularly)
             $value = $this->getMain()->getRequest()->unsetVal($encParamName);
             if ($value !== null) {
                 $this->dieUsage("File upload param {$encParamName} is not a file upload; " . 'be sure to use multipart/form-data for your POST and include ' . 'a filename in the Content-Disposition header.', "badupload_{$encParamName}");
             }
         }
     } else {
         $value = $this->getMain()->getVal($encParamName, $default);
         if (isset($value) && $type == 'namespace') {
             $type = MWNamespace::getValidNamespaces();
         }
         if (isset($value) && $type == 'submodule') {
             if (isset($paramSettings[self::PARAM_SUBMODULE_MAP])) {
                 $type = array_keys($paramSettings[self::PARAM_SUBMODULE_MAP]);
             } else {
                 $type = $this->getModuleManager()->getNames($paramName);
             }
         }
         $request = $this->getMain()->getRequest();
         $rawValue = $request->getRawVal($encParamName);
         if ($rawValue === null) {
             $rawValue = $default;
         }
         // Preserve U+001F for self::parseMultiValue(), or error out if that won't be called
         if (isset($value) && substr($rawValue, 0, 1) === "") {
             if ($multi) {
                 // This loses the potential $wgContLang->checkTitleEncoding() transformation
                 // done by WebRequest for $_GET. Let's call that a feature.
                 $value = join("", $request->normalizeUnicode(explode("", $rawValue)));
             } else {
                 $this->dieUsage("U+001F multi-value separation may only be used for multi-valued parameters.", 'badvalue_notmultivalue');
             }
         }
         // Check for NFC normalization, and warn
         if ($rawValue !== $value) {
             $this->handleParamNormalization($paramName, $value, $rawValue);
         }
     }
     if (isset($value) && ($multi || is_array($type))) {
         $value = $this->parseMultiValue($encParamName, $value, $multi, is_array($type) ? $type : null);
     }
     // More validation only when choices were not given
     // choices were validated in parseMultiValue()
     if (isset($value)) {
         if (!is_array($type)) {
             switch ($type) {
                 case 'NULL':
                     // nothing to do
                     break;
                 case 'string':
                 case 'text':
                 case 'password':
                     if ($required && $value === '') {
                         $this->dieUsageMsg(['missingparam', $paramName]);
                     }
                     break;
                 case 'integer':
                     // Force everything using intval() and optionally validate limits
                     $min = isset($paramSettings[self::PARAM_MIN]) ? $paramSettings[self::PARAM_MIN] : null;
                     $max = isset($paramSettings[self::PARAM_MAX]) ? $paramSettings[self::PARAM_MAX] : null;
                     $enforceLimits = isset($paramSettings[self::PARAM_RANGE_ENFORCE]) ? $paramSettings[self::PARAM_RANGE_ENFORCE] : false;
                     if (is_array($value)) {
                         $value = array_map('intval', $value);
                         if (!is_null($min) || !is_null($max)) {
                             foreach ($value as &$v) {
                                 $this->validateLimit($paramName, $v, $min, $max, null, $enforceLimits);
                             }
                         }
                     } else {
                         $value = intval($value);
                         if (!is_null($min) || !is_null($max)) {
                             $this->validateLimit($paramName, $value, $min, $max, null, $enforceLimits);
                         }
                     }
                     break;
                 case 'limit':
                     if (!$parseLimit) {
                         // Don't do any validation whatsoever
                         break;
                     }
                     if (!isset($paramSettings[self::PARAM_MAX]) || !isset($paramSettings[self::PARAM_MAX2])) {
                         ApiBase::dieDebug(__METHOD__, "MAX1 or MAX2 are not defined for the limit {$encParamName}");
                     }
                     if ($multi) {
                         ApiBase::dieDebug(__METHOD__, "Multi-values not supported for {$encParamName}");
                     }
                     $min = isset($paramSettings[self::PARAM_MIN]) ? $paramSettings[self::PARAM_MIN] : 0;
                     if ($value == 'max') {
                         $value = $this->getMain()->canApiHighLimits() ? $paramSettings[self::PARAM_MAX2] : $paramSettings[self::PARAM_MAX];
                         $this->getResult()->addParsedLimit($this->getModuleName(), $value);
                     } else {
                         $value = intval($value);
                         $this->validateLimit($paramName, $value, $min, $paramSettings[self::PARAM_MAX], $paramSettings[self::PARAM_MAX2]);
                     }
                     break;
                 case 'boolean':
                     if ($multi) {
                         ApiBase::dieDebug(__METHOD__, "Multi-values not supported for {$encParamName}");
                     }
                     break;
                 case 'timestamp':
                     if (is_array($value)) {
                         foreach ($value as $key => $val) {
                             $value[$key] = $this->validateTimestamp($val, $encParamName);
                         }
                     } else {
                         $value = $this->validateTimestamp($value, $encParamName);
                     }
                     break;
                 case 'user':
                     if (is_array($value)) {
                         foreach ($value as $key => $val) {
                             $value[$key] = $this->validateUser($val, $encParamName);
                         }
                     } else {
                         $value = $this->validateUser($value, $encParamName);
                     }
                     break;
                 case 'upload':
                     // nothing to do
                     break;
                 case 'tags':
                     // If change tagging was requested, check that the tags are valid.
                     if (!is_array($value) && !$multi) {
                         $value = [$value];
                     }
                     $tagsStatus = ChangeTags::canAddTagsAccompanyingChange($value);
                     if (!$tagsStatus->isGood()) {
                         $this->dieStatus($tagsStatus);
                     }
                     break;
                 default:
                     ApiBase::dieDebug(__METHOD__, "Param {$encParamName}'s type is unknown - {$type}");
             }
         }
         // Throw out duplicates if requested
         if (!$dupes && is_array($value)) {
             $value = array_unique($value);
         }
         // Set a warning if a deprecated parameter has been passed
         if ($deprecated && $value !== false) {
             $this->setWarning("The {$encParamName} parameter has been deprecated.");
             $feature = $encParamName;
             $m = $this;
             while (!$m->isMain()) {
                 $p = $m->getParent();
                 $name = $m->getModuleName();
                 $param = $p->encodeParamName($p->getModuleManager()->getModuleGroup($name));
                 $feature = "{$param}={$name}&{$feature}";
                 $m = $p;
             }
             $this->logFeatureUsage($feature);
         }
     } elseif ($required) {
         $this->dieUsageMsg(['missingparam', $paramName]);
     }
     return $value;
 }
 function execute($par)
 {
     $this->setHeaders();
     $this->outputHeader();
     $this->getOutput()->allowClickjacking();
     $this->getOutput()->addHTML(Html::openElement('table', array('class' => 'mw-datatable', 'id' => 'mw-trackingcategories-table')) . "\n" . "<thead><tr>\n\t\t\t<th>" . $this->msg('trackingcategories-msg')->escaped() . "\n\t\t\t</th>\n\t\t\t<th>" . $this->msg('trackingcategories-name')->escaped() . "</th>\n\t\t\t<th>" . $this->msg('trackingcategories-desc')->escaped() . "\n\t\t\t</th>\n\t\t\t</tr></thead>");
     foreach ($this->getConfig()->get('TrackingCategories') as $catMsg) {
         /*
          * Check if the tracking category varies by namespace
          * Otherwise only pages in the current namespace will be displayed
          * If it does vary, show pages considering all namespaces
          */
         $msgObj = $this->msg($catMsg)->inContentLanguage();
         $allMsgs = array();
         $catDesc = $catMsg . '-desc';
         $catMsgTitle = Title::makeTitleSafe(NS_MEDIAWIKI, $catMsg);
         if (!$catMsgTitle) {
             continue;
         }
         $catMsgTitleText = Linker::link($catMsgTitle, htmlspecialchars($catMsg));
         // Match things like {{NAMESPACE}} and {{NAMESPACENUMBER}}.
         // False positives are ok, this is just an efficiency shortcut
         if (strpos($msgObj->plain(), '{{') !== false) {
             $ns = MWNamespace::getValidNamespaces();
             foreach ($ns as $namesp) {
                 $tempTitle = Title::makeTitleSafe($namesp, $catMsg);
                 if (!$tempTitle) {
                     continue;
                 }
                 $catName = $msgObj->title($tempTitle)->text();
                 # Allow tracking categories to be disabled by setting them to "-"
                 if ($catName !== '-') {
                     $catTitle = Title::makeTitleSafe(NS_CATEGORY, $catName);
                     if ($catTitle) {
                         $catTitleText = Linker::link($catTitle, htmlspecialchars($catName));
                         $allMsgs[] = $catTitleText;
                     }
                 }
             }
         } else {
             $catName = $msgObj->text();
             # Allow tracking categories to be disabled by setting them to "-"
             if ($catName !== '-') {
                 $catTitle = Title::makeTitleSafe(NS_CATEGORY, $catName);
                 if ($catTitle) {
                     $catTitleText = Linker::link($catTitle, htmlspecialchars($catName));
                     $allMsgs[] = $catTitleText;
                 }
             }
         }
         # Extra message, when no category was found
         if (!count($allMsgs)) {
             $allMsgs[] = $this->msg('trackingcategories-disabled')->parse();
         }
         /*
          * Show category description if it exists as a system message
          * as category-name-desc
          */
         $descMsg = $this->msg($catDesc);
         if ($descMsg->isBlank()) {
             $descMsg = $this->msg('trackingcategories-nodesc');
         }
         $this->getOutput()->addHTML(Html::openElement('tr') . Html::openElement('td', array('class' => 'mw-trackingcategories-name')) . $this->getLanguage()->commaList(array_unique($allMsgs)) . Html::closeElement('td') . Html::openElement('td', array('class' => 'mw-trackingcategories-msg')) . $catMsgTitleText . Html::closeElement('td') . Html::openElement('td', array('class' => 'mw-trackingcategories-desc')) . $descMsg->parse() . Html::closeElement('td') . Html::closeElement('tr'));
     }
     $this->getOutput()->addHTML(Html::closeElement('table'));
 }