/** * Additional params include: * - dbDirectory : directory containing the DB and the lock file directory * [defaults to $wgSQLiteDataDir] * - dbFilePath : use this to force the path of the DB file * - trxMode : one of (deferred, immediate, exclusive) * @param array $p */ function __construct(array $p) { global $wgSharedDB, $wgSQLiteDataDir; $this->dbDir = isset($p['dbDirectory']) ? $p['dbDirectory'] : $wgSQLiteDataDir; if (isset($p['dbFilePath'])) { parent::__construct($p); // Standalone .sqlite file mode. // Super doesn't open when $user is false, but we can work with $dbName, // which is derived from the file path in this case. $this->openFile($p['dbFilePath']); } else { $this->mDBname = $p['dbname']; // Stock wiki mode using standard file names per DB. parent::__construct($p); // Super doesn't open when $user is false, but we can work with $dbName if ($p['dbname'] && !$this->isOpen()) { if ($this->open($p['host'], $p['user'], $p['password'], $p['dbname'])) { if ($wgSharedDB) { $this->attachDatabase($wgSharedDB); } } } } $this->trxMode = isset($p['trxMode']) ? strtoupper($p['trxMode']) : null; if ($this->trxMode && !in_array($this->trxMode, array('DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'))) { $this->trxMode = null; wfWarn("Invalid SQLite transaction mode provided."); } $this->lockMgr = new FSLockManager(array('lockDirectory' => "{$this->dbDir}/locks")); }
/** * Additional params include: * - dbDirectory : directory containing the DB and the lock file directory * [defaults to $wgSQLiteDataDir] * - dbFilePath : use this to force the path of the DB file * - trxMode : one of (deferred, immediate, exclusive) * @param array $p */ function __construct(array $p) { global $wgSharedDB, $wgSQLiteDataDir; $this->dbDir = isset($p['dbDirectory']) ? $p['dbDirectory'] : $wgSQLiteDataDir; if (isset($p['dbFilePath'])) { $this->mFlags = isset($p['flags']) ? $p['flags'] : 0; // Standalone .sqlite file mode $this->openFile($p['dbFilePath']); // @FIXME: clean up base constructor so this can call super instead $this->mTrxAtomicLevels = new SplStack(); } else { $this->mDBname = $p['dbname']; // Stock wiki mode using standard file names per DB parent::__construct($p); // parent doesn't open when $user is false, but we can work with $dbName if ($p['dbname'] && !$this->isOpen()) { if ($this->open($p['host'], $p['user'], $p['password'], $p['dbname'])) { if ($wgSharedDB) { $this->attachDatabase($wgSharedDB); } } } } $this->trxMode = isset($p['trxMode']) ? strtoupper($p['trxMode']) : null; if ($this->trxMode && !in_array($this->trxMode, array('DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'))) { $this->trxMode = null; wfWarn("Invalid SQLite transaction mode provided."); } $this->lockMgr = new FSLockManager(array('lockDirectory' => "{$this->dbDir}/locks")); }
public function onAfterInsert($object, array $row, array $metadata) { if (!$object instanceof PostRevision) { wfWarn(__METHOD__ . ': Object is no PostRevision instance'); return; } if (!isset($metadata['workflow'])) { wfWarn(__METHOD__ . ': Missing required metadata: workflow'); return; } $workflow = $metadata['workflow']; if (!$workflow instanceof Workflow) { throw new InvalidDataException('Workflow metadata is not Workflow instance'); } if ($workflow->getType() !== 'topic') { wfWarn(__METHOD__ . ': Expected "topic" workflow but received "' . $workflow->getType() . '"'); return; } /** @var $title Title */ $title = $workflow->getArticleTitle(); if (!$title) { return; } $this->onAfterInsertExpectedChange($row['rev_change_type'], $metadata['workflow']); }
/** * Use the HTML tidy extension to use the tidy library in-process, * saving the overhead of spawning a new process. * * @param string $text HTML to check * @param bool $stderr Whether to read result from error status instead of output * @param int &$retval Exit code (-1 on internal error) * @return string|null */ protected function cleanWrapped($text, $stderr = false, &$retval = null) { if (!class_exists('tidy')) { wfWarn("Unable to load internal tidy class."); $retval = -1; return null; } $tidy = new \tidy(); $tidy->parseString($text, $this->config['tidyConfigFile'], 'utf8'); if ($stderr) { $retval = $tidy->getStatus(); return $tidy->errorBuffer; } $tidy->cleanRepair(); $retval = $tidy->getStatus(); if ($retval == 2) { // 2 is magic number for fatal error // http://www.php.net/manual/en/function.tidy-get-status.php $cleansource = null; } else { $cleansource = tidy_get_output($tidy); if (!empty($this->config['debugComment']) && $retval > 0) { $cleansource .= "<!--\nTidy reports:\n" . str_replace('-->', '-->', $tidy->errorBuffer) . "\n-->"; } } return $cleansource; }
/** * Registeres a feature for a service object. * Registers a warning when the service is not registered, but does not give an error. * * @since 0.6.6 * * @param $serviceIdentifier String: internal service identifier * @param $featureName String * @param $featureClassName String */ public static function registerServiceFeature($serviceIdentifier, $featureName, $featureClassName) { if (array_key_exists($serviceIdentifier, self::$registeredServices)) { $service = self::getServiceInstance($serviceIdentifier); $service->addFeature($featureName, $featureClassName); } else { // If the feature is not registered, register a warning. This is not an error though! wfWarn("Tried to register feature '{$featureName}' with class '{$featureClassName}' to non-registered service '{$serviceIdentifier}'."); } }
function __construct() { $this->cliMode = true; $this->connLogger = new \Psr\Log\NullLogger(); $this->queryLogger = new \Psr\Log\NullLogger(); $this->errorLogger = function (Exception $e) { wfWarn(get_class($e) . ": {$e->getMessage()}"); }; $this->currentDomain = DatabaseDomain::newUnspecified(); }
public function __construct($text, $model_id = CONTENT_MODEL_TEXT) { parent::__construct($model_id); if ($text === null || $text === false) { wfWarn("TextContent constructed with \$text = " . var_export($text, true) . "! " . "This may indicate an error in the caller's scope."); $text = ''; } if (!is_string($text)) { throw new MWException("TextContent expects a string in the constructor."); } $this->mText = $text; }
public function __construct($testName, array $opts = []) { $this->testName = $testName; $this->profiler = new ProfilerStub([]); $this->trxProfiler = new TransactionProfiler(); $this->cliMode = isset($opts['cliMode']) ? $opts['cliMode'] : true; $this->connLogger = new \Psr\Log\NullLogger(); $this->queryLogger = new \Psr\Log\NullLogger(); $this->errorLogger = function (Exception $e) { wfWarn(get_class($e) . ": {$e->getMessage()}"); }; $this->currentDomain = DatabaseDomain::newUnspecified(); }
/** * @see ParameterManipulation::manipulate * * @since 0.7 */ public function manipulate(Parameter &$parameter, array &$parameters) { global $egMapsOLLayerGroups, $egMapsOLAvailableLayers; $layerDefs = array(); $layerNames = array(); foreach ($parameter->getValue() as $layerOrGroup) { $lcLayerOrGroup = strtolower($layerOrGroup); // Layer groups. Loop over all items and add them when not present yet. if (array_key_exists($lcLayerOrGroup, $egMapsOLLayerGroups)) { foreach ($egMapsOLLayerGroups[$lcLayerOrGroup] as $layerName) { if (!in_array($layerName, $layerNames)) { if (is_array($egMapsOLAvailableLayers[$layerName])) { $layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName][0]; } else { $layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName]; } $layerNames[] = $layerName; } } } elseif (array_key_exists($lcLayerOrGroup, $egMapsOLAvailableLayers)) { if (!in_array($lcLayerOrGroup, $layerNames)) { if (is_array($egMapsOLAvailableLayers[$lcLayerOrGroup])) { $layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup][0]; } else { $layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup]; } $layerNames[] = $lcLayerOrGroup; } } else { $title = Title::newFromText($layerOrGroup, Maps_NS_LAYER); if ($title->getNamespace() == Maps_NS_LAYER && $title->exists()) { $layerPage = new MapsLayerPage($title); if ($layerPage->hasValidDefinition('openlayers')) { $layer = $layerPage->getLayer(); if (!in_array($layerOrGroup, $layerNames)) { $layerDefs[] = $layer->getJavaScriptDefinition(); $layerNames[] = $layerOrGroup; } } else { wfWarn("Invalid layer ({$layerOrGroup}) encountered after validation."); } } else { wfWarn("Invalid layer ({$layerOrGroup}) encountered after validation."); } } } $parameter->setValue($layerDefs); MapsMappingServices::getServiceInstance('openlayers')->addLayerDependencies($this->getDependencies($layerNames)); }
/** * @param IContextSource $context * @param AbstractRevision $newRevision * @param AbstractRevision|null $oldRevision * @param Title $title * @return Status */ public function validate(IContextSource $context, AbstractRevision $newRevision, AbstractRevision $oldRevision = null, Title $title) { $spamObj = BaseBlacklist::getInstance('spam'); if (!$spamObj instanceof \SpamBlacklist) { wfWarn(__METHOD__ . ': Expected a SpamBlacklist instance but instead received: ' . get_class($spamObj)); return Status::newFatal('something'); } $links = $this->getLinks($newRevision, $title); $matches = $spamObj->filter($links, $title); if ($matches !== false) { $status = Status::newFatal('spamprotectiontext'); foreach ($matches as $match) { $status->fatal('spamprotectionmatch', $match); } return $status; } return Status::newGood(); }
/** * Get the site ids of other projects to use. * * @param array $siteLinkGroups * @return string[] */ public function getOtherProjectsSiteIds(array $siteLinkGroups) { $localSite = $this->getLocalSite(); if ($localSite === null) { wfWarn('Site not found for ' . $this->localSiteId); return array(); } $currentGroupId = $localSite->getGroup(); $otherProjectsSiteIds = array(); $this->expandSpecialGroups($siteLinkGroups); foreach ($siteLinkGroups as $groupId) { if ($groupId === $currentGroupId) { continue; } $siteToAdd = $this->getSiteForGroup($groupId, $localSite->getLanguageCode()); if ($siteToAdd) { $otherProjectsSiteIds[] = $siteToAdd->getGlobalId(); } } return $otherProjectsSiteIds; }
/** * Break down $job into approximately ($bSize/$cSize) leaf jobs and a single partition * job that covers the remaining backlink range (if needed). Jobs for the first $bSize * titles are collated ($cSize per job) into leaf jobs to do actual work. All the * resulting jobs are of the same class as $job. No partition job is returned if the * range covered by $job was less than $bSize, as the leaf jobs have full coverage. * * The leaf jobs have the 'pages' param set to a (<page ID>:(<namespace>,<DB key>),...) * map so that the run() function knows what pages to act on. The leaf jobs will keep * the same job title as the parent job (e.g. $job). * * The partition jobs have the 'range' parameter set to a map of the format * (start:<integer>, end:<integer>, batchSize:<integer>, subranges:((<start>,<end>),...)), * the 'table' parameter set to that of $job, and the 'recursive' parameter set to true. * This method can be called on the resulting job to repeat the process again. * * The job provided ($job) must have the 'recursive' parameter set to true and the 'table' * parameter must be set to a backlink table. The job title will be used as the title to * find backlinks for. Any 'range' parameter must follow the same format as mentioned above. * This should be managed by recursive calls to this method. * * The first jobs return are always the leaf jobs. This lets the caller use push() to * put them directly into the queue and works well if the queue is FIFO. In such a queue, * the leaf jobs have to get finished first before anything can resolve the next partition * job, which keeps the queue very small. * * $opts includes: * - params : extra job parameters to include in each job * * @param Job $job * @param int $bSize BacklinkCache partition size; usually $wgUpdateRowsPerJob * @param int $cSize Max titles per leaf job; Usually 1 or a modest value * @param array $opts Optional parameter map * @return Job[] List of Job objects */ public static function partitionBacklinkJob(Job $job, $bSize, $cSize, $opts = array()) { $class = get_class($job); $title = $job->getTitle(); $params = $job->getParams(); if (isset($params['pages']) || empty($params['recursive'])) { $ranges = array(); // sanity; this is a leaf node wfWarn(__METHOD__ . " called on {$job->getType()} leaf job (explosive recursion)."); } elseif (isset($params['range'])) { // This is a range job to trigger the insertion of partitioned/title jobs... $ranges = $params['range']['subranges']; $realBSize = $params['range']['batchSize']; } else { // This is a base job to trigger the insertion of partitioned jobs... $ranges = $title->getBacklinkCache()->partition($params['table'], $bSize); $realBSize = $bSize; } $extraParams = isset($opts['params']) ? $opts['params'] : array(); $jobs = array(); // Combine the first range (of size $bSize) backlinks into leaf jobs if (isset($ranges[0])) { list($start, $end) = $ranges[0]; $titles = $title->getBacklinkCache()->getLinks($params['table'], $start, $end); foreach (array_chunk(iterator_to_array($titles), $cSize) as $titleBatch) { $pages = array(); foreach ($titleBatch as $tl) { $pages[$tl->getArticleId()] = array($tl->getNamespace(), $tl->getDBKey()); } $jobs[] = new $class($title, array('pages' => $pages) + $extraParams); } } // Take all of the remaining ranges and build a partition job from it if (isset($ranges[1])) { $jobs[] = new $class($title, array('recursive' => true, 'table' => $params['table'], 'range' => array('start' => $ranges[1][0], 'end' => $ranges[count($ranges) - 1][1], 'batchSize' => $realBSize, 'subranges' => array_slice($ranges, 1))) + $extraParams); } return $jobs; }
/** * Spawn an external HTML tidy process and get corrected markup back from it. * Also called in OutputHandler.php for full page validation * * @param string $text HTML to check * @param bool $stderr Whether to read result from STDERR rather than STDOUT * @param int &$retval Exit code (-1 on internal error) * @return string|null */ protected function cleanWrapped($text, $stderr = false, &$retval = null) { $cleansource = ''; $opts = ' -utf8'; if ($stderr) { $descriptorspec = [0 => ['pipe', 'r'], 1 => ['file', wfGetNull(), 'a'], 2 => ['pipe', 'w']]; } else { $descriptorspec = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['file', wfGetNull(), 'a']]; } $readpipe = $stderr ? 2 : 1; $pipes = []; $process = proc_open("{$this->config['tidyBin']} -config {$this->config['tidyConfigFile']} " . $this->config['tidyCommandLine'] . $opts, $descriptorspec, $pipes); // NOTE: At least on linux, the process will be created even if tidy is not installed. // This means that missing tidy will be treated as a validation failure. if (is_resource($process)) { // Theoretically, this style of communication could cause a deadlock // here. If the stdout buffer fills up, then writes to stdin could // block. This doesn't appear to happen with tidy, because tidy only // writes to stdout after it's finished reading from stdin. Search // for tidyParseStdin and tidySaveStdout in console/tidy.c fwrite($pipes[0], $text); fclose($pipes[0]); while (!feof($pipes[$readpipe])) { $cleansource .= fgets($pipes[$readpipe], 1024); } fclose($pipes[$readpipe]); $retval = proc_close($process); } else { wfWarn("Unable to start external tidy process"); $retval = -1; } if (!$stderr && $cleansource == '' && $text != '') { // Some kind of error happened, so we couldn't get the corrected text. // Just give up; we'll use the source text and append a warning. $cleansource = null; } return $cleansource; }
protected function getResultText(SMWQueryResult $res, $outputmode) { if (!is_callable('renderGraphviz')) { wfWarn('The SRF Graph printer needs the GraphViz extension to be installed.'); return ''; } global $wgGraphVizSettings; $this->isHTML = true; $graphInput = "digraph {$this->m_graphName} {"; if ($this->m_graphSize != '') { $graphInput .= "size=\"{$this->m_graphSize}\";"; } if ($this->m_nodeShape) { $graphInput .= "node [shape={$this->m_nodeShape}];"; } $graphInput .= "rankdir={$this->m_rankdir};"; while ($row = $res->getNext()) { $graphInput .= $this->getGVForItem($row, $outputmode); } $graphInput .= "}"; // Calls renderGraphViz function from MediaWiki GraphViz extension $result = renderGraphviz($graphInput); if ($this->m_graphLegend && $this->m_graphColor) { $arrayCount = 0; $arraySize = count($this->m_graphColors); $result .= "<P>"; foreach ($this->m_labelArray as $m_label) { if ($arrayCount >= $arraySize) { $arrayCount = 0; } $color = $this->m_graphColors[$arrayCount]; $result .= "<font color={$color}>{$color}: {$m_label} </font><br />"; $arrayCount += 1; } $result .= "</P>"; } return $result; }
/** * @param DatabaseUpdater $updater */ public function doSchemaUpdate(DatabaseUpdater $updater) { $db = $updater->getDB(); $type = $db->getType(); if ($type !== 'mysql' && $type !== 'sqlite') { wfWarn("Database type '{$type}' is not supported by the Wikibase repository."); return; } $this->addChangesTable($updater, $type); // Update from 0.1. if (!$db->tableExists('wb_terms')) { $updater->dropTable('wb_items_per_site'); $updater->dropTable('wb_items'); $updater->dropTable('wb_aliases'); $updater->dropTable('wb_texts_per_lang'); $updater->addExtensionTable('wb_terms', $this->getUpdateScriptPath('Wikibase', $db->getType())); $this->store->rebuild(); } $this->updateEntityPerPageTable($updater, $db); $this->updateTermsTable($updater, $db); $this->updateItemsPerSiteTable($updater, $db); $this->updateChangesTable($updater, $db); $this->registerPropertyInfoTableUpdates($updater); }
/** * Create a new Title from text, such as what one would find in a link. De- * codes any HTML entities in the text. * * @param string $text The link text; spaces, prefixes, and an * initial ':' indicating the main namespace are accepted. * @param int $defaultNamespace The namespace to use if none is specified * by a prefix. If you want to force a specific namespace even if * $text might begin with a namespace prefix, use makeTitle() or * makeTitleSafe(). * @throws InvalidArgumentException * @return Title|null Title or null on an error. */ public static function newFromText($text, $defaultNamespace = NS_MAIN) { if (is_object($text)) { throw new InvalidArgumentException('$text must be a string.'); } elseif (!is_string($text)) { wfDebugLog('T76305', wfGetAllCallers(5)); wfWarn(__METHOD__ . ': $text must be a string. This will throw an InvalidArgumentException in future.', 2); } try { return Title::newFromTextThrow($text, $defaultNamespace); } catch (MalformedTitleException $ex) { return null; } }
/** * Returns the page's content model id (see the CONTENT_MODEL_XXX constants). * * Will use the revisions actual content model if the page exists, * and the page's default if the page doesn't exist yet. * * @return String * * @since 1.21 */ public function getContentModel() { if ( $this->exists() ) { // look at the revision's actual content model $rev = $this->getRevision(); if ( $rev !== null ) { return $rev->getContentModel(); } else { $title = $this->mTitle->getPrefixedDBkey(); wfWarn( "Page $title exists but has no (visible) revisions!" ); } } // use the default model for this page return $this->mTitle->getContentModel(); }
/** * Get the local name for a specified canonical name * * @param string $name * @param string|bool $subpage * @return string */ public static function getLocalNameFor($name, $subpage = false) { global $wgContLang; $aliases = $wgContLang->getSpecialPageAliases(); $aliasList = self::getAliasList(); // Find the first alias that maps back to $name if (isset($aliases[$name])) { $found = false; foreach ($aliases[$name] as $alias) { $caseFoldedAlias = $wgContLang->caseFold($alias); $caseFoldedAlias = str_replace(' ', '_', $caseFoldedAlias); if (isset($aliasList[$caseFoldedAlias]) && $aliasList[$caseFoldedAlias] === $name) { $name = $alias; $found = true; break; } } if (!$found) { wfWarn("Did not find a usable alias for special page '{$name}'. " . "It seems all defined aliases conflict?"); } } else { // Check if someone misspelled the correct casing if (is_array($aliases)) { foreach ($aliases as $n => $values) { if (strcasecmp($name, $n) === 0) { wfWarn("Found alias defined for {$n} when searching for " . "special page aliases for {$name}. Case mismatch?"); return self::getLocalNameFor($n, $subpage); } } } wfWarn("Did not find alias for special page '{$name}'. " . "Perhaps no aliases are defined for it?"); } if ($subpage !== false && !is_null($subpage)) { $name = "{$name}/{$subpage}"; } return $wgContLang->ucfirst($name); }
/** * Get the local name for a specified canonical name * * @param $name String * @param $subpage String|Bool * * @return String */ static function getLocalNameFor($name, $subpage = false) { global $wgContLang; $aliases = $wgContLang->getSpecialPageAliases(); if (isset($aliases[$name][0])) { $name = $aliases[$name][0]; } else { // Try harder in case someone misspelled the correct casing $found = false; foreach ($aliases as $n => $values) { if (strcasecmp($name, $n) === 0) { wfWarn("Found alias defined for {$n} when searching for " . "special page aliases for {$name}. Case mismatch?"); $name = $values[0]; $found = true; break; } } if (!$found) { wfWarn("Did not find alias for special page '{$name}'. " . "Perhaps no aliases are defined for it?"); } } if ($subpage !== false && !is_null($subpage)) { $name = "{$name}/{$subpage}"; } return $wgContLang->ucfirst($name); }
/** * Returns the page's content model id (see the CONTENT_MODEL_XXX constants). * * Will use the revisions actual content model if the page exists, * and the page's default if the page doesn't exist yet. * * @return string * * @since 1.21 */ public function getContentModel() { if ($this->exists()) { $cache = ObjectCache::getMainWANInstance(); return $cache->getWithSetCallback($cache->makeKey('page', 'content-model', $this->getLatest()), $cache::TTL_MONTH, function () { $rev = $this->getRevision(); if ($rev) { // Look at the revision's actual content model return $rev->getContentModel(); } else { $title = $this->mTitle->getPrefixedDBkey(); wfWarn("Page {$title} exists but has no (visible) revisions!"); return $this->mTitle->getContentModel(); } }); } // use the default model for this page return $this->mTitle->getContentModel(); }
/** * Fill a MagicWord object with data from here * * @param MagicWord $mw */ function getMagic($mw) { // Saves a function call if (!$this->mMagicHookDone) { $this->doMagicHook(); } if (isset($this->mMagicExtensions[$mw->mId])) { $rawEntry = $this->mMagicExtensions[$mw->mId]; } else { $rawEntry = self::$dataCache->getSubitem($this->mCode, 'magicWords', $mw->mId); } if (!is_array($rawEntry)) { wfWarn("\"{$rawEntry}\" is not a valid magic word for \"{$mw->mId}\""); } else { $mw->mCaseSensitive = $rawEntry[0]; $mw->mSynonyms = array_slice($rawEntry, 1); } }
/** * Returns message in the requested format * * @deprecated since 1.18 * * @param string $key Key of the message * @param array $options Processing rules. * Can take the following options: * parse: parses wikitext to HTML * parseinline: parses wikitext to HTML and removes the surrounding * p's added by parser or tidy * escape: filters message through htmlspecialchars * escapenoentities: same, but allows entity references like   through * replaceafter: parameters are substituted after parsing or escaping * parsemag: transform the message using magic phrases * content: fetch message for content language instead of interface * Also can accept a single associative argument, of the form 'language' => 'xx': * language: Language object or language code to fetch message for * (overridden by content). * Behavior for conflicting options (e.g., parse+parseinline) is undefined. * * @return string */ function wfMsgExt($key, $options) { wfDeprecated(__METHOD__, '1.21'); $args = func_get_args(); array_shift($args); array_shift($args); $options = (array) $options; $validOptions = array('parse', 'parseinline', 'escape', 'escapenoentities', 'replaceafter', 'parsemag', 'content'); foreach ($options as $arrayKey => $option) { if (!preg_match('/^[0-9]+|language$/', $arrayKey)) { // An unknown index, neither numeric nor "language" wfWarn("wfMsgExt called with incorrect parameter key {$arrayKey}", 1, E_USER_WARNING); } elseif (preg_match('/^[0-9]+$/', $arrayKey) && !in_array($option, $validOptions)) { // A numeric index with unknown value wfWarn("wfMsgExt called with incorrect parameter {$option}", 1, E_USER_WARNING); } } if (in_array('content', $options, true)) { $forContent = true; $langCode = true; $langCodeObj = null; } elseif (array_key_exists('language', $options)) { $forContent = false; $langCode = wfGetLangObj($options['language']); $langCodeObj = $langCode; } else { $forContent = false; $langCode = false; $langCodeObj = null; } $string = wfMsgGetKey($key, true, $langCode, false); if (!in_array('replaceafter', $options, true)) { $string = wfMsgReplaceArgs($string, $args); } $messageCache = MessageCache::singleton(); $parseInline = in_array('parseinline', $options, true); if (in_array('parse', $options, true) || $parseInline) { $string = $messageCache->parse($string, null, true, !$forContent, $langCodeObj); if ($string instanceof ParserOutput) { $string = $string->getText(); } if ($parseInline) { $string = Parser::stripOuterParagraph($string); } } elseif (in_array('parsemag', $options, true)) { $string = $messageCache->transform($string, !$forContent, $langCodeObj); } if (in_array('escape', $options, true)) { $string = htmlspecialchars($string); } elseif (in_array('escapenoentities', $options, true)) { $string = Sanitizer::escapeHtmlAllowEntities($string); } if (in_array('replaceafter', $options, true)) { $string = wfMsgReplaceArgs($string, $args); } return $string; }
function getRow() { $id = $this->id(); $dbw = wfGetDB(DB_MASTER); if (!$id) { $id = $dbw->nextSequenceValue('thread_thread_id'); } // If there's no root, bail out with an error message if (!$this->rootId && !($this->type & Threads::TYPE_DELETED)) { throw new MWException("Non-deleted thread saved with empty root ID"); } if ($this->replyCount < -1) { wfWarn("Saving thread {$id} with negative reply count {$this->replyCount} " . wfGetAllCallers()); $this->replyCount = -1; } // Reflect schema changes here. return array('thread_id' => $id, 'thread_root' => $this->rootId, 'thread_parent' => $this->parentId, 'thread_article_namespace' => $this->articleNamespace, 'thread_article_title' => $this->articleTitle, 'thread_article_id' => $this->articleId, 'thread_modified' => $dbw->timestamp($this->modified), 'thread_created' => $dbw->timestamp($this->created), 'thread_ancestor' => $this->ancestorId, 'thread_type' => $this->type, 'thread_subject' => $this->subject, 'thread_author_id' => $this->authorId, 'thread_author_name' => $this->authorName, 'thread_summary_page' => $this->summaryId, 'thread_editedness' => $this->editedness, 'thread_sortkey' => $this->sortkey, 'thread_replies' => $this->replyCount, 'thread_signature' => $this->signature); }
/** * Format an auto summary argument * * @since 0.4 * * @param mixed $arg * * @return string */ protected function formatArg($arg) { try { if ($arg instanceof Snak) { return $this->snakFormatter->formatSnak($arg); } elseif ($arg instanceof EntityId) { return $this->idFormatter->formatEntityId($arg); } elseif ($arg instanceof DataValue) { return $this->valueFormatter->format($arg); } elseif (method_exists($arg, '__toString')) { return strval($arg); } elseif (is_object($arg)) { return '<' . get_class($arg) . '>'; } elseif (is_array($arg)) { if (!empty($arg) && !isset($arg[0])) { // turn assoc array into a list $arg = $this->formatKeyValuePairs($arg); } $strings = $this->formatArgList($arg); return $this->language->commaList($strings); } else { return strval($arg); } } catch (Exception $ex) { wfWarn(__METHOD__ . ': failed to render value: ' . $ex->getMessage()); } return '?'; }
/** * Recursively check a condition. Conditions are in the form * array( '&' or '|' or '^' or '!', cond1, cond2, ... ) * where cond1, cond2, ... are themselves conditions; *OR* * APCOND_EMAILCONFIRMED, *OR* * array( APCOND_EMAILCONFIRMED ), *OR* * array( APCOND_EDITCOUNT, number of edits ), *OR* * array( APCOND_AGE, seconds since registration ), *OR* * similar constructs defined by extensions. * This function evaluates the former type recursively, and passes off to * self::checkCondition for evaluation of the latter type. * * @param $cond Mixed: a condition, possibly containing other conditions * @param $user User The user to check the conditions against * @return bool Whether the condition is true */ private static function recCheckCondition($cond, User $user) { $validOps = array('&', '|', '^', '!'); if (is_array($cond) && count($cond) >= 2 && in_array($cond[0], $validOps)) { # Recursive condition if ($cond[0] == '&') { // AND (all conds pass) foreach (array_slice($cond, 1) as $subcond) { if (!self::recCheckCondition($subcond, $user)) { return false; } } return true; } elseif ($cond[0] == '|') { // OR (at least one cond passes) foreach (array_slice($cond, 1) as $subcond) { if (self::recCheckCondition($subcond, $user)) { return true; } } return false; } elseif ($cond[0] == '^') { // XOR (exactly one cond passes) if (count($cond) > 3) { wfWarn('recCheckCondition() given XOR ("^") condition on three or more conditions. Check your $wgAutopromote and $wgAutopromoteOnce settings.'); } return self::recCheckCondition($cond[1], $user) xor self::recCheckCondition($cond[2], $user); } elseif ($cond[0] == '!') { // NOT (no conds pass) foreach (array_slice($cond, 1) as $subcond) { if (self::recCheckCondition($subcond, $user)) { return false; } } return true; } } # If we got here, the array presumably does not contain other condi- # tions; it's not recursive. Pass it off to self::checkCondition. if (!is_array($cond)) { $cond = array($cond); } return self::checkCondition($cond, $user); }
/** * Use the HTML tidy extension to use the tidy library in-process, * saving the overhead of spawning a new process. * * @param string $text HTML to check * @param bool $stderr Whether to read result from error status instead of output * @param int &$retval Exit code (-1 on internal error) * @return string|null */ private static function execInternalTidy($text, $stderr = false, &$retval = null) { global $wgTidyConf, $wgDebugTidy; wfProfileIn(__METHOD__); if (!class_exists('tidy')) { wfWarn("Unable to load internal tidy class."); $retval = -1; wfProfileOut(__METHOD__); return null; } $tidy = new tidy(); $tidy->parseString($text, $wgTidyConf, 'utf8'); if ($stderr) { $retval = $tidy->getStatus(); wfProfileOut(__METHOD__); return $tidy->errorBuffer; } $tidy->cleanRepair(); $retval = $tidy->getStatus(); if ($retval == 2) { // 2 is magic number for fatal error // http://www.php.net/manual/en/function.tidy-get-status.php $cleansource = null; } else { $cleansource = tidy_get_output($tidy); if ($wgDebugTidy && $retval > 0) { $cleansource .= "<!--\nTidy reports:\n" . str_replace('-->', '-->', $tidy->errorBuffer) . "\n-->"; } } wfProfileOut(__METHOD__); return $cleansource; }
unset($serverParts); // Set defaults for configuration variables // that are derived from the server name by default // Note: $wgEmergencyContact and $wgPasswordSender may be false or empty string (T104142) if (!$wgEmergencyContact) { $wgEmergencyContact = 'wikiadmin@' . $wgServerName; } if (!$wgPasswordSender) { $wgPasswordSender = 'apache@' . $wgServerName; } if (!$wgNoReplyAddress) { $wgNoReplyAddress = $wgPasswordSender; } if ($wgSecureLogin && substr($wgServer, 0, 2) !== '//') { $wgSecureLogin = false; wfWarn('Secure login was enabled on a server that only supports ' . 'HTTP or HTTPS. Disabling secure login.'); } $wgVirtualRestConfig['global']['domain'] = $wgCanonicalServer; // Now that GlobalFunctions is loaded, set defaults that depend on it. if ($wgTmpDirectory === false) { $wgTmpDirectory = wfTempDir(); } // We don't use counters anymore. Left here for extensions still // expecting this to exist. Should be removed sometime 1.26 or later. if (!isset($wgDisableCounters)) { $wgDisableCounters = true; } if ($wgMainWANCache === false) { // Setup a WAN cache from $wgMainCacheType with no relayer. // Sites using multiple datacenters can configure a relayer. $wgMainWANCache = 'mediawiki-main-default';
/** * Coalesce consecutive changes by the same user to the same entity into one. * A run of changes may be broken if the action performed changes (e.g. deletion * instead of update) or if a sitelink pointing to the local wiki was modified. * * Some types of actions, like deletion, will break runs. * Interleaved changes to different items will break runs. * * @param EntityChange[] $changes * * @return EntityChange[] grouped changes */ private function coalesceRuns(array $changes) { $coalesced = array(); $currentRun = array(); $currentUser = null; $currentEntity = null; $currentAction = null; $breakNext = false; foreach ($changes as $change) { try { $action = $change->getAction(); $meta = $change->getMetadata(); $user = $meta['user_text']; $entityId = $change->getEntityId()->__toString(); $break = $breakNext || $currentAction !== $action || $currentUser !== $user || $currentEntity !== $entityId; $breakNext = false; if (!$break && $change instanceof ItemChange) { $siteLinkDiff = $change->getSiteLinkDiff(); if (isset($siteLinkDiff[$this->localSiteId])) { // TODO: don't break if only the link's badges changed $break = true; $breakNext = true; } } if ($break) { if (!empty($currentRun)) { try { $coalesced[] = $this->mergeChanges($currentRun); } catch (MWException $ex) { // Something went wrong while trying to merge the changes. // Just keep the original run. wfWarn($ex->getMessage()); $coalesced = array_merge($coalesced, $currentRun); } } $currentRun = array(); $currentUser = $user; $currentEntity = $entityId; $currentAction = $action === EntityChange::ADD ? EntityChange::UPDATE : $action; } $currentRun[] = $change; // skip any change that failed to process in some way (bug T51417) } catch (Exception $ex) { wfLogWarning(__METHOD__ . ':' . $ex->getMessage()); } } if (!empty($currentRun)) { try { $coalesced[] = $this->mergeChanges($currentRun); } catch (MWException $ex) { // Something went wrong while trying to merge the changes. // Just keep the original run. wfWarn($ex->getMessage()); $coalesced = array_merge($coalesced, $currentRun); } } return $coalesced; }
/** * Make a "broken" link to an image * * @param Title $title * @param string $label Link label (plain text) * @param string $query Query string * @param string $unused1 Unused parameter kept for b/c * @param string $unused2 Unused parameter kept for b/c * @param bool $time A file of a certain timestamp was requested * @return string */ public static function makeBrokenImageLinkObj($title, $label = '', $query = '', $unused1 = '', $unused2 = '', $time = false) { if (!$title instanceof Title) { wfWarn(__METHOD__ . ': Requires $title to be a Title object.'); return "<!-- ERROR -->" . htmlspecialchars($label); } global $wgEnableUploads, $wgUploadMissingFileUrl, $wgUploadNavigationUrl; if ($label == '') { $label = $title->getPrefixedText(); } $encLabel = htmlspecialchars($label); $currentExists = $time ? wfFindFile($title) != false : false; if (($wgUploadMissingFileUrl || $wgUploadNavigationUrl || $wgEnableUploads) && !$currentExists) { $redir = RepoGroup::singleton()->getLocalRepo()->checkRedirect($title); if ($redir) { return self::linkKnown($title, $encLabel, array(), wfCgiToArray($query)); } $href = self::getUploadUrl($title, $query); return '<a href="' . htmlspecialchars($href) . '" class="new" title="' . htmlspecialchars($title->getPrefixedText(), ENT_QUOTES) . '">' . $encLabel . '</a>'; } return self::linkKnown($title, $encLabel, array(), wfCgiToArray($query)); }
/** * Get URLs for icons if available. * @param MessageGroup $g * @param int $size Length of the edge of a bounding box to fit the icon. * @return null|array * @since 2013-04-01 */ public static function getIcon(MessageGroup $g, $size) { $icon = $g->getIcon(); if (substr($icon, 0, 7) !== 'wiki://') { return null; } $formats = array(); $filename = substr($icon, 7); $file = wfFindFile($filename); if (!$file) { wfWarn("Unknown message group icon file {$icon}"); return null; } if ($file->isVectorized()) { $formats['vector'] = $file->getFullUrl(); } $formats['raster'] = $file->createThumb($size, $size); return $formats; }