/** Build $this->messages array */ private function initMessagesHref() { # List of default messages for the sidebar: $URL_messages = array('mainpage', 'portal-url', 'currentevents-url', 'recentchanges-url', 'randompage-url', 'helppage'); foreach ($URL_messages as $m) { $titleName = MessageCache::singleton()->get($m); $title = Title::newFromText($titleName); $this->messages[$m]['href'] = $title->getLocalURL(); } }
protected function setUp() { global $wgLanguageCode, $wgContLang; if ($wgLanguageCode != $wgContLang->getCode()) { throw new MWException("Error in MediaWikiLangTestCase::setUp(): " . "\$wgLanguageCode ('{$wgLanguageCode}') is different from " . "\$wgContLang->getCode() (" . $wgContLang->getCode() . ")"); } parent::setUp(); $this->setUserLang('en'); // For mainpage to be 'Main Page' $this->setContentLang('en'); MessageCache::singleton()->disable(); }
public function setUp() { global $wgLanguageCode, $wgLang, $wgContLang; self::$oldLang = $wgLang; self::$oldContLang = $wgContLang; if ($wgLanguageCode != $wgContLang->getCode()) { throw new MWException("Error in MediaWikiLangTestCase::setUp(): " . "\$wgLanguageCode ('{$wgLanguageCode}') is different from " . "\$wgContLang->getCode() (" . $wgContLang->getCode() . ")"); } $wgLanguageCode = 'en'; # For mainpage to be 'Main Page' $wgContLang = $wgLang = Language::factory($wgLanguageCode); MessageCache::singleton()->disable(); }
public function setUp() { global $wgLanguageCode, $wgLang, $wgContLang; self::$oldLang = $wgLang; self::$oldContLang = $wgContLang; if ($wgLanguageCode != $wgContLang->getCode()) { die("nooo!"); } $wgLanguageCode = 'en'; # For mainpage to be 'Main Page' $wgContLang = $wgLang = Language::factory($wgLanguageCode); MessageCache::singleton()->disable(); }
protected function setUp() { global $wgLanguageCode, $wgContLang; parent::setUp(); if ($wgLanguageCode != $wgContLang->getCode()) { throw new MWException("Error in MediaWikiLangTestCase::setUp(): " . "\$wgLanguageCode ('{$wgLanguageCode}') is different from " . "\$wgContLang->getCode() (" . $wgContLang->getCode() . ")"); } $langCode = 'en'; # For mainpage to be 'Main Page' $langObj = Language::factory($langCode); $this->setMwGlobals(array('wgLanguageCode' => $langCode, 'wgLang' => $langObj, 'wgContLang' => $langObj)); MessageCache::singleton()->disable(); }
protected function setUp() { global $wgLanguageCode, $wgContLang; parent::setUp(); if ($wgLanguageCode != $wgContLang->getCode()) { throw new MWException("Error in MediaWikiLangTestCase::setUp(): " . "\$wgLanguageCode ('{$wgLanguageCode}') is different from " . "\$wgContLang->getCode() (" . $wgContLang->getCode() . ")"); } // HACK: Call getLanguage() so the real $wgContLang is cached as the user language // rather than our fake one. This is to avoid breaking other, unrelated tests. RequestContext::getMain()->getLanguage(); $langCode = 'en'; # For mainpage to be 'Main Page' $langObj = Language::factory($langCode); $this->setMwGlobals(array('wgLanguageCode' => $langCode, 'wgLang' => $langObj, 'wgContLang' => $langObj)); MessageCache::singleton()->disable(); }
/** * From WikimediaMessages * * @return bool */ public static function onMessageCacheGet(&$lcKey) { global $wgLanguageCode; static $keys = array('centralauth-groupname'); if (in_array($lcKey, $keys, true)) { $prefixedKey = "miraheze-{$lcKey}"; // MessageCache uses ucfirst if ord( key ) is < 128, which is true of all // of the above. Revisit if non-ASCII keys are used. $ucKey = ucfirst($lcKey); $cache = MessageCache::singleton(); if ($cache->getMsgFromNamespace($ucKey, $wgLanguageCode) === false) { $lcKey = $prefixedKey; } } return true; }
/** * When core requests certain messages, change the key to a Kol-Zchut version. * * @note Don't make this a closure, it causes the Database Dumps to fail. * See https://bugs.php.net/bug.php?id=52144 * * @param String &$lcKey message key to check and possibly convert * * @return bool */ public static function onMessageCacheGet(&$lcKey) { global $wgLanguageCode; static $keys = array('aboutpage', 'aboutsite', 'copyright', 'copyrightwarning', 'deletereason-dropdown', 'edithelppage', 'hidetoc', 'showtoc', 'lastmodifiedat', 'lastmodifiedatby', 'login', 'logouttext', 'nav-login-createaccount', 'userlogin', 'userloginnocreate', 'logout', 'userlogout', 'notloggedin', 'nologin', 'gotaccountlink', 'createaccounterror', 'signupstart', 'noarticletext', 'noarticletext-nopermission', 'protect-dropdown', 'siteuser', 'siteusers', 'tagline', 'tooltip-p-logo', 'tooltip-n-mainpage', 'tooltip-n-mainpage-description', "accesskey-p-logo", "accesskey-n-mainpage", 'enotif_body_intro_deleted', 'enotif_body_intro_created', 'enotif_body_intro_moved', 'enotif_body_intro_restored', 'enotif_body_intro_changed', 'enotif_lastvisited', 'enotif_lastdiff', 'enotif_body', 'search-nonefound', 'upload', 'userpage', 'helena-disclaimers', 'wr-langlinks-label'); if (in_array($lcKey, $keys, true)) { $prefixedKey = "kz-{$lcKey}"; // MessageCache uses ucfirst if ord( key ) is < 128, which is true of all // of the above. Revisit if non-ASCII keys are used. $ucKey = ucfirst($lcKey); $cache = MessageCache::singleton(); if ($cache->getMsgFromNamespace($ucKey, $wgLanguageCode) === false) { $lcKey = $prefixedKey; } } return true; }
/** * @param $title Title * @return null|string */ protected function getContent($title) { if ($title->getNamespace() === NS_MEDIAWIKI) { // The first "true" is to use the database, the second is to use the content langue // and the last one is to specify the message key already contains the language in it ("/de", etc.) $text = MessageCache::singleton()->get($title->getDBkey(), true, true, true); return $text === false ? '' : $text; } if (!$title->isCssJsSubpage() && !$title->isCssOrJsPage()) { return null; } $revision = Revision::newFromTitle($title, false, Revision::READ_NORMAL); if (!$revision) { return null; } return $revision->getRawText(); }
/** Build $this->messages array */ private function initMessagesHref() { # List of default messages for the sidebar. The sidebar doesn't care at # all whether they are full URLs, interwiki links or local titles. $URL_messages = array('mainpage', 'portal-url', 'currentevents-url', 'recentchanges-url', 'randompage-url', 'helppage'); # We're assuming that isValidURI works as advertised: it's also # tested separately, in tests/phpunit/includes/HttpTest.php. foreach ($URL_messages as $m) { $titleName = MessageCache::singleton()->get($m); if (Http::isValidURI($titleName)) { $this->messages[$m]['href'] = $titleName; } else { $title = Title::newFromText($titleName); $this->messages[$m]['href'] = $title->getLocalURL(); } } }
/** * There's a fallback case where the message key is given as fully qualified -- this * should ignore the passed $lang and use the language from the key * * @dataProvider provideMessagesForFullKeys */ public function testFullKeyBehaviour($message, $lang, $expectedContent) { $result = MessageCache::singleton()->get($message, true, $lang, true); $this->assertEquals($expectedContent, $result, "Full key message fallback failed."); }
/** * Generate the generic "this page has been changed" e-mail text. */ private function composeCommonMailtext() { global $wgPasswordSender, $wgNoReplyAddress; global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress; global $wgEnotifImpersonal, $wgEnotifUseRealName; $this->composed_common = true; # You as the WikiAdmin and Sysops can make use of plenty of # named variables when composing your notification emails while # simply editing the Meta pages $keys = array(); $postTransformKeys = array(); $pageTitleUrl = $this->title->getCanonicalURL(); $pageTitle = $this->title->getPrefixedText(); if ($this->oldid) { // Always show a link to the diff which triggered the mail. See bug 32210. $keys['$NEWPAGE'] = "\n\n" . wfMessage('enotif_lastdiff', $this->title->getCanonicalURL(array('diff' => 'next', 'oldid' => $this->oldid)))->inContentLanguage()->text(); if (!$wgEnotifImpersonal) { // For personal mail, also show a link to the diff of all changes // since last visited. $keys['$NEWPAGE'] .= "\n\n" . wfMessage('enotif_lastvisited', $this->title->getCanonicalURL(array('diff' => '0', 'oldid' => $this->oldid)))->inContentLanguage()->text(); } $keys['$OLDID'] = $this->oldid; // Deprecated since MediaWiki 1.21, not used by default. Kept for backwards-compatibility. $keys['$CHANGEDORCREATED'] = wfMessage('changed')->inContentLanguage()->text(); } else { # clear $OLDID placeholder in the message template $keys['$OLDID'] = ''; $keys['$NEWPAGE'] = ''; // Deprecated since MediaWiki 1.21, not used by default. Kept for backwards-compatibility. $keys['$CHANGEDORCREATED'] = wfMessage('created')->inContentLanguage()->text(); } $keys['$PAGETITLE'] = $this->title->getPrefixedText(); $keys['$PAGETITLE_URL'] = $this->title->getCanonicalURL(); $keys['$PAGEMINOREDIT'] = $this->minorEdit ? wfMessage('minoredit')->inContentLanguage()->text() : ''; $keys['$UNWATCHURL'] = $this->title->getCanonicalURL('action=unwatch'); if ($this->editor->isAnon()) { # real anon (user:xxx.xxx.xxx.xxx) $keys['$PAGEEDITOR'] = wfMessage('enotif_anon_editor', $this->editor->getName())->inContentLanguage()->text(); $keys['$PAGEEDITOR_EMAIL'] = wfMessage('noemailtitle')->inContentLanguage()->text(); } else { $keys['$PAGEEDITOR'] = $wgEnotifUseRealName && $this->editor->getRealName() !== '' ? $this->editor->getRealName() : $this->editor->getName(); $emailPage = SpecialPage::getSafeTitleFor('Emailuser', $this->editor->getName()); $keys['$PAGEEDITOR_EMAIL'] = $emailPage->getCanonicalURL(); } $keys['$PAGEEDITOR_WIKI'] = $this->editor->getUserPage()->getCanonicalURL(); $keys['$HELPPAGE'] = wfExpandUrl(Skin::makeInternalOrExternalUrl(wfMessage('helppage')->inContentLanguage()->text())); # Replace this after transforming the message, bug 35019 $postTransformKeys['$PAGESUMMARY'] = $this->summary == '' ? ' - ' : $this->summary; // Now build message's subject and body // Messages: // enotif_subject_deleted, enotif_subject_created, enotif_subject_moved, // enotif_subject_restored, enotif_subject_changed $this->subject = wfMessage('enotif_subject_' . $this->pageStatus)->inContentLanguage()->params($pageTitle, $keys['$PAGEEDITOR'])->text(); // Messages: // enotif_body_intro_deleted, enotif_body_intro_created, enotif_body_intro_moved, // enotif_body_intro_restored, enotif_body_intro_changed $keys['$PAGEINTRO'] = wfMessage('enotif_body_intro_' . $this->pageStatus)->inContentLanguage()->params($pageTitle, $keys['$PAGEEDITOR'], $pageTitleUrl)->text(); $body = wfMessage('enotif_body')->inContentLanguage()->plain(); $body = strtr($body, $keys); $body = MessageCache::singleton()->transform($body, false, null, $this->title); $this->body = wordwrap(strtr($body, $postTransformKeys), 72); # Reveal the page editor's address as REPLY-TO address only if # the user has not opted-out and the option is enabled at the # global configuration level. $adminAddress = new MailAddress($wgPasswordSender, wfMessage('emailsender')->inContentLanguage()->text()); if ($wgEnotifRevealEditorAddress && $this->editor->getEmail() != '' && $this->editor->getOption('enotifrevealaddr')) { $editorAddress = MailAddress::newFromUser($this->editor); if ($wgEnotifFromEditor) { $this->from = $editorAddress; } else { $this->from = $adminAddress; $this->replyto = $editorAddress; } } else { $this->from = $adminAddress; $this->replyto = new MailAddress($wgNoReplyAddress); } }
/** * Add content from plain text * @since 1.17 * @param $bar array * @param $text string * @return Array */ function addToSidebarPlain(&$bar, $text) { $lines = explode("\n", $text); $heading = ''; foreach ($lines as $line) { if (strpos($line, '*') !== 0) { continue; } $line = rtrim($line, "\r"); // for Windows compat if (strpos($line, '**') !== 0) { $heading = trim($line, '* '); if (!array_key_exists($heading, $bar)) { $bar[$heading] = array(); } } else { $line = trim($line, '* '); if (strpos($line, '|') !== false) { // sanity check $line = MessageCache::singleton()->transform($line, false, null, $this->getTitle()); $line = array_map('trim', explode('|', $line, 2)); if (count($line) !== 2) { // Second sanity check, could be hit by people doing // funky stuff with parserfuncs... (bug 33321) continue; } $extraAttribs = array(); $msgLink = $this->msg($line[0])->inContentLanguage(); if ($msgLink->exists()) { $link = $msgLink->text(); if ($link == '-') { continue; } } else { $link = $line[0]; } $msgText = $this->msg($line[1]); if ($msgText->exists()) { $text = $msgText->text(); } else { $text = $line[1]; } if (preg_match('/^(?i:' . wfUrlProtocols() . ')/', $link)) { $href = $link; // Parser::getExternalLinkAttribs won't work here because of the Namespace things global $wgNoFollowLinks, $wgNoFollowDomainExceptions; if ($wgNoFollowLinks && !wfMatchesDomainList($href, $wgNoFollowDomainExceptions)) { $extraAttribs['rel'] = 'nofollow'; } global $wgExternalLinkTarget; if ($wgExternalLinkTarget) { $extraAttribs['target'] = $wgExternalLinkTarget; } } else { $title = Title::newFromText($link); if ($title) { $title = $title->fixSpecialName(); $href = $title->getLinkURL(); } else { $href = 'INVALID-TITLE'; } } $bar[$heading][] = array_merge(array('text' => $text, 'href' => $href, 'id' => 'n-' . Sanitizer::escapeId(strtr($line[1], ' ', '-'), 'noninitial'), 'active' => false), $extraAttribs); } else { continue; } } } return $bar; }
/** * Get the language in which the content of this page is written. * Defaults to $wgContLang, but in certain cases it can be e.g. * $wgLang (such as special pages, which are in the user language). * * @since 1.18 * @return object Language */ public function getPageLanguage() { global $wgLang; if ($this->getNamespace() == NS_SPECIAL) { // special pages are in the user language return $wgLang; } elseif ($this->isRedirect()) { // the arrow on a redirect page is aligned according to the user language return $wgLang; } elseif ($this->isCssOrJsPage()) { // css/js should always be LTR and is, in fact, English return wfGetLangObj('en'); } elseif ($this->getNamespace() == NS_MEDIAWIKI) { // Parse mediawiki messages with correct target language list(, $lang) = MessageCache::singleton()->figureMessage($this->getText()); return wfGetLangObj($lang); } global $wgContLang; // If nothing special, it should be in the wiki content language $pageLang = $wgContLang; // Hook at the end because we don't want to override the above stuff wfRunHooks('PageContentLanguage', array($this, &$pageLang, $wgLang)); return wfGetLangObj($pageLang); }
/** * Get the language in which the content of the given page is written. * * This default implementation just returns $wgContLang (except for pages * in the MediaWiki namespace) * * Note that the pages language is not cacheable, since it may in some * cases depend on user settings. * * Also note that the page language may or may not depend on the actual content of the page, * that is, this method may load the content in order to determine the language. * * @since 1.21 * * @param Title $title The page to determine the language for. * @param Content $content The page's content, if you have it handy, to avoid reloading it. * * @return Language The page's language */ public function getPageLanguage(Title $title, Content $content = null) { global $wgContLang, $wgLang; $pageLang = $wgContLang; if ($title->getNamespace() == NS_MEDIAWIKI) { // Parse mediawiki messages with correct target language list(, $lang) = MessageCache::singleton()->figureMessage($title->getText()); $pageLang = wfGetLangObj($lang); } wfRunHooks('PageContentLanguage', array($title, &$pageLang, $wgLang)); return wfGetLangObj($pageLang); }
/** * Wrapper for what ever method we use to get message contents. * * @since 1.17 * * @return string * @throws MWException If message key array is empty. */ protected function fetchMessage() { if ($this->message === null) { $cache = MessageCache::singleton(); foreach ($this->keysToTry as $key) { $message = $cache->get($key, $this->useDatabase, $this->language); if ($message !== false && $message !== '') { break; } } // NOTE: The constructor makes sure keysToTry isn't empty, // so we know that $key and $message are initialized. $this->key = $key; $this->message = $message; } return $this->message; }
/** * Set up the global variables for a consistent environment for each test. * Ideally this should replace the global configuration entirely. */ protected function setupGlobals($opts = '', $config = '') { global $wgFileBackends; # Find out values for some special options. $lang = self::getOptionValue('language', $opts, 'en'); $variant = self::getOptionValue('variant', $opts, false); $maxtoclevel = self::getOptionValue('wgMaxTocLevel', $opts, 999); $linkHolderBatchSize = self::getOptionValue('wgLinkHolderBatchSize', $opts, 1000); $uploadDir = $this->getUploadDir(); if ($this->getCliArg('use-filebackend=')) { if (self::$backendToUse) { $backend = self::$backendToUse; } else { $name = $this->getCliArg('use-filebackend='); $useConfig = array(); foreach ($wgFileBackends as $conf) { if ($conf['name'] == $name) { $useConfig = $conf; } } $useConfig['name'] = 'local-backend'; // swap name $class = $conf['class']; self::$backendToUse = new $class($useConfig); $backend = self::$backendToUse; } } else { $backend = new FSFileBackend(array('name' => 'local-backend', 'lockManager' => 'nullLockManager', 'containerPaths' => array('local-public' => "{$uploadDir}", 'local-thumb' => "{$uploadDir}/thumb"))); } $settings = array('wgServer' => 'http://Britney-Spears', 'wgScript' => '/index.php', 'wgScriptPath' => '/', 'wgArticlePath' => '/wiki/$1', 'wgExtensionAssetsPath' => '/extensions', 'wgActionPaths' => array(), 'wgLocalFileRepo' => array('class' => 'LocalRepo', 'name' => 'local', 'url' => 'http://example.com/images', 'hashLevels' => 2, 'transformVia404' => false, 'backend' => $backend), 'wgEnableUploads' => self::getOptionValue('wgEnableUploads', $opts, true), 'wgStylePath' => '/skins', 'wgStyleSheetPath' => '/skins', 'wgSitename' => 'MediaWiki', 'wgLanguageCode' => $lang, 'wgDBprefix' => $this->db->getType() != 'oracle' ? 'unittest_' : 'ut_', 'wgRawHtml' => isset($opts['rawhtml']), 'wgLang' => null, 'wgContLang' => null, 'wgNamespacesWithSubpages' => array(0 => isset($opts['subpage'])), 'wgMaxTocLevel' => $maxtoclevel, 'wgCapitalLinks' => true, 'wgNoFollowLinks' => true, 'wgNoFollowDomainExceptions' => array(), 'wgThumbnailScriptPath' => false, 'wgUseImageResize' => false, 'wgUseTeX' => isset($opts['math']), 'wgMathDirectory' => $uploadDir . '/math', 'wgLocaltimezone' => 'UTC', 'wgAllowExternalImages' => true, 'wgUseTidy' => false, 'wgDefaultLanguageVariant' => $variant, 'wgVariantArticlePath' => false, 'wgGroupPermissions' => array('*' => array('createaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true)), 'wgNamespaceProtection' => array(NS_MEDIAWIKI => 'editinterface'), 'wgDefaultExternalStore' => array(), 'wgForeignFileRepos' => array(), 'wgLinkHolderBatchSize' => $linkHolderBatchSize, 'wgExperimentalHtmlIds' => false, 'wgExternalLinkTarget' => false, 'wgAlwaysUseTidy' => false, 'wgHtml5' => true, 'wgCleanupPresentationalAttributes' => true, 'wgWellFormedXml' => true, 'wgAllowMicrodataAttributes' => true, 'wgAdaptiveMessageCache' => true, 'wgUseDatabaseMessages' => true); if ($config) { $configLines = explode("\n", $config); foreach ($configLines as $line) { list($var, $value) = explode('=', $line, 2); $settings[$var] = eval("return {$value};"); //??? } } $this->savedGlobals = array(); foreach ($settings as $var => $val) { if (array_key_exists($var, $GLOBALS)) { $this->savedGlobals[$var] = $GLOBALS[$var]; } $GLOBALS[$var] = $val; } $langObj = Language::factory($lang); $GLOBALS['wgContLang'] = $langObj; $context = new RequestContext(); $GLOBALS['wgLang'] = $context->getLanguage(); $GLOBALS['wgMemc'] = new EmptyBagOStuff(); $GLOBALS['wgOut'] = $context->getOutput(); $GLOBALS['wgUser'] = $context->getUser(); global $wgHooks; $wgHooks['ParserTestParser'][] = 'ParserTestParserHook::setup'; $wgHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp'; MagicWord::clearCache(); RepoGroup::destroySingleton(); FileBackendGroup::destroySingleton(); # Create dummy files in storage $this->setupUploads(); # Publish the articles after we have the final language set $this->publishTestArticles(); # The entries saved into RepoGroup cache with previous globals will be wrong. RepoGroup::destroySingleton(); FileBackendGroup::destroySingleton(); MessageCache::singleton()->destroyInstance(); return $context; }
/** * Wrapper for what ever method we use to get message contents * * @return string */ protected function fetchMessage() { if (!isset($this->message)) { $cache = MessageCache::singleton(); if (is_array($this->key)) { if (!count($this->key)) { throw new MWException("Given empty message key array."); } foreach ($this->key as $key) { $message = $cache->get($key, $this->useDatabase, $this->language, false, $this->fixWhitespace); if ($message !== false && $message !== '') { break; } } $this->message = $message; } else { $this->message = $cache->get($this->key, $this->useDatabase, $this->language, false, $this->fixWhitespace); } } return $this->message; }
function addDBData() { $this->tablesUsed[] = 'site_stats'; $this->tablesUsed[] = 'interwiki'; # disabled for performance #$this->tablesUsed[] = 'image'; # Hack: insert a few Wikipedia in-project interwiki prefixes, # for testing inter-language links $this->db->insert('interwiki', array(array('iw_prefix' => 'wikipedia', 'iw_url' => 'http://en.wikipedia.org/wiki/$1', 'iw_api' => '', 'iw_wikiid' => '', 'iw_local' => 0), array('iw_prefix' => 'meatball', 'iw_url' => 'http://www.usemod.com/cgi-bin/mb.pl?$1', 'iw_api' => '', 'iw_wikiid' => '', 'iw_local' => 0), array('iw_prefix' => 'zh', 'iw_url' => 'http://zh.wikipedia.org/wiki/$1', 'iw_api' => '', 'iw_wikiid' => '', 'iw_local' => 1), array('iw_prefix' => 'es', 'iw_url' => 'http://es.wikipedia.org/wiki/$1', 'iw_api' => '', 'iw_wikiid' => '', 'iw_local' => 1), array('iw_prefix' => 'fr', 'iw_url' => 'http://fr.wikipedia.org/wiki/$1', 'iw_api' => '', 'iw_wikiid' => '', 'iw_local' => 1), array('iw_prefix' => 'ru', 'iw_url' => 'http://ru.wikipedia.org/wiki/$1', 'iw_api' => '', 'iw_wikiid' => '', 'iw_local' => 1)), __METHOD__, array('IGNORE')); # Update certain things in site_stats $this->db->insert('site_stats', array('ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1), __METHOD__); # Reinitialise the LocalisationCache to match the database state Language::getLocalisationCache()->unloadAll(); # Clear the message cache MessageCache::singleton()->clear(); $user = User::newFromId(0); LinkCache::singleton()->clear(); # Avoids the odd failure at creating the nullRevision # Upload DB table entries for files. # We will upload the actual files later. Note that if anything causes LocalFile::load() # to be triggered before then, it will break via maybeUpgrade() setting the fileExists # member to false and storing it in cache. $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Foobar.jpg')); if (!$this->db->selectField('image', '1', array('img_name' => $image->getName()))) { $image->recordUpload2('', 'Upload of some lame file', 'Some lame file', array('size' => 12345, 'width' => 1941, 'height' => 220, 'bits' => 24, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/jpeg', 'metadata' => serialize(array()), 'sha1' => wfBaseConvert('', 16, 36, 31), 'fileExists' => true), $this->db->timestamp('20010115123500'), $user); } # This image will be blacklisted in [[MediaWiki:Bad image list]] $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Bad.jpg')); if (!$this->db->selectField('image', '1', array('img_name' => $image->getName()))) { $image->recordUpload2('', 'zomgnotcensored', 'Borderline image', array('size' => 12345, 'width' => 320, 'height' => 240, 'bits' => 24, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/jpeg', 'metadata' => serialize(array()), 'sha1' => wfBaseConvert('', 16, 36, 31), 'fileExists' => true), $this->db->timestamp('20010115123500'), $user); } }
/** * Clears caches when article is deleted * * @param $title Title */ public static function onArticleDelete( $title ) { // Update existence markers on article/talk tabs... if ( $title->isTalkPage() ) { $other = $title->getSubjectPage(); } else { $other = $title->getTalkPage(); } $other->invalidateCache(); $other->purgeSquid(); $title->touchLinks(); $title->purgeSquid(); // File cache HTMLFileCache::clearFileCache( $title ); InfoAction::invalidateCache( $title ); // Messages if ( $title->getNamespace() == NS_MEDIAWIKI ) { MessageCache::singleton()->replace( $title->getDBkey(), false ); } // Images if ( $title->getNamespace() == NS_FILE ) { $update = new HTMLCacheUpdate( $title, 'imagelinks' ); $update->doUpdate(); } // User talk pages if ( $title->getNamespace() == NS_USER_TALK ) { $user = User::newFromName( $title->getText(), false ); if ( $user ) { $user->setNewtalk( false ); } } // Image redirects RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect( $title ); }
public function execute() { $params = $this->extractRequestParams(); if (is_null($params['lang'])) { $langObj = $this->getLanguage(); } elseif (!Language::isValidCode($params['lang'])) { $this->dieUsage('Invalid language code for parameter lang', 'invalidlang'); } else { $langObj = Language::factory($params['lang']); } if ($params['enableparser']) { if (!is_null($params['title'])) { $title = Title::newFromText($params['title']); if (!$title || $title->isExternal()) { $this->dieUsageMsg(['invalidtitle', $params['title']]); } } else { $title = Title::newFromText('API'); } } $prop = array_flip((array) $params['prop']); // Determine which messages should we print if (in_array('*', $params['messages'])) { $message_names = Language::getMessageKeysFor($langObj->getCode()); if ($params['includelocal']) { $message_names = array_unique(array_merge($message_names, MessageCache::singleton()->getAllMessageKeys($this->getConfig()->get('LanguageCode')))); } sort($message_names); $messages_target = $message_names; } else { $messages_target = $params['messages']; } // Filter messages that have the specified prefix // Because we sorted the message array earlier, they will appear in a clump: if (isset($params['prefix'])) { $skip = false; $messages_filtered = []; foreach ($messages_target as $message) { // === 0: must be at beginning of string (position 0) if (strpos($message, $params['prefix']) === 0) { if (!$skip) { $skip = true; } $messages_filtered[] = $message; } elseif ($skip) { break; } } $messages_target = $messages_filtered; } // Filter messages that contain specified string if (isset($params['filter'])) { $messages_filtered = []; foreach ($messages_target as $message) { // !== is used because filter can be at the beginning of the string if (strpos($message, $params['filter']) !== false) { $messages_filtered[] = $message; } } $messages_target = $messages_filtered; } // Whether we have any sort of message customisation filtering $customiseFilterEnabled = $params['customised'] !== 'all'; if ($customiseFilterEnabled) { global $wgContLang; $customisedMessages = AllMessagesTablePager::getCustomisedStatuses(array_map([$langObj, 'ucfirst'], $messages_target), $langObj->getCode(), !$langObj->equals($wgContLang)); $customised = $params['customised'] === 'modified'; } // Get all requested messages and print the result $skip = !is_null($params['from']); $useto = !is_null($params['to']); $result = $this->getResult(); foreach ($messages_target as $message) { // Skip all messages up to $params['from'] if ($skip && $message === $params['from']) { $skip = false; } if ($useto && $message > $params['to']) { break; } if (!$skip) { $a = ['name' => $message, 'normalizedname' => MessageCache::normalizeKey($message)]; $args = []; if (isset($params['args']) && count($params['args']) != 0) { $args = $params['args']; } if ($customiseFilterEnabled) { $messageIsCustomised = isset($customisedMessages['pages'][$langObj->ucfirst($message)]); if ($customised === $messageIsCustomised) { if ($customised) { $a['customised'] = true; } } else { continue; } } $msg = wfMessage($message, $args)->inLanguage($langObj); if (!$msg->exists()) { $a['missing'] = true; } else { // Check if the parser is enabled: if ($params['enableparser']) { $msgString = $msg->title($title)->text(); } else { $msgString = $msg->plain(); } if (!$params['nocontent']) { ApiResult::setContentValue($a, 'content', $msgString); } if (isset($prop['default'])) { $default = wfMessage($message)->inLanguage($langObj)->useDatabase(false); if (!$default->exists()) { $a['defaultmissing'] = true; } elseif ($default->plain() != $msgString) { $a['default'] = $default->plain(); } } } $fit = $result->addValue(['query', $this->getModuleName()], null, $a); if (!$fit) { $this->setContinueEnumParameter('from', $message); break; } } } $result->addIndexedTagName(['query', $this->getModuleName()], 'message'); }
protected function loadWikiMessages() { $dbr = wfGetDB(DB_SLAVE, array()); echo "Loading page list...\n"; $res = $dbr->select('page', '*', array('page_namespace' => NS_MEDIAWIKI), 'evaluate_messaging.php'); $rows = array(); $byRev = array(); foreach ($res as $row) { $rows[] = $row; $byRev[$row->page_latest] = false; } $res->free(); echo "Loading revisions...\n"; $res = $dbr->select('revision', '*', array('rev_id' => array_keys($byRev)), 'evaluate_messaging.php'); foreach ($res as $row) { $byRev[$row->rev_id] = $row; } $res->free(); echo "Loading contents...\n"; $i = 0; $messages = array(); foreach ($rows as $row) { list($key, $langcode) = MessageCache::singleton()->figureMessage($row->page_title); $revision = Revision::newFromRow($byRev[$row->page_latest]); $content = $revision->getRawText(); $messages[$langcode][lcfirst($key)] = $content; if (++$i % 100 == 0) { echo "."; flush(); } } echo "\n"; $this->wikiMessages = $messages; $this->saveToFile(self::WIKI_MESSAGES_CACHE, $messages); }
/** * Since wfMsg() and co suck, they don't return false if the message key they * looked up didn't exist but instead the key wrapped in <>'s, this function checks for the * nonexistence of messages by checking the MessageCache::get() result directly. * * @deprecated since 1.18. Use Message::isDisabled(). * * @param string $key The message key looked up * @return bool True if the message *doesn't* exist. */ function wfEmptyMsg($key) { wfDeprecated(__METHOD__, '1.21'); return MessageCache::singleton()->get($key, true, false) === false; }
/** * @return string Safe HTML */ function getHTML() { global $wgShowDBErrorBacktrace, $wgShowHostnames, $wgShowSQLErrors; $sorry = htmlspecialchars($this->msg('dberr-problems', 'Sorry! This site is experiencing technical difficulties.')); $again = htmlspecialchars($this->msg('dberr-again', 'Try waiting a few minutes and reloading.')); if ($wgShowHostnames || $wgShowSQLErrors) { $info = str_replace('$1', Html::element('span', array('dir' => 'ltr'), $this->error), htmlspecialchars($this->msg('dberr-info', '(Cannot access the database: $1)'))); } else { $info = htmlspecialchars($this->msg('dberr-info-hidden', '(Cannot access the database)')); } # No database access MessageCache::singleton()->disable(); $html = "<h1>{$sorry}</h1><p>{$again}</p><p><small>{$info}</small></p>"; if ($wgShowDBErrorBacktrace) { $html .= '<p>Backtrace:</p><pre>' . htmlspecialchars($this->getTraceAsString()) . '</pre>'; } $html .= '<hr />'; $html .= $this->searchForm(); return $html; }
/** * Clears caches when article is deleted * * @param Title $title */ public static function onArticleDelete(Title $title) { global $wgContLang; // Update existence markers on article/talk tabs... $other = $title->getOtherPage(); $other->purgeSquid(); $title->touchLinks(); $title->purgeSquid(); MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle($title); // File cache HTMLFileCache::clearFileCache($title); InfoAction::invalidateCache($title); // Messages if ($title->getNamespace() == NS_MEDIAWIKI) { MessageCache::singleton()->replace($title->getDBkey(), false); if ($wgContLang->hasVariants()) { $wgContLang->updateConversionTable($title); } } // Images if ($title->getNamespace() == NS_FILE) { DeferredUpdates::addUpdate(new HTMLCacheUpdate($title, 'imagelinks')); } // User talk pages if ($title->getNamespace() == NS_USER_TALK) { $user = User::newFromName($title->getText(), false); if ($user) { $user->setNewtalk(false); } } // Image redirects RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect($title); }
/** * Since wfMsg() and co suck, they don't return false if the message key they * looked up didn't exist but a XHTML string, this function checks for the * nonexistance of messages by checking the MessageCache::get() result directly. * * @param $key String: the message key looked up * @return Boolean True if the message *doesn't* exist. */ function wfEmptyMsg($key) { return MessageCache::singleton()->get($key, true, false) === false; }
/** * Get the default message text or false if the message doesn't exist * * @return string|bool */ public function getDefaultMessageText() { global $wgContLang; if ($this->getNamespace() != NS_MEDIAWIKI) { // Just in case return false; } list($name, $lang) = MessageCache::singleton()->figureMessage($wgContLang->lcfirst($this->getText())); $message = wfMessage($name)->inLanguage($lang)->useDatabase(false); if ($message->exists()) { return $message->plain(); } else { return false; } }
/** * Get the error message as HTML. This is done by parsing the wikitext error * message. * @param string $shortContext A short enclosing context message name, to * be used when there is a single error * @param string $longContext A long enclosing context message name, for a list * @return string */ public function getHTML($shortContext = false, $longContext = false) { $text = $this->getWikiText($shortContext, $longContext); $out = MessageCache::singleton()->parse($text, null, true, true); return $out instanceof ParserOutput ? $out->getText() : $out; }
/** * Parse the conversion table stored in the cache. * * The tables should be in blocks of the following form: * -{ * word => word ; * word => word ; * ... * }- * * To make the tables more manageable, subpages are allowed * and will be parsed recursively if $recursive == true. * * @param string $code Language code * @param string $subpage Subpage name * @param bool $recursive Parse subpages recursively? Defaults to true. * * @return array */ function parseCachedTable($code, $subpage = '', $recursive = true) { static $parsed = []; $key = 'Conversiontable/' . $code; if ($subpage) { $key .= '/' . $subpage; } if (array_key_exists($key, $parsed)) { return []; } $parsed[$key] = true; if ($subpage === '') { $txt = MessageCache::singleton()->getMsgFromNamespace($key, $code); } else { $txt = false; $title = Title::makeTitleSafe(NS_MEDIAWIKI, $key); if ($title && $title->exists()) { $revision = Revision::newFromTitle($title); if ($revision) { if ($revision->getContentModel() == CONTENT_MODEL_WIKITEXT) { $txt = $revision->getContent(Revision::RAW)->getNativeData(); } // @todo in the future, use a specialized content model, perhaps based on json! } } } # Nothing to parse if there's no text if ($txt === false || $txt === null || $txt === '') { return []; } // get all subpage links of the form // [[MediaWiki:Conversiontable/zh-xx/...|...]] $linkhead = $this->mLangObj->getNsText(NS_MEDIAWIKI) . ':Conversiontable'; $subs = StringUtils::explode('[[', $txt); $sublinks = []; foreach ($subs as $sub) { $link = explode(']]', $sub, 2); if (count($link) != 2) { continue; } $b = explode('|', $link[0], 2); $b = explode('/', trim($b[0]), 3); if (count($b) == 3) { $sublink = $b[2]; } else { $sublink = ''; } if ($b[0] == $linkhead && $b[1] == $code) { $sublinks[] = $sublink; } } // parse the mappings in this page $blocks = StringUtils::explode('-{', $txt); $ret = []; $first = true; foreach ($blocks as $block) { if ($first) { // Skip the part before the first -{ $first = false; continue; } $mappings = explode('}-', $block, 2)[0]; $stripped = str_replace(["'", '"', '*', '#'], '', $mappings); $table = StringUtils::explode(';', $stripped); foreach ($table as $t) { $m = explode('=>', $t, 3); if (count($m) != 2) { continue; } // trim any trailling comments starting with '//' $tt = explode('//', $m[1], 2); $ret[trim($m[0])] = trim($tt[0]); } } // recursively parse the subpages if ($recursive) { foreach ($sublinks as $link) { $s = $this->parseCachedTable($code, $link, $recursive); $ret = $s + $ret; } } if ($this->mUcfirst) { foreach ($ret as $k => $v) { $ret[$this->mLangObj->ucfirst($k)] = $this->mLangObj->ucfirst($v); } } return $ret; }
/** * This function commits all DB changes as needed before * the user can receive a response (in case commit fails) * * @param IContextSource $context * @param callable $postCommitWork [default: null] * @since 1.27 */ public static function preOutputCommit(IContextSource $context, callable $postCommitWork = null) { // Either all DBs should commit or none ignore_user_abort(true); $config = $context->getConfig(); $request = $context->getRequest(); $output = $context->getOutput(); $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); // Commit all changes $lbFactory->commitMasterChanges(__METHOD__, ['maxWriteDuration' => $config->get('MaxUserDBWriteDuration')]); wfDebug(__METHOD__ . ': primary transaction round committed'); // Run updates that need to block the user or affect output (this is the last chance) DeferredUpdates::doUpdates('enqueue', DeferredUpdates::PRESEND); wfDebug(__METHOD__ . ': pre-send deferred updates completed'); // Decide when clients block on ChronologyProtector DB position writes $urlDomainDistance = $request->wasPosted() && $output->getRedirect() && $lbFactory->hasOrMadeRecentMasterChanges(INF) ? self::getUrlDomainDistance($output->getRedirect(), $context) : false; if ($urlDomainDistance === 'local' || $urlDomainDistance === 'remote') { // OutputPage::output() will be fast; $postCommitWork will not be useful for // masking the latency of syncing DB positions accross all datacenters synchronously. // Instead, make use of the RTT time of the client follow redirects. $flags = $lbFactory::SHUTDOWN_CHRONPROT_ASYNC; $cpPosTime = microtime(true); // Client's next request should see 1+ positions with this DBMasterPos::asOf() time if ($urlDomainDistance === 'local') { // Client will stay on this domain, so set an unobtrusive cookie $expires = time() + ChronologyProtector::POSITION_TTL; $options = ['prefix' => '']; $request->response()->setCookie('cpPosTime', $cpPosTime, $expires, $options); } else { // Cookies may not work across wiki domains, so use a URL parameter $safeUrl = $lbFactory->appendPreShutdownTimeAsQuery($output->getRedirect(), $cpPosTime); $output->redirect($safeUrl); } } else { // OutputPage::output() is fairly slow; run it in $postCommitWork to mask // the latency of syncing DB positions accross all datacenters synchronously $flags = $lbFactory::SHUTDOWN_CHRONPROT_SYNC; if ($lbFactory->hasOrMadeRecentMasterChanges(INF)) { $cpPosTime = microtime(true); // Set a cookie in case the DB position store cannot sync accross datacenters. // This will at least cover the common case of the user staying on the domain. $expires = time() + ChronologyProtector::POSITION_TTL; $options = ['prefix' => '']; $request->response()->setCookie('cpPosTime', $cpPosTime, $expires, $options); } } // Record ChronologyProtector positions for DBs affected in this request at this point $lbFactory->shutdown($flags, $postCommitWork); wfDebug(__METHOD__ . ': LBFactory shutdown completed'); // Set a cookie to tell all CDN edge nodes to "stick" the user to the DC that handles this // POST request (e.g. the "master" data center). Also have the user briefly bypass CDN so // ChronologyProtector works for cacheable URLs. if ($request->wasPosted() && $lbFactory->hasOrMadeRecentMasterChanges()) { $expires = time() + $config->get('DataCenterUpdateStickTTL'); $options = ['prefix' => '']; $request->response()->setCookie('UseDC', 'master', $expires, $options); $request->response()->setCookie('UseCDNCache', 'false', $expires, $options); } // Avoid letting a few seconds of replica DB lag cause a month of stale data. This logic is // also intimately related to the value of $wgCdnReboundPurgeDelay. if ($lbFactory->laggedReplicaUsed()) { $maxAge = $config->get('CdnMaxageLagged'); $output->lowerCdnMaxage($maxAge); $request->response()->header("X-Database-Lagged: true"); wfDebugLog('replication', "Lagged DB used; CDN cache TTL limited to {$maxAge} seconds"); } // Avoid long-term cache pollution due to message cache rebuild timeouts (T133069) if (MessageCache::singleton()->isDisabled()) { $maxAge = $config->get('CdnMaxageSubstitute'); $output->lowerCdnMaxage($maxAge); $request->response()->header("X-Response-Substitute: true"); } }